在硬件级别用于校验和计算的卸载标志在DPDK 18.08的较新版本中无效。设置这些标志后,在硬件级别未计算校验和。校验和值与应用程序软件设置的值相同这会导致IPV4标头校验和错误以及UDP校验和错误,并最终导致路由器丢包。这些校验和卸载标志适用于旧版本的DPDK,并且相同的标志和相同的代码现在不起作用。
rte_mbuf结构中的ol_flags已用于在软件级别设置IPV4和UDP数据包的校验和卸载.DPDK 18.08是否存在关于IPV4和UDP数据包的这些校验和卸载标志的已知问题? 下面显示了使用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;
}
您能建议一种解决方法来克服这些校验和错误和数据包丢失吗?
答案 0 :(得分:0)
代码有两个问题:
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 :(得分:0)
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中得到支持。
作为另一个选项,我确实尝试在端口初始化期间与选项2一起设置txmode卸载。)
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);
这也不起作用。 请提出我可以尝试的其他解决方法。