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

问题描述 投票:1回答:2

用于硬件级校验和计算的卸载标志对于较新版本的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;

}

您能否建议一个解决方案来解决这些校验和错误和数据包丢失?

rhel7 dpdk
2个回答
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


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。

因此,作为另一种选择,我尝试在端口初始化期间设置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);

这也行不通。请建议我可以尝试的任何其他解决方法。

© www.soinside.com 2019 - 2024. All rights reserved.