在rte_mbuf结构中使用ol_flags的校验和卸载设置无效

时间:2019-03-29 19:31:42

标签: rhel7 dpdk

在硬件级别用于校验和计算的卸载标志在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;

}

您能建议一种解决方法来克服这些校验和错误和数据包丢失吗?

2 个答案:

答案 0 :(得分:0)

代码有两个问题:

  1. l2_len必须正确设置(可能是以太网报头的长度?)
  2. 我们最好使用DPDK的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()

来源:DPDK Programmers Guide

答案 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);

这也不起作用。 请提出我可以尝试的其他解决方法。