Skip to content

Commit 7ed8ee9

Browse files
authored
Add ip_mtu_discover and ipv6_mtu_discover socket options (#1466)
1 parent 7798f03 commit 7ed8ee9

File tree

5 files changed

+248
-5
lines changed

5 files changed

+248
-5
lines changed

src/backend/libc/net/sockopt.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use crate::fd::BorrowedFd;
1414
use crate::ffi::CStr;
1515
use crate::io;
1616
use crate::net::sockopt::Timeout;
17+
#[cfg(linux_kernel)]
18+
use crate::net::sockopt::{Ipv4PathMtuDiscovery, Ipv6PathMtuDiscovery};
1719
#[cfg(target_os = "linux")]
1820
use crate::net::xdp::{XdpMmapOffsets, XdpOptionsFlags, XdpRingOffset, XdpStatistics, XdpUmemReg};
1921
#[cfg(not(any(
@@ -504,6 +506,36 @@ pub(crate) fn ipv6_mtu(fd: BorrowedFd<'_>) -> io::Result<u32> {
504506
getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_MTU)
505507
}
506508

509+
#[cfg(linux_kernel)]
510+
#[inline]
511+
pub(crate) fn set_ip_mtu_discover(
512+
fd: BorrowedFd<'_>,
513+
value: Ipv4PathMtuDiscovery,
514+
) -> io::Result<()> {
515+
setsockopt(fd, c::IPPROTO_IP, c::IP_MTU_DISCOVER, value)
516+
}
517+
518+
#[cfg(linux_kernel)]
519+
#[inline]
520+
pub(crate) fn ip_mtu_discover(fd: BorrowedFd<'_>) -> io::Result<Ipv4PathMtuDiscovery> {
521+
getsockopt(fd, c::IPPROTO_IP, c::IP_MTU_DISCOVER)
522+
}
523+
524+
#[cfg(linux_kernel)]
525+
#[inline]
526+
pub(crate) fn set_ipv6_mtu_discover(
527+
fd: BorrowedFd<'_>,
528+
value: Ipv6PathMtuDiscovery,
529+
) -> io::Result<()> {
530+
setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_MTU_DISCOVER, value)
531+
}
532+
533+
#[cfg(linux_kernel)]
534+
#[inline]
535+
pub(crate) fn ipv6_mtu_discover(fd: BorrowedFd<'_>) -> io::Result<Ipv6PathMtuDiscovery> {
536+
getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_MTU_DISCOVER)
537+
}
538+
507539
#[inline]
508540
pub(crate) fn set_ip_multicast_if(fd: BorrowedFd<'_>, value: &Ipv4Addr) -> io::Result<()> {
509541
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
@@ -13,7 +13,7 @@ use crate::fd::BorrowedFd;
1313
#[cfg(feature = "alloc")]
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(all(target_os = "linux", feature = "time"))]
@@ -29,7 +29,9 @@ use alloc::string::String;
2929
use core::mem::{size_of, MaybeUninit};
3030
use core::time::Duration;
3131
use linux_raw_sys::general::{__kernel_old_timeval, __kernel_sock_timeval};
32-
use linux_raw_sys::net::{IPV6_MTU, IPV6_MULTICAST_IF, IP_MTU, IP_MULTICAST_IF};
32+
use linux_raw_sys::net::{
33+
IPV6_MTU, IPV6_MTU_DISCOVER, IPV6_MULTICAST_IF, IP_MTU, IP_MTU_DISCOVER, IP_MULTICAST_IF,
34+
};
3335
#[cfg(target_os = "linux")]
3436
use linux_raw_sys::xdp::{xdp_mmap_offsets, xdp_statistics, xdp_statistics_v1};
3537
#[cfg(target_arch = "x86")]
@@ -466,6 +468,32 @@ pub(crate) fn ipv6_mtu(fd: BorrowedFd<'_>) -> io::Result<u32> {
466468
getsockopt(fd, c::IPPROTO_IPV6, IPV6_MTU)
467469
}
468470

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

src/net/sockopt.rs

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,110 @@ pub enum Timeout {
202202
Send = c::SO_SNDTIMEO as _,
203203
}
204204

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

797+
/// `setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, value)`
798+
///
799+
/// See the [module-level documentation] for more.
800+
///
801+
/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions
802+
#[cfg(linux_kernel)]
803+
#[inline]
804+
#[doc(alias = "IP_MTU_DISCOVER")]
805+
pub fn set_ip_mtu_discover<Fd: AsFd>(fd: Fd, value: Ipv4PathMtuDiscovery) -> io::Result<()> {
806+
backend::net::sockopt::set_ip_mtu_discover(fd.as_fd(), value)
807+
}
808+
809+
/// `getsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER)`
810+
///
811+
/// See the [module-level documentation] for more.
812+
///
813+
/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions
814+
#[cfg(linux_kernel)]
815+
#[inline]
816+
#[doc(alias = "IP_MTU_DISCOVER")]
817+
pub fn ip_mtu_discover<Fd: AsFd>(fd: Fd) -> io::Result<Ipv4PathMtuDiscovery> {
818+
backend::net::sockopt::ip_mtu_discover(fd.as_fd())
819+
}
820+
821+
/// `setsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, value)`
822+
///
823+
/// See the [module-level documentation] for more.
824+
///
825+
/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions
826+
#[cfg(linux_kernel)]
827+
#[inline]
828+
#[doc(alias = "IPV6_MTU_DISCOVER")]
829+
pub fn set_ipv6_mtu_discover<Fd: AsFd>(fd: Fd, value: Ipv6PathMtuDiscovery) -> io::Result<()> {
830+
backend::net::sockopt::set_ipv6_mtu_discover(fd.as_fd(), value)
831+
}
832+
833+
/// `getsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER)`
834+
///
835+
/// See the [module-level documentation] for more.
836+
///
837+
/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions
838+
#[cfg(linux_kernel)]
839+
#[inline]
840+
#[doc(alias = "IPV6_MTU_DISCOVER")]
841+
pub fn ipv6_mtu_discover<Fd: AsFd>(fd: Fd) -> io::Result<Ipv6PathMtuDiscovery> {
842+
backend::net::sockopt::ipv6_mtu_discover(fd.as_fd())
843+
}
844+
693845
/// `setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, value)`
694846
///
695847
/// See the [module-level documentation] for more.

tests/net/sockopt.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,34 @@ fn test_socketopts_ipv6_mtu() {
570570
}
571571
}
572572

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

0 commit comments

Comments
 (0)