From d829f5084e913a2d15b5b26d497e245a65d58acf Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 29 Mar 2025 15:08:13 +0000 Subject: [PATCH] socket::sockopt AttachReusePortCbpf for Linux addition. Set a BPF program to the socket to set how packets are handled within the reuseport group. --- changelog/2621.added.md | 1 + src/sys/socket/sockopt.rs | 12 ++++++++++++ test/sys/test_sockopt.rs | 25 +++++++++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 changelog/2621.added.md diff --git a/changelog/2621.added.md b/changelog/2621.added.md new file mode 100644 index 0000000000..ad8b8c415e --- /dev/null +++ b/changelog/2621.added.md @@ -0,0 +1 @@ +Added `socket::sockopt::AttachReusePortCbpf` for Linux diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index f30844881d..5dcf199d23 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -1269,6 +1269,18 @@ sockopt_impl!( libc::SO_EXCLBIND, bool ); +#[cfg(target_os = "linux")] +sockopt_impl!( + /// To be used with `ReusePort`, + /// we can then attach a BPF (classic) + /// to set how the packets are assigned + /// to the socket (e.g. cpu distribution). + AttachReusePortCbpf, + SetOnly, + libc::SOL_SOCKET, + libc::SO_ATTACH_REUSEPORT_CBPF, + libc::sock_fprog +); #[allow(missing_docs)] // Not documented by Linux! diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index 27e08411b5..afd5aff7ea 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -1194,3 +1194,28 @@ fn test_solfilter() { assert_eq!(Err(Errno::ENOENT), setsockopt(&s, attach, data)); assert_eq!(Err(Errno::ENOENT), setsockopt(&s, detach, data)); } + +#[cfg(target_os = "linux")] +#[test] +pub fn test_so_attach_reuseport_cbpf() { + let fd = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + setsockopt(&fd, sockopt::ReusePort, &true).unwrap(); + setsockopt(&fd, sockopt::ReuseAddr, &true).unwrap(); + let mut flt: [libc::sock_filter; 2] = unsafe { std::mem::zeroed() }; + flt[0].code = (libc::BPF_LD | libc::BPF_W | libc::BPF_ABS) as u16; + flt[0].k = (libc::SKF_AD_OFF + libc::SKF_AD_CPU) as u32; + flt[1].code = (libc::BPF_RET | 0x10) as u16; + let fp = libc::sock_fprog { + len: flt.len() as u16, + filter: flt.as_mut_ptr(), + }; + setsockopt(&fd, sockopt::AttachReusePortCbpf, &fp).unwrap_or_else(|e| { + assert_eq!(e, nix::errno::Errno::ENOPROTOOPT); + }); +}