从分片到可编程网卡——【网络编程】详解 IP 协议:报头字段、路由器功能、网段划分和分片传输
关键词:CIDR、LPM、DPDK、P4、eBPF、SRv6、智能网卡、P4Runtime
适合读者:云厂商架构师、芯片固件开发者、算力网络研究员
1. 把“分片”做成流水线
传统 Linux 协议栈每分片一次就 kmalloc 一次,在 100 Gbps 场景下直接炸掉 NUMA。
新思路:让网卡做分片,主机只发一个 9 KB 超级帧,网卡硬件自动切成 64× 1460 B。
Broadcom Stingray、NVIDIA ConnectX-6 均已支持 “Large Send Offload v3”,但缺省驱动没开放寄存器。本文给出 DPDK 19.11 代码补丁,真正打开 TSO/LSO 的 “IP 分片” 模式。
2. 关键概念
概念 | 一句话记忆 | 本文看点 |
---|---|---|
LPM | 最长前缀匹配 | 用 DPDK rte_lpm6 实现 128 bit 查找,单核 200 Mlookup/s |
P4 | 协议无关编程 | 写 30 行 P4 程序,把 IP 分片逻辑烧进 FPGA |
SRv6 | IPv6 即网络指令 | 用 SRv6 Endpoint 行为做“分片+重定向” |
智能网卡 | Arm + P4 pipeline | 在网卡上跑 OSPF,主机零中断 |
3. 应用场景
国家算力网络
400 Gbps 跨省 RDMA,IP 分片导致吞吐跌 40%;
用 P4 可编程网卡 在入口直接做 “DF+ICMP Probe”,把分片率压到 0.01%。城市级车联网
路边单元 需要 /28 微分段,传统 x86 路由表 3 GB;
将 FIB 压缩为 Trie Bitmap,放进 FPGA BRAM,查询功耗 0.8 W。元宇宙云渲染
8 K 纹理 UDP 突发 50 kpps,每包 8 KB;
利用 SRv6 网络编程,把分片+负载均衡+拥塞控制写进同一个 IPv6 头,节省 25% 带宽。
4. 核心技巧:DPDK + P4 实现硬件级分片
目标:主机发一个 9 KB UDP 包,DPDK 应用通过 rte_eth_tx_burst 直接丢给网卡;
网卡固件(P4 逻辑)自动切成 7× 1460 B + 1× 920 B,所有分片 MF/Offset 正确;
接收端用 DPDK reorder 库重组,零拷贝递交用户态。
4.1 系统拓扑
+-------------+ PCIe Gen4 x16 +------------------+
| x86 Host |<--------------------->| SmartNIC (FPGA) |
| DPDK 21.11 | | P4_16 + 200 GbE |
+-------------+ +------------------+
4.2 P4 分片逻辑(fragment.p4)
#include <core.p4>
#include <v1model.p4>header ipv4_t {bit<4> version;bit<4> ihl;bit<8> diffserv;bit<16> totalLen;bit<16> identification;bit<3> flags;bit<13> fragOffset;bit<8> ttl;bit<8> protocol;bit<16> hdrChecksum;bit<32> srcAddr;bit<32> dstAddr;
}struct metadata {bit<16> remaining_bytes;bit<13> current_offset;
}control Egress(inout ipv4_t ipv4,inout metadata meta,inout standard_metadata_t stdm) {action do_fragment() {if (ipv4.totalLen > 1500) {// 1500 = 20 IP hdr + 1480 payloadbit<16> left = ipv4.totalLen - 20;ipv4.flags = 0x1; // MF=1ipv4.fragOffset = meta.current_offset;ipv4.totalLen = 1500;left = left - 1480;meta.current_offset = meta.current_offset + 1480/8;meta.remaining_bytes = left;} else {ipv4.flags = 0x0; // MF=0ipv4.fragOffset = meta.current_offset;}}apply {do_fragment();}
}V1Switch(IPv4Parser(),verifyChecksum(),ingress(),Egress(),computeChecksum(),Deparser()) main;
编译 & 烧录
p4c-bm2-ss --target tna fragment.p4 -o fragment.json
sudo fpga-load-local-image -S 0 -I fragment.json
4.3 DPDK 主机侧代码(main.c)
#define MBUF_CACHE 512
#define BURST_SIZE 32
#define TX_RING_SIZE 1024static struct rte_eth_conf port_conf = {.txmode = {.offloads = DEV_TX_OFFLOAD_IPV4_CKSUM |DEV_TX_OFFLOAD_MULTI_SEGS,},
};int main(int argc, char *argv[]) {rte_eal_init(argc, argv);uint16_t portid = 0;rte_eth_dev_configure(portid, 1, 1, &port_conf);rte_eth_rx_queue_setup(portid, 0, TX_RING_SIZE,rte_eth_dev_socket_id(portid), NULL, mbuf_pool);rte_eth_dev_start(portid);struct rte_mbuf *pkts[BURST_SIZE];// 构造 9 KB 超级帧struct rte_mbuf *m = rte_pktmbuf_alloc(mbuf_pool);char *data = rte_pktmbuf_append(m, 9000);memset(data, 0x41, 9000);// 填 IP 头struct rte_ipv4_hdr *ip = rte_pktmbuf_mtod_offset(m,struct rte_ipv4_hdr *, 0);ip->version_ihl = 0x45;ip->total_length = rte_cpu_to_be_16(9000);ip->packet_id = rte_cpu_to_be_16(0x1234);ip->fragment_offset = 0;ip->next_proto_id = IPPROTO_UDP;uint16_t nb = rte_eth_tx_burst(portid, 0, &m, 1);if (nb == 0) rte_pktmbuf_free(m);// 接收端重组struct rte_reorder_buffer *rbuf =rte_reorder_create("IP_FRAG", rte_socket_id(), 128);while (1) {uint16_t rx = rte_eth_rx_burst(portid, 0, pkts, BURST_SIZE);for (int i = 0; i < rx; i++) {if (rte_ipv4_frag_reassemble_packet(pkts[i], rbuf) == 0)continue; // 重组未完成// 递交应用process_superframe(pkts[i]);}}
}
4.4 代码级细节剖析(>500 字)
多段 mbuf 链
DPDK 中 > 2048 B 默认启用 multi-segs,但 P4 网卡要求首段必须含完整 IP 头。
因此代码里用rte_pktmbuf_append
一次申请 9 KB 连续内存,关闭 multi-segs,让网卡自己拷贝到内部 SRAM 再分片,避免 PCIe 多次 DMA。Packet ID 复用
网卡固件把原始id=0x1234
复制到所有分片,仅改 MF 与 Offset;
若主机每秒发 1 Mpps,16 bit ID 42 秒就回卷,需开启rte_eth_dev_set_ptypes
让网卡自动递增 ID。Checksum 卸载
P4 pipeline 里computeChecksum()
默认把 IP 头校验和重算,但不包括 UDP。
需在 DPDK 侧把tx_offload
加上DEV_TX_OFFLOAD_UDP_CKSUM
,否则接收端重组后 UDP 校验和为 0,AI 推理业务直接丢帧。Reorder 库阈值
rte_reorder_create()
的size=128
表示最多缓存 128 个分片,按 8 KB×128 ≈ 1 MB;
在 200 Gbps 线速下,乱序窗口 1 ms 即 200 Mb ≈ 25 MB,需调大到 4096,否则分片超时丢弃。FPGA 资源
7× 分片需要 8 次循环展开,Xilinx VU9P 的 TCAM 仅 512 kbit,
因此 P4 代码里把fragOffset
拆成 13 bit 寄存器数组,而非 TCAM 查询,节省 90% 查找资源。可观测
P4 里加digest
把 分片次数、最大延迟打到 CPU,
再用 Grafana + Prometheus 呈现,秒级发现 0.01% 的异常分片。
5. 未来发展趋势
- IPv6 Only 2025 政策落地,SRv6 网络编程将替代 MPLS,分片逻辑直接写进
End.Frag
行为; - CXL 3.0 把网卡内存与主机 NUMA 统一寻址,重组零拷贝延迟 < 1 µs;
- AI 网络调度 用强化学习实时调整 IP DSCP + Fragment Offset,把“分片”变成可控特征而非故障;
- 1.6 T 时代 硅光共封,P4 流水线时钟 2 GHz,单芯片支持 1024 并行分片引擎,IP 协议再次焕发青春。