用于硬件级校验和计算的卸载标志对于较新版本的DPDK 18.08无效。设置这些标志后,硬件级别不会计算得到的校验和。校验和值与应用软件设置的值保持一致。此结果在错误的IPV4标头校验和错误和UDP错误校验和错误以及最终丢包在路由器上。这些校验和卸载标志正在使用较旧版本的DPDK,并且相同的标志和相同的代码片段现在不起作用。
rte_mbuf结构中的ol_flags已用于在软件级别为IPV4和UDP数据包设置校验和卸载。对于IPV4和UDP数据包的这些校验和卸载标志,DPDK 18.08是否存在任何已知问题?使用rte_mbuf结构的ol_flags用于校验和卸载设置的代码如下所示。
struct ipv4_hdr *ip = NULL;
struct udp_hdr* udphdr;
struct rte_mbuf *mbuf;
ip = (struct ipv4_hdr*)(rte_pktmbuf_mtod(m, unsigned char *) + l2_data_shift);
udphdr = (struct udp_hdr*)(rte_pktmbuf_mtod(m, unsigned char *) + l2_data_shift + sizeof(struct ipv4_hdr));
ip->hdr_checksum = 0;
m->data_len = m->pkt_len = l2_data_shift +rte_be_to_cpu_16(ip->total_length);
mbuf->l3_len = sizeof(struct ipv4_hdr);
m->ol_flags |= PKT_TX_IP_CKSUM | PKT_TX_UDP_CKSUM;
udphdr->dgram_cksum =ipv4sum(ip);
uint16_t ipv4sum(struct ipv4_hdr * ip_hdr)
{
uint16_t proto;
uint32_t sum;
proto = ip_hdr->next_proto_id;
proto = rte_cpu_to_be_16(proto);
sum = proto;
sum += rte_cpu_to_be_16((uint16_t)(rte_be_to_cpu_16(ip_hdr->total_length) - sizeof(struct ipv4_hdr)));
if (sum > UINT16_MAX) sum -= UINT16_MAX;
sum += ip_hdr->src_addr & 0xFFFF;
if (sum > UINT16_MAX) sum -= UINT16_MAX;
sum += (ip_hdr->src_addr >> 16);
if (sum > UINT16_MAX) sum -= UINT16_MAX;
sum += ip_hdr->dst_addr & 0xFFFF;
if (sum > UINT16_MAX) sum -= UINT16_MAX;
sum += (ip_hdr->dst_addr >> 16);
if (sum > UINT16_MAX) sum -= UINT16_MAX;
sum = ((sum & 0xffff0000) >> 16) + (sum & 0xffff);
sum &= 0x0ffff;
return (uint16_t)sum;
}
您能否建议一个解决方案来解决这些校验和错误和数据包丢失?
代码有两个问题:
l2_len
(可能是以太网头的长度?)ipv4sum()
而不是自定义函数rte_ipv4_phdr_cksum()
。因此,要计算外部IP和UDP校验和:
mb->l2_len = len(out_eth)
mb->l3_len = len(out_ip)
mb->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CSUM | PKT_TX_UDP_CKSUM
set out_ip checksum to 0 in the packet
set out_udp checksum to pseudo header using rte_ipv4_phdr_cksum()
以防万一,要计算外部IP和TCP校验和:
mb->l2_len = len(out_eth)
mb->l3_len = len(out_ip)
mb->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CSUM | PKT_TX_TCP_CKSUM
set out_ip checksum to 0 in the packet
set out_tcp checksum to pseudo header using rte_ipv4_phdr_cksum()
1.)我忘了提到l2 len的设置如下。
if (ETHER_TYPE_VLAN == eth_type)
{
mbuf->l2_len = sizeof(struct ether_hdr) + sizeof(struct vlan_hdr);
}
else {
mbuf->ol_flags = PKT_TX_VLAN_PKT;
mbuf->l2_len = sizeof(struct ether_hdr);
}
2.)在设置l2_len和l3_len后我确实尝试使用第二个选项,但它没有用。
ip->hdr_checksum = 0;
mbuf->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CKSUM | PKT_TX_UDP_CKSUM;
udphdr->dgram_cksum = rte_ipv4_phdr_cksum(mbuf->l3_len, mbuf->ol_flags);
3.)如前所述,它支持硬件广告DEV_TX_OFFLOAD_IPV4_CKSUM,DEV_TX_OFFLOAD_UDP_CKSUM和DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM。
因此,作为另一种选择,我尝试在端口初始化期间设置txmode offloads以及选项2。)
struct rte_eth_conf port_conf;
port_conf.txmode.offloads |= DEV_TX_OFFLOAD_UDP_CKSUM |DEV_TX_OFFLOAD_IPV4_CKSUM;
ret = rte_eth_dev_configure(port, nbqueue, nbqueue, &port_conf);
这也行不通。请建议我可以尝试的任何其他解决方法。