Skip to content

Commit 9ff902f

Browse files
committed
Add support for Packet MMAP
1 parent 4ed2ea2 commit 9ff902f

File tree

14 files changed

+711
-14
lines changed

14 files changed

+711
-14
lines changed

Cargo.toml

+3-3
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ once_cell = { version = "1.5.2", optional = true }
3636
# libc backend can be selected via adding `--cfg=rustix_use_libc` to
3737
# `RUSTFLAGS` or enabling the `use-libc` cargo feature.
3838
[target.'cfg(all(not(rustix_use_libc), not(miri), target_os = "linux", target_endian = "little", any(target_arch = "arm", all(target_arch = "aarch64", target_pointer_width = "64"), target_arch = "riscv64", all(rustix_use_experimental_asm, target_arch = "powerpc64"), all(rustix_use_experimental_asm, target_arch = "mips"), all(rustix_use_experimental_asm, target_arch = "mips32r6"), all(rustix_use_experimental_asm, target_arch = "mips64"), all(rustix_use_experimental_asm, target_arch = "mips64r6"), target_arch = "x86", all(target_arch = "x86_64", target_pointer_width = "64"))))'.dependencies]
39-
linux-raw-sys = { version = "0.4.12", default-features = false, features = ["general", "errno", "ioctl", "no_std", "elf"] }
39+
linux-raw-sys = { version = "0.6.4", default-features = false, features = ["general", "errno", "ioctl", "no_std", "elf"] }
4040
libc_errno = { package = "errno", version = "0.3.8", default-features = false, optional = true }
4141
libc = { version = "0.2.152", default-features = false, features = ["extra_traits"], optional = true }
4242

