Skip to main content

zenith_linux/
xsk.rs

1//! AF_XDP Socket 管理
2//!
3//! 封装 AF_XDP Socket 的创建、配置、绑定和生命周期管理:
4//! - Socket 创建(AF_XDP, SOCK_RAW)
5//! - Socket 选项配置(SO_RCVBUF, SO_SNDBUF, XDP_MMAP_OFFSETS 等)
6//! - 绑定到网卡队列(bind)
7//! - 与 UMEM 和 Ring 集成
8//!
9//! # 设计原则
10//! - 单 Owner:每个 XskSocket 由一个 Worker 独占拥有
11//! - 零堆分配热路径:批量操作使用预分配缓冲区
12//! - 类型安全:使用 XdpDesc(内核 xdp_desc)而非裸 u64
13//!
14//! # unsafe 使用
15//! 本文件封装 AF_XDP 系统调用(socket/bind/close/setsockopt 等)
16//! 是 crate 内部四个被精确放开 `#[allow(unsafe_code)]` 的文件之一。
17
18#![allow(unsafe_code)]
19
20use crate::descriptor::{Descriptor, DescriptorEngine, XdpDesc};
21use crate::error::{LinuxError, Result, UmemError, XskError};
22use crate::ring::{RingOffsets, RingType, XskRing};
23use crate::umem::UmemManager;
24use std::sync::atomic::{AtomicBool, Ordering};
25use std::sync::Arc;
26
27/// Fill Ring 预填的分块大小(避免大块堆分配,栈上数组批量入队)
28const PREFILL_CHUNK: usize = 64;
29
30/// 构造 `xdp_umem_reg` 注册参数(纯函数,便于单测)
31///
32/// 对应内核 UAPI `struct xdp_umem_reg`(include/uapi/linux/if_xdp.h):
33/// - `addr`:UMEM 映射区基址(用户态虚拟地址)
34/// - `len`:UMEM 总字节数
35/// - `chunk_size`:帧大小(必须 2 的幂且 ≥ 2048)
36/// - `headroom`:帧头预留
37/// - `flags`/`tx_metadata_len`:保留字段,置 0(不启用 TX metadata)
38fn build_umem_reg(addr: *const u8, len: usize, chunk_size: u32, headroom: u32) -> libc::xdp_umem_reg {
39    libc::xdp_umem_reg {
40        addr: addr as u64,
41        len: len as u64,
42        chunk_size,
43        headroom,
44        flags: 0,
45        tx_metadata_len: 0,
46    }
47}
48
49/// 将内核 `xdp_ring_offset` 转换为 [`RingOffsets`](纯函数,便于单测)
50///
51/// `len` 为该 ring 的 mmap 总字节数:`desc + ring_size * sizeof(XdpDesc)`,
52/// 与内核 `xsk_mmap` 期望的映射长度一致。
53fn to_ring_offsets(k: &libc::xdp_ring_offset, ring_size: u32) -> RingOffsets {
54    RingOffsets {
55        producer: k.producer,
56        consumer: k.consumer,
57        desc: k.desc,
58        flags: k.flags,
59        len: k.desc + u64::from(ring_size) * std::mem::size_of::<XdpDesc>() as u64,
60    }
61}
62
63/// bind() 四环 mmap 局部 RAII 守卫
64///
65/// 修复「四环 mmap 任一失败时已成功的裸 base 泄漏」:每张成功的 ring mmap
66/// 逐张登记进守卫;Drop 时对未 disarm 的条目执行 munmap。映射成功移交
67/// `XskRing`(所有权归 KernelRing、由其 Drop munmap)后才 disarm 摘除,
68/// 保证任何 `?` 提前返回路径都精确回收前序裸映射、且绝不 double-munmap
69/// 已移交的映射。
70#[derive(Debug)]
71struct RingMmapGuard {
72    /// 已登记映射(登记顺序 = RX → TX → FILL → COMPLETION)
73    entries: Vec<RingMmapEntry>,
74}
75
76/// 单张待回收 ring mmap 的登记条目
77#[derive(Debug)]
78struct RingMmapEntry {
79    /// mmap 基址
80    base: *mut u8,
81    /// mmap 字节数
82    len: usize,
83    /// 已移交 XskRing(不再由本守卫回收)
84    disarmed: bool,
85}
86
87impl RingMmapGuard {
88    /// 创建空守卫
89    fn new() -> Self {
90        Self {
91            entries: Vec::new(),
92        }
93    }
94
95    /// 登记一张成功映射,返回其登记序号(后续 `disarm` 凭序号摘除)
96    fn register(&mut self, base: *mut u8, len: usize) -> usize {
97        self.entries.push(RingMmapEntry {
98            base,
99            len,
100            disarmed: false,
101        });
102        self.entries.len() - 1
103    }
104
105    /// 摘除登记(映射所有权已移交 XskRing/KernelRing,此后由其 Drop munmap)
106    ///
107    /// 序号为 `register` 返回值;非法序号静默忽略(防御,不 panic)。
108    fn disarm(&mut self, idx: usize) {
109        if let Some(entry) = self.entries.get_mut(idx) {
110            entry.disarmed = true;
111        }
112    }
113}
114
115impl Drop for RingMmapGuard {
116    fn drop(&mut self) {
117        for entry in &self.entries {
118            if entry.disarmed || entry.base.is_null() {
119                continue;
120            }
121            // SAFETY 不变量由 guard_unmap 收口执行(见该函数 SAFETY 注释)。
122            guard_unmap(entry.base, entry.len);
123        }
124    }
125}
126
127/// 守卫回收单条映射的收口点。
128///
129/// 生产构建:真实 `munmap`。
130/// 单元测试构建:若线程开启 [`GUARD_TEST_STUB`],仅把 (base, len) 记入
131/// [`GUARD_UNMAP_LOG`] 而不真正 `munmap`——guard 单测据此做确定性断言,
132/// 消除"并发测试里的 mmap 立即复用刚释放地址"带来的页可达性竞态;
133/// 测试创建的匿名页由各测试显式 `munmap` 清理。
134#[cfg(not(test))]
135fn guard_unmap(base: *mut u8, len: usize) {
136    // SAFETY: 未 disarm 的映射所有权仍归守卫(每张 mmap 成功仅 register
137    // 一次、此处仅 munmap 一次;已移交 XskRing 的映射均已 disarm 跳过);
138    // base/len 来自注册时成功的 mmap,munmap 精确回收。
139    unsafe {
140        libc::munmap(base as *mut libc::c_void, len);
141    }
142}
143
144/// 见上方生产版本的 SAFETY 注释与 stub 语义说明。
145#[cfg(test)]
146fn guard_unmap(base: *mut u8, len: usize) {
147    if GUARD_TEST_STUB.with(|s| s.get()) {
148        GUARD_UNMAP_LOG.with(|l| l.borrow_mut().push((base as usize, len)));
149        return;
150    }
151    // SAFETY: 与生产路径同一套所有权不变量,调用方为真实匿名映射。
152    unsafe {
153        libc::munmap(base as *mut libc::c_void, len);
154    }
155}
156
157#[cfg(test)]
158thread_local! {
159    /// 见 [`guard_unmap`]:stub 开关(线程局部,测试相互隔离)
160    static GUARD_TEST_STUB: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
161    /// 见 [`guard_unmap`]:stub 模式下 Drop 的 munmap 记账 (base, len)
162    static GUARD_UNMAP_LOG: std::cell::RefCell<Vec<(usize, usize)>> = const { std::cell::RefCell::new(Vec::new()) };
163}
164
165/// AF_XDP Socket 配置
166#[derive(Debug, Clone)]
167pub struct XskConfig {
168    /// 网卡接口索引
169    pub ifindex: u32,
170    /// 队列 ID
171    pub queue_id: u32,
172    /// 是否使用 Zero-Copy 模式
173    pub zero_copy: bool,
174    /// Fill Ring 大小(必须是 2 的幂)
175    pub fill_ring_size: u32,
176    /// RX Ring 大小
177    pub rx_ring_size: u32,
178    /// TX Ring 大小
179    pub tx_ring_size: u32,
180    /// Completion Ring 大小
181    pub completion_ring_size: u32,
182    /// UMEM 共享标志
183    pub shared_umem: bool,
184    /// UMEM 帧(chunk)大小,必须是 2 的幂且 ≥ 2048(XDP_UMEM_MIN_CHUNK_SIZE)
185    pub frame_size: u32,
186    /// UMEM 帧头预留(headroom),必须 < frame_size
187    pub headroom: u32,
188    /// SO_RCVBUF 内核接收缓冲(字节)。默认 1MB;调用方可按需调整。
189    pub so_rcvbuf: i32,
190    /// SO_SNDBUF 内核发送缓冲(字节)。默认 1MB;调用方可按需调整。
191    pub so_sndbuf: i32,
192    /// Fill Ring 预填/再填充的分块大小(栈上批量数组)。默认 64。
193    pub prefill_chunk: usize,
194}
195
196impl Default for XskConfig {
197    fn default() -> Self {
198        Self {
199            ifindex: 0,
200            queue_id: 0,
201            zero_copy: true,
202            fill_ring_size: 2048,
203            rx_ring_size: 2048,
204            tx_ring_size: 2048,
205            completion_ring_size: 2048,
206            shared_umem: false,
207            frame_size: 4096,
208            headroom: 0,
209            so_rcvbuf: 1024 * 1024,
210            so_sndbuf: 1024 * 1024,
211            prefill_chunk: 64,
212        }
213    }
214}
215
216/// AF_XDP Socket 状态
217#[derive(Debug, Clone, Copy, PartialEq, Eq)]
218pub enum XskState {
219    /// 已创建(未配置)
220    Created,
221    /// 已配置(已设置选项)
222    Configured,
223    /// 已绑定(已绑定到网卡队列)
224    Bound,
225    /// 已关闭
226    Closed,
227}
228
229/// AF_XDP Socket
230///
231/// 封装单个 AF_XDP Socket 的完整生命周期管理。
232/// 单 Owner 设计:每个 Socket 由一个 Worker 独占。
233pub struct XskSocket {
234    /// Socket 文件描述符
235    fd: Option<i32>,
236    /// 配置
237    config: XskConfig,
238    /// 当前状态
239    state: XskState,
240    /// UMEM 管理器(共享所有权,Arc 仅用于多 Worker 共享 UMEM 的场景)
241    umem: Option<Arc<UmemManager>>,
242    /// Fill Ring
243    fill_ring: XskRing,
244    /// RX Ring
245    rx_ring: XskRing,
246    /// TX Ring
247    tx_ring: XskRing,
248    /// Completion Ring
249    completion_ring: XskRing,
250    /// 描述符引擎
251    descriptor_engine: DescriptorEngine,
252    /// Fill Ring 预填游标(已登记的 UMEM 帧数,防重复登记同一批帧)
253    prefilled_frames: u32,
254    /// 是否活跃
255    active: AtomicBool,
256}
257
258impl std::fmt::Debug for XskSocket {
259    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
260        f.debug_struct("XskSocket")
261            .field("fd", &self.fd)
262            .field("config", &self.config)
263            .field("state", &self.state)
264            .field("active", &self.active)
265            .finish()
266    }
267}
268
269impl XskSocket {
270    /// 创建 AF_XDP Socket(**模拟模式**,显式选择)
271    ///
272    /// 四环使用用户态 `Vec<XdpDesc>` backing store,不触碰任何内核 AF_XDP 资源,
273    /// 适合无 root / 无 XDP 内核支持环境下的开发与测试。
274    ///
275    /// 真实内核模式请显式使用 [`XskSocket::new_real`](或手动串联
276    /// `create_socket → configure → bind`)。本类型**绝不静默降级**:
277    /// 模式在构造时选定,`bind` 失败一律返回错误(Fail-Closed)。
278    pub fn new(config: XskConfig) -> Result<Self> {
279        let fill_ring_size = config.fill_ring_size;
280        let rx_ring_size = config.rx_ring_size;
281        let tx_ring_size = config.tx_ring_size;
282        let completion_ring_size = config.completion_ring_size;
283
284        // checked 算术:四个 u32 先提升为 u64 再求和,杜绝 u32 加法溢出
285        let total_descriptors = u64::from(fill_ring_size)
286            + u64::from(rx_ring_size)
287            + u64::from(tx_ring_size)
288            + u64::from(completion_ring_size);
289        // fail-closed:四环容量之和超出 20-bit 帧索引域(> 2^20)时拒绝构造
290        let descriptor_engine = DescriptorEngine::new(total_descriptors)?;
291
292        Ok(Self {
293            fd: None,
294            config,
295            state: XskState::Created,
296            umem: None,
297            fill_ring: XskRing::new(RingType::Fill, fill_ring_size)?,
298            rx_ring: XskRing::new(RingType::Rx, rx_ring_size)?,
299            tx_ring: XskRing::new(RingType::Tx, tx_ring_size)?,
300            completion_ring: XskRing::new(RingType::Completion, completion_ring_size)?,
301            descriptor_engine,
302            prefilled_frames: 0,
303            active: AtomicBool::new(false),
304        })
305    }
306
307    /// 创建**真实内核模式** AF_XDP Socket(显式选择,Fail-Closed)
308    ///
309    /// 完整执行真实系统调用链:
310    /// 1. `socket(AF_XDP, SOCK_RAW, 0)`
311    /// 2. `setsockopt(SO_RCVBUF/SO_SNDBUF)`
312    /// 3. `bind()`:`XDP_UMEM_REG` 注册 → 四环大小 → `getsockopt(XDP_MMAP_OFFSETS)`
313    ///    → 四环 mmap → `bind(sockaddr_xdp)` → Fill Ring 预填
314    ///
315    /// 任何一步失败立即返回错误(WSL2 等不支持环境下返回明确错误),
316    /// **绝不回退到模拟模式**;模拟模式请显式使用 [`XskSocket::new`]。
317    ///
318    /// # 参数
319    /// * `config` - Socket 配置(ifindex/queue_id/四环大小/帧大小等)
320    /// * `umem` - 已完成 `create()`(mmap)的 UMEM 管理器
321    pub fn new_real(config: XskConfig, umem: Arc<UmemManager>) -> Result<Self> {
322        let mut socket = Self::new(config)?;
323        socket.create_socket()?;
324        socket.configure()?;
325        socket.bind(umem)?;
326        debug_assert!(socket.is_kernel_mode());
327        Ok(socket)
328    }
329
330    /// 创建 Socket(系统调用)
331    pub fn create_socket(&mut self) -> Result<()> {
332        // 错误语义精确化:非 Created 状态(Configured/Bound/Closed 均非法;
333        // AlreadyBound 仅描述"已绑定"子集)统一报 InvalidState 并注明实际状态
334        if self.state != XskState::Created {
335            return Err(XskError::InvalidState(format!(
336                "create_socket expects state=Created, actual state={:?}",
337                self.state
338            ))
339            .into());
340        }
341
342        // SAFETY: AF_XDP(44)、SOCK_RAW、protocol 0 为有效常量。
343        // socket() 是纯系统调用,参数为编译期常量,不存在运行时风险。
344        // 注意:AF_XDP 正确值为 44(linux/socket.h: #define AF_XDP 44),
345        // 此前误写为 48 导致 EAFNOSUPPORT。统一使用 libc::AF_XDP 命名常量。
346        let fd = unsafe { libc::socket(libc::AF_XDP, libc::SOCK_RAW, 0) };
347        if fd < 0 {
348            let err = std::io::Error::last_os_error();
349            return Err(XskError::SocketCreate(format!("socket() failed: {}", err)).into());
350        }
351
352        self.fd = Some(fd);
353        self.state = XskState::Configured;
354
355        Ok(())
356    }
357
358    /// 配置 Socket 选项
359    pub fn configure(&mut self) -> Result<()> {
360        let fd = self.get_fd()?;
361
362        // SAFETY: fd 已通过 get_fd()? 验证为非负有效值。
363        // rcvbuf 为栈变量,指针在调用期间有效;size 参数为 sizeof(i32),与实际数据一致。
364        let rcvbuf: i32 = self.config.so_rcvbuf;
365        let ret = unsafe {
366            libc::setsockopt(
367                fd,
368                libc::SOL_SOCKET,
369                libc::SO_RCVBUF,
370                &rcvbuf as *const i32 as *const libc::c_void,
371                std::mem::size_of::<i32>() as libc::socklen_t,
372            )
373        };
374        if ret < 0 {
375            let err = std::io::Error::last_os_error();
376            return Err(XskError::SocketOption(format!("SO_RCVBUF failed: {}", err)).into());
377        }
378
379        // SAFETY: fd 已通过 get_fd()? 验证为非负有效值。
380        // sndbuf 为栈变量,指针在调用期间有效;size 参数为 sizeof(i32),与实际数据一致。
381        let sndbuf: i32 = self.config.so_sndbuf;
382        let ret = unsafe {
383            libc::setsockopt(
384                fd,
385                libc::SOL_SOCKET,
386                libc::SO_SNDBUF,
387                &sndbuf as *const i32 as *const libc::c_void,
388                std::mem::size_of::<i32>() as libc::socklen_t,
389            )
390        };
391        if ret < 0 {
392            let err = std::io::Error::last_os_error();
393            return Err(XskError::SocketOption(format!("SO_SNDBUF failed: {}", err)).into());
394        }
395
396        Ok(())
397    }
398
399    /// 配置单个 Ring 的大小(setsockopt SOL_XDP)
400    ///
401    /// optname 为 XDP_UMEM_FILL_RING / XDP_UMEM_COMPLETION_RING / XDP_RX_RING / XDP_TX_RING。
402    /// size 必须是 2 的幂。
403    fn set_ring_size(&self, optname: libc::c_int, size: u32) -> Result<()> {
404        let fd = self.get_fd()?;
405        // SAFETY: fd 已验证有效;size 为栈变量,指针在调用期间有效;
406        // optlen 为 sizeof(u32),与实际传入的数据一致。
407        let ret = unsafe {
408            libc::setsockopt(
409                fd,
410                libc::SOL_XDP,
411                optname,
412                &size as *const u32 as *const libc::c_void,
413                std::mem::size_of::<u32>() as libc::socklen_t,
414            )
415        };
416        if ret < 0 {
417            let err = std::io::Error::last_os_error();
418            return Err(XskError::SocketOption(format!(
419                "ring size setsockopt(opt={optname}, size={size}) failed: {err}"
420            ))
421            .into());
422        }
423        Ok(())
424    }
425
426    /// 通过 `getsockopt(XDP_MMAP_OFFSETS)` 获取内核四环偏移
427    fn get_mmap_offsets(fd: i32) -> Result<libc::xdp_mmap_offsets> {
428        // SAFETY: offsets 为栈上零初始化结构体,getsockopt 按 optlen 写入;
429        // optlen 传入结构体完整大小,旧内核(v1 布局,无 flags 字段)会按其实际
430        // 大小裁剪写入,剩余字段保持零值(flags=0 → need_wakeup 恒 false)。
431        let mut offsets: libc::xdp_mmap_offsets = unsafe { std::mem::zeroed() };
432        let mut optlen = std::mem::size_of::<libc::xdp_mmap_offsets>() as libc::socklen_t;
433        // SAFETY: fd 已验证有效;offsets/optlen 均为栈上有效变量,指针在调用期间有效。
434        let ret = unsafe {
435            libc::getsockopt(
436                fd,
437                libc::SOL_XDP,
438                libc::XDP_MMAP_OFFSETS,
439                &mut offsets as *mut libc::xdp_mmap_offsets as *mut libc::c_void,
440                &mut optlen,
441            )
442        };
443        if ret < 0 {
444            let err = std::io::Error::last_os_error();
445            return Err(XskError::SocketOption(format!(
446                "getsockopt(XDP_MMAP_OFFSETS) failed: {err}"
447            ))
448            .into());
449        }
450        Ok(offsets)
451    }
452
453    /// mmap 单个内核 ring 区域(MAP_SHARED + 内核 UAPI 页偏移)
454    ///
455    /// `pgoff` 为内核 UAPI 定义的 ring 页偏移(`libc::XDP_PGOFF_RX_RING` 等,
456    /// 权威值见 include/uapi/linux/if_xdp.h:RX=0x0、TX=0x80000000、
457    /// FILL=0x100000000、COMPLETION=0x180000000)。
458    fn mmap_kernel_ring(fd: i32, pgoff: libc::off_t, length: usize, name: &str) -> Result<*mut u8> {
459        // SAFETY: fd 已验证有效;pgoff 为内核 UAPI 常量;length 由
460        // getsockopt(XDP_MMAP_OFFSETS) 偏移 + ring 容量计算,非零。
461        // MAP_SHARED 是 AF_XDP ring 映射的必需标志(与内核共享同一段内存)。
462        // 返回值已检查 MAP_FAILED。
463        let addr = unsafe {
464            libc::mmap(
465                std::ptr::null_mut(),
466                length,
467                libc::PROT_READ | libc::PROT_WRITE,
468                libc::MAP_SHARED,
469                fd,
470                pgoff,
471            )
472        };
473        if addr == libc::MAP_FAILED {
474            let err = std::io::Error::last_os_error();
475            return Err(XskError::SocketOption(format!(
476                "{name} ring mmap(pgoff={pgoff:#x}, len={length}) failed: {err}"
477            ))
478            .into());
479        }
480        Ok(addr as *mut u8)
481    }
482
483    /// 绑定到网卡队列(真实内核注册,Fail-Closed)
484    ///
485    /// 完整 AF_XDP 绑定序列(与 libbpf `xsk_socket__create` 顺序一致):
486    /// 1. `setsockopt(XDP_UMEM_REG)` 注册 UMEM 内存区
487    /// 2. `setsockopt(XDP_UMEM_FILL_RING/COMPLETION_RING/RX_RING/TX_RING)` 配置四环大小
488    /// 3. `getsockopt(XDP_MMAP_OFFSETS)` 获取四环内核布局偏移
489    /// 4. `mmap` 四环(XDP_PGOFF_RX_RING / XDP_PGOFF_TX_RING /
490    ///    XDP_UMEM_PGOFF_FILL_RING / XDP_UMEM_PGOFF_COMPLETION_RING),
491    ///    四环切换为内核 mmap 模式(任一失败,已映射区域由 RingMmapGuard 回收)
492    /// 5. `bind(sockaddr_xdp)` 绑定到 ifindex+queue_id
493    /// 6. Fill Ring 预填帧地址,`XDP_RING_NEED_WAKEUP` 置位时
494    ///    `sendto(MSG_DONTWAIT)` 唤醒内核
495    ///
496    /// WSL2 等不支持环境下任一步骤失败即返回明确错误,**绝不静默降级为模拟模式**。
497    pub fn bind(&mut self, umem: Arc<UmemManager>) -> Result<()> {
498        // ── 0. 全部纯参数校验前移到任何 syscall/setsockopt 之前(Fail-Closed)──
499        // 此前 is_power_of_two 校验在 bind() 成功之后才执行:校验失败时已
500        // 完成内核 bind,socket 处于"已绑定但配置非法"的矛盾状态。
501        if !umem.is_initialized() || umem.as_ptr().is_null() {
502            return Err(LinuxError::Umem(UmemError::NotCreated));
503        }
504        if self.config.frame_size == 0 {
505            return Err(XskError::SocketOption(
506                "frame_size 必须 > 0(XDP_UMEM_MIN_CHUNK_SIZE=2048)".to_string(),
507            )
508            .into());
509        }
510        // frame_size 为 XDP_UMEM chunk_size 契约,必须 2 的幂(纯参数校验)
511        if !self.config.frame_size.is_power_of_two() {
512            return Err(XskError::SocketOption(format!(
513                "frame_size={} 必须是 2 的幂(XDP_UMEM chunk_size 契约)",
514                self.config.frame_size
515            ))
516            .into());
517        }
518        // UMEM 帧数与描述符引擎容量也是纯参数:在任何 syscall 前完成计算与
519        // 构造校验(fail-closed:超 20-bit 帧索引域 / 非法帧移位直接拒绝)。
520        let frame_size = self.config.frame_size;
521        let umem_frames = (umem.size() / frame_size as usize).min(u32::MAX as usize) as u32;
522        // with_frame_shift fail-closed:frame_size 已校验为 2 的幂且 > 0,
523        // trailing_zeros ∈ 11..=15 仍由引擎构造器二次校验(双重防护)
524        let new_engine =
525            DescriptorEngine::with_frame_shift(u64::from(umem_frames), frame_size.trailing_zeros())?;
526
527        let fd = self.get_fd()?;
528
529        // ── 1. 注册 UMEM(XDP_UMEM_REG)────────────────────────────
530        // UMEM 必须已 mmap(umem.create() 先于本调用),as_ptr() 返回映射基址。
531        let reg = build_umem_reg(
532            umem.as_ptr(),
533            umem.size(),
534            self.config.frame_size,
535            self.config.headroom,
536        );
537        // SAFETY: fd 已验证有效;reg 为栈变量,指针在调用期间有效;
538        // optlen 为 sizeof(xdp_umem_reg),与结构体一致。
539        let ret = unsafe {
540            libc::setsockopt(
541                fd,
542                libc::SOL_XDP,
543                libc::XDP_UMEM_REG,
544                &reg as *const libc::xdp_umem_reg as *const libc::c_void,
545                std::mem::size_of::<libc::xdp_umem_reg>() as libc::socklen_t,
546            )
547        };
548        if ret < 0 {
549            let err = std::io::Error::last_os_error();
550            return Err(XskError::SocketOption(format!("XDP_UMEM_REG failed: {err}")).into());
551        }
552
553        // ── 2. 配置四环大小 ────────────────────────────────────────
554        self.set_ring_size(libc::XDP_UMEM_FILL_RING, self.config.fill_ring_size)?;
555        self.set_ring_size(libc::XDP_UMEM_COMPLETION_RING, self.config.completion_ring_size)?;
556        self.set_ring_size(libc::XDP_RX_RING, self.config.rx_ring_size)?;
557        self.set_ring_size(libc::XDP_TX_RING, self.config.tx_ring_size)?;
558
559        // ── 3. 获取内核四环偏移(XDP_MMAP_OFFSETS)──────────────────
560        let offsets = Self::get_mmap_offsets(fd)?;
561
562        // ── 4. mmap 四环并构造内核模式 XskRing ──────────────────────
563        // 任一步失败时 self 上的四环保持原状(绝不出现半内核半模拟的混合状态);
564        // 已成功的 ring mmap 全部登记进 RingMmapGuard:任何 `?` 提前返回由
565        // guard Drop 回收前序映射,彻底消除裸 base 泄漏。
566        let rx_off = to_ring_offsets(&offsets.rx, self.config.rx_ring_size);
567        let tx_off = to_ring_offsets(&offsets.tx, self.config.tx_ring_size);
568        let fr_off = to_ring_offsets(&offsets.fr, self.config.fill_ring_size);
569        let cr_off = to_ring_offsets(&offsets.cr, self.config.completion_ring_size);
570
571        let mut mmap_guard = RingMmapGuard::new();
572        let rx_base = Self::mmap_kernel_ring(
573            fd,
574            libc::XDP_PGOFF_RX_RING,
575            rx_off.len as usize,
576            "RX",
577        )?;
578        let rx_slot = mmap_guard.register(rx_base, rx_off.len as usize);
579        let tx_base = Self::mmap_kernel_ring(
580            fd,
581            libc::XDP_PGOFF_TX_RING,
582            tx_off.len as usize,
583            "TX",
584        )?;
585        let tx_slot = mmap_guard.register(tx_base, tx_off.len as usize);
586        let fr_base = Self::mmap_kernel_ring(
587            fd,
588            libc::XDP_UMEM_PGOFF_FILL_RING as libc::off_t,
589            fr_off.len as usize,
590            "FILL",
591        )?;
592        let fr_slot = mmap_guard.register(fr_base, fr_off.len as usize);
593        let cr_base = Self::mmap_kernel_ring(
594            fd,
595            libc::XDP_UMEM_PGOFF_COMPLETION_RING as libc::off_t,
596            cr_off.len as usize,
597            "COMPLETION",
598        )?;
599        let cr_slot = mmap_guard.register(cr_base, cr_off.len as usize);
600
601        // SAFETY: 四个 base 均来自上方成功的 ring mmap(长度 = offsets.len),
602        // offsets 来自内核 getsockopt;本 Socket 单 Owner。构造成功即移交映射
603        // 所有权给 XskRing(KernelRing Drop 时 munmap)并从 guard 摘除;
604        // 构造失败/中途 `?` 时剩余映射由 guard Drop 精确回收。
605        let rx_ring = unsafe { XskRing::with_kernel_ring(RingType::Rx, rx_base, rx_off) }?;
606        mmap_guard.disarm(rx_slot);
607        let tx_ring = unsafe { XskRing::with_kernel_ring(RingType::Tx, tx_base, tx_off) }?;
608        mmap_guard.disarm(tx_slot);
609        let fill_ring = unsafe { XskRing::with_kernel_ring(RingType::Fill, fr_base, fr_off) }?;
610        mmap_guard.disarm(fr_slot);
611        let completion_ring =
612            unsafe { XskRing::with_kernel_ring(RingType::Completion, cr_base, cr_off) }?;
613        mmap_guard.disarm(cr_slot);
614
615        // ── 5. 准备 bind 地址(sockaddr_xdp)───────────────────────
616        // SAFETY: sockaddr_xdp 为栈分配,通过 zeroed() 初始化为全零;
617        // 随后所有字段(sxdp_family, sxdp_ifindex, sxdp_queue_id, sxdp_flags)均被显式赋值,
618        // 保证传给 bind() 的结构体完整且有效。
619        let mut addr: libc::sockaddr_xdp = unsafe { std::mem::zeroed() };
620        addr.sxdp_family = libc::AF_XDP as u16;
621        addr.sxdp_ifindex = self.config.ifindex;
622        addr.sxdp_queue_id = self.config.queue_id;
623        // sxdp_flags 命名常量(内核 UAPI):
624        // XDP_ZEROCOPY(1<<2) 强制零拷贝 / XDP_COPY(1<<1) 强制复制模式;
625        // 共享 UMEM 时叠加 XDP_SHARED_UMEM(1<<0)。
626        let mut flags: u16 = if self.config.zero_copy {
627            libc::XDP_ZEROCOPY
628        } else {
629            libc::XDP_COPY
630        };
631        if self.config.shared_umem {
632            flags |= libc::XDP_SHARED_UMEM;
633        }
634        addr.sxdp_flags = flags;
635
636        let addr_ptr = &addr as *const libc::sockaddr_xdp as *const libc::sockaddr;
637        let addr_len = std::mem::size_of::<libc::sockaddr_xdp>() as libc::socklen_t;
638
639        // SAFETY: fd 已通过 get_fd()? 验证为非负有效值。
640        // addr_ptr 指向栈上有效的 sockaddr_xdp 结构体,addr_len 为结构体正确大小。
641        let ret = unsafe { libc::bind(fd, addr_ptr, addr_len) };
642        if ret < 0 {
643            let err = std::io::Error::last_os_error();
644            return Err(XskError::BindFailed(format!(
645                "bind() failed: {err}(WSL2/无驱动支持环境属预期失败,绝不降级模拟)"
646            ))
647            .into());
648        }
649
650        // ── 6. bind 成功:四环统一切换为内核 mmap 模式 ──────────────
651        self.fill_ring = fill_ring;
652        self.rx_ring = rx_ring;
653        self.tx_ring = tx_ring;
654        self.completion_ring = completion_ring;
655
656        // 以 bind() 前置校验阶段预构的真实 UMEM 帧引擎替换 new() 中的
657        // 四环容量占位引擎(帧数 = UMEM 字节 / 帧大小,构造已通过
658        // 20-bit 帧索引域与帧移位双重校验)
659        self.descriptor_engine = new_engine;
660        self.prefilled_frames = 0;
661
662        self.umem = Some(umem);
663        self.state = XskState::Bound;
664        self.active.store(true, Ordering::SeqCst);
665
666        // ── 7. Fill Ring 预填帧地址,needs_wakeup 时唤醒内核 ────────
667        self.prefill_fill_ring()?;
668
669        Ok(())
670    }
671
672    /// Fill Ring 预填:将 UMEM 前 N 个帧地址写入 Fill Ring
673    ///
674    /// N = min(fill_ring 容量, UMEM 帧数)。每个帧同时在描述符引擎中登记
675    /// (位图置位),保证守恒等式成立。预填后若内核 `XDP_RING_NEED_WAKEUP`
676    /// 置位,通过 `sendto(fd, NULL, 0, MSG_DONTWAIT, NULL, 0)` 唤醒内核轮询。
677    ///
678    /// # 返回
679    /// * `Result<u32>` - 实际预填的帧数
680    pub fn prefill_fill_ring(&mut self) -> Result<u32> {
681        let frame_size = self.config.frame_size;
682        if frame_size == 0 {
683            return Err(XskError::SocketOption("frame_size 必须 > 0".to_string()).into());
684        }
685        let umem = match &self.umem {
686            Some(u) => Arc::clone(u),
687            None => return Ok(0), // 模拟模式无 UMEM,无帧可填
688        };
689
690        // UMEM 帧数 = 总字节 / 帧大小(checked:usize 除法不溢出;
691        // 帧数钳制到 u32 范围,防巨型 UMEM 截断)
692        let umem_frames = (umem.size() / frame_size as usize).min(u32::MAX as usize) as u32;
693        let target = self.fill_ring.capacity().min(umem_frames);
694        let owner = self.config.queue_id as u16;
695
696        // 游标续填:从 prefilled_frames 继续,禁止从 0 重复登记同一批帧
697        // (重复 allocate 会重复计数,破坏守恒等式)
698        let start = self.prefilled_frames.min(target);
699        let mut filled: u32 = 0;
700        // 预填分块大小可配置(钳制到栈上数组容量内,保持零堆分配热路径)
701        let chunk_size = self.config.prefill_chunk.clamp(1, PREFILL_CHUNK);
702        let mut chunk = [XdpDesc::zero(); PREFILL_CHUNK];
703        while start.saturating_add(filled) < target {
704            let frame_base = start.saturating_add(filled);
705            // target - frame_base ≤ target ≤ u32::MAX,转 usize 安全
706            let batch = ((target - frame_base) as usize).min(chunk_size);
707            for (j, slot) in chunk.iter_mut().enumerate().take(batch) {
708                // frame_base + j < target ≤ u32::MAX,不会溢出
709                let frame_index = frame_base + j as u32;
710                // 在描述符引擎登记帧(位图置位),保持守恒等式
711                let _ = self.descriptor_engine.allocate(frame_index, owner)?;
712                *slot = XdpDesc {
713                    addr: u64::from(frame_index) * u64::from(frame_size),
714                    len: 0,
715                    options: 0,
716                };
717            }
718            let n = self.fill_ring.enqueue_batch(&chunk[..batch])?;
719            filled = filled.saturating_add(n);
720            if n as usize != batch {
721                break; // ring 已满,停止预填
722            }
723        }
724        self.prefilled_frames = start.saturating_add(filled);
725
726        // XDP_RING_NEED_WAKEUP 置位时唤醒内核消费 Fill Ring
727        // (模拟模式 need_wakeup 恒 false,自动跳过)
728        if filled > 0 && self.fill_ring.need_wakeup() {
729            self.notify_fill()?;
730        }
731        Ok(filled)
732    }
733
734    /// 是否为内核 mmap 模式(bind 成功后四环已切换为内核共享映射)
735    #[inline]
736    pub fn is_kernel_mode(&self) -> bool {
737        self.rx_ring.is_kernel_mode()
738    }
739
740    /// 关闭 Socket
741    pub fn close(&mut self) -> Result<()> {
742        self.active.store(false, Ordering::SeqCst);
743
744        // take() 确保 fd 只被尝试关闭一次:即使 close() 返回错误,
745        // fd 也已从 self.fd 移除,Drop 不会再次关闭(避免 double-close)
746        if let Some(fd) = self.fd.take() {
747            // SAFETY: fd 在 self.fd 中仅当 create_socket() 成功时才存在(非负)。
748            // close() 系统调用对有效 fd 是安全的,且 take() 确保 fd 不会被并发关闭。
749            let ret = unsafe { libc::close(fd) };
750            if ret < 0 {
751                // fd 已被 Linux 关闭(close(2) 即使返回 EINTR 也已关闭 fd),
752                // 仅报告错误,不重试
753                self.state = XskState::Closed;
754                let err = std::io::Error::last_os_error();
755                return Err(XskError::CloseFailed(format!("close() failed: {}", err)).into());
756            }
757        }
758
759        self.state = XskState::Closed;
760
761        Ok(())
762    }
763
764    /// 获取 Socket FD
765    #[inline]
766    pub fn fd(&self) -> Option<i32> {
767        self.fd
768    }
769
770    /// 获取状态
771    #[inline]
772    pub fn state(&self) -> XskState {
773        self.state
774    }
775
776    /// 是否活跃
777    #[inline]
778    pub fn is_active(&self) -> bool {
779        self.active.load(Ordering::SeqCst)
780    }
781
782    /// 获取 Fill Ring 引用
783    #[inline]
784    pub fn fill_ring(&self) -> &XskRing {
785        &self.fill_ring
786    }
787
788    /// 获取 Fill Ring 可变引用
789    #[inline]
790    pub fn fill_ring_mut(&mut self) -> &mut XskRing {
791        &mut self.fill_ring
792    }
793
794    /// 获取 RX Ring 引用
795    #[inline]
796    pub fn rx_ring(&self) -> &XskRing {
797        &self.rx_ring
798    }
799
800    /// 获取 RX Ring 可变引用
801    #[inline]
802    pub fn rx_ring_mut(&mut self) -> &mut XskRing {
803        &mut self.rx_ring
804    }
805
806    /// 获取 TX Ring 引用
807    #[inline]
808    pub fn tx_ring(&self) -> &XskRing {
809        &self.tx_ring
810    }
811
812    /// 获取 TX Ring 可变引用
813    #[inline]
814    pub fn tx_ring_mut(&mut self) -> &mut XskRing {
815        &mut self.tx_ring
816    }
817
818    /// 获取 Completion Ring 引用
819    #[inline]
820    pub fn completion_ring(&self) -> &XskRing {
821        &self.completion_ring
822    }
823
824    /// 获取 Completion Ring 可变引用
825    #[inline]
826    pub fn completion_ring_mut(&mut self) -> &mut XskRing {
827        &mut self.completion_ring
828    }
829
830    /// 获取描述符引擎引用
831    #[inline]
832    pub fn descriptor_engine(&self) -> &DescriptorEngine {
833        &self.descriptor_engine
834    }
835
836    /// 批量填充 Fill Ring
837    ///
838    /// 向 Fill Ring 注入可用的 XdpDesc,供内核接收数据包。
839    ///
840    /// # 参数
841    /// * `count` - 填充数量
842    ///
843    /// # 返回
844    /// * `Result<u32>` - 实际填充数量
845    pub fn fill_descriptors(&mut self, count: u32) -> Result<u32> {
846        let mut descs = Vec::with_capacity(count as usize);
847        let mut allocated_indices = Vec::with_capacity(count as usize);
848        for i in 0..count {
849            // 修复「从 0 重复登记帧」:引擎位图已置位的帧不得再次 allocate
850            // (allocate 对已分配帧 fail-closed 返回 AlreadyAllocated);
851            // 只登记尚未被引擎分配的帧,与 prefill_fill_ring 的游标语义一致,
852            // 保证 allocated == freed + active 守恒等式不被双登记破坏。
853            if self.descriptor_engine.is_allocated(i) {
854                continue;
855            }
856            let desc = self
857                .descriptor_engine
858                .allocate(i, self.config.queue_id as u16)?;
859            descs.push(*desc.xdp_desc());
860            allocated_indices.push(i);
861        }
862        let filled = match self.fill_ring.enqueue_batch(&descs) {
863            Ok(n) => n,
864            Err(e) => {
865                // fail-closed 回滚:enqueue 失败时,已分配的帧位图置位但未入环,
866                // 形成孤立帧(无法回收)。必须以位图为权威回滚这些帧,
867                // 保持 allocated == freed + active 守恒等式。
868                for &idx in &allocated_indices {
869                    self.descriptor_engine.rollback_allocate(idx);
870                }
871                return Err(e);
872            }
873        };
874        // 真实内核模式:enqueue 后检查是否需要唤醒内核轮询 Fill Ring
875        if self.fill_ring.need_wakeup() {
876            self.notify_fill()?;
877        }
878        Ok(filled)
879    }
880
881    /// 接收数据包(从 RX Ring)
882    ///
883    /// # 参数
884    /// * `max_batch` - 最大批量
885    ///
886    /// # 返回
887    /// * `Result<Vec<Descriptor>>` - 接收到的描述符列表
888    pub fn receive_batch(&mut self, max_batch: u32) -> Result<Vec<Descriptor>> {
889        let raw_descs = self.rx_ring.dequeue_batch(max_batch)?;
890        let mut descriptors = Vec::with_capacity(raw_descs.len());
891
892        for raw_xdp in raw_descs {
893            // fail-closed:frame index 高位域非法(> MAX_FRAME_INDEX)时
894            // from_xdp 直接拒绝,非法描述符绝不进入验证管线。
895            // 使用引擎实际 frame_shift 而非硬编码 12,保证非 4096 帧大小下索引正确
896            let desc = Descriptor::from_xdp(
897                raw_xdp,
898                self.config.queue_id as u16,
899                0,
900                self.descriptor_engine.frame_shift(),
901            )?;
902            self.descriptor_engine
903                .verify(&desc, self.config.queue_id as u16)?;
904            descriptors.push(desc);
905        }
906
907        Ok(descriptors)
908    }
909
910    /// 接收数据包到预分配缓冲区(零堆分配路径)
911    ///
912    /// # 参数
913    /// * `buffer` - 预分配的 Descriptor 缓冲区
914    ///
915    /// # 返回
916    /// * `Result<u32>` - 实际接收数量
917    pub fn receive_batch_to(&mut self, buffer: &mut [Descriptor]) -> Result<u32> {
918        let max_batch = buffer.len() as u32;
919        let raw_descs = self.rx_ring.dequeue_batch(max_batch)?;
920        let count = raw_descs.len() as u32;
921
922        for (i, raw_xdp) in raw_descs.iter().enumerate() {
923            let desc = Descriptor::from_xdp(
924                *raw_xdp,
925                self.config.queue_id as u16,
926                0,
927                self.descriptor_engine.frame_shift(),
928            )?;
929            self.descriptor_engine
930                .verify(&desc, self.config.queue_id as u16)?;
931            buffer[i] = desc;
932        }
933
934        Ok(count)
935    }
936
937    /// 发送数据包(到 TX Ring)
938    ///
939    /// # 参数
940    /// * `descriptors` - 要发送的描述符列表
941    ///
942    /// # 返回
943    /// * `Result<u32>` - 实际发送数量
944    pub fn send_batch(&mut self, descriptors: &[Descriptor]) -> Result<u32> {
945        let mut raw_descs: Vec<XdpDesc> = Vec::with_capacity(descriptors.len());
946
947        for desc in descriptors {
948            self.descriptor_engine
949                .verify(desc, self.config.queue_id as u16)?;
950            raw_descs.push(*desc.xdp_desc());
951        }
952
953        let sent = self.tx_ring.enqueue_batch(&raw_descs)?;
954        // 真实内核模式:enqueue 后检查是否需要唤醒内核轮询 TX Ring
955        if self.tx_ring.need_wakeup() {
956            self.notify_tx()?;
957        }
958        Ok(sent)
959    }
960
961    /// 批量发送(从预分配缓冲区)
962    ///
963    /// # 参数
964    /// * `descriptors` - 预分配的 XdpDesc 数组
965    ///
966    /// # 返回
967    /// * `Result<u32>` - 实际发送数量
968    pub fn send_xdp_batch(&mut self, descriptors: &[XdpDesc]) -> Result<u32> {
969        // 与 send_batch 对称的描述符验证管线:每个 raw XdpDesc 必须通过
970        // from_xdp 帧索引域校验 + descriptor_engine.verify 所有权/代际验证,
971        // 杜绝未验证的 raw addr 直接进入内核 TX Ring(conservation 破坏 / 帧混淆)
972        for raw_xdp in descriptors {
973            let desc = Descriptor::from_xdp(
974                *raw_xdp,
975                self.config.queue_id as u16,
976                0,
977                self.descriptor_engine.frame_shift(),
978            )?;
979            self.descriptor_engine
980                .verify(&desc, self.config.queue_id as u16)?;
981        }
982        let sent = self.tx_ring.enqueue_batch(descriptors)?;
983        if self.tx_ring.need_wakeup() {
984            self.notify_tx()?;
985        }
986        Ok(sent)
987    }
988
989    /// 唤醒内核处理 TX Ring(sendto 系统调用)
990    ///
991    /// 当 `XDP_RING_NEED_WAKEUP` 标志置位时,通过 `sendto(fd, NULL, 0, MSG_DONTWAIT, NULL, 0)`
992    /// 通知内核从 TX Ring 消费描述符并发送数据包。
993    ///
994    /// 模拟模式下为空操作(无需唤醒)。
995    #[inline]
996    pub fn notify_tx(&self) -> Result<()> {
997        let fd = match self.fd {
998            Some(f) if f >= 0 => f,
999            _ => return Ok(()), // 无效 fd 或模拟模式,静默跳过
1000        };
1001        // SAFETY: fd 已验证为有效值。sendto with NULL/0 是 AF_XDP 的标准唤醒路径,
1002        // 不涉及数据拷贝,仅通知内核轮询 TX Ring。
1003        let ret = unsafe {
1004            libc::sendto(
1005                fd,
1006                std::ptr::null(),
1007                0,
1008                libc::MSG_DONTWAIT,
1009                std::ptr::null(),
1010                0,
1011            )
1012        };
1013        if ret < 0 {
1014            let err = std::io::Error::last_os_error();
1015            // EAGAIN/EWOULDBLOCK/EINTR 为非致命错误,不阻断数据面
1016            if matches!(
1017                err.raw_os_error(),
1018                Some(libc::EAGAIN) | Some(libc::EINTR)
1019            ) {
1020                return Ok(());
1021            }
1022            return Err(
1023                XskError::NotifyFailed(format!("notify_tx sendto failed: {err}")).into(),
1024            );
1025        }
1026        Ok(())
1027    }
1028
1029    /// 唤醒内核处理 Fill Ring(sendto 系统调用)
1030    ///
1031    /// 当 `XDP_RING_NEED_WAKEUP` 标志置位时,通过
1032    /// `sendto(fd, NULL, 0, MSG_DONTWAIT, NULL, 0)`
1033    /// 通知内核从 Fill Ring 获取空描述符并接收数据包。
1034    /// (本实现四环齐备,xsk_sendmsg 路径可正常进入内核唤醒逻辑。)
1035    ///
1036    /// 模拟模式下为空操作(无 fd,无需唤醒)。
1037    #[inline]
1038    pub fn notify_fill(&self) -> Result<()> {
1039        let fd = match self.fd {
1040            Some(f) if f >= 0 => f,
1041            _ => return Ok(()),
1042        };
1043        // SAFETY: fd 已验证为有效值。sendto with NULL/0 + MSG_DONTWAIT 是 AF_XDP 的
1044        // 标准唤醒路径,不涉及数据拷贝,仅通知内核轮询已绑定队列的 Fill Ring。
1045        let ret = unsafe {
1046            libc::sendto(
1047                fd,
1048                std::ptr::null(),
1049                0,
1050                libc::MSG_DONTWAIT,
1051                std::ptr::null(),
1052                0,
1053            )
1054        };
1055        if ret < 0 {
1056            let err = std::io::Error::last_os_error();
1057            // EAGAIN/EWOULDBLOCK/EINTR 为非致命错误,不阻断数据面
1058            if matches!(
1059                err.raw_os_error(),
1060                Some(libc::EAGAIN) | Some(libc::EINTR)
1061            ) {
1062                return Ok(());
1063            }
1064            return Err(
1065                XskError::NotifyFailed(format!("notify_fill sendto failed: {err}")).into(),
1066            );
1067        }
1068        Ok(())
1069    }
1070
1071    /// 回收发送完成的描述符(从 Completion Ring)
1072    ///
1073    /// # 参数
1074    /// * `max_batch` - 最大批量
1075    ///
1076    /// # 返回
1077    /// * `Result<u32>` - 回收数量
1078    pub fn recycle_completed(&mut self, max_batch: u32) -> Result<u32> {
1079        let raw_descs = self.completion_ring.dequeue_batch(max_batch)?;
1080        let count = raw_descs.len() as u32;
1081
1082        for raw_xdp in &raw_descs {
1083            // frame index 域校验 fail-closed(非法 raw addr 直接拒绝该批次)
1084            let desc = Descriptor::from_xdp(
1085                *raw_xdp,
1086                self.config.queue_id as u16,
1087                0,
1088                self.descriptor_engine.frame_shift(),
1089            )?;
1090            self.descriptor_engine.release(&desc)?;
1091        }
1092
1093        Ok(count)
1094    }
1095
1096    /// 批量接收并回收(零拷贝路径)
1097    ///
1098    /// # 参数
1099    /// * `max_batch` - 最大批量
1100    ///
1101    /// # 返回
1102    /// * `Result<Vec<Descriptor>>` - 接收到的描述符
1103    pub fn receive_and_refill(&mut self, max_batch: u32) -> Result<Vec<Descriptor>> {
1104        let received = self.receive_batch(max_batch)?;
1105
1106        if !received.is_empty() {
1107            self.fill_descriptors(received.len() as u32)?;
1108        }
1109
1110        Ok(received)
1111    }
1112
1113    /// 获取 UMEM 引用
1114    pub fn umem(&self) -> Option<&Arc<UmemManager>> {
1115        self.umem.as_ref()
1116    }
1117
1118    /// 返回底层 AF_XDP socket 文件描述符。
1119    ///
1120    /// - socket 已创建且未关闭:`Ok(fd)`,fd ≥ 0
1121    /// - 尚未调用 `create_socket()` 或已关闭:`Err(XskError::NotBound)`
1122    ///
1123    /// 该 fd 可用于 `poll(2)`/`select(2)`/`epoll(2)` 等待 RX 队列唤醒,
1124    /// 或用于 SO_RCVBUF / SO_SNDBUF 调优。调用方不应 close 该 fd。
1125    pub fn get_fd(&self) -> Result<i32> {
1126        self.fd.ok_or_else(|| XskError::NotBound.into())
1127    }
1128
1129    /// 队列 ID(构造配置原值;XSKMAP 注册 `queue_id → xsk_fd` 的 map key)
1130    #[inline]
1131    pub fn queue_id(&self) -> u32 {
1132        self.config.queue_id
1133    }
1134}
1135
1136impl Drop for XskSocket {
1137    fn drop(&mut self) {
1138        let _ = self.close();
1139    }
1140}
1141
1142#[cfg(test)]
1143mod tests {
1144    use super::*;
1145
1146    #[test]
1147    fn test_xsk_config_default() {
1148        let config = XskConfig::default();
1149        assert_eq!(config.ifindex, 0);
1150        assert_eq!(config.queue_id, 0);
1151        assert!(config.zero_copy);
1152    }
1153
1154    #[test]
1155    fn test_xsk_socket_creation() {
1156        let config = XskConfig::default();
1157        let socket = XskSocket::new(config);
1158        assert!(socket.is_ok());
1159        let socket = socket.unwrap();
1160        assert_eq!(socket.state(), XskState::Created);
1161        assert!(!socket.is_active());
1162    }
1163
1164    #[test]
1165    fn test_xsk_socket_create_and_configure() {
1166        let config = XskConfig::default();
1167        let mut socket = XskSocket::new(config).unwrap();
1168
1169        let result = socket.create_socket();
1170        if result.is_ok() {
1171            let result = socket.configure();
1172            assert!(result.is_ok());
1173        }
1174    }
1175
1176    #[test]
1177    fn test_xsk_ring_operations() {
1178        let config = XskConfig::default();
1179        let socket = XskSocket::new(config).unwrap();
1180
1181        assert_eq!(socket.fill_ring().capacity(), 2048);
1182        assert_eq!(socket.rx_ring().capacity(), 2048);
1183        assert_eq!(socket.tx_ring().capacity(), 2048);
1184        assert_eq!(socket.completion_ring().capacity(), 2048);
1185    }
1186
1187    #[test]
1188    fn test_xsk_descriptor_engine() {
1189        let config = XskConfig::default();
1190        let socket = XskSocket::new(config).unwrap();
1191
1192        let engine = socket.descriptor_engine();
1193        let desc = engine.allocate(0, 1).unwrap();
1194        assert_eq!(desc.index(), 0);
1195        assert_eq!(desc.addr(), 0);
1196
1197        engine.verify(&desc, 1).unwrap();
1198        engine.release(&desc).unwrap();
1199
1200        assert!(engine.verify_conservation());
1201    }
1202
1203    #[test]
1204    fn test_xsk_fill_and_receive() {
1205        let config = XskConfig::default();
1206        let mut socket = XskSocket::new(config).unwrap();
1207
1208        // 填充 Fill Ring
1209        let filled = socket.fill_descriptors(4).unwrap();
1210        assert_eq!(filled, 4);
1211        assert_eq!(socket.fill_ring().available_data(), 4);
1212
1213        // 手动将描述符转移到 RX Ring(模拟内核行为)
1214        let descs = socket.fill_ring_mut().dequeue_batch(4).unwrap();
1215        assert_eq!(descs.len(), 4);
1216        socket.rx_ring_mut().enqueue_batch(&descs).unwrap();
1217
1218        // 接收
1219        let received = socket.receive_batch(4).unwrap();
1220        assert_eq!(received.len(), 4);
1221
1222        for desc in &received {
1223            assert_eq!(desc.addr(), (desc.index() as u64) << 12);
1224        }
1225    }
1226
1227    #[test]
1228    fn test_xsk_send_and_complete() {
1229        let config = XskConfig::default();
1230        let mut socket = XskSocket::new(config).unwrap();
1231
1232        // 分配描述符模拟 TX 场景
1233        let d0 = socket.descriptor_engine().allocate(100, 0).unwrap();
1234        let d1 = socket.descriptor_engine().allocate(101, 0).unwrap();
1235
1236        let descs = [d0, d1];
1237        let sent = socket.send_batch(&descs).unwrap();
1238        assert_eq!(sent, 2);
1239
1240        // 模拟内核完成
1241        let tx_descs = socket.tx_ring_mut().dequeue_batch(2).unwrap();
1242        socket.completion_ring_mut().enqueue_batch(&tx_descs).unwrap();
1243
1244        // 回收
1245        let recycled = socket.recycle_completed(2).unwrap();
1246        assert_eq!(recycled, 2);
1247
1248        assert!(socket.descriptor_engine().verify_conservation());
1249    }
1250
1251    #[test]
1252    fn test_xsk_receive_batch_to_buffer() {
1253        let config = XskConfig::default();
1254        let mut socket = XskSocket::new(config).unwrap();
1255
1256        // 填充并转移到 RX
1257        socket.fill_descriptors(3).unwrap();
1258        let descs = socket.fill_ring_mut().dequeue_batch(3).unwrap();
1259        socket.rx_ring_mut().enqueue_batch(&descs).unwrap();
1260
1261        // 使用预分配缓冲区
1262        let mut buffer = [Descriptor::default(); 4];
1263        let count = socket.receive_batch_to(&mut buffer).unwrap();
1264        assert_eq!(count, 3);
1265    }
1266
1267    #[test]
1268    fn test_xsk_config_custom_values() {
1269        let config = XskConfig {
1270            ifindex: 5,
1271            queue_id: 3,
1272            zero_copy: false,
1273            fill_ring_size: 512,
1274            rx_ring_size: 1024,
1275            tx_ring_size: 256,
1276            completion_ring_size: 128,
1277            shared_umem: true,
1278            frame_size: 4096,
1279            headroom: 0,
1280            so_rcvbuf: 1024 * 1024,
1281            so_sndbuf: 1024 * 1024,
1282            prefill_chunk: 64,
1283        };
1284        assert_eq!(config.ifindex, 5);
1285        assert_eq!(config.queue_id, 3);
1286        assert!(!config.zero_copy);
1287        assert_eq!(config.fill_ring_size, 512);
1288        assert_eq!(config.rx_ring_size, 1024);
1289        assert_eq!(config.tx_ring_size, 256);
1290        assert_eq!(config.completion_ring_size, 128);
1291        assert!(config.shared_umem);
1292    }
1293
1294    #[test]
1295    fn test_xsk_config_clone() {
1296        let config = XskConfig {
1297            ifindex: 42,
1298            queue_id: 7,
1299            ..Default::default()
1300        };
1301        let cloned = config.clone();
1302        assert_eq!(cloned.ifindex, 42);
1303        assert_eq!(cloned.queue_id, 7);
1304    }
1305
1306    #[test]
1307    fn test_xsk_state_transitions() {
1308        let config = XskConfig::default();
1309        let mut socket = XskSocket::new(config).unwrap();
1310        assert_eq!(socket.state(), XskState::Created);
1311        assert!(!socket.is_active());
1312
1313        let result = socket.create_socket();
1314        if result.is_ok() {
1315            assert_eq!(socket.state(), XskState::Configured);
1316        }
1317    }
1318
1319    #[test]
1320    fn test_xsk_socket_debug_format() {
1321        let config = XskConfig::default();
1322        let socket = XskSocket::new(config).unwrap();
1323        let debug = format!("{:?}", socket);
1324        assert!(debug.contains("XskSocket"));
1325        assert!(debug.contains("state"));
1326        assert!(debug.contains("active"));
1327    }
1328
1329    #[test]
1330    fn test_xsk_ring_sizes_from_config() {
1331        let config = XskConfig {
1332            fill_ring_size: 256,
1333            rx_ring_size: 512,
1334            tx_ring_size: 1024,
1335            completion_ring_size: 2048,
1336            ..Default::default()
1337        };
1338        let socket = XskSocket::new(config).unwrap();
1339
1340        assert_eq!(socket.fill_ring().capacity(), 256);
1341        assert_eq!(socket.rx_ring().capacity(), 512);
1342        assert_eq!(socket.tx_ring().capacity(), 1024);
1343        assert_eq!(socket.completion_ring().capacity(), 2048);
1344    }
1345
1346    #[test]
1347    fn test_xsk_queue_id_config() {
1348        let config = XskConfig {
1349            queue_id: 42,
1350            ..Default::default()
1351        };
1352        let socket = XskSocket::new(config).unwrap();
1353        let desc = socket.descriptor_engine().allocate(0, 42).unwrap();
1354        assert_eq!(desc.owner(), 42);
1355    }
1356
1357    #[test]
1358    fn test_xsk_zero_copy_config() {
1359        let config = XskConfig {
1360            zero_copy: true,
1361            ..Default::default()
1362        };
1363        assert!(config.zero_copy);
1364
1365        let config = XskConfig {
1366            zero_copy: false,
1367            ..Default::default()
1368        };
1369        assert!(!config.zero_copy);
1370    }
1371
1372    #[test]
1373    fn test_xsk_send_xdp_batch() {
1374        let config = XskConfig::default();
1375        let mut socket = XskSocket::new(config).unwrap();
1376
1377        // send_xdp_batch 现在与 send_batch 对称验证所有权:
1378        // 每个 raw XdpDesc 必须通过 from_xdp 帧索引域校验 + engine.verify。
1379        // 先在引擎中分配帧 0 和帧 1(addr = frame_index << frame_shift = i << 12)
1380        let _ = socket.descriptor_engine().allocate(0, 42).unwrap();
1381        let _ = socket.descriptor_engine().allocate(1, 42).unwrap();
1382
1383        let xdp_descs = [
1384            XdpDesc {
1385                addr: 0, // frame 0: 0 << 12 = 0
1386                len: 100,
1387                options: 0,
1388            },
1389            XdpDesc {
1390                addr: 4096, // frame 1: 1 << 12 = 4096
1391                len: 200,
1392                options: 0,
1393            },
1394        ];
1395
1396        let sent = socket.send_xdp_batch(&xdp_descs).unwrap();
1397        assert_eq!(sent, 2);
1398        assert_eq!(socket.tx_ring().available_data(), 2);
1399    }
1400
1401    #[test]
1402    fn test_xsk_receive_and_refill() {
1403        let config = XskConfig::default();
1404        let mut socket = XskSocket::new(config).unwrap();
1405
1406        socket.fill_descriptors(4).unwrap();
1407        let descs = socket.fill_ring_mut().dequeue_batch(4).unwrap();
1408        socket.rx_ring_mut().enqueue_batch(&descs).unwrap();
1409
1410        let received = socket.receive_and_refill(4).unwrap();
1411        assert_eq!(received.len(), 4);
1412    }
1413
1414    #[test]
1415    fn test_xsk_fill_descriptors_zero_count() {
1416        let config = XskConfig::default();
1417        let mut socket = XskSocket::new(config).unwrap();
1418
1419        let filled = socket.fill_descriptors(0).unwrap();
1420        assert_eq!(filled, 0);
1421    }
1422
1423    #[test]
1424    fn test_xsk_receive_empty_rx_ring() {
1425        let config = XskConfig::default();
1426        let mut socket = XskSocket::new(config).unwrap();
1427
1428        let received = socket.receive_batch(10).unwrap();
1429        assert!(received.is_empty());
1430    }
1431
1432    #[test]
1433    fn test_xsk_recycle_empty_completion_ring() {
1434        let config = XskConfig::default();
1435        let mut socket = XskSocket::new(config).unwrap();
1436
1437        let recycled = socket.recycle_completed(10).unwrap();
1438        assert_eq!(recycled, 0);
1439    }
1440
1441    #[test]
1442    fn test_xsk_state_variants() {
1443        let states = vec![
1444            XskState::Created,
1445            XskState::Configured,
1446            XskState::Bound,
1447            XskState::Closed,
1448        ];
1449        for state in states {
1450            let debug = format!("{:?}", state);
1451            assert!(!debug.is_empty());
1452        }
1453    }
1454
1455    #[test]
1456    fn test_xsk_socket_fd_none_in_simulation() {
1457        let config = XskConfig::default();
1458        let socket = XskSocket::new(config).unwrap();
1459        assert!(socket.fd().is_none());
1460    }
1461
1462    #[test]
1463    fn test_xsk_umem_none_initially() {
1464        let config = XskConfig::default();
1465        let socket = XskSocket::new(config).unwrap();
1466        assert!(socket.umem().is_none());
1467    }
1468
1469    #[test]
1470    fn test_xsk_conservation_after_send_and_recycle() {
1471        let config = XskConfig::default();
1472        let mut socket = XskSocket::new(config).unwrap();
1473
1474        let d0 = socket.descriptor_engine().allocate(10, 0).unwrap();
1475        let d1 = socket.descriptor_engine().allocate(11, 0).unwrap();
1476
1477        assert!(socket.descriptor_engine().verify_conservation());
1478
1479        let descs = [d0, d1];
1480        socket.send_batch(&descs).unwrap();
1481
1482        let tx_descs = socket.tx_ring_mut().dequeue_batch(2).unwrap();
1483        socket.completion_ring_mut().enqueue_batch(&tx_descs).unwrap();
1484
1485        socket.recycle_completed(2).unwrap();
1486
1487        assert!(socket.descriptor_engine().verify_conservation());
1488    }
1489
1490    #[test]
1491    fn test_build_umem_reg_pure_logic() {
1492        // UMEM 注册参数纯逻辑:字段必须与内核 xdp_umem_reg 布局一致
1493        let addr = 0x7f00_0000usize as *const u8;
1494        let reg = build_umem_reg(addr, 2 * 1024 * 1024, 4096, 256);
1495        assert_eq!(reg.addr, 0x7f00_0000u64);
1496        assert_eq!(reg.len, 2 * 1024 * 1024u64);
1497        assert_eq!(reg.chunk_size, 4096);
1498        assert_eq!(reg.headroom, 256);
1499        assert_eq!(reg.flags, 0, "保留标志必须置 0");
1500        assert_eq!(reg.tx_metadata_len, 0, "不启用 TX metadata");
1501
1502        // 空地址/零 headroom 边界
1503        let reg0 = build_umem_reg(std::ptr::null(), 4096, 2048, 0);
1504        assert_eq!(reg0.addr, 0);
1505        assert_eq!(reg0.headroom, 0);
1506    }
1507
1508    #[test]
1509    fn test_to_ring_offsets_pure_logic() {
1510        // ring 偏移纯逻辑:len = desc + ring_size * sizeof(XdpDesc)
1511        let k = libc::xdp_ring_offset {
1512            producer: 0,
1513            consumer: 64,
1514            desc: 128,
1515            flags: 192,
1516        };
1517        let off = to_ring_offsets(&k, 256);
1518        assert_eq!(off.producer, 0);
1519        assert_eq!(off.consumer, 64);
1520        assert_eq!(off.desc, 128);
1521        assert_eq!(off.flags, 192);
1522        assert_eq!(
1523            off.len,
1524            128 + 256 * std::mem::size_of::<XdpDesc>() as u64,
1525            "mmap 长度必须覆盖 desc 偏移 + 全部描述符"
1526        );
1527        // XdpDesc 必须与内核 xdp_desc 同为 16 字节
1528        assert_eq!(std::mem::size_of::<XdpDesc>(), 16);
1529    }
1530
1531    #[test]
1532    fn test_xsk_new_is_simulation_mode() {
1533        // 构造时显式选择:new() = 模拟模式,绝不隐式进入内核模式
1534        let socket = XskSocket::new(XskConfig::default()).unwrap();
1535        assert!(!socket.is_kernel_mode());
1536        assert!(!socket.rx_ring().is_kernel_mode());
1537        assert!(!socket.fill_ring().is_kernel_mode());
1538        assert!(socket.fd().is_none());
1539    }
1540
1541    #[test]
1542    fn test_xsk_bind_rejects_uncreated_umem() {
1543        // Fail-Closed:UMEM 未 create() 时 bind 必须返回明确错误(NotCreated)
1544        let mut socket = match XskSocket::new(XskConfig::default()) {
1545            Ok(s) => s,
1546            Err(_) => return,
1547        };
1548        if socket.create_socket().is_err() {
1549            return; // 环境不支持 AF_XDP socket(如无权限),跳过
1550        }
1551        let umem = Arc::new(
1552            UmemManager::new(crate::umem::UmemConfig {
1553                size: 4096 * 16,
1554                hugepage: false,
1555                locked: false,
1556                shared: false,
1557            })
1558            .unwrap(),
1559        );
1560        // 注意:未调用 umem.create()
1561        let result = socket.bind(umem);
1562        assert!(result.is_err(), "UMEM 未 mmap 时 bind 必须失败");
1563        assert!(!socket.is_kernel_mode(), "失败后不得进入内核模式(无混合状态)");
1564    }
1565
1566    #[test]
1567    fn test_xsk_new_real_fail_closed_on_invalid_ifindex() {
1568        // Fail-Closed:ifindex=0 永远非法,new_real 必须返回错误且绝不降级模拟
1569        let mut umem = UmemManager::new(crate::umem::UmemConfig {
1570            size: 4096 * 64,
1571            hugepage: false,
1572            locked: false,
1573            shared: false,
1574        })
1575        .unwrap();
1576        umem.create().unwrap();
1577        let config = XskConfig {
1578            ifindex: 0, // 非法接口索引
1579            queue_id: 0,
1580            zero_copy: false,
1581            fill_ring_size: 64,
1582            rx_ring_size: 64,
1583            tx_ring_size: 64,
1584            completion_ring_size: 64,
1585            shared_umem: false,
1586            frame_size: 4096,
1587            headroom: 0,
1588            so_rcvbuf: 1024 * 1024,
1589            so_sndbuf: 1024 * 1024,
1590            prefill_chunk: 64,
1591        };
1592        let result = XskSocket::new_real(config, Arc::new(umem));
1593        match result {
1594            Ok(s) => {
1595                // 极端环境(ifindex 0 竟可绑定):必须是完整内核模式
1596                assert!(s.is_kernel_mode());
1597                assert_eq!(s.state(), XskState::Bound);
1598            }
1599            Err(e) => {
1600                // 预期路径:明确错误,无 panic、无静默降级
1601                let msg = format!("{e}");
1602                assert!(!msg.is_empty());
1603            }
1604        }
1605    }
1606
1607    #[test]
1608    fn test_prefill_fill_ring_kernel_mode_logic() {
1609        // 预填纯逻辑:注入匿名 mmap 假内核 Fill Ring + 真实 UMEM,
1610        // 验证帧地址按 frame_size 步进写入共享区、producer 索引正确、守恒成立
1611        let config = XskConfig {
1612            fill_ring_size: 16,
1613            frame_size: 4096,
1614            ..Default::default()
1615        };
1616        let mut socket = XskSocket::new(config).unwrap();
1617
1618        // 真实 UMEM:8 帧 × 4096
1619        let mut umem = UmemManager::new(crate::umem::UmemConfig {
1620            size: 4096 * 8,
1621            hugepage: false,
1622            locked: false,
1623            shared: false,
1624        })
1625        .unwrap();
1626        umem.create().unwrap();
1627        socket.umem = Some(Arc::new(umem));
1628
1629        // 假内核 Fill Ring(匿名 mmap,容量 16)
1630        let desc_off = 64u64;
1631        let ring_size = 16u32;
1632        let len = desc_off + u64::from(ring_size) * 16;
1633        // SAFETY: 测试内匿名 mmap,参数有效;检查 MAP_FAILED。
1634        let base = unsafe {
1635            libc::mmap(
1636                std::ptr::null_mut(),
1637                len as usize,
1638                libc::PROT_READ | libc::PROT_WRITE,
1639                libc::MAP_SHARED | libc::MAP_ANONYMOUS,
1640                -1,
1641                0,
1642            )
1643        };
1644        assert_ne!(base, libc::MAP_FAILED);
1645        let base = base as *mut u8;
1646        let offsets = crate::ring::RingOffsets {
1647            producer: 0,
1648            consumer: 8,
1649            desc: desc_off,
1650            flags: 16,
1651            len,
1652        };
1653        // SAFETY: base 有效、offsets 在映射区内、测试单线程。
1654        socket.fill_ring = unsafe {
1655            XskRing::with_kernel_ring(RingType::Fill, base, offsets)
1656        }
1657        .unwrap();
1658
1659        // UMEM 仅 8 帧 → 预填数 = min(16, 8) = 8
1660        let filled = socket.prefill_fill_ring().unwrap();
1661        assert_eq!(filled, 8);
1662
1663        // 验证共享区:producer == 8,desc[i].addr == i * 4096
1664        // SAFETY: 读取本测试拥有的映射区,偏移在 len 内。
1665        unsafe {
1666            assert_eq!((base as *const u32).read(), 8);
1667            for i in 0..8u64 {
1668                let d = (base.add(desc_off as usize) as *const XdpDesc)
1669                    .add(i as usize)
1670                    .read();
1671                assert_eq!(d.addr, i * 4096, "帧地址必须按 frame_size 步进");
1672                assert_eq!(d.len, 0);
1673            }
1674        }
1675        // 守恒:8 个帧已在引擎登记(allocated == freed + active)
1676        assert!(socket.descriptor_engine().verify_conservation());
1677    }
1678
1679    #[test]
1680    fn test_prefill_fill_ring_simulation_mode_no_umem() {
1681        // 模拟模式无 UMEM:预填为无操作,返回 0
1682        let mut socket = XskSocket::new(XskConfig::default()).unwrap();
1683        assert_eq!(socket.prefill_fill_ring().unwrap(), 0);
1684    }
1685
1686    // ── RingMmapGuard 单元测试(真实匿名 mmap 验证回收/移交语义)───────
1687
1688    /// 测试辅助:匿名 mmap 4096 字节共享页,返回基址(失败即测试失败)
1689    fn anon_mmap_page() -> *mut u8 {
1690        // SAFETY: 测试内匿名 mmap,参数为有效常量;下方检查 MAP_FAILED。
1691        let base = unsafe {
1692            libc::mmap(
1693                std::ptr::null_mut(),
1694                4096,
1695                libc::PROT_READ | libc::PROT_WRITE,
1696                libc::MAP_SHARED | libc::MAP_ANONYMOUS,
1697                -1,
1698                0,
1699            )
1700        };
1701        assert_ne!(base, libc::MAP_FAILED, "匿名 mmap 失败");
1702        base as *mut u8
1703    }
1704
1705    /// 测试辅助:mincore 探测页是否仍在映射中(false = 已被 munmap)
1706    fn page_is_mapped(addr: *const u8) -> bool {
1707        let mut vec = [0u8; 1];
1708        // SAFETY: mincore 仅查询页驻留状态;vec 为栈上 1 字节有效缓冲区,
1709        // addr 为页对齐地址(mmap 返回值);页未映射时返回 ENOMEM 而非 UB。
1710        let ret = unsafe { libc::mincore(addr as *mut libc::c_void, 4096, vec.as_mut_ptr()) };
1711        ret == 0
1712    }
1713
1714    #[test]
1715    fn test_ring_mmap_guard_disarm_path_keeps_mapping() {
1716        // 正常路径:disarm 后 guard Drop 不得 munmap(映射所有权已移交)
1717        let base = anon_mmap_page();
1718        {
1719            let mut guard = RingMmapGuard::new();
1720            let slot = guard.register(base, 4096);
1721            guard.disarm(slot);
1722        } // guard Drop:唯一条目已 disarm,跳过 munmap
1723        // SAFETY: base 未被 munmap(disarm 语义),4096 字节区域内。
1724        unsafe {
1725            base.write(0xAB);
1726            assert_eq!(base.read(), 0xAB, "disarm 后映射必须仍可访问");
1727        }
1728        assert!(page_is_mapped(base), "disarm 的映射不得被 munmap");
1729        // 测试清理(模拟 KernelRing Drop 的 munmap)
1730        // SAFETY: base 为本测试映射的 4096 字节区域,此后不再使用。
1731        unsafe {
1732            libc::munmap(base as *mut libc::c_void, 4096);
1733        }
1734    }
1735
1736    #[test]
1737    fn test_ring_mmap_guard_failure_path_munmaps_all() {
1738        // 失败路径:未 disarm 的映射在 guard Drop 时全部回收(防裸 base 泄漏)。
1739        // 用记账桩做确定性断言(避免并发测试复用刚释放地址的竞态抖动)。
1740        GUARD_TEST_STUB.with(|s| s.set(true));
1741        GUARD_UNMAP_LOG.with(|l| l.borrow_mut().clear());
1742        let b1 = anon_mmap_page();
1743        let b2 = anon_mmap_page();
1744        {
1745            let mut guard = RingMmapGuard::new();
1746            guard.register(b1, 4096);
1747            guard.register(b2, 4096);
1748            // 模拟中途 `?` 提前返回:不 disarm 任何条目,guard 直接 Drop
1749        }
1750        let log = GUARD_UNMAP_LOG.with(|l| l.borrow().clone());
1751        assert_eq!(
1752            log,
1753            vec![(b1 as usize, 4096), (b2 as usize, 4096)],
1754            "失败路径遗留映射必须全部按登记顺序回收"
1755        );
1756        GUARD_TEST_STUB.with(|s| s.set(false));
1757        GUARD_UNMAP_LOG.with(|l| l.borrow_mut().clear());
1758        // SAFETY: b1/b2 为本测试映射的页,测试结束清理。
1759        unsafe {
1760            libc::munmap(b1 as *mut libc::c_void, 4096);
1761            libc::munmap(b2 as *mut libc::c_void, 4096);
1762        }
1763    }
1764
1765    #[test]
1766    fn test_ring_mmap_guard_partial_disarm_only_munmaps_armed() {
1767        // 部分移交路径:已移交(disarm)的保留,未移交(armed)的全部回收
1768        GUARD_TEST_STUB.with(|s| s.set(true));
1769        GUARD_UNMAP_LOG.with(|l| l.borrow_mut().clear());
1770        let b1 = anon_mmap_page();
1771        let b2 = anon_mmap_page();
1772        let b3 = anon_mmap_page();
1773        {
1774            let mut guard = RingMmapGuard::new();
1775            let s1 = guard.register(b1, 4096);
1776            guard.register(b2, 4096);
1777            guard.register(b3, 4096);
1778            guard.disarm(s1);
1779        }
1780        let log = GUARD_UNMAP_LOG.with(|l| l.borrow().clone());
1781        assert_eq!(
1782            log,
1783            vec![(b2 as usize, 4096), (b3 as usize, 4096)],
1784            "仅未移交(armed)映射 b2/b3 须被回收,已移交 b1 不得回收"
1785        );
1786        GUARD_TEST_STUB.with(|s| s.set(false));
1787        GUARD_UNMAP_LOG.with(|l| l.borrow_mut().clear());
1788        // SAFETY: 三页均为本测试映射的匿名页,测试结束清理。
1789        unsafe {
1790            libc::munmap(b1 as *mut libc::c_void, 4096);
1791            libc::munmap(b2 as *mut libc::c_void, 4096);
1792            libc::munmap(b3 as *mut libc::c_void, 4096);
1793        }
1794    }
1795
1796    #[test]
1797    fn test_xsk_fill_descriptors_no_double_register() {
1798        // 修复「fill_descriptors 从 0 重复登记帧破坏守恒」:
1799        // 第二次填充同一批帧时必须跳过已分配帧(返回 0),allocate 不再双计数
1800        let config = XskConfig::default();
1801        let mut socket = XskSocket::new(config).unwrap();
1802
1803        let filled = socket.fill_descriptors(4).unwrap();
1804        assert_eq!(filled, 4);
1805        let (allocated, _) = socket.descriptor_engine().conservation_stats();
1806        assert_eq!(allocated, 4);
1807
1808        let again = socket.fill_descriptors(4).unwrap();
1809        assert_eq!(again, 0, "已分配帧不得重复登记");
1810        let (allocated_after, _) = socket.descriptor_engine().conservation_stats();
1811        assert_eq!(allocated_after, 4, "重复填充不得双计数");
1812        assert!(socket.descriptor_engine().verify_conservation());
1813    }
1814}