Skip to content

Commit

Permalink
Add support for Packet MMAP
Browse files Browse the repository at this point in the history
  • Loading branch information
DBLouis committed Feb 9, 2024
1 parent 4ed2ea2 commit 9ff902f
Show file tree
Hide file tree
Showing 14 changed files with 711 additions and 14 deletions.
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ once_cell = { version = "1.5.2", optional = true }
# libc backend can be selected via adding `--cfg=rustix_use_libc` to
# `RUSTFLAGS` or enabling the `use-libc` cargo feature.
[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]
linux-raw-sys = { version = "0.4.12", default-features = false, features = ["general", "errno", "ioctl", "no_std", "elf"] }
linux-raw-sys = { version = "0.6.4", default-features = false, features = ["general", "errno", "ioctl", "no_std", "elf"] }
libc_errno = { package = "errno", version = "0.3.8", default-features = false, optional = true }
libc = { version = "0.2.152", default-features = false, features = ["extra_traits"], optional = true }

Expand All @@ -53,7 +53,7 @@ libc = { version = "0.2.152", default-features = false, features = ["extra_trait
# Some syscalls do not have libc wrappers, such as in `io_uring`. For these,
# the libc backend uses the linux-raw-sys ABI and `libc::syscall`.
[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]
linux-raw-sys = { version = "0.4.12", default-features = false, features = ["general", "ioctl", "no_std"] }
linux-raw-sys = { version = "0.6.4", default-features = false, features = ["general", "ioctl", "no_std"] }

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

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

# Enable `rustix::thread::*`.
thread = ["linux-raw-sys/prctl"]
Expand Down
75 changes: 75 additions & 0 deletions examples/packet.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//! Packet MMAP.

#[cfg(all(feature = "mm", feature = "net", feature = "std", target_os = "linux"))]
fn main() -> std::io::Result<()> {
use rustix::mm::{mmap, munmap, MapFlags, ProtFlags};
use rustix::net::{
bind_link, eth,
netdevice::name_to_index,
packet::{PacketReq, PacketReqAny, SocketAddrLink},
recvfrom, socket_with,
sockopt::{
get_packet_stats, set_packet_rx_ring, set_packet_tx_ring, set_packet_version,
PacketVersion,
},
AddressFamily, RecvFlags, SocketFlags, SocketType,
};
use std::{env::args, ptr};

let name = args().nth(0).unwrap();

let family = AddressFamily::PACKET;
let type_ = SocketType::RAW;
let flags = SocketFlags::empty();
let fd = socket_with(family, type_, flags, None)?;

let index = name_to_index(&fd, &name)?;

set_packet_version(&fd, PacketVersion::V2)?;

let req = PacketReq {
block_size: 4096,
block_nr: 4,
frame_size: 2048,
frame_nr: 8,
};
let size = req.block_size as usize * req.block_nr as usize;

let req = PacketReqAny::V2(req);
set_packet_rx_ring(&fd, &req)?;
set_packet_tx_ring(&fd, &req)?;

let rx = unsafe {
mmap(
ptr::null_mut(),
size * 2,
ProtFlags::READ | ProtFlags::WRITE,
MapFlags::SHARED,
&fd,
0,
)
}?;
let _tx = rx.wrapping_add(size);

let addr = SocketAddrLink::new(eth::ALL, index);
bind_link(&fd, &addr)?;

while let Ok(_) = recvfrom(&fd, &mut [], RecvFlags::empty()) {}

let stats = get_packet_stats(&fd, PacketVersion::V2)?;
println!("{:?}", stats);

unsafe { munmap(rx, size * 2) }?;

Ok(())
}

#[cfg(any(
not(feature = "mm"),
not(feature = "net"),
not(feature = "std"),
not(target_os = "linux")
))]
fn main() -> Result<(), &'static str> {
Err("This example requires --features=mm,net,std and is only supported on Linux.")
}
21 changes: 11 additions & 10 deletions src/backend/linux_raw/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,14 @@ pub(crate) use linux_raw_sys::{
cmsg_macros::*,
general::{O_CLOEXEC as SOCK_CLOEXEC, O_NONBLOCK as SOCK_NONBLOCK},
if_ether::*,
if_packet::*,
net::{
linger, msghdr, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_un, socklen_t, AF_DECnet,
__kernel_sa_family_t as sa_family_t, __kernel_sockaddr_storage as sockaddr_storage,
cmsghdr, in6_addr, in_addr, ip_mreq, ip_mreq_source, ip_mreqn, ipv6_mreq, AF_APPLETALK,
AF_ASH, AF_ATMPVC, AF_ATMSVC, AF_AX25, AF_BLUETOOTH, AF_BRIDGE, AF_CAN, AF_ECONET,
AF_IEEE802154, AF_INET, AF_INET6, AF_IPX, AF_IRDA, AF_ISDN, AF_IUCV, AF_KEY, AF_LLC,
AF_NETBEUI, AF_NETLINK, AF_NETROM, AF_PACKET, AF_PHONET, AF_PPPOX, AF_RDS, AF_ROSE,
cmsghdr, ifreq, in6_addr, in_addr, ip_mreq, ip_mreq_source, ip_mreqn, ipv6_mreq,
AF_APPLETALK, AF_ASH, AF_ATMPVC, AF_ATMSVC, AF_AX25, AF_BLUETOOTH, AF_BRIDGE, AF_CAN,
AF_ECONET, AF_IEEE802154, AF_INET, AF_INET6, AF_IPX, AF_IRDA, AF_ISDN, AF_IUCV, AF_KEY,
AF_LLC, AF_NETBEUI, AF_NETLINK, AF_NETROM, AF_PACKET, AF_PHONET, AF_PPPOX, AF_RDS, AF_ROSE,
AF_RXRPC, AF_SECURITY, AF_SNA, AF_TIPC, AF_UNIX, AF_UNSPEC, AF_WANPIPE, AF_X25, AF_XDP,
IP6T_SO_ORIGINAL_DST, IPPROTO_FRAGMENT, IPPROTO_ICMPV6, IPPROTO_MH, IPPROTO_ROUTING,
IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_FREEBIND, IPV6_MULTICAST_HOPS,
Expand All @@ -71,12 +72,12 @@ pub(crate) use linux_raw_sys::{
MSG_CMSG_CLOEXEC, MSG_CONFIRM, MSG_DONTROUTE, MSG_DONTWAIT, MSG_EOR, MSG_ERRQUEUE,
MSG_MORE, MSG_NOSIGNAL, MSG_OOB, MSG_PEEK, MSG_TRUNC, MSG_WAITALL, SCM_CREDENTIALS,
SCM_RIGHTS, SHUT_RD, SHUT_RDWR, SHUT_WR, SOCK_DGRAM, SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET,
SOCK_STREAM, SOL_SOCKET, SOL_XDP, SO_ACCEPTCONN, SO_BROADCAST, SO_COOKIE, SO_DOMAIN,
SO_ERROR, SO_INCOMING_CPU, SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE, SO_ORIGINAL_DST,
SO_PASSCRED, SO_PROTOCOL, SO_RCVBUF, SO_RCVTIMEO_NEW, SO_RCVTIMEO_NEW as SO_RCVTIMEO,
SO_RCVTIMEO_OLD, SO_REUSEADDR, SO_REUSEPORT, SO_SNDBUF, SO_SNDTIMEO_NEW,
SO_SNDTIMEO_NEW as SO_SNDTIMEO, SO_SNDTIMEO_OLD, SO_TYPE, TCP_CONGESTION, TCP_CORK,
TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_NODELAY, TCP_QUICKACK,
SOCK_STREAM, SOL_PACKET, SOL_SOCKET, SOL_XDP, SO_ACCEPTCONN, SO_BROADCAST, SO_COOKIE,
SO_DOMAIN, SO_ERROR, SO_INCOMING_CPU, SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE,
SO_ORIGINAL_DST, SO_PASSCRED, SO_PROTOCOL, SO_RCVBUF, SO_RCVTIMEO_NEW,
SO_RCVTIMEO_NEW as SO_RCVTIMEO, SO_RCVTIMEO_OLD, SO_REUSEADDR, SO_REUSEPORT, SO_SNDBUF,
SO_SNDTIMEO_NEW, SO_SNDTIMEO_NEW as SO_SNDTIMEO, SO_SNDTIMEO_OLD, SO_TYPE, TCP_CONGESTION,
TCP_CORK, TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_NODELAY, TCP_QUICKACK,
TCP_THIN_LINEAR_TIMEOUTS, TCP_USER_TIMEOUT,
},
netlink::*,
Expand Down
60 changes: 59 additions & 1 deletion src/backend/linux_raw/net/sockopt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ use crate::fd::BorrowedFd;
#[cfg(feature = "alloc")]
use crate::ffi::CStr;
use crate::io;
use crate::net::sockopt::Timeout;
#[cfg(target_os = "linux")]
use crate::net::packet::{PacketReqAny, PacketStats, PacketStats3, PacketStatsAny};
use crate::net::sockopt::{PacketVersion, Timeout};
#[cfg(target_os = "linux")]
use crate::net::xdp::{XdpMmapOffsets, XdpOptionsFlags, XdpRingOffset, XdpStatistics, XdpUmemReg};
use crate::net::{
Expand Down Expand Up @@ -967,6 +969,62 @@ pub(crate) fn get_xdp_options(fd: BorrowedFd<'_>) -> io::Result<XdpOptionsFlags>
getsockopt(fd, c::SOL_XDP, c::XDP_OPTIONS)
}

#[cfg(target_os = "linux")]
#[inline]
pub(crate) fn set_packet_rx_ring(fd: BorrowedFd<'_>, value: &PacketReqAny) -> io::Result<()> {
match value {
PacketReqAny::V1(value) | PacketReqAny::V2(value) => {
setsockopt(fd, c::SOL_PACKET, c::PACKET_RX_RING, value)
}
PacketReqAny::V3(value) => setsockopt(fd, c::SOL_PACKET, c::PACKET_RX_RING, value),
}
}

#[cfg(target_os = "linux")]
#[inline]
pub(crate) fn set_packet_tx_ring(fd: BorrowedFd<'_>, value: &PacketReqAny) -> io::Result<()> {
match value {
PacketReqAny::V1(value) | PacketReqAny::V2(value) => {
setsockopt(fd, c::SOL_PACKET, c::PACKET_TX_RING, value)
}
PacketReqAny::V3(value) => setsockopt(fd, c::SOL_PACKET, c::PACKET_TX_RING, value),
}
}

#[cfg(target_os = "linux")]
#[inline]
pub(crate) fn set_packet_version(fd: BorrowedFd<'_>, value: PacketVersion) -> io::Result<()> {
setsockopt(fd, c::SOL_PACKET, c::PACKET_VERSION, value)
}

#[cfg(target_os = "linux")]
#[inline]
pub(crate) fn get_packet_version(fd: BorrowedFd<'_>) -> io::Result<PacketVersion> {
getsockopt(fd, c::SOL_PACKET, c::PACKET_VERSION)
}

#[cfg(target_os = "linux")]
#[inline]
pub(crate) fn get_packet_stats(
fd: BorrowedFd<'_>,
version: PacketVersion,
) -> io::Result<PacketStatsAny> {
match version {
PacketVersion::V1 => {
let stats: PacketStats = getsockopt(fd, c::SOL_PACKET, c::PACKET_STATISTICS)?;
Ok(PacketStatsAny::V1(stats))
}
PacketVersion::V2 => {
let stats: PacketStats = getsockopt(fd, c::SOL_PACKET, c::PACKET_STATISTICS)?;
Ok(PacketStatsAny::V2(stats))
}
PacketVersion::V3 => {
let stats: PacketStats3 = getsockopt(fd, c::SOL_PACKET, c::PACKET_STATISTICS)?;
Ok(PacketStatsAny::V3(stats))
}
}
}

#[inline]
fn to_ip_mreq(multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> c::ip_mreq {
c::ip_mreq {
Expand Down
31 changes: 31 additions & 0 deletions src/backend/linux_raw/net/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ use crate::backend::conv::{
use crate::fd::{BorrowedFd, OwnedFd};
use crate::io::{self, IoSlice, IoSliceMut};
#[cfg(target_os = "linux")]
use crate::net::packet::SocketAddrLink;
#[cfg(target_os = "linux")]
use crate::net::xdp::SocketAddrXdp;
use crate::net::{
AddressFamily, Protocol, RecvAncillaryBuffer, RecvMsgReturn, SendAncillaryBuffer, Shutdown,
Expand Down Expand Up @@ -439,6 +441,18 @@ pub(crate) fn sendmsg_xdp(
})
}

#[cfg(target_os = "linux")]
#[inline]
pub(crate) fn sendmsg_link(
_sockfd: BorrowedFd<'_>,
_addr: &SocketAddrLink,
_iov: &[IoSlice<'_>],
_control: &mut SendAncillaryBuffer<'_, '_, '_>,
_msg_flags: SendFlags,
) -> io::Result<usize> {
todo!()
}

#[inline]
pub(crate) fn shutdown(fd: BorrowedFd<'_>, how: Shutdown) -> io::Result<()> {
#[cfg(not(target_arch = "x86"))]
Expand Down Expand Up @@ -660,6 +674,17 @@ pub(crate) fn sendto_xdp(
}
}

#[cfg(target_os = "linux")]
#[inline]
pub(crate) fn sendto_link(
_fd: BorrowedFd<'_>,
_buf: &[u8],
_flags: SendFlags,
_addr: &SocketAddrLink,
) -> io::Result<usize> {
todo!()
}

#[inline]
pub(crate) unsafe fn recv(
fd: BorrowedFd<'_>,
Expand Down Expand Up @@ -931,6 +956,12 @@ pub(crate) fn bind_xdp(fd: BorrowedFd<'_>, addr: &SocketAddrXdp) -> io::Result<(
}
}

#[cfg(target_os = "linux")]
#[inline]
pub(crate) fn bind_link(_fd: BorrowedFd<'_>, _addr: &SocketAddrLink) -> io::Result<()> {
todo!()
}

#[inline]
pub(crate) fn connect_v4(fd: BorrowedFd<'_>, addr: &SocketAddrV4) -> io::Result<()> {
#[cfg(not(target_arch = "x86"))]
Expand Down
10 changes: 10 additions & 0 deletions src/backend/linux_raw/net/write_sockaddr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use crate::backend::c;
#[cfg(target_os = "linux")]
use crate::net::packet::SocketAddrLink;
#[cfg(target_os = "linux")]
use crate::net::xdp::SocketAddrXdp;
use crate::net::{SocketAddrAny, SocketAddrStorage, SocketAddrUnix, SocketAddrV4, SocketAddrV6};
use core::mem::size_of;
Expand All @@ -18,6 +20,8 @@ pub(crate) unsafe fn write_sockaddr(
SocketAddrAny::Unix(unix) => write_sockaddr_unix(unix, storage),
#[cfg(target_os = "linux")]
SocketAddrAny::Xdp(xdp) => write_sockaddr_xdp(xdp, storage),
#[cfg(target_os = "linux")]
SocketAddrAny::Link(link) => write_sockaddr_link(link, storage),
}
}

Expand Down Expand Up @@ -80,3 +84,9 @@ unsafe fn write_sockaddr_xdp(xdp: &SocketAddrXdp, storage: *mut SocketAddrStorag
core::ptr::write(storage.cast(), encoded);
size_of::<c::sockaddr_xdp>()
}

#[cfg(target_os = "linux")]
unsafe fn write_sockaddr_link(link: &SocketAddrLink, storage: *mut SocketAddrStorage) -> usize {
core::ptr::write(storage.cast(), link);
size_of::<c::sockaddr_ll>()
}
2 changes: 2 additions & 0 deletions src/net/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ mod wsa;

#[cfg(linux_kernel)]
pub mod netdevice;
#[cfg(linux_kernel)]
pub mod packet;
pub mod sockopt;

pub use crate::maybe_polyfill::net::{
Expand Down
Loading

0 comments on commit 9ff902f

Please sign in to comment.