Skip to content

Commit 6b46e92

Browse files
committed
Add ip_mtu_discover and ipv6_mtu_discover socket options
1 parent 0a6cb07 commit 6b46e92

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(
@@ -502,6 +504,36 @@ pub(crate) fn ipv6_mtu(fd: BorrowedFd<'_>) -> io::Result<u32> {
502504
getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_MTU)
503505
}
504506

507+
#[cfg(linux_kernel)]
508+
#[inline]
509+
pub(crate) fn set_ip_mtu_discover(
510+
fd: BorrowedFd<'_>,
511+
value: Ipv4PathMtuDiscovery,
512+
) -> io::Result<()> {
513+
setsockopt(fd, c::IPPROTO_IP, c::IP_MTU_DISCOVER, value)
514+
}
515+
516+
#[cfg(linux_kernel)]
517+
#[inline]
518+
pub(crate) fn ip_mtu_discover(fd: BorrowedFd<'_>) -> io::Result<Ipv4PathMtuDiscovery> {
519+
getsockopt(fd, c::IPPROTO_IP, c::IP_MTU_DISCOVER)
520+
}
521+
522+
#[cfg(linux_kernel)]
523+
#[inline]
524+
pub(crate) fn set_ipv6_mtu_discover(
525+
fd: BorrowedFd<'_>,
526+
value: Ipv6PathMtuDiscovery,
527+
) -> io::Result<()> {
528+
setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_MTU_DISCOVER, value)
529+
}
530+
531+
#[cfg(linux_kernel)]
532+
#[inline]
533+
pub(crate) fn ipv6_mtu_discover(fd: BorrowedFd<'_>) -> io::Result<Ipv6PathMtuDiscovery> {
534+
getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_MTU_DISCOVER)
535+
}
536+
505537
#[inline]
506538
pub(crate) fn set_ip_multicast_if(fd: BorrowedFd<'_>, value: &Ipv4Addr) -> io::Result<()> {
507539
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: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,110 @@ pub enum Timeout {
198198
Send = c::SO_SNDTIMEO as _,
199199
}
200200

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

793+
/// `setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, value)`
794+
///
795+
/// See the [module-level documentation] for more.
796+
///
797+
/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions
798+
#[cfg(linux_kernel)]
799+
#[inline]
800+
#[doc(alias = "IP_MTU_DISCOVER")]
801+
pub fn set_ip_mtu_discover<Fd: AsFd>(fd: Fd, value: Ipv4PathMtuDiscovery) -> io::Result<()> {
802+
backend::net::sockopt::set_ip_mtu_discover(fd.as_fd(), value)
803+
}
804+
805+
/// `getsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER)`
806+
///
807+
/// See the [module-level documentation] for more.
808+
///
809+
/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions
810+
#[cfg(linux_kernel)]
811+
#[inline]
812+
#[doc(alias = "IP_MTU_DISCOVER")]
813+
pub fn ip_mtu_discover<Fd: AsFd>(fd: Fd) -> io::Result<Ipv4PathMtuDiscovery> {
814+
backend::net::sockopt::ip_mtu_discover(fd.as_fd())
815+
}
816+
817+
/// `setsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, value)`
818+
///
819+
/// See the [module-level documentation] for more.
820+
///
821+
/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions
822+
#[cfg(linux_kernel)]
823+
#[inline]
824+
#[doc(alias = "IPV6_MTU_DISCOVER")]
825+
pub fn set_ipv6_mtu_discover<Fd: AsFd>(fd: Fd, value: Ipv6PathMtuDiscovery) -> io::Result<()> {
826+
backend::net::sockopt::set_ipv6_mtu_discover(fd.as_fd(), value)
827+
}
828+
829+
/// `getsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER)`
830+
///
831+
/// See the [module-level documentation] for more.
832+
///
833+
/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions
834+
#[cfg(linux_kernel)]
835+
#[inline]
836+
#[doc(alias = "IPV6_MTU_DISCOVER")]
837+
pub fn ipv6_mtu_discover<Fd: AsFd>(fd: Fd) -> io::Result<Ipv6PathMtuDiscovery> {
838+
backend::net::sockopt::ipv6_mtu_discover(fd.as_fd())
839+
}
840+
689841
/// `setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, value)`
690842
///
691843
/// 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
@@ -565,6 +565,34 @@ fn test_socketopts_ipv6_mtu() {
565565
}
566566
}
567567

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

0 commit comments

Comments
 (0)