@@ -53,7 +53,7 @@ libc = { version = "0.2.152", default-features = false, features = ["extra_trait
5353
# Some syscalls do not have libc wrappers, such as in `io_uring`. For these,
5454
# the libc backend uses the linux-raw-sys ABI and `libc::syscall`.
5555
[target.'cfg(all(any(target_os = "android", target_os = "linux"), any(rustix_use_libc, miri, not(all(target_os = "linux", target_endian = "little", any(target_arch = "arm", all(target_arch = "aarch64", target_pointer_width = "64"), target_arch = "riscv64", all(rustix_use_experimental_asm, target_arch = "powerpc64"), all(rustix_use_experimental_asm, target_arch = "mips"), all(rustix_use_experimental_asm, target_arch = "mips32r6"), all(rustix_use_experimental_asm, target_arch = "mips64"), all(rustix_use_experimental_asm, target_arch = "mips64r6"), target_arch = "x86", all(target_arch = "x86_64", target_pointer_width = "64")))))))'.dependencies]
56-
linux-raw-sys = { version = "0.4.12", default-features = false, features = ["general", "ioctl", "no_std"] }
56+
linux-raw-sys = { version = "0.6.4", default-features = false, features = ["general", "ioctl", "no_std"] }
5757

5858
# For the libc backend on Windows, use the Winsock API in windows-sys.
5959
[target.'cfg(windows)'.dependencies.windows-sys]
@@ -141,7 +141,7 @@ io_uring = ["event", "fs", "net", "linux-raw-sys/io_uring"]
141141
mount = []
142142

143143
# Enable `rustix::net::*`.
144-
net = ["linux-raw-sys/net", "linux-raw-sys/netlink", "linux-raw-sys/if_ether", "linux-raw-sys/xdp"]
144+
net = ["linux-raw-sys/net", "linux-raw-sys/netlink", "linux-raw-sys/if_ether", "linux-raw-sys/if_packet", "linux-raw-sys/xdp"]
145145

146146
# Enable `rustix::thread::*`.
147147
thread = ["linux-raw-sys/prctl"]

examples/packet.rs

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//! Packet MMAP.
2+
3+
#[cfg(all(feature = "mm", feature = "net", feature = "std", target_os = "linux"))]
4+
fn main() -> std::io::Result<()> {
5+
use rustix::mm::{mmap, munmap, MapFlags, ProtFlags};
6+
use rustix::net::{
7+
bind_link, eth,
8+
netdevice::name_to_index,
9+
packet::{PacketReq, PacketReqAny, SocketAddrLink},
10+
recvfrom, socket_with,
11+
sockopt::{
12+
get_packet_stats, set_packet_rx_ring, set_packet_tx_ring, set_packet_version,
13+
PacketVersion,
14+
},
15+
AddressFamily, RecvFlags, SocketFlags, SocketType,
16+
};
17+
use std::{env::args, ptr};
18+
19+
let name = args().nth(0).unwrap();
20+
21+
let family = AddressFamily::PACKET;
22+
let type_ = SocketType::RAW;
23+
let flags = SocketFlags::empty();
24+
let fd = socket_with(family, type_, flags, None)?;
25+
26+
let index = name_to_index(&fd, &name)?;
27+
28+
set_packet_version(&fd, PacketVersion::V2)?;
29+
30+
let req = PacketReq {
31+
block_size: 4096,
32+
block_nr: 4,
33+
frame_size: 2048,
34+
frame_nr: 8,
35+
};
36+
let size = req.block_size as usize * req.block_nr as usize;
37+
38+
let req = PacketReqAny::V2(req);
39+
set_packet_rx_ring(&fd, &req)?;
40+
set_packet_tx_ring(&fd, &req)?;
41+
42+
let rx = unsafe {
43+
mmap(
44+
ptr::null_mut(),
45+
size * 2,
46+
ProtFlags::READ | ProtFlags::WRITE,
47+
MapFlags::SHARED,
48+
&fd,
49+
0,
50+
)
51+
}?;
52+
let _tx = rx.wrapping_add(size);
53+
54+
let addr = SocketAddrLink::new(eth::ALL, index);
55+
bind_link(&fd, &addr)?;
56+
57+
while let Ok(_) = recvfrom(&fd, &mut [], RecvFlags::empty()) {}
58+
59+
let stats = get_packet_stats(&fd, PacketVersion::V2)?;
60+
println!("{:?}", stats);
61+
62+
unsafe { munmap(rx, size * 2) }?;
63+
64+
Ok(())
65+
}
66+
67+
#[cfg(any(
68+
not(feature = "mm"),
69+
not(feature = "net"),
70+
not(feature = "std"),
71+
not(target_os = "linux")
72+
))]
73+
fn main() -> Result<(), &'static str> {
74+
Err("This example requires --features=mm,net,std and is only supported on Linux.")
75+
}

