版本:16.11.2,当解析或组装ip/icmp/icmpv6/igmp/udp/tcp/sctp报文时,会发现都存在两个字节(16位)的checksum字段,其生成及校验算法相同。实现方式有两种:1,软件方式计算;2,offload到网卡计算。本文主要介绍软件计算方法及dpdk中的实现。
注意:当代码中设置了offload标志后,就不能使用软件方法计算,否则校验和重复计算会导致错误,因为硬件计算时校验和字段不为0。
算法
1 | |
实现
1 | |
单mbuf接口
ipv4
1rte_ipv4_udptcp_cksum()ipv6
1rte_ipv6_udptcp_cksum()
mbuf链表接口
ipv4
1
2
3
4
5
6
7
8
9
10
11
12
13
14inline uint16_t mbuf_ipv4_udptcp_cksum(const struct rte_mbuf *m, const struct ipv4_hdr *ipv4_hdr) { uint32_t cksum; uint16_t l4_cksum; uint32_t l4_len; l4_len = rte_be_to_cpu_16(ipv4_hdr->total_length) - sizeof(struct ipv4_hdr); rte_raw_cksum_mbuf(m, sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr), l4_len, &l4_cksum); cksum = l4_cksum; cksum += rte_ipv4_phdr_cksum(ipv4_hdr, 0); cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff); cksum = (~cksum) & 0xffff; if (cksum == 0) cksum = 0xffff; return cksum; }ipv6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15inline uint16_t mbuf_ipv6_udptcp_cksum(const struct rte_mbuf *m, const struct ipv6_hdr *ipv6_hdr) { uint32_t cksum; uint16_t l4_cksum; uint32_t l4_len; //因为mbuf中不存在扩展头,所以offset的计算中不需要考虑扩展头 l4_len = rte_be_to_cpu_16(ipv6_hdr->payload_len); rte_raw_cksum_mbuf(m, sizeof(struct ether_hdr) + sizeof(struct ipv6_hdr), l4_len, &l4_cksum); cksum = l4_cksum; cksum += rte_ipv6_phdr_cksum(ipv6_hdr, 0); cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff); cksum = (~cksum) & 0xffff; if (cksum == 0) cksum = 0xffff; return cksum; }