手写 DPDK 协议栈(四):实现 ICMP Echo Reply,让 ping 通起来
标签:DPDK ICMP ping IPv4
icmp/icmp.c 将 ARP 之后的 IPv4 分流继续推进到 ICMP。Echo Request/Reply 是最适合验证三层收发正确性的协议:不需要端口和连接状态,但要求正确交换地址并重算校验和。
1. Echo 报文结构
ICMP Echo:
| Type 1B | Code 1B | Checksum 2B | Identifier 2B | Sequence 2B | Data N字节 |
字段 长度 Request Reply 作用
type 1 字节 8 0 ICMP 消息类型。8 表示 ping 请求,0 表示 ping 应答。
code 1 字节 0 0 类型下的细分原因。Echo 类型里固定为 0。
checksum 2 字节 计算值 重新计算值 ICMP 校验和,覆盖 ICMP 头 + ICMP 数据,不包含 IP 头,也没有 UDP/TCP 那种伪首部。
identifier 2 字节 请求方设置 原样返回 标识一次 ping 会话,常用于区分不同进程或不同 ping 实例。
sequence 2 字节 请求方递增 原样返回 序列号,用来判断第几个 Echo 包,也用于计算丢包和 RTT。
data N 字节 任意数据 原样返回 ping 负载。Reply 必须把 Request 的数据原样带回去。
请求 type=8,应答 type=0;identifier、sequence 和 payload 都应原样返回。ICMP 校验和覆盖 ICMP 头和数据,不包含 IP 伪首部。
2. 接收并定位协议头
struct rte_ether_hdr *eth = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr *);
struct rte_ipv4_hdr *ip = rte_pktmbuf_mtod_offset(
mbuf, struct rte_ipv4_hdr *, sizeof(*eth));
if (ip->next_proto_id != IPPROTO_ICMP)
return;
struct rte_icmp_hdr *icmp = (struct rte_icmp_hdr *)(ip + 1);
if (icmp->icmp_type != RTE_IP_ICMP_ECHO_REQUEST)
return;
示例假定 IPv4 头为标准 20 字节。更通用的实现应从 version_ihl 得到 IHL * 4,并对 mbuf 长度、IP 总长度做边界检查。
3. 原地改包与重算校验和
icmp->icmp_type = RTE_IP_ICMP_ECHO_REPLY;
icmp->icmp_code = 0;
icmp->icmp_cksum = 0;
icmp->icmp_cksum = rte_raw_cksum(icmp, icmp_len);
ip->hdr_checksum = 0;
ip->hdr_checksum = rte_ipv4_cksum(ip);
/* 交换 Ethernet 和 IPv4 的源、目的地址后发送 */
原地回包可减少一次分配,但一定要在发送前同时交换二层和三层地址,并在所有字段更新完成后重新计算校验和。
4. 实验结果

ping 成功意味着:主机已通过 ARP 找到 DPDK 网卡 MAC,DPDK 正确解析 IPv4/ICMP,且回包的以太网头、IP 头与 ICMP 校验和全部有效。
小结
ICMP 是第一个“真正穿过 IPv4”的协议实验。它验证了偏移解析、网络字节序、校验和和回包地址交换,为 UDP、TCP 的组包与分发打下了同一套基础。
368



被折叠的 条评论
为什么被折叠?