src/backend/linux_raw/c.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,14 @@ pub(crate) use linux_raw_sys::{
5555
cmsg_macros::*,
5656
general::{O_CLOEXEC as SOCK_CLOEXEC, O_NONBLOCK as SOCK_NONBLOCK},
5757
if_ether::*,
58+
if_packet::*,
5859
net::{
5960
linger, msghdr, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_un, socklen_t, AF_DECnet,
6061
__kernel_sa_family_t as sa_family_t, __kernel_sockaddr_storage as sockaddr_storage,
61-
cmsghdr, in6_addr, in_addr, ip_mreq, ip_mreq_source, ip_mreqn, ipv6_mreq, AF_APPLETALK,
62-
AF_ASH, AF_ATMPVC, AF_ATMSVC, AF_AX25, AF_BLUETOOTH, AF_BRIDGE, AF_CAN, AF_ECONET,
63-
AF_IEEE802154, AF_INET, AF_INET6, AF_IPX, AF_IRDA, AF_ISDN, AF_IUCV, AF_KEY, AF_LLC,
64-
AF_NETBEUI, AF_NETLINK, AF_NETROM, AF_PACKET, AF_PHONET, AF_PPPOX, AF_RDS, AF_ROSE,
62+
cmsghdr, ifreq, in6_addr, in_addr, ip_mreq, ip_mreq_source, ip_mreqn, ipv6_mreq,
63+
AF_APPLETALK, AF_ASH, AF_ATMPVC, AF_ATMSVC, AF_AX25, AF_BLUETOOTH, AF_BRIDGE, AF_CAN,
64+
AF_ECONET, AF_IEEE802154, AF_INET, AF_INET6, AF_IPX, AF_IRDA, AF_ISDN, AF_IUCV, AF_KEY,
65+
AF_LLC, AF_NETBEUI, AF_NETLINK, AF_NETROM, AF_PACKET, AF_PHONET, AF_PPPOX, AF_RDS, AF_ROSE,
6566
AF_RXRPC, AF_SECURITY, AF_SNA, AF_TIPC, AF_UNIX, AF_UNSPEC, AF_WANPIPE, AF_X25, AF_XDP,
6667
IP6T_SO_ORIGINAL_DST, IPPROTO_FRAGMENT, IPPROTO_ICMPV6, IPPROTO_MH, IPPROTO_ROUTING,
6768
IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_FREEBIND, IPV6_MULTICAST_HOPS,
@@ -71,12 +72,12 @@ pub(crate) use linux_raw_sys::{
7172
MSG_CMSG_CLOEXEC, MSG_CONFIRM, MSG_DONTROUTE, MSG_DONTWAIT, MSG_EOR, MSG_ERRQUEUE,
7273
MSG_MORE, MSG_NOSIGNAL, MSG_OOB, MSG_PEEK, MSG_TRUNC, MSG_WAITALL, SCM_CREDENTIALS,
7374
SCM_RIGHTS, SHUT_RD, SHUT_RDWR, SHUT_WR, SOCK_DGRAM, SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET,
74-
SOCK_STREAM, SOL_SOCKET, SOL_XDP, SO_ACCEPTCONN, SO_BROADCAST, SO_COOKIE, SO_DOMAIN,
75-
SO_ERROR, SO_INCOMING_CPU, SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE, SO_ORIGINAL_DST,
76-
SO_PASSCRED, SO_PROTOCOL, SO_RCVBUF, SO_RCVTIMEO_NEW, SO_RCVTIMEO_NEW as SO_RCVTIMEO,
77-
SO_RCVTIMEO_OLD, SO_REUSEADDR, SO_REUSEPORT, SO_SNDBUF, SO_SNDTIMEO_NEW,
78-
SO_SNDTIMEO_NEW as SO_SNDTIMEO, SO_SNDTIMEO_OLD, SO_TYPE, TCP_CONGESTION, TCP_CORK,
79-
TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_NODELAY, TCP_QUICKACK,
75+
SOCK_STREAM, SOL_PACKET, SOL_SOCKET, SOL_XDP, SO_ACCEPTCONN, SO_BROADCAST, SO_COOKIE,
76+
SO_DOMAIN, SO_ERROR, SO_INCOMING_CPU, SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE,
77+
SO_ORIGINAL_DST, SO_PASSCRED, SO_PROTOCOL, SO_RCVBUF, SO_RCVTIMEO_NEW,
78+
SO_RCVTIMEO_NEW as SO_RCVTIMEO, SO_RCVTIMEO_OLD, SO_REUSEADDR, SO_REUSEPORT, SO_SNDBUF,
79+
SO_SNDTIMEO_NEW, SO_SNDTIMEO_NEW as SO_SNDTIMEO, SO_SNDTIMEO_OLD, SO_TYPE, TCP_CONGESTION,
80+
TCP_CORK, TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_NODELAY, TCP_QUICKACK,
8081
TCP_THIN_LINEAR_TIMEOUTS, TCP_USER_TIMEOUT,
8182
},
8283
netlink::*,

src/backend/linux_raw/net/sockopt.rs

+59-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ use crate::fd::BorrowedFd;
1111
#[cfg(feature = "alloc")]
1212
use crate::ffi::CStr;
1313
use crate::io;
14-
use crate::net::sockopt::Timeout;
14+
#[cfg(target_os = "linux")]
15+
use crate::net::packet::{PacketReqAny, PacketStats, PacketStats3, PacketStatsAny};
16+
use crate::net::sockopt::{PacketVersion, Timeout};
1517
#[cfg(target_os = "linux")]
1618
use crate::net::xdp::{XdpMmapOffsets, XdpOptionsFlags, XdpRingOffset, XdpStatistics, XdpUmemReg};
1719
use crate::net::{
@@ -967,6 +969,62 @@ pub(crate) fn get_xdp_options(fd: BorrowedFd<'_>) -> io::Result<XdpOptionsFlags>
967969
getsockopt(fd, c::SOL_XDP, c::XDP_OPTIONS)
968970
}
969971

972+
#[cfg(target_os = "linux")]
973+
#[inline]
974+
pub(crate) fn set_packet_rx_ring(fd: BorrowedFd<'_>, value: &PacketReqAny) -> io::Result<()> {
975+
match value {
976+
PacketReqAny::V1(value) | PacketReqAny::V2(value) => {
977+
setsockopt(fd, c::SOL_PACKET, c::PACKET_RX_RING, value)
978+
}
979+
PacketReqAny::V3(value) => setsockopt(fd, c::SOL_PACKET, c::PACKET_RX_RING, value),
980+
}
981+
}
982+
983+
#[cfg(target_os = "linux")]
984+
#[inline]
985+
pub(crate) fn set_packet_tx_ring(fd: BorrowedFd<'_>, value: &PacketReqAny) -> io::Result<()> {
986+
match value {
987+
PacketReqAny::V1(value) | PacketReqAny::V2(value) => {
988+
setsockopt(fd, c::SOL_PACKET, c::PACKET_TX_RING, value)
989+
}
990+
PacketReqAny::V3(value) => setsockopt(fd, c::SOL_PACKET, c::PACKET_TX_RING, value),
991+
}
992+
}
993+
994+
#[cfg(target_os = "linux")]
995+
#[inline]
996+
pub(crate) fn set_packet_version(fd: BorrowedFd<'_>, value: PacketVersion) -> io::Result<()> {
997+
setsockopt(fd, c::SOL_PACKET, c::PACKET_VERSION, value)
998+
}
999+
1000+
#[cfg(target_os = "linux")]
1001+
#[inline]
1002+
pub(crate) fn get_packet_version(fd: BorrowedFd<'_>) -> io::Result<PacketVersion> {
1003+
getsockopt(fd, c::SOL_PACKET, c::PACKET_VERSION)
1004+
}
1005+
1006+
#[cfg(target_os = "linux")]
1007+
#[inline]
1008+
pub(crate) fn get_packet_stats(
1009+
fd: BorrowedFd<'_>,
1010+
version: PacketVersion,
1011+
) -> io::Result<PacketStatsAny> {
1012+
match version {
1013+
PacketVersion::V1 => {
1014+
let stats: PacketStats = getsockopt(fd, c::SOL_PACKET, c::PACKET_STATISTICS)?;
1015+
Ok(PacketStatsAny::V1(stats))
1016+
}
1017+
PacketVersion::V2 => {
1018+
let stats: PacketStats = getsockopt(fd, c::SOL_PACKET, c::PACKET_STATISTICS)?;
1019+
Ok(PacketStatsAny::V2(stats))
1020+
}
1021+
PacketVersion::V3 => {
1022+
let stats: PacketStats3 = getsockopt(fd, c::SOL_PACKET, c::PACKET_STATISTICS)?;
1023+
Ok(PacketStatsAny::V3(stats))
1024+
}
1025+
}
1026+
}
1027+
9701028
#[inline]
9711029
fn to_ip_mreq(multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> c::ip_mreq {
9721030
c::ip_mreq {

src/backend/linux_raw/net/syscalls.rs

+31
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ use crate::backend::conv::{
2323
use crate::fd::{BorrowedFd, OwnedFd};
2424
use crate::io::{self, IoSlice, IoSliceMut};
2525
#[cfg(target_os = "linux")]
26+
use crate::net::packet::SocketAddrLink;
27+
#[cfg(target_os = "linux")]
2628
use crate::net::xdp::SocketAddrXdp;
2729
use crate::net::{
2830
AddressFamily, Protocol, RecvAncillaryBuffer, RecvMsgReturn, SendAncillaryBuffer, Shutdown,
@@ -439,6 +441,18 @@ pub(crate) fn sendmsg_xdp(
439441
})
440442
}
441443

444+
#[cfg(target_os = "linux")]
445+
#[inline]
446+
pub(crate) fn sendmsg_link(
447+
_sockfd: BorrowedFd<'_>,
448+
_addr: &SocketAddrLink,
449+
_iov: &[IoSlice<'_>],
450+
_control: &mut SendAncillaryBuffer<'_, '_, '_>,
451+
_msg_flags: SendFlags,
452+
) -> io::Result<usize> {
453+
todo!()
454+
}
455+
442456
#[inline]
443457
pub(crate) fn shutdown(fd: BorrowedFd<'_>, how: Shutdown) -> io::Result<()> {
444458
#[cfg(not(target_arch = "x86"))]
@@ -660,6 +674,17 @@ pub(crate) fn sendto_xdp(
660674
}
661675
}
662676

677+
#[cfg(target_os = "linux")]
678+
#[inline]
679+
pub(crate) fn sendto_link(
680+
_fd: BorrowedFd<'_>,
681+
_buf: &[u8],
682+
_flags: SendFlags,
683+
_addr: &SocketAddrLink,
684+
) -> io::Result<usize> {
685+
todo!()
686+
}
687+
663688
#[inline]
664689
pub(crate) unsafe fn recv(
665690
fd: BorrowedFd<'_>,
@@ -931,6 +956,12 @@ pub(crate) fn bind_xdp(fd: BorrowedFd<'_>, addr: &SocketAddrXdp) -> io::Result<(
931956
}
932957
}
933958

959+
#[cfg(target_os = "linux")]
960+
#[inline]
961+
pub(crate) fn bind_link(_fd: BorrowedFd<'_>, _addr: &SocketAddrLink) -> io::Result<()> {
962+
todo!()
963+
}
964+
934965
#[inline]
935966
pub(crate) fn connect_v4(fd: BorrowedFd<'_>, addr: &SocketAddrV4) -> io::Result<()> {
936967
#[cfg(not(target_arch = "x86"))]

src/backend/linux_raw/net/write_sockaddr.rs

+10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
use crate::backend::c;
66
#[cfg(target_os = "linux")]
7+
use crate::net::packet::SocketAddrLink;
8+
#[cfg(target_os = "linux")]
79
use crate::net::xdp::SocketAddrXdp;
810
use crate::net::{SocketAddrAny, SocketAddrStorage, SocketAddrUnix, SocketAddrV4, SocketAddrV6};
911
use core::mem::size_of;
@@ -18,6 +20,8 @@ pub(crate) unsafe fn write_sockaddr(
1820
SocketAddrAny::Unix(unix) => write_sockaddr_unix(unix, storage),
1921
#[cfg(target_os = "linux")]
2022
SocketAddrAny::Xdp(xdp) => write_sockaddr_xdp(xdp, storage),
23+
#[cfg(target_os = "linux")]
24+
SocketAddrAny::Link(link) => write_sockaddr_link(link, storage),
2125
}
2226
}
2327

@@ -80,3 +84,9 @@ unsafe fn write_sockaddr_xdp(xdp: &SocketAddrXdp, storage: *mut SocketAddrStorag
8084
core::ptr::write(storage.cast(), encoded);
8185
size_of::<c::sockaddr_xdp>()
8286
}
87+
88+
#[cfg(target_os = "linux")]
89+
unsafe fn write_sockaddr_link(link: &SocketAddrLink, storage: *mut SocketAddrStorage) -> usize {
90+
core::ptr::write(storage.cast(), link);
91+
size_of::<c::sockaddr_ll>()
92+
}

src/net/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ mod wsa;
1818

1919
#[cfg(linux_kernel)]
2020
pub mod netdevice;
21+
#[cfg(linux_kernel)]
22+
pub mod packet;
2123
pub mod sockopt;
2224

2325
pub use crate::maybe_polyfill::net::{

0 commit comments

Comments
 (0)