Skip to main content

zenith_linux/
ring.rs

1//! AF_XDP Ring 操作封装
2//!
3//! 实现与内核 AF_XDP Ring 兼容的四环操作(Fill/RX/TX/Completion):
4//! - 支持模拟模式(Vec<XdpDesc> backing store,用于测试和开发)
5//! - 支持内核 mmap 模式(通过 XDP_MMAP_OFFSETS 获取内核 ring 地址)
6//! - SPSC 无锁批量操作
7//! - 基于 XdpDesc(内核 xdp_desc)的描述符传递
8//!
9//! # 内核 Ring 结构
10//!
11//! AF_XDP Ring 在内核中的内存布局(每 ring):
12//! ```text
13//! [flags]      (4 bytes) - XDP_RING_NEED_WAKEUP 等标志
14//! [producer]   (4 bytes) - 生产者索引(用户态写,内核态读)
15//! [consumer]   (4 bytes) - 消费者索引(内核态写,用户态读)
16//! [desc0]      (16 bytes) - 第一个 xdp_desc
17//! [desc1]      (16 bytes) - 第二个 xdp_desc
18//! ...
19//! ```
20//!
21//! # 偏移量
22//!
23//! 通过 getsockopt(XDP_MMAP_OFFSETS) 获取各 ring 偏移:
24//! - XDP_RX_RING_OFFSET: RX Ring 在 mmap 中的偏移
25//! - XDP_TX_RING_OFFSET: TX Ring 在 mmap 中的偏移
26//! - XDP_FILL_RING_OFFSET: Fill Ring 在 mmap 中的偏移
27//! - XDP_COMPLETION_RING_OFFSET: Completion Ring 在 mmap 中的偏移
28//!
29//! # unsafe 使用
30//! 本文件实现与内核共享内存的 Ring 原语,包含 mmap 地址读写与裸指针访问。
31//! 是 crate 内部四个被精确放开 `#[allow(unsafe_code)]` 的文件之一。
32
33#![allow(unsafe_code)]
34
35use crate::descriptor::XdpDesc;
36use crate::error::{Result, RingError};
37use std::sync::atomic::{AtomicU32, Ordering};
38
39/// XDP_RING_NEED_WAKEUP 标志(内核 UAPI `include/uapi/linux/if_xdp.h`:`(1 << 0)` = 0x1)
40///
41/// 当此标志置位时,用户态必须通过 sendto()/recvfrom() 唤醒内核轮询。
42/// - TX Ring:调用 sendto(fd, NULL, 0, MSG_DONTWAIT, NULL, 0)
43/// - Fill Ring:调用 recvfrom(fd, NULL, 0, MSG_DONTWAIT, NULL, NULL)
44///
45/// 注:0x1 是内核唯一定义;此前误写 0x2(bit 1)时内核从不写该位,
46/// `need_wakeup()` 恒为 false,notify_tx/notify_fill 路径静默永不唤醒。
47pub const XDP_RING_NEED_WAKEUP: u32 = 0x1;
48
49/// 模拟模式([`RingStorage::Simulated`])环容量硬上限(2^20 = 1M 项)
50///
51/// Simulated 模式的 descriptors 为真实堆分配(16B × capacity = ≤ 16 MiB);
52/// 不设上限时调用方可请求 2^31 项(32 GiB)触发 OOM abort(`vec!` 分配失败
53/// 走 alloc_error_handler 直接 abort,Fail-Closed 无法返回错误)。
54pub const MAX_SIMULATED_CAPACITY: u32 = 1 << 20;
55
56/// Ring 类型
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub enum RingType {
59    /// Fill Ring(用户态 → 内核态:填充可接收的描述符)
60    Fill,
61    /// RX Ring(内核态 → 用户态:接收完成的描述符)
62    Rx,
63    /// TX Ring(用户态 → 内核态:发送的描述符)
64    Tx,
65    /// Completion Ring(内核态 → 用户态:发送完成的描述符)
66    Completion,
67}
68
69/// Ring 内存布局偏移(相对于 ring 起始地址)
70///
71/// 与内核 `xdp_ring_offset` 结构一致:
72/// - producer: 生产者索引的偏移
73/// - consumer: 消费者索引的偏移
74/// - desc: 描述符数组起始偏移
75/// - flags: 标志位偏移
76/// - len: ring 长度(字节)
77#[derive(Debug, Clone, Copy)]
78pub struct RingOffsets {
79    /// 生产者索引偏移
80    pub producer: u64,
81    /// 消费者索引偏移
82    pub consumer: u64,
83    /// 描述符数组起始偏移
84    pub desc: u64,
85    /// 标志位偏移
86    pub flags: u64,
87    /// ring 总长度(字节)
88    pub len: u64,
89}
90
91/// AF_XDP Ring
92///
93/// # 两种模式(枚举互斥,禁止混用)
94///
95/// 1. **模拟模式**([`RingStorage::Simulated`]):使用 `Vec<XdpDesc>` 作为 backing store,
96///    索引通过 AtomicU32 模拟,适合无 root 权限的开发和测试。
97///
98/// 2. **内核 mmap 模式**([`RingStorage::Kernel`]):通过 mmap 映射内核 ring 内存,
99///    producer/consumer 索引与描述符数组均直接读写内核共享区。
100pub struct XskRing {
101    /// Ring 类型
102    ring_type: RingType,
103    /// 容量(必须是 2 的幂)
104    capacity: u32,
105    /// 位掩码(capacity - 1)
106    mask: u32,
107    /// 存储后端(模拟 Vec / 内核 mmap 二选一,类型层面禁止混用)
108    storage: RingStorage,
109}
110
111/// Ring 存储后端
112///
113/// 修复「内核模式描述符来自空 Vec 导致越界」问题:
114/// 内核模式的描述符来自 mmap 共享区,模拟模式使用用户态 Vec,
115/// 两种后端由枚举互斥表达,任何路径都不可能拿错存储。
116enum RingStorage {
117    /// 模拟模式:用户态 backing store(测试/开发)
118    Simulated {
119        /// 生产者索引(用户态写)
120        producer_idx: AtomicU32,
121        /// 消费者索引(用户态读)
122        consumer_idx: AtomicU32,
123        /// 描述符数组 backing store
124        descriptors: Vec<XdpDesc>,
125    },
126    /// 内核 mmap 模式:所有指针均指向内核共享映射区
127    Kernel(KernelRing),
128}
129
130/// 内核 mmap 模式的 ring 视图
131///
132/// 持有 mmap 区域所有权:`Drop` 时执行 `munmap`。
133struct KernelRing {
134    /// mmap 区域基址
135    mmap_base: *mut u8,
136    /// mmap 区域长度(字节)
137    mmap_len: usize,
138    /// 生产者索引(内核共享区,用户态写)
139    producer: *mut AtomicU32,
140    /// 消费者索引(内核共享区,内核态写)
141    consumer: *mut AtomicU32,
142    /// 描述符数组起始地址(内核共享区)
143    descs: *mut XdpDesc,
144    /// flags 字段指针(XDP_RING_NEED_WAKEUP);旧内核(< 5.4)无此字段时为 None
145    flags: Option<*const AtomicU32>,
146}
147
148impl Drop for KernelRing {
149    fn drop(&mut self) {
150        // SAFETY: mmap_base/mmap_len 来自 with_kernel_ring 接管的有效 mmap 区域,
151        // 本结构独占其所有权,Drop 时精确 munmap 一次(此后无任何引用)。
152        unsafe {
153            libc::munmap(self.mmap_base as *mut libc::c_void, self.mmap_len);
154        }
155    }
156}
157
158impl std::fmt::Debug for XskRing {
159    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160        f.debug_struct("XskRing")
161            .field("ring_type", &self.ring_type)
162            .field("capacity", &self.capacity)
163            .field("producer_idx", &self.producer_index())
164            .field("consumer_idx", &self.consumer_index())
165            .field("kernel_mode", &self.is_kernel_mode())
166            .finish()
167    }
168}
169
170// SAFETY: XskRing 设计为单 Owner(Worker)独占,无 Arc/Rc 共享路径。
171// Send/Sync 安全的原因:
172// 1. 模拟模式:所有数据存储在 Vec<XdpDesc> 中,AtomicU32 索引操作本身线程安全,
173//    且 Worker 独占调用 enqueue/dequeue,不存在数据竞争。
174// 2. 内核模式(RingStorage::Kernel):mmap 区域由 KernelRing 独占持有(Drop 时 munmap),
175//    producer/consumer/descs 指针指向该区域,Worker 独占访问内核 ring(SPSC 模型:
176//    用户态与内核各持一端,通过 Acquire/Release 原子索引同步)。
177// 3. 裸指针不自动实现 Send/Sync,此处手动 impl 是对上述安全契约的显式声明。
178unsafe impl Send for XskRing {}
179unsafe impl Sync for XskRing {}
180
181impl XskRing {
182    /// 创建模拟模式的 Ring
183    ///
184    /// # 参数
185    /// * `ring_type` - Ring 类型
186    /// * `capacity` - 容量(向上取整到 2 的幂,最小 16)
187    ///
188    /// # 返回
189    /// * `Result<Self>` - Ring 实例
190    ///
191    /// # Fail-Closed
192    /// - `capacity == 0`:拒绝(原 `max(16)` 会静默掩盖调用方传 0 的错误)
193    /// - 取整后超出 [`MAX_SIMULATED_CAPACITY`]:拒绝。模拟模式的
194    ///   descriptors 是真实堆分配(`XdpDesc` 16B × capacity),不设上限时
195    ///   恶意/失控调用方可请求高达 2^31 项(32 GiB)触发 OOM abort——
196    ///   `vec!` 分配失败走 `alloc_error_handler` 直接 abort,连错误都返回不了。
197    /// - 取整后超出 u32 可表示的最大 2 的幂(2^31):拒绝。原
198    ///   `next_power_of_two()` 在 `capacity > 2^31` 时 debug panic、
199    ///   release 回绕为 0(mask = 0 - 1 = u32::MAX,后续索引全越界),
200    ///   此处改用 `checked_next_power_of_two()` 显式报错。
201    pub fn new(ring_type: RingType, capacity: u32) -> Result<Self> {
202        if capacity == 0 {
203            return Err(RingError::InvalidOffsets(
204                "ring capacity 必须 > 0".to_string(),
205            )
206            .into());
207        }
208        let actual_capacity = capacity
209            .max(16)
210            .checked_next_power_of_two()
211            .ok_or_else(|| {
212                RingError::InvalidOffsets(format!(
213                    "ring capacity {capacity} 超出最大可表示容量 2^31"
214                ))
215            })?;
216        if actual_capacity > MAX_SIMULATED_CAPACITY {
217            return Err(RingError::InvalidOffsets(format!(
218                "ring capacity {actual_capacity} 超出模拟模式上限 {MAX_SIMULATED_CAPACITY}"
219            ))
220            .into());
221        }
222        let mask = actual_capacity - 1;
223
224        Ok(Self {
225            ring_type,
226            capacity: actual_capacity,
227            mask,
228            storage: RingStorage::Simulated {
229                producer_idx: AtomicU32::new(0),
230                consumer_idx: AtomicU32::new(0),
231                descriptors: vec![XdpDesc::zero(); actual_capacity as usize],
232            },
233        })
234    }
235
236    /// 创建内核 mmap 模式的 Ring(接管 mmap 区域所有权,Drop 时 munmap)
237    ///
238    /// # 参数
239    /// * `ring_type` - Ring 类型
240    /// * `mmap_base` - mmap 区域基址(必须指向有效的、已映射的内核 ring 内存)
241    /// * `offsets` - Ring 偏移量(由 getsockopt(XDP_MMAP_OFFSETS) 获取;
242    ///   `len` 为该 ring 的 mmap 总字节数 = `desc + ring_size * sizeof(XdpDesc)`)
243    ///
244    /// # 返回
245    /// * `Result<Self>` - Ring 实例;偏移/长度非法时返回 `RingError::InvalidOffsets`(Fail-Closed)
246    ///
247    /// # Safety
248    /// 调用者必须保证以下条件:
249    /// 1. `mmap_base` 指向长度 ≥ `offsets.len` 的有效 mmap 映射区域(来自 xsk fd 的
250    ///    ring mmap)。本函数成功后该区域所有权转移给 XskRing,由 `Drop` 执行 `munmap`,
251    ///    调用者不得再自行 `munmap`。
252    /// 2. `offsets` 中的偏移量必须与内核 ring 布局一致(通过 getsockopt 获取,
253    ///    由内核保证正确性);本函数仍会对偏移做边界校验,非法即返回错误。
254    /// 3. 调用者必须保证 XskRing 仅在单 Worker 上下文中使用(单 Owner,无并发共享),
255    ///    因为内核 ring 的 producer/consumer 索引需要严格的 happens-before 关系。
256    pub unsafe fn with_kernel_ring(
257        ring_type: RingType,
258        mmap_base: *mut u8,
259        offsets: RingOffsets,
260    ) -> Result<Self> {
261        // ── Fail-Closed 校验:任何偏移/长度非法直接返回错误 ──────────────
262        if mmap_base.is_null() {
263            return Err(RingError::InvalidOffsets("mmap_base 为空指针".to_string()).into());
264        }
265        // checked 算术:desc 区长度 = len - desc(防止 desc > len 时下溢)
266        let desc_area = offsets.len.checked_sub(offsets.desc).ok_or_else(|| {
267            RingError::InvalidOffsets(format!(
268                "desc 偏移 {} 超出 ring 长度 {}",
269                offsets.desc, offsets.len
270            ))
271        })?;
272        let desc_size = std::mem::size_of::<XdpDesc>() as u64;
273        let capacity_u64 = desc_area / desc_size;
274        if capacity_u64 == 0 || capacity_u64 > u64::from(u32::MAX) {
275            return Err(RingError::InvalidOffsets(format!(
276                "描述符容量 {capacity_u64} 非法"
277            ))
278            .into());
279        }
280        let capacity = capacity_u64 as u32;
281        // 内核 ring 大小必须是 2 的幂(xsk_setsockopt 强制);不合法即拒绝,
282        // 绝不向上取整(否则 mask 与内核实际 ring 大小不一致导致越界)。
283        if !capacity.is_power_of_two() {
284            return Err(RingError::InvalidOffsets(format!(
285                "容量 {capacity} 不是 2 的幂"
286            ))
287            .into());
288        }
289        // producer/consumer/flags 偏移必须落在映射区内(off < len 后 len - off 不会下溢)
290        let word = std::mem::size_of::<u32>() as u64;
291        for (name, off) in [
292            ("producer", offsets.producer),
293            ("consumer", offsets.consumer),
294        ] {
295            if off >= offsets.len || offsets.len - off < word {
296                return Err(RingError::InvalidOffsets(format!(
297                    "{name} 偏移 {off} 越界(len={})",
298                    offsets.len
299                ))
300                .into());
301            }
302        }
303        if offsets.flags > 0 && (offsets.flags >= offsets.len || offsets.len - offsets.flags < word)
304        {
305            return Err(RingError::InvalidOffsets(format!(
306                "flags 偏移 {} 越界(len={})",
307                offsets.flags, offsets.len
308            ))
309            .into());
310        }
311
312        // SAFETY: 调用者契约保证 mmap_base 指向长度 ≥ offsets.len 的有效映射区;
313        // 上述校验已保证 producer/consumer/desc/flags 各偏移均落在映射区内,
314        // 且内核保证这些偏移满足 u32/xdp_desc 对齐要求。
315        let kernel = KernelRing {
316            mmap_base,
317            mmap_len: offsets.len as usize,
318            producer: unsafe { mmap_base.add(offsets.producer as usize) as *mut AtomicU32 },
319            consumer: unsafe { mmap_base.add(offsets.consumer as usize) as *mut AtomicU32 },
320            descs: unsafe { mmap_base.add(offsets.desc as usize) as *mut XdpDesc },
321            flags: if offsets.flags > 0 {
322                Some(unsafe { mmap_base.add(offsets.flags as usize) as *const AtomicU32 })
323            } else {
324                None
325            },
326        };
327
328        Ok(Self {
329            ring_type,
330            capacity,
331            mask: capacity - 1,
332            storage: RingStorage::Kernel(kernel),
333        })
334    }
335
336    /// 计算 ring 槽位:`base + offset` 后按 mask 回绕
337    ///
338    /// producer/consumer 为 u32 单调递增索引,到达 `u32::MAX` 后按内核语义
339    /// 自然回绕(wrapping_add);mask = capacity - 1(2 的幂减 1)保证结果
340    /// 恒落在 `[0, capacity)`,不会越界。
341    #[inline]
342    fn ring_slot(base: u32, offset: u32, mask: u32) -> u32 {
343        base.wrapping_add(offset) & mask
344    }
345
346    /// 获取 producer 原子索引引用(按存储后端分发)
347    #[inline]
348    fn producer_atomic(&self) -> &AtomicU32 {
349        match &self.storage {
350            RingStorage::Simulated { producer_idx, .. } => producer_idx,
351            // SAFETY: producer 指向 KernelRing 持有的内核共享映射区,
352            // 偏移经 with_kernel_ring 校验,映射在 KernelRing Drop 前始终有效。
353            RingStorage::Kernel(k) => unsafe { &*k.producer },
354        }
355    }
356
357    /// 获取 consumer 原子索引引用(按存储后端分发)
358    #[inline]
359    fn consumer_atomic(&self) -> &AtomicU32 {
360        match &self.storage {
361            RingStorage::Simulated { consumer_idx, .. } => consumer_idx,
362            // SAFETY: 同 producer_atomic,consumer 指针经校验且映射有效。
363            RingStorage::Kernel(k) => unsafe { &*k.consumer },
364        }
365    }
366
367    /// 读取指定槽位的描述符(按存储后端分发)
368    #[inline]
369    fn read_desc(&self, slot: u32) -> XdpDesc {
370        match &self.storage {
371            RingStorage::Simulated { descriptors, .. } => descriptors[slot as usize],
372            // SAFETY: slot = index & mask < capacity,descs 指向内核共享描述符数组,
373            // 容量由 with_kernel_ring 按 mmap 长度校验,slot 必然落在映射区内。
374            // XdpDesc 为 Copy 类型,直接按值读取。
375            RingStorage::Kernel(k) => unsafe { k.descs.add(slot as usize).read() },
376        }
377    }
378
379    /// 写入指定槽位的描述符(按存储后端分发)
380    #[inline]
381    fn write_desc(&mut self, slot: u32, desc: XdpDesc) {
382        match &mut self.storage {
383            RingStorage::Simulated { descriptors, .. } => descriptors[slot as usize] = desc,
384            // SAFETY: 同 read_desc;SPSC 单生产者语义,描述符写入先于
385            // producer 的 Release 存储完成,对消费者(内核)建立 happens-before。
386            RingStorage::Kernel(k) => unsafe { k.descs.add(slot as usize).write(desc) },
387        }
388    }
389
390    /// 获取可用空间(生产者可写入的位置数)
391    #[inline]
392    pub fn available_space(&self) -> u32 {
393        let producer = self.producer_atomic().load(Ordering::Relaxed);
394        let consumer = self.consumer_atomic().load(Ordering::Acquire);
395        // wrapping_sub:索引回绕后差值仍为正确的占用数(不变式:0 ≤ p - c ≤ capacity)
396        self.capacity - (producer.wrapping_sub(consumer))
397    }
398
399    /// 获取可读数据(消费者可读取的位置数)
400    #[inline]
401    pub fn available_data(&self) -> u32 {
402        let producer = self.producer_atomic().load(Ordering::Acquire);
403        let consumer = self.consumer_atomic().load(Ordering::Relaxed);
404        producer.wrapping_sub(consumer)
405    }
406
407    /// 批量入队(生产者操作)
408    ///
409    /// # 参数
410    /// * `descriptors` - 要入队的 XdpDesc 数组
411    ///
412    /// # 返回
413    /// * `Result<u32>` - 实际入队数量
414    pub fn enqueue_batch(&mut self, descriptors: &[XdpDesc]) -> Result<u32> {
415        if descriptors.is_empty() {
416            return Ok(0);
417        }
418
419        let available = self.available_space();
420        let to_enqueue = descriptors.len() as u32;
421
422        if to_enqueue > available {
423            return Err(RingError::BatchSizeExceeded {
424                requested: to_enqueue,
425                maximum: available,
426            }
427            .into());
428        }
429
430        let start_idx = self.producer_atomic().load(Ordering::Relaxed);
431
432        for (i, desc) in descriptors.iter().enumerate() {
433            let slot = Self::ring_slot(start_idx, i as u32, self.mask);
434            self.write_desc(slot, *desc);
435        }
436
437        // Release 存储 producer:保证上述描述符写入先于索引对消费者(内核)可见。
438        // wrapping_add:u32 索引按内核语义自然回绕。
439        self.producer_atomic()
440            .store(start_idx.wrapping_add(to_enqueue), Ordering::Release);
441
442        Ok(to_enqueue)
443    }
444
445    /// 批量出队(消费者操作)
446    ///
447    /// # 参数
448    /// * `max_batch` - 最大批量大小
449    ///
450    /// # 返回
451    /// * `Result<Vec<XdpDesc>>` - 描述符数组
452    pub fn dequeue_batch(&mut self, max_batch: u32) -> Result<Vec<XdpDesc>> {
453        let available = self.available_data();
454        let to_dequeue = available.min(max_batch);
455
456        if to_dequeue == 0 {
457            return Ok(Vec::new());
458        }
459
460        let consumer = self.consumer_atomic().load(Ordering::Relaxed);
461        let mut result = Vec::with_capacity(to_dequeue as usize);
462
463        for i in 0..to_dequeue {
464            let slot = Self::ring_slot(consumer, i, self.mask);
465            result.push(self.read_desc(slot));
466        }
467
468        // Release 存储 consumer:保证描述符读取先于索引对生产者(内核)可见
469        self.consumer_atomic()
470            .store(consumer.wrapping_add(to_dequeue), Ordering::Release);
471
472        Ok(result)
473    }
474
475    /// 批量出队到预分配缓冲区(零堆分配路径)
476    ///
477    /// # 参数
478    /// * `buffer` - 预分配的 XdpDesc 缓冲区
479    ///
480    /// # 返回
481    /// * `Result<u32>` - 实际出队数量
482    pub fn dequeue_batch_to(&mut self, buffer: &mut [XdpDesc]) -> Result<u32> {
483        let available = self.available_data();
484        let max = buffer.len() as u32;
485        let to_dequeue = available.min(max);
486
487        if to_dequeue == 0 {
488            return Ok(0);
489        }
490
491        let consumer = self.consumer_atomic().load(Ordering::Relaxed);
492
493        for (i, slot) in buffer.iter_mut().enumerate().take(to_dequeue as usize) {
494            let idx = Self::ring_slot(consumer, i as u32, self.mask);
495            *slot = self.read_desc(idx);
496        }
497
498        self.consumer_atomic()
499            .store(consumer.wrapping_add(to_dequeue), Ordering::Release);
500
501        Ok(to_dequeue)
502    }
503
504    /// 批量入队到预分配描述符(零 Vec 分配)
505    ///
506    /// # 参数
507    /// * `descriptors` - 预分配的 XdpDesc 数组切片
508    ///
509    /// # 返回
510    /// * `Result<u32>` - 实际入队数量
511    pub fn enqueue_batch_from(&mut self, descriptors: &[XdpDesc]) -> Result<u32> {
512        self.enqueue_batch(descriptors)
513    }
514
515    /// 回退消费者索引
516    ///
517    /// count 不得超过当前消费者索引,否则索引回绕到 u32::MAX 导致后续读取未初始化数据
518    pub fn revert_consumer(&mut self, count: u32) {
519        debug_assert!(
520            count <= self.consumer_index(),
521            "回退计数 {count} 超过当前消费者索引 {}",
522            self.consumer_index()
523        );
524        self.consumer_atomic().fetch_sub(count, Ordering::Release);
525    }
526
527    /// 回退生产者索引
528    ///
529    /// count 不得超过当前生产者索引,否则索引回绕到 u32::MAX 导致后续写入越界
530    pub fn revert_producer(&mut self, count: u32) {
531        debug_assert!(
532            count <= self.producer_index(),
533            "回退计数 {count} 超过当前生产者索引 {}",
534            self.producer_index()
535        );
536        self.producer_atomic().fetch_sub(count, Ordering::Release);
537    }
538
539    /// 获取容量
540    #[inline]
541    pub fn capacity(&self) -> u32 {
542        self.capacity
543    }
544
545    /// 获取 Ring 类型
546    #[inline]
547    pub fn ring_type(&self) -> RingType {
548        self.ring_type
549    }
550
551    /// 获取当前生产者索引
552    #[inline]
553    pub fn producer_index(&self) -> u32 {
554        self.producer_atomic().load(Ordering::Relaxed)
555    }
556
557    /// 获取当前消费者索引
558    #[inline]
559    pub fn consumer_index(&self) -> u32 {
560        self.consumer_atomic().load(Ordering::Relaxed)
561    }
562
563    /// 是否为内核 mmap 模式
564    #[inline]
565    pub fn is_kernel_mode(&self) -> bool {
566        matches!(self.storage, RingStorage::Kernel(_))
567    }
568
569    /// 检查内核是否需要唤醒(XDP_RING_NEED_WAKEUP 标志)
570    ///
571    /// 在内核模式下,读取内核 ring 的 flags 字段。
572    /// 当 `XDP_RING_NEED_WAKEUP` 标志置位时,用户态须通过 syscall 唤醒内核:
573    /// `sendto(fd, NULL, 0, MSG_DONTWAIT, NULL, 0)`。
574    ///
575    /// 模拟模式下始终返回 false(无需唤醒)。
576    #[inline]
577    pub fn need_wakeup(&self) -> bool {
578        match &self.storage {
579            RingStorage::Kernel(k) => match k.flags {
580                // SAFETY: flags 指针在 with_kernel_ring 中由内核 mmap 区域计算得出并经边界校验,
581                // 映射由 KernelRing 持有(Drop 才 munmap),且仅单 Worker 访问(无数据竞争)。
582                Some(ptr) => unsafe {
583                    let flags = (*ptr).load(Ordering::Acquire);
584                    (flags & XDP_RING_NEED_WAKEUP) != 0
585                },
586                None => false,
587            },
588            RingStorage::Simulated { .. } => false,
589        }
590    }
591}
592
593#[cfg(test)]
594mod tests {
595    use super::*;
596
597    fn make_desc(addr: u64, len: u32) -> XdpDesc {
598        XdpDesc {
599            addr,
600            len,
601            options: 0,
602        }
603    }
604
605    #[test]
606    fn test_ring_creation() {
607        let ring = XskRing::new(RingType::Fill, 64).unwrap();
608        assert_eq!(ring.capacity(), 64);
609        assert_eq!(ring.ring_type(), RingType::Fill);
610        assert_eq!(ring.available_data(), 0);
611        assert_eq!(ring.available_space(), 64);
612        assert!(!ring.is_kernel_mode());
613    }
614
615    #[test]
616    fn test_ring_capacity_power_of_two() {
617        let ring = XskRing::new(RingType::Rx, 10).unwrap();
618        assert_eq!(ring.capacity(), 16);
619    }
620
621    #[test]
622    fn test_ring_enqueue_dequeue() {
623        let mut ring = XskRing::new(RingType::Tx, 16).unwrap();
624
625        let descs = [
626            make_desc(0, 64),
627            make_desc(4096, 128),
628            make_desc(8192, 256),
629            make_desc(12288, 512),
630            make_desc(16384, 1024),
631        ];
632        let enqueued = ring.enqueue_batch(&descs).unwrap();
633        assert_eq!(enqueued, 5);
634        assert_eq!(ring.available_data(), 5);
635        assert_eq!(ring.available_space(), 11);
636
637        let dequeued = ring.dequeue_batch(3).unwrap();
638        assert_eq!(dequeued.len(), 3);
639        assert_eq!(dequeued[0].addr, 0);
640        assert_eq!(dequeued[1].addr, 4096);
641        assert_eq!(dequeued[2].addr, 8192);
642        assert_eq!(ring.available_data(), 2);
643
644        let dequeued = ring.dequeue_batch(10).unwrap();
645        assert_eq!(dequeued.len(), 2);
646        assert_eq!(ring.available_data(), 0);
647    }
648
649    #[test]
650    fn test_ring_full() {
651        let mut ring = XskRing::new(RingType::Completion, 16).unwrap();
652        let descs: Vec<XdpDesc> = (0..17).map(|i| make_desc(i * 4096, 0)).collect();
653        let result = ring.enqueue_batch(&descs);
654        assert!(result.is_err());
655    }
656
657    #[test]
658    fn test_ring_wrapping() {
659        let mut ring = XskRing::new(RingType::Fill, 16).unwrap();
660
661        let descs: Vec<XdpDesc> = (0..16).map(|i| make_desc(i * 4096, 0)).collect();
662        ring.enqueue_batch(&descs).unwrap();
663        ring.dequeue_batch(16).unwrap();
664
665        assert_eq!(ring.available_data(), 0);
666        assert_eq!(ring.available_space(), 16);
667
668        ring.enqueue_batch(&[make_desc(65536, 0), make_desc(69632, 0)]).unwrap();
669        assert_eq!(ring.available_data(), 2);
670    }
671
672    #[test]
673    fn test_ring_dequeue_to_buffer() {
674        let mut ring = XskRing::new(RingType::Rx, 8).unwrap();
675        let descs = [make_desc(1024, 100), make_desc(2048, 200), make_desc(3072, 300), make_desc(4096, 400)];
676        ring.enqueue_batch(&descs).unwrap();
677
678        let mut buffer = [XdpDesc::zero(); 3];
679        let count = ring.dequeue_batch_to(&mut buffer).unwrap();
680        assert_eq!(count, 3);
681        assert_eq!(buffer[0].addr, 1024);
682        assert_eq!(buffer[1].addr, 2048);
683        assert_eq!(buffer[2].addr, 3072);
684    }
685
686    #[test]
687    fn test_ring_revert() {
688        let mut ring = XskRing::new(RingType::Tx, 16).unwrap();
689
690        ring.enqueue_batch(&[make_desc(0, 0), make_desc(4096, 0), make_desc(8192, 0)])
691            .unwrap();
692        assert_eq!(ring.available_data(), 3);
693
694        ring.revert_producer(2);
695        assert_eq!(ring.available_data(), 1);
696
697        ring.dequeue_batch(1).unwrap();
698        assert_eq!(ring.available_data(), 0);
699
700        ring.revert_consumer(1);
701        assert_eq!(ring.available_data(), 1);
702    }
703
704    #[test]
705    fn test_ring_empty_dequeue() {
706        let mut ring = XskRing::new(RingType::Rx, 16).unwrap();
707        let result = ring.dequeue_batch(10).unwrap();
708        assert!(result.is_empty());
709    }
710
711    #[test]
712    fn test_ring_zero_length() {
713        let mut ring = XskRing::new(RingType::Fill, 16).unwrap();
714        let result = ring.enqueue_batch(&[]).unwrap();
715        assert_eq!(result, 0);
716    }
717
718    #[test]
719    fn test_ring_capacity_minimum_16() {
720        let ring = XskRing::new(RingType::Rx, 1).unwrap();
721        assert_eq!(ring.capacity(), 16);
722        assert!(ring.capacity().is_power_of_two());
723    }
724
725    #[test]
726    fn test_ring_capacity_exact_power_of_two() {
727        for cap in [16, 32, 64, 128, 256, 512, 1024, 2048, 4096] {
728            let ring = XskRing::new(RingType::Tx, cap).unwrap();
729            assert_eq!(ring.capacity(), cap);
730            assert!(ring.capacity().is_power_of_two());
731        }
732    }
733
734    #[test]
735    fn test_ring_capacity_rounds_up() {
736        let test_cases = vec![
737            (17, 32),
738            (33, 64),
739            (100, 128),
740            (255, 256),
741            (1000, 1024),
742        ];
743        for (input, expected) in test_cases {
744            let ring = XskRing::new(RingType::Completion, input).unwrap();
745            assert_eq!(
746                ring.capacity(),
747                expected,
748                "Input {} should round up to {}",
749                input,
750                expected
751            );
752            assert!(ring.capacity().is_power_of_two());
753        }
754    }
755
756    #[test]
757    fn test_ring_new_fail_closed_on_invalid_capacity() {
758        // Fail-Closed:capacity == 0 必须返回错误(不再被 max(16) 静默掩盖)
759        assert!(XskRing::new(RingType::Rx, 0).is_err());
760        // Fail-Closed:capacity > 2^31 时 next_power_of_two 会 debug panic /
761        // release 回绕为 0,必须显式返回错误而非 panic/回绕
762        assert!(XskRing::new(RingType::Rx, u32::MAX).is_err());
763        assert!(XskRing::new(RingType::Rx, (1u32 << 31) + 1).is_err());
764        // Fail-Closed:超出模拟模式堆分配上限必须返回错误而非 OOM abort——
765        // 2^31 项 × 16B = 32 GiB 的真实堆分配在容量受限环境直接 abort(alloc_error_handler),
766        // 连错误都返回不了;MAX_SIMULATED_CAPACITY 是 Simulated 模式可安全分配的上界
767        assert!(XskRing::new(RingType::Rx, 1u32 << 31).is_err());
768        assert!(XskRing::new(RingType::Rx, MAX_SIMULATED_CAPACITY + 1).is_err());
769        // 边界:上限本身(2^20 = 1M 项 ≤ 16 MiB)合法
770        assert!(XskRing::new(RingType::Rx, MAX_SIMULATED_CAPACITY).is_ok());
771    }
772
773    #[test]
774    fn test_ring_empty_boundary() {
775        let mut ring = XskRing::new(RingType::Rx, 32).unwrap();
776        assert_eq!(ring.available_data(), 0);
777        assert_eq!(ring.available_space(), 32);
778
779        let result = ring.dequeue_batch(10).unwrap();
780        assert!(result.is_empty());
781        assert_eq!(ring.consumer_index(), 0);
782    }
783
784    #[test]
785    fn test_ring_full_boundary() {
786        let mut ring = XskRing::new(RingType::Tx, 16).unwrap();
787        let descs: Vec<XdpDesc> = (0..16).map(|i| make_desc(i * 4096, 64)).collect();
788
789        let enqueued = ring.enqueue_batch(&descs).unwrap();
790        assert_eq!(enqueued, 16);
791        assert_eq!(ring.available_data(), 16);
792        assert_eq!(ring.available_space(), 0);
793
794        let overflow = ring.enqueue_batch(&[make_desc(65536, 0)]);
795        assert!(overflow.is_err());
796    }
797
798    #[test]
799    fn test_ring_full_then_partial_consume() {
800        let mut ring = XskRing::new(RingType::Rx, 16).unwrap();
801        let descs: Vec<XdpDesc> = (0..16).map(|i| make_desc(i * 4096, 64)).collect();
802        ring.enqueue_batch(&descs).unwrap();
803        assert_eq!(ring.available_space(), 0);
804
805        let consumed = ring.dequeue_batch(5).unwrap();
806        assert_eq!(consumed.len(), 5);
807        assert_eq!(ring.available_space(), 5);
808        assert_eq!(ring.available_data(), 11);
809    }
810
811    #[test]
812    fn test_ring_index_wrapping_producer() {
813        let mut ring = XskRing::new(RingType::Fill, 16).unwrap();
814
815        for i in 0..16 {
816            ring.enqueue_batch(&[make_desc(i * 4096, 0)]).unwrap();
817        }
818        assert_eq!(ring.producer_index(), 16);
819
820        ring.dequeue_batch(8).unwrap();
821        assert_eq!(ring.consumer_index(), 8);
822
823        for i in 16..24 {
824            ring.enqueue_batch(&[make_desc(i * 4096, 0)]).unwrap();
825        }
826        assert_eq!(ring.producer_index(), 24);
827        assert_eq!(ring.available_data(), 16);
828    }
829
830    #[test]
831    fn test_ring_index_wrapping_consumer() {
832        let mut ring = XskRing::new(RingType::Rx, 16).unwrap();
833
834        for _ in 0..3 {
835            let descs: Vec<XdpDesc> = (0..16).map(|i| make_desc(i * 4096, 0)).collect();
836            ring.enqueue_batch(&descs).unwrap();
837            let consumed = ring.dequeue_batch(16).unwrap();
838            assert_eq!(consumed.len(), 16);
839        }
840
841        assert_eq!(ring.producer_index(), 48);
842        assert_eq!(ring.consumer_index(), 48);
843        assert_eq!(ring.available_data(), 0);
844    }
845
846    #[test]
847    fn test_ring_batch_exceeds_available_space() {
848        let mut ring = XskRing::new(RingType::Tx, 32).unwrap();
849        let descs: Vec<XdpDesc> = (0..10).map(|i| make_desc(i * 4096, 0)).collect();
850        ring.enqueue_batch(&descs).unwrap();
851
852        assert_eq!(ring.available_space(), 22);
853
854        let too_many: Vec<XdpDesc> = (0..30).map(|i| make_desc(i * 4096, 0)).collect();
855        let result = ring.enqueue_batch(&too_many);
856        assert!(result.is_err());
857    }
858
859    #[test]
860    fn test_ring_dequeue_batch_to_empty_buffer() {
861        let mut ring = XskRing::new(RingType::Rx, 16).unwrap();
862        let descs = [make_desc(1024, 100)];
863        ring.enqueue_batch(&descs).unwrap();
864
865        let mut buffer = [];
866        let count = ring.dequeue_batch_to(&mut buffer).unwrap();
867        assert_eq!(count, 0);
868    }
869
870    #[test]
871    fn test_ring_enqueue_batch_from_alias() {
872        let mut ring = XskRing::new(RingType::Fill, 16).unwrap();
873        let descs = [make_desc(4096, 128), make_desc(8192, 256)];
874        let count = ring.enqueue_batch_from(&descs).unwrap();
875        assert_eq!(count, 2);
876        assert_eq!(ring.available_data(), 2);
877    }
878
879    #[test]
880    fn test_ring_revert_producer_zero() {
881        let mut ring = XskRing::new(RingType::Tx, 16).unwrap();
882        ring.revert_producer(0);
883        assert_eq!(ring.producer_index(), 0);
884        assert_eq!(ring.available_data(), 0);
885    }
886
887    #[test]
888    fn test_ring_revert_consumer_zero() {
889        let mut ring = XskRing::new(RingType::Rx, 16).unwrap();
890        ring.revert_consumer(0);
891        assert_eq!(ring.consumer_index(), 0);
892        assert_eq!(ring.available_data(), 0);
893    }
894
895    #[test]
896    fn test_ring_types_all_work() {
897        let types = vec![
898            RingType::Fill,
899            RingType::Rx,
900            RingType::Tx,
901            RingType::Completion,
902        ];
903        for ring_type in types {
904            let mut ring = XskRing::new(ring_type, 16).unwrap();
905            assert_eq!(ring.ring_type(), ring_type);
906            let desc = make_desc(0, 0);
907            ring.enqueue_batch(&[desc]).unwrap();
908            let result = ring.dequeue_batch(1).unwrap();
909            assert_eq!(result.len(), 1);
910        }
911    }
912
913    #[test]
914    fn test_ring_fifo_order() {
915        let mut ring = XskRing::new(RingType::Rx, 32).unwrap();
916        let descs: Vec<XdpDesc> = (0..10u32).map(|i| make_desc(i as u64 * 4096, i * 100)).collect();
917
918        ring.enqueue_batch(&descs).unwrap();
919        let dequeued = ring.dequeue_batch(10).unwrap();
920
921        for (i, desc) in dequeued.iter().enumerate() {
922            assert_eq!(desc.addr, i as u64 * 4096);
923            assert_eq!(desc.len, i as u32 * 100);
924        }
925    }
926
927    #[test]
928    fn test_need_wakeup_simulated_mode() {
929        // 模拟模式下 need_wakeup 始终返回 false(无内核需要唤醒)
930        let ring = XskRing::new(RingType::Tx, 64).unwrap();
931        assert!(!ring.need_wakeup());
932
933        let fill_ring = XskRing::new(RingType::Fill, 64).unwrap();
934        assert!(!fill_ring.need_wakeup());
935    }
936
937    #[test]
938    fn test_xdp_ring_need_wakeup_constant() {
939        // XDP_RING_NEED_WAKEUP = 0x1(内核 UAPI if_xdp.h: (1 << 0),固化防回归)
940        assert_eq!(XDP_RING_NEED_WAKEUP, 0x1);
941    }
942
943    #[test]
944    fn test_ring_slot_wrapping_pure_logic() {
945        // 纯逻辑:u32 索引在 u32::MAX 边界自然回绕,mask 保证落入 [0, capacity)
946        assert_eq!(XskRing::ring_slot(0, 0, 15), 0);
947        assert_eq!(XskRing::ring_slot(u32::MAX, 1, 15), 0); // MAX+1 回绕到 0
948        assert_eq!(XskRing::ring_slot(u32::MAX - 1, 3, 15), 1); // (MAX-1)+3 回绕到 1
949        assert_eq!(XskRing::ring_slot(u32::MAX - 2, 4, 15), 1); // (MAX-2)+4 回绕到 1
950        assert_eq!(XskRing::ring_slot(5, 3, 15), 8);
951        // mask 为 2 的幂减 1 时结果恒 < capacity
952        for base in [0u32, 1, 15, 16, u32::MAX - 7, u32::MAX] {
953            for off in [0u32, 1, 7, 16, 100] {
954                assert!(XskRing::ring_slot(base, off, 15) < 16);
955            }
956        }
957    }
958
959    #[test]
960    fn test_simulated_ring_index_wrap_at_u32_max() {
961        // 模拟模式:producer/consumer 推到 u32::MAX 附近,验证跨回绕边界 FIFO 正确
962        let mut ring = XskRing::new(RingType::Tx, 16).unwrap();
963        if let RingStorage::Simulated {
964            producer_idx,
965            consumer_idx,
966            ..
967        } = &ring.storage
968        {
969            producer_idx.store(u32::MAX - 2, Ordering::SeqCst);
970            consumer_idx.store(u32::MAX - 2, Ordering::SeqCst);
971        } else {
972            panic!("new() 必须是模拟模式");
973        }
974
975        let descs: Vec<XdpDesc> = (0..4u32).map(|i| make_desc(u64::from(i) * 4096, i)).collect();
976        assert_eq!(ring.enqueue_batch(&descs).unwrap(), 4);
977        assert_eq!(ring.available_data(), 4);
978        // producer 已回绕:(MAX-2) + 4 = MAX+2 → 1
979        assert_eq!(ring.producer_index(), 1);
980
981        let out = ring.dequeue_batch(4).unwrap();
982        assert_eq!(out.len(), 4);
983        for (i, d) in out.iter().enumerate() {
984            assert_eq!(d.addr, (i as u64) * 4096);
985        }
986        assert_eq!(ring.consumer_index(), 1);
987        assert_eq!(ring.available_data(), 0);
988        assert_eq!(ring.available_space(), 16);
989    }
990
991    /// 构造匿名 mmap 上的「假内核 ring」布局(无需真实 AF_XDP socket)
992    ///
993    /// 返回 (mmap 基址, RingOffsets)。映射所有权随 with_kernel_ring 转移,
994    /// 由 XskRing Drop 时 munmap。
995    fn fake_kernel_ring_layout(ring_size: u32, flags_value: u32) -> (*mut u8, RingOffsets) {
996        let desc_off = 64u64;
997        let len = desc_off + u64::from(ring_size) * std::mem::size_of::<XdpDesc>() as u64;
998        let map_len = len as usize;
999        // SAFETY: 测试内匿名 mmap,参数均为有效常量;下方检查 MAP_FAILED。
1000        let base = unsafe {
1001            libc::mmap(
1002                std::ptr::null_mut(),
1003                map_len,
1004                libc::PROT_READ | libc::PROT_WRITE,
1005                libc::MAP_SHARED | libc::MAP_ANONYMOUS,
1006                -1,
1007                0,
1008            )
1009        };
1010        assert_ne!(base, libc::MAP_FAILED, "匿名 mmap 失败");
1011        let base = base as *mut u8;
1012        // SAFETY: base 指向刚映射的 map_len 字节区域,偏移 16..20 在区域内。
1013        unsafe {
1014            (base.add(16) as *mut u32).write(flags_value);
1015        }
1016        (
1017            base,
1018            RingOffsets {
1019                producer: 0,
1020                consumer: 8,
1021                desc: desc_off,
1022                flags: 16,
1023                len,
1024            },
1025        )
1026    }
1027
1028    #[test]
1029    fn test_kernel_mode_ring_enqueue_dequeue_via_mmap() {
1030        let (base, offsets) = fake_kernel_ring_layout(4, 0);
1031        // SAFETY: base 指向有效的匿名映射区,offsets 布局经手工构造且在映射区内;
1032        // 测试单线程访问,满足单 Owner 契约。
1033        let mut ring = unsafe { XskRing::with_kernel_ring(RingType::Tx, base, offsets) }
1034            .expect("合法偏移必须成功");
1035
1036        assert!(ring.is_kernel_mode());
1037        assert_eq!(ring.capacity(), 4);
1038        assert_eq!(ring.available_space(), 4);
1039
1040        let descs = [make_desc(4096, 64), make_desc(8192, 128)];
1041        assert_eq!(ring.enqueue_batch(&descs).unwrap(), 2);
1042
1043        // 验证数据真实写入内核共享区:producer == 2,desc[0].addr == 4096
1044        // SAFETY: 读取本测试刚写入的映射区,偏移均在映射长度内。
1045        unsafe {
1046            assert_eq!((base as *const u32).read(), 2, "producer 索引应写入共享区");
1047            let d0 = (base.add(64) as *const XdpDesc).read();
1048            assert_eq!(d0.addr, 4096);
1049            assert_eq!(d0.len, 64);
1050            let d1 = (base.add(64 + 16) as *const XdpDesc).read();
1051            assert_eq!(d1.addr, 8192);
1052        }
1053
1054        let out = ring.dequeue_batch(4).unwrap();
1055        assert_eq!(out.len(), 2);
1056        assert_eq!(out[0].addr, 4096);
1057        assert_eq!(out[1].addr, 8192);
1058        // SAFETY: 读取共享区 consumer 索引。
1059        unsafe {
1060            assert_eq!((base.add(8) as *const u32).read(), 2, "consumer 索引应写入共享区");
1061        }
1062        // ring Drop 时自动 munmap(映射所有权已转移)
1063    }
1064
1065    #[test]
1066    fn test_kernel_mode_ring_need_wakeup_flag() {
1067        let (base, offsets) = fake_kernel_ring_layout(4, XDP_RING_NEED_WAKEUP);
1068        // SAFETY: 同上一个测试,映射有效、单线程。
1069        let ring = unsafe { XskRing::with_kernel_ring(RingType::Fill, base, offsets) }
1070            .expect("合法偏移必须成功");
1071        assert!(ring.need_wakeup(), "flags 置位时 need_wakeup 必须为 true");
1072
1073        // 清除 flags 后应为 false
1074        // SAFETY: base 仍有效(ring 未 drop),偏移 16 在映射区内。
1075        unsafe {
1076            (base.add(16) as *mut u32).write(0u32);
1077        }
1078        assert!(!ring.need_wakeup());
1079    }
1080
1081    #[test]
1082    fn test_kernel_mode_ring_no_flags_field() {
1083        // 旧内核(< 5.4)无 flags 字段:offsets.flags == 0 → need_wakeup 恒 false
1084        let (base, mut offsets) = fake_kernel_ring_layout(4, 0);
1085        offsets.flags = 0;
1086        // SAFETY: 映射有效、单线程。
1087        let ring = unsafe { XskRing::with_kernel_ring(RingType::Rx, base, offsets) }
1088            .expect("合法偏移必须成功");
1089        assert!(!ring.need_wakeup());
1090    }
1091
1092    #[test]
1093    fn test_kernel_mode_ring_rejects_invalid_offsets() {
1094        let (base, offsets) = fake_kernel_ring_layout(4, 0);
1095
1096        // 空指针
1097        let r = unsafe { XskRing::with_kernel_ring(RingType::Rx, std::ptr::null_mut(), offsets) };
1098        assert!(r.is_err(), "空 mmap_base 必须拒绝");
1099
1100        // desc > len(下溢路径)
1101        let bad = RingOffsets { desc: 4096, ..offsets };
1102        let r = unsafe { XskRing::with_kernel_ring(RingType::Rx, base, bad) };
1103        assert!(r.is_err(), "desc > len 必须拒绝");
1104
1105        // 容量非 2 的幂(len - desc = 3 * 16)
1106        let bad = RingOffsets { len: offsets.desc + 3 * 16, ..offsets };
1107        let r = unsafe { XskRing::with_kernel_ring(RingType::Rx, base, bad) };
1108        assert!(r.is_err(), "非 2 的幂容量必须拒绝");
1109
1110        // producer 偏移越界
1111        let bad = RingOffsets { producer: offsets.len, ..offsets };
1112        let r = unsafe { XskRing::with_kernel_ring(RingType::Rx, base, bad) };
1113        assert!(r.is_err(), "producer 越界必须拒绝");
1114
1115        // flags 偏移越界
1116        let bad = RingOffsets { flags: offsets.len + 4, ..offsets };
1117        let r = unsafe { XskRing::with_kernel_ring(RingType::Rx, base, bad) };
1118        assert!(r.is_err(), "flags 越界必须拒绝");
1119
1120        // 清理:上述 Err 路径未接管映射,需手动 munmap
1121        // SAFETY: base 指向本测试映射的 offsets.len 字节区域,且未转移所有权。
1122        unsafe {
1123            libc::munmap(base as *mut libc::c_void, offsets.len as usize);
1124        }
1125    }
1126
1127    #[test]
1128    fn test_kernel_mode_ring_wrap_across_u32_max() {
1129        let (base, offsets) = fake_kernel_ring_layout(16, 0);
1130        // SAFETY: 映射有效、单线程。
1131        let mut ring = unsafe { XskRing::with_kernel_ring(RingType::Completion, base, offsets) }
1132            .expect("合法偏移必须成功");
1133
1134        // 直接把共享区 producer/consumer 写到 u32::MAX 附近(模拟内核长期运行后的状态)
1135        // SAFETY: base 有效,偏移 0/8 在映射区内。
1136        unsafe {
1137            (base as *mut u32).write(u32::MAX - 1);
1138            (base.add(8) as *mut u32).write(u32::MAX - 1);
1139        }
1140        assert_eq!(ring.available_data(), 0);
1141        assert_eq!(ring.available_space(), 16);
1142
1143        let descs: Vec<XdpDesc> = (0..4u32).map(|i| make_desc(u64::from(i) * 4096, i)).collect();
1144        assert_eq!(ring.enqueue_batch(&descs).unwrap(), 4);
1145        // producer 回绕:(MAX-1) + 4 = 2
1146        assert_eq!(ring.producer_index(), 2);
1147        assert_eq!(ring.available_data(), 4);
1148
1149        let out = ring.dequeue_batch(4).unwrap();
1150        assert_eq!(out.len(), 4);
1151        for (i, d) in out.iter().enumerate() {
1152            assert_eq!(d.addr, (i as u64) * 4096, "跨回绕边界 FIFO 顺序必须保持");
1153        }
1154        assert_eq!(ring.consumer_index(), 2);
1155    }
1156}