From 01a74db5bd79d18a1b61fc6d4c479642da01ccac Mon Sep 17 00:00:00 2001 From: arctic-alpaca <67190338+arctic-alpaca@users.noreply.github.com> Date: Thu, 7 Dec 2023 15:44:56 +0100 Subject: [PATCH] aya: Add `bpf_map_delete_elem` for `XskMap` --- aya/src/maps/xdp/xsk_map.rs | 21 ++++++++++++++++++++- test/integration-test/src/tests/xdp.rs | 19 ++++++++++++++++--- xtask/public-api/aya.txt | 2 ++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/aya/src/maps/xdp/xsk_map.rs b/aya/src/maps/xdp/xsk_map.rs index 95c593cc3..40cc2a582 100644 --- a/aya/src/maps/xdp/xsk_map.rs +++ b/aya/src/maps/xdp/xsk_map.rs @@ -7,7 +7,7 @@ use std::{ use crate::{ maps::{check_bounds, check_kv_size, MapData, MapError}, - sys::{bpf_map_update_elem, SyscallError}, + sys::{bpf_map_delete_elem, bpf_map_update_elem, SyscallError}, }; /// An array of AF_XDP sockets. @@ -78,4 +78,23 @@ impl> XskMap { )?; Ok(()) } + + /// Removes the `AF_XDP` socket stored at `index` from the map. + /// + /// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`] + /// if `bpf_map_update_elem` fails. + pub fn clear_index(&mut self, index: u32) -> Result<(), MapError> { + let data = self.inner.borrow_mut(); + check_bounds(data, index)?; + let fd = data.fd().as_fd(); + bpf_map_delete_elem(fd, &index) + .map(|_| ()) + .map_err(|(_, io_error)| { + SyscallError { + call: "bpf_map_delete_elem", + io_error, + } + .into() + }) + } } diff --git a/test/integration-test/src/tests/xdp.rs b/test/integration-test/src/tests/xdp.rs index 5a9859d5a..4ce63f78a 100644 --- a/test/integration-test/src/tests/xdp.rs +++ b/test/integration-test/src/tests/xdp.rs @@ -29,7 +29,7 @@ fn af_xdp() { // So this needs to be page aligned. Pages are 4k on all mainstream architectures except for // Apple Silicon which uses 16k pages. So let's align on that for tests to run natively there. #[repr(C, align(16384))] - struct PacketMap(MaybeUninit<[u8; 4096]>); + struct PacketMap(MaybeUninit<[u8; 2 * 4096]>); // Safety: don't access alloc down the line. let mut alloc = Box::new(PacketMap(MaybeUninit::uninit())); @@ -58,10 +58,12 @@ fn af_xdp() { socks.set(0, rx.as_raw_fd(), 0).unwrap(); let frame = umem.frame(BufIdx(0)).unwrap(); + let frame1 = umem.frame(BufIdx(1)).unwrap(); - // Produce a frame to be filled by the kernel - let mut writer = fq_cq.fill(1); + // Produce two frames to be filled by the kernel + let mut writer = fq_cq.fill(2); writer.insert_once(frame.offset); + writer.insert_once(frame1.offset); writer.commit(); let sock = UdpSocket::bind("127.0.0.1:0").unwrap(); @@ -82,6 +84,17 @@ fn af_xdp() { assert_eq!(&udp[0..2], port.to_be_bytes().as_slice()); // Source assert_eq!(&udp[2..4], 1777u16.to_be_bytes().as_slice()); // Dest assert_eq!(payload, b"hello AF_XDP"); + + assert_eq!(rx.available(), 1); + // Removes socket from map, no more packets will be redirected. + socks.clear_index(0).unwrap(); + assert_eq!(rx.available(), 1); + sock.send_to(b"hello AF_XDP", "127.0.0.1:1777").unwrap(); + assert_eq!(rx.available(), 1); + // Adds socket to map again, packets will be redirected again. + socks.set(0, rx.as_raw_fd(), 0).unwrap(); + sock.send_to(b"hello AF_XDP", "127.0.0.1:1777").unwrap(); + assert_eq!(rx.available(), 2); } #[test] diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index 108c051fa..3543d3716 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -1083,6 +1083,7 @@ pub fn aya::maps::XskMap::len(&self) -> u32 impl> aya::maps::XskMap pub fn aya::maps::XskMap::pin>(self, path: P) -> core::result::Result<(), aya::pin::PinError> impl> aya::maps::XskMap +pub fn aya::maps::XskMap::clear_index(&mut self, index: u32) -> core::result::Result<(), aya::maps::MapError> pub fn aya::maps::XskMap::set(&mut self, index: u32, socket_fd: impl std::os::fd::raw::AsRawFd, flags: u64) -> core::result::Result<(), aya::maps::MapError> impl core::convert::TryFrom for aya::maps::XskMap pub type aya::maps::XskMap::Error = aya::maps::MapError @@ -2422,6 +2423,7 @@ pub fn aya::maps::XskMap::len(&self) -> u32 impl> aya::maps::XskMap pub fn aya::maps::XskMap::pin>(self, path: P) -> core::result::Result<(), aya::pin::PinError> impl> aya::maps::XskMap +pub fn aya::maps::XskMap::clear_index(&mut self, index: u32) -> core::result::Result<(), aya::maps::MapError> pub fn aya::maps::XskMap::set(&mut self, index: u32, socket_fd: impl std::os::fd::raw::AsRawFd, flags: u64) -> core::result::Result<(), aya::maps::MapError> impl core::convert::TryFrom for aya::maps::XskMap pub type aya::maps::XskMap::Error = aya::maps::MapError