feat(packet): 实现 TPACKET V1/V2 mmap ring buffer (Issue #2030)#2096
Open
sparkzky wants to merge 8 commits into
Open
feat(packet): 实现 TPACKET V1/V2 mmap ring buffer (Issue #2030)#2096sparkzky wants to merge 8 commits into
sparkzky wants to merge 8 commits into
Conversation
…nity#2030) 为 AF_PACKET socket 实现 TPACKET mmap ring buffer,使 tcpdump/libpcap 能 通过零拷贝环形缓冲区高效抓包。本次实现 Phase 1:TPACKET V1/V2 的 PACKET_RX_RING + mmap + poll/epoll 唤醒 + PACKET_VERSION/STATISTICS/RESERVE/HDRLEN。 主要改动: - uapi.rs: 补充 TPACKET 常量与 #[repr(C)] 结构体(TpacketReq/Hdr/2Hdr/Stats) - ring.rs: 新建 ring buffer 核心,per-block 物理页分配(避免大块连续分配在 内存碎片化时 ENOMEM),VLAN 剥离,tp_status Release 序发布 - base.rs: Socket trait 新增 mmap_layout() 方法 - inode.rs: blanket impl 转发 page_cache/fs/metadata,mmap() 无 ring 时返回 EINVAL - mod.rs: PacketSocket 集成 rx_ring/tpacket_version/tp_reserve 字段 - rx.rs: can_recv 检查 ring USER 帧,deliver_from_iface ring 路径唤醒 wait_queue/epoll/fasync - sockopt.rs: SOL_PACKET 选项处理(VERSION/RX_RING/RESERVE/STATISTICS/HDRLEN 等) - packet_ring_test: 用户态 C 测试程序 对抗性 review 修复(P0/P1): - ring.rs: 修复 fill_frame 中 ifindex/pkt_type 未定义编译错误 - rx.rs: ring 路径补充 send_sigio(FASYNC_POLL_IN) - ring.rs: page_mkwrite 调用 filemap_page_mkwrite(计划 P1-1 修正) - ring.rs: per-block 物理页分配(计划 P2-4 修正),frame_base 按 block 索引寻址 编译验证:make kernel 通过,产物 bin/kernel/kernel.elf Signed-off-by: --global <sparkhhhhhhhhhh@outlook.com>
P2-1: has_user_frames 加 O(N) 扫描性能注释(非热路径,可接受; 未来可优化为 AtomicU32 user_frame_count 懒更新) P2-2: V2 时间戳改用 PosixTimeSpec::now() 获取真纳秒(等价 Linux ktime_get_real_ts64),不再用微秒×1000 缩放;V1 保持微秒不变 P2-3: packet_ring_test 改为自包含——poll 前主动 sendto 发送测试帧 到 lo,读帧时校验数据一致性,rc=0 仅在校验通过时返回 P2-4: validate_ring_config 将 block_nr*block_size 溢出检查前移到 frame_size 校验之前(防御性编程) 编译验证:make kernel 通过 Signed-off-by: --global <sparkhhhhhhhhhh@outlook.com>
根因:PacketRing::setup 分配页时用 PageType::Normal,但 filemap_page_mkwrite 要求 PageType::File → 返回 SIGBUS, 导致用户空间写 tp_status 翻回帧时崩溃。 修复:PacketFakeFs::page_mkwrite 直接返回 empty(),与 PerfFakeFs 模式一致。ring buffer 页是预分配内核页,不需要文件回写准备。 do_wp_page 会正确跳过 Normal 页的 dirty-tracking。 测试:packet_ring_test 支持 V1/V2 命令行切换,两个版本均在 DragonOS QEMU 内端到端验证通过(11步全部 PASSED)。 同时为 filemap_page_mkwrite 的每个 SIGBUS 返回点添加 log::warn! 诊断日志,便于未来排查类似问题。 Refs: DragonOS-Community#2030
Signed-off-by: --global <sparkhhhhhhhhhh@outlook.com>
1. tp_status原子/非原子混用UB: fill_frame中先raw write tp_status=0
再由publish()原子写入,违反Rust内存模型。删除冗余raw write,
页在分配时已清零,publish()是唯一写入者。
2. wire_len对DGRAM错误减MAC头: tp_len应报告完整可见包长,
MAC头跳过在数据拷贝时处理,不在tp_len中减。
3. 硬编码偏移改用struct: fill_frame从*(dst.add(N) as *mut T)=V
改为core::ptr::write(dst as *mut TpacketHdr/Tpacket2Hdr, hdr{...}),
编译器检查布局,消除uapi.rs中的#[allow(dead_code)]。
4. mmap bounds校验: inode.rs mmap()增加offset+len越界检查,
超出ring size返回EINVAL(匹配Linux行为)。
5. 清理死代码: 删除不可达的frames_per_block==0检查,
删除PacketMetadata中未使用的dst_mac/wire_len/mac_offset字段,
删除re-export上的#[allow(unused_imports)]。
V2端到端测试验证通过,无回归。
Refs: DragonOS-Community#2030
1. cargo fmt: 格式化 ring.rs/mod.rs/rx.rs/inode.rs 2. af_packet_sockopt.cc: PACKET_VERSION 从“不支持”列表移除, 新增独立测试验证 V1/V2 接受、非法值返回 EINVAL(匹配 Linux 6.6) 3. Dunitest 此前因 ASSERT_EQ(setsockopt(VERSION,999), 0) 失败而退出 Refs: DragonOS-Community#2030
# Conflicts: # kernel/src/mm/fault.rs
Linus 风格 review 后的精简(PR DragonOS-Community#2096): - fault.rs: 还原到 origin/master。PR 给共享核心缺页路径 filemap_page_mkwrite 塞的 7 个 log::warn! 是纯调试脚手架—— packet ring 通过 PacketFakeFs::page_mkwrite 重写已完全绕过该函数, 这些日志污染的是 ext2 等所有真实文件系统的热路径。 - ring.rs: has_user_frames 删除 20 行描述「未实现的未来优化」的注释 (描述不存在代码的文档比没有更糟);page_mkwrite 14 行注释压缩到 4 行; 删除冗余的 wire_len = visible_len 别名;sll_off 复用 hdrlen() 单一 真相源替代魔数 28/32。 编译通过,cargo fmt 干净。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概述
为 DragonOS AF_PACKET socket 实现 TPACKET mmap ring buffer(Issue #2030),使
tcpdump/libpcap能通过零拷贝环形缓冲区高效抓包。本次实现 Phase 1:TPACKET V1/V2 的PACKET_RX_RING+mmap+poll/epoll唤醒 +PACKET_VERSION/STATISTICS/RESERVE/HDRLEN。Closes #2030
改动
#[repr(C)]结构体(TpacketReq/Hdr/2Hdr/Stats)tp_statusRelease 序发布Sockettrait 新增mmap_layout()方法page_cache/fs/metadata,无 ring 时mmap()返回EINVALPacketSocket集成rx_ring/tpacket_version/tp_reserve字段can_recv检查 ring USER 帧,deliver_from_ifacering 路径唤醒wait_queue/epoll/fasyncSOL_PACKET选项处理(VERSION/RX_RING/RESERVE/STATISTICS/HDRLEN等)设计要点
mmap_layout()返回 page_cache + fs + sizerx_buffer路径,向后兼容Arc<Mutex<PacketRing>>串行化write_frame,外层rx_ringMutex 只保护 setup/teardownblock_size连续物理页,避免单次大块分配在内存碎片化时 ENOMEM(对应 Linuxalloc_pg_vec)编译验证
```
make kernel
Kernel Build Done.
```
测试
packet_ring_testtcpdump抓包验证EINVAL