Skip to content

Commit 4375f96

Browse files
committed
Add ip_mtu_discover and ipv6_mtu_discover socket options
1 parent 92466d9 commit 4375f96

File tree

5 files changed

+232
-6
lines changed

5 files changed

+232
-6
lines changed

src/backend/libc/net/sockopt.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::fd::BorrowedFd;
1313
))]
1414
use crate::ffi::CStr;
1515
use crate::io;
16-
use crate::net::sockopt::Timeout;
16+
use crate::net::sockopt::{Ipv4PathMtuDiscovery, Ipv6PathMtuDiscovery, Timeout};
1717
#[cfg(target_os = "linux")]
1818
use crate::net::xdp::{XdpMmapOffsets, XdpOptionsFlags, XdpRingOffset, XdpStatistics, XdpUmemReg};
1919
#[cfg(not(any(
@@ -502,6 +502,32 @@ pub(crate) fn ipv6_mtu(fd: BorrowedFd<'_>) -> io::Result<u32> {
502502
getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_MTU)
503503
}
504504

505+
#[inline]
506+
pub(crate) fn set_ip_mtu_discover(
507+
fd: BorrowedFd<'_>,
508+
value: Ipv4PathMtuDiscovery,
509+
) -> io::Result<()> {
510+
setsockopt(fd, c::IPPROTO_IP, c::IP_MTU_DISCOVER, value)
511+
}
512+
513+
#[inline]
514+
pub(crate) fn ip_mtu_discover(fd: BorrowedFd<'_>) -> io::Result<Ipv4PathMtuDiscovery> {
515+
getsockopt(fd, c::IPPROTO_IP, c::IP_MTU_DISCOVER)
516+
}
517+
518+
#[inline]
519+
pub(crate) fn set_ipv6_mtu_discover(
520+
fd: BorrowedFd<'_>,
521+
value: Ipv6PathMtuDiscovery,
522+
) -> io::Result<()> {
523+
setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_MTU_DISCOVER, value)
524+
}
525+
526+
#[inline]
527+
pub(crate) fn ipv6_mtu_discover(fd: BorrowedFd<'_>) -> io::Result<Ipv6PathMtuDiscovery> {
528+
getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_MTU_DISCOVER)
529+
}
530+
505531
#[inline]
506532
pub(crate) fn set_ip_multicast_if(fd: BorrowedFd<'_>, value: &Ipv4Addr) -> io::Result<()> {
507533
setsockopt(fd, c::IPPROTO_IP, c::IP_MULTICAST_IF, to_imr_addr(value))

src/backend/linux_raw/c.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,12 @@ pub(crate) use linux_raw_sys::{
8787
AF_RXRPC, AF_SECURITY, AF_SNA, AF_TIPC, AF_UNIX, AF_UNSPEC, AF_VSOCK, AF_WANPIPE, AF_X25,
8888
AF_XDP, IP6T_SO_ORIGINAL_DST, IPPROTO_FRAGMENT, IPPROTO_ICMPV6, IPPROTO_MH,
8989
IPPROTO_ROUTING, IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_FREEBIND,
90-
IPV6_MULTICAST_HOPS, IPV6_MULTICAST_LOOP, IPV6_RECVTCLASS, IPV6_TCLASS, IPV6_UNICAST_HOPS,
91-
IPV6_V6ONLY, IP_ADD_MEMBERSHIP, IP_ADD_SOURCE_MEMBERSHIP, IP_DROP_MEMBERSHIP,
92-
IP_DROP_SOURCE_MEMBERSHIP, IP_FREEBIND, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_RECVTOS,
90+
IPV6_MULTICAST_HOPS, IPV6_MULTICAST_LOOP, IPV6_PMTUDISC_DO, IPV6_PMTUDISC_DONT,
91+
IPV6_PMTUDISC_INTERFACE, IPV6_PMTUDISC_OMIT, IPV6_PMTUDISC_PROBE, IPV6_PMTUDISC_WANT,
92+
IPV6_RECVTCLASS, IPV6_TCLASS, IPV6_UNICAST_HOPS, IPV6_V6ONLY, IP_ADD_MEMBERSHIP,
93+
IP_ADD_SOURCE_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP, IP_FREEBIND,
94+
IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_PMTUDISC_DO, IP_PMTUDISC_DONT,
95+
IP_PMTUDISC_INTERFACE, IP_PMTUDISC_OMIT, IP_PMTUDISC_PROBE, IP_PMTUDISC_WANT, IP_RECVTOS,
9396
IP_TOS, IP_TTL, MSG_CMSG_CLOEXEC, MSG_CONFIRM, MSG_CTRUNC, MSG_DONTROUTE, MSG_DONTWAIT,
9497
MSG_EOR, MSG_ERRQUEUE, MSG_MORE, MSG_NOSIGNAL, MSG_OOB, MSG_PEEK, MSG_TRUNC, MSG_WAITALL,
9598
SCM_CREDENTIALS, SCM_RIGHTS, SHUT_RD, SHUT_RDWR, SHUT_WR, SOCK_DGRAM, SOCK_RAW, SOCK_RDM,

src/backend/linux_raw/net/sockopt.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::fd::BorrowedFd;
1111
#[cfg(feature = "alloc")]
1212
use crate::ffi::CStr;
1313
use crate::io;
14-
use crate::net::sockopt::Timeout;
14+
use crate::net::sockopt::{Ipv4PathMtuDiscovery, Ipv6PathMtuDiscovery, Timeout};
1515
#[cfg(target_os = "linux")]
1616
use crate::net::xdp::{XdpMmapOffsets, XdpOptionsFlags, XdpRingOffset, XdpStatistics, XdpUmemReg};
1717
use crate::net::{
@@ -25,7 +25,9 @@ use alloc::string::String;
2525
use core::mem::{size_of, MaybeUninit};
2626
use core::time::Duration;
2727
use linux_raw_sys::general::{__kernel_old_timeval, __kernel_sock_timeval};
28-
use linux_raw_sys::net::{IPV6_MTU, IPV6_MULTICAST_IF, IP_MTU, IP_MULTICAST_IF};
28+
use linux_raw_sys::net::{
29+
IPV6_MTU, IPV6_MTU_DISCOVER, IPV6_MULTICAST_IF, IP_MTU, IP_MTU_DISCOVER, IP_MULTICAST_IF,
30+
};
2931
#[cfg(target_os = "linux")]
3032
use linux_raw_sys::xdp::{xdp_mmap_offsets, xdp_statistics, xdp_statistics_v1};
3133
#[cfg(target_arch = "x86")]
@@ -462,6 +464,32 @@ pub(crate) fn ipv6_mtu(fd: BorrowedFd<'_>) -> io::Result<u32> {
462464
getsockopt(fd, c::IPPROTO_IPV6, IPV6_MTU)
463465
}
464466

467+
#[inline]
468+
pub(crate) fn set_ip_mtu_discover(
469+
fd: BorrowedFd<'_>,
470+
value: Ipv4PathMtuDiscovery,
471+
) -> io::Result<()> {
472+
setsockopt(fd, c::IPPROTO_IP, IP_MTU_DISCOVER, value)
473+
}
474+
475+
#[inline]
476+
pub(crate) fn ip_mtu_discover(fd: BorrowedFd<'_>) -> io::Result<Ipv4PathMtuDiscovery> {
477+
getsockopt(fd, c::IPPROTO_IP, IP_MTU_DISCOVER)
478+
}
479+
480+
#[inline]
481+
pub(crate) fn set_ipv6_mtu_discover(
482+
fd: BorrowedFd<'_>,
483+
value: Ipv6PathMtuDiscovery,
484+
) -> io::Result<()> {
485+
setsockopt(fd, c::IPPROTO_IPV6, IPV6_MTU_DISCOVER, value)
486+
}
487+
488+
#[inline]
489+
pub(crate) fn ipv6_mtu_discover(fd: BorrowedFd<'_>) -> io::Result<Ipv6PathMtuDiscovery> {
490+
getsockopt(fd, c::IPPROTO_IPV6, IPV6_MTU_DISCOVER)
491+
}
492+
465493
#[inline]
466494
pub(crate) fn set_ip_multicast_if_with_ifindex(
467495
fd: BorrowedFd<'_>,

src/net/sockopt.rs

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,104 @@ pub enum Timeout {
198198
Send = c::SO_SNDTIMEO as _,
199199
}
200200

201+
/// A type for holding raw integer IPv4 Path MTU Discovery options.
202+
pub type RawIpv4PathMtuDiscovery = i32;
203+
204+
/// IPv4 Path MTU Discovery option values (`IP_PMTUDISC_*`) for use with
205+
/// [`set_ip_mtu_discover`] and [`ip_mtu_discover`].
206+
///
207+
/// # References
208+
/// - [Linux]
209+
/// - [Linux INET header]
210+
///
211+
/// [Linux]: https://man7.org/linux/man-pages/man7/ip.7.html
212+
/// [Linux INET header]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/in.h?h=v6.14#n135
213+
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
214+
#[repr(transparent)]
215+
pub struct Ipv4PathMtuDiscovery(RawIpv4PathMtuDiscovery);
216+
217+
impl Ipv4PathMtuDiscovery {
218+
/// `IP_PMTUDISC_DONT`
219+
#[doc(alias = "IP_PMTUDISC_DONT")]
220+
pub const DONT: Self = Self(c::IP_PMTUDISC_DONT as _);
221+
/// `IP_PMTUDISC_WANT`
222+
#[doc(alias = "IP_PMTUDISC_WANT")]
223+
pub const WANT: Self = Self(c::IP_PMTUDISC_WANT as _);
224+
/// `IP_PMTUDISC_DO`
225+
#[doc(alias = "IP_PMTUDISC_DO")]
226+
pub const DO: Self = Self(c::IP_PMTUDISC_DO as _);
227+
/// `IP_PMTUDISC_PROBE`
228+
#[doc(alias = "IP_PMTUDISC_PROBE")]
229+
pub const PROBE: Self = Self(c::IP_PMTUDISC_PROBE as _);
230+
/// `IP_PMTUDISC_INTERFACE`
231+
#[doc(alias = "IP_PMTUDISC_INTERFACE")]
232+
pub const INTERFACE: Self = Self(c::IP_PMTUDISC_INTERFACE as _);
233+
/// `IP_PMTUDISC_OMIT`
234+
#[doc(alias = "IP_PMTUDISC_OMIT")]
235+
pub const OMIT: Self = Self(c::IP_PMTUDISC_OMIT as _);
236+
237+
/// Constructs an option from a raw integer.
238+
#[inline]
239+
pub const fn from_raw(raw: RawIpv4PathMtuDiscovery) -> Self {
240+
Self(raw)
241+
}
242+
243+
/// Returns the raw integer for this option.
244+
#[inline]
245+
pub const fn as_raw(self) -> RawIpv4PathMtuDiscovery {
246+
self.0
247+
}
248+
}
249+
250+
/// A type for holding raw integer IPv6 Path MTU Discovery options.
251+
pub type RawIpv6PathMtuDiscovery = i32;
252+
253+
/// IPv6 Path MTU Discovery option values (`IPV6_PMTUDISC_*`) for use with
254+
/// [`set_ipv6_mtu_discover`] and [`ipv6_mtu_discover`].
255+
///
256+
/// # References
257+
/// - [Linux]
258+
/// - [Linux INET6 header]
259+
///
260+
/// [Linux]: https://man7.org/linux/man-pages/man7/ipv6.7.html
261+
/// [Linux INET6 header]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/in6.h?h=v6.14#n185
262+
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
263+
#[repr(transparent)]
264+
pub struct Ipv6PathMtuDiscovery(RawIpv6PathMtuDiscovery);
265+
266+
impl Ipv6PathMtuDiscovery {
267+
/// `IPV6_PMTUDISC_DONT`
268+
#[doc(alias = "IPV6_PMTUDISC_DONT")]
269+
pub const DONT: Self = Self(c::IPV6_PMTUDISC_DONT as _);
270+
/// `IPV6_PMTUDISC_WANT`
271+
#[doc(alias = "IPV6_PMTUDISC_WANT")]
272+
pub const WANT: Self = Self(c::IPV6_PMTUDISC_WANT as _);
273+
/// `IPV6_PMTUDISC_DO`
274+
#[doc(alias = "IPV6_PMTUDISC_DO")]
275+
pub const DO: Self = Self(c::IPV6_PMTUDISC_DO as _);
276+
/// `IPV6_PMTUDISC_PROBE`
277+
#[doc(alias = "IPV6_PMTUDISC_PROBE")]
278+
pub const PROBE: Self = Self(c::IPV6_PMTUDISC_PROBE as _);
279+
/// `IPV6_PMTUDISC_INTERFACE`
280+
#[doc(alias = "IPV6_PMTUDISC_INTERFACE")]
281+
pub const INTERFACE: Self = Self(c::IPV6_PMTUDISC_INTERFACE as _);
282+
/// `IPV6_PMTUDISC_OMIT`
283+
#[doc(alias = "IPV6_PMTUDISC_OMIT")]
284+
pub const OMIT: Self = Self(c::IPV6_PMTUDISC_OMIT as _);
285+
286+
/// Constructs an option from a raw integer.
287+
#[inline]
288+
pub const fn from_raw(raw: RawIpv6PathMtuDiscovery) -> Self {
289+
Self(raw)
290+
}
291+
292+
/// Returns the raw integer for this option.
293+
#[inline]
294+
pub const fn as_raw(self) -> RawIpv6PathMtuDiscovery {
295+
self.0
296+
}
297+
}
298+
201299
/// `getsockopt(fd, SOL_SOCKET, SO_TYPE)`—Returns the type of a socket.
202300
///
203301
/// See the [module-level documentation] for more.
@@ -686,6 +784,50 @@ pub fn ipv6_mtu<Fd: AsFd>(fd: Fd) -> io::Result<u32> {
686784
backend::net::sockopt::ipv6_mtu(fd.as_fd())
687785
}
688786

787+
/// `setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, value)`
788+
///
789+
/// See the [module-level documentation] for more.
790+
///
791+
/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions
792+
#[inline]
793+
#[doc(alias = "IP_MTU_DISCOVER")]
794+
pub fn set_ip_mtu_discover<Fd: AsFd>(fd: Fd, value: Ipv4PathMtuDiscovery) -> io::Result<()> {
795+
backend::net::sockopt::set_ip_mtu_discover(fd.as_fd(), value)
796+
}
797+
798+
/// `getsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER)`
799+
///
800+
/// See the [module-level documentation] for more.
801+
///
802+
/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions
803+
#[inline]
804+
#[doc(alias = "IP_MTU_DISCOVER")]
805+
pub fn ip_mtu_discover<Fd: AsFd>(fd: Fd) -> io::Result<Ipv4PathMtuDiscovery> {
806+
backend::net::sockopt::ip_mtu_discover(fd.as_fd())
807+
}
808+
809+
/// `setsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, value)`
810+
///
811+
/// See the [module-level documentation] for more.
812+
///
813+
/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions
814+
#[inline]
815+
#[doc(alias = "IPV6_MTU_DISCOVER")]
816+
pub fn set_ipv6_mtu_discover<Fd: AsFd>(fd: Fd, value: Ipv6PathMtuDiscovery) -> io::Result<()> {
817+
backend::net::sockopt::set_ipv6_mtu_discover(fd.as_fd(), value)
818+
}
819+
820+
/// `getsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER)`
821+
///
822+
/// See the [module-level documentation] for more.
823+
///
824+
/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions
825+
#[inline]
826+
#[doc(alias = "IPV6_MTU_DISCOVER")]
827+
pub fn ipv6_mtu_discover<Fd: AsFd>(fd: Fd) -> io::Result<Ipv6PathMtuDiscovery> {
828+
backend::net::sockopt::ipv6_mtu_discover(fd.as_fd())
829+
}
830+
689831
/// `setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, value)`
690832
///
691833
/// See the [module-level documentation] for more.

tests/net/sockopt.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,33 @@ fn test_socketopts_ipv6_mtu() {
565565
}
566566
}
567567

568+
#[test]
569+
fn test_ip_mtu_discover() {
570+
crate::init();
571+
572+
// IPv4
573+
{
574+
use sockopt::Ipv4PathMtuDiscovery as P;
575+
576+
let s = rustix::net::socket(AddressFamily::INET, SocketType::DGRAM, None).unwrap();
577+
for val in [P::DONT, P::WANT, P::DO, P::PROBE, P::INTERFACE, P::OMIT] {
578+
sockopt::set_ip_mtu_discover(&s, val).unwrap();
579+
assert_eq!(sockopt::ip_mtu_discover(&s), Ok(val));
580+
}
581+
}
582+
583+
// IPv6
584+
{
585+
use sockopt::Ipv6PathMtuDiscovery as P;
586+
587+
let s = rustix::net::socket(AddressFamily::INET6, SocketType::DGRAM, None).unwrap();
588+
for val in [P::DONT, P::WANT, P::DO, P::PROBE, P::INTERFACE, P::OMIT] {
589+
sockopt::set_ipv6_mtu_discover(&s, val).unwrap();
590+
assert_eq!(sockopt::ipv6_mtu_discover(&s), Ok(val));
591+
}
592+
}
593+
}
594+
568595
#[test]
569596
fn test_sockopts_multicast_ifv4() {
570597
crate::init();

0 commit comments

Comments
 (0)