cdpdknicoffloading

DPDK19.11.10: HW offload for IPV4 with VLAN tag is not working properly


I am using DPDK19.11.10 on centos.

The application is working fine with HW offloading if I send only the IPV4 packet without the VLAN header.

If I add the VLAN header with IPV4, HW offloading is not working. If capture the pcap on ubuntu gateway the IP header is corrupted with Fragmented IP packet even though we are not fragmenting IP packet.

We verified capabalities like this:

if (!(dev->tx_offload_capa & DEV_TX_OFFLOAD_VLAN_INSERT)) {
          rte_panic(" VLAN offload not supported");
}

Below is my code:

.offloads = (DEV_TX_OFFLOAD_IPV4_CKSUM |
                              DEV_TX_OFFLOAD_UDP_CKSUM | DEV_TX_OFFLOAD_TCP_CKSUM | DEV_TX_OFFLOAD_VLAN_INSERT),
m->l2_len = L2_HDR_SIZE;
m->l3_len = L3_IPV4_HDR_SIZE;
ip_hdr->check       = 0;
m->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CKSUM;
ip_hdr = rte_pktmbuf_mtod(m, struct iphdr *);
vlan1_hdr = (struct vlan1_hdr *) rte_pktmbuf_prepend(m, sizeof(struct vlan1_hdr));
eth_hdr = (struct ethernet_hdr *) rte_pktmbuf_prepend(m, (uint16_t)sizeof(struct ethernet_hdr));

Once I received the packet in the ubuntu gateway the IP packet is corrupted as a fragmented IP packet. enter image description here

The same code works fine if I removed the VLAN header. Does anything else need to add here?


Solution

  • By the sound of it,

    1. You might misunderstand the way how HW Tx VLAN offload is supposed to work;
    2. Your code does not update m->l2_len when it inserts a VLAN header.

    First of all, your code enables support for HW Tx VLAN offload, but, oddly enough, it does not actually attempt to use it. If one wants to use hardware Tx VLAN offload, they should set PKT_TX_VLAN in m->ol_flags and fill out m->vlan_tci. The VLAN header will be added by the hardware.

    However, your code prepends the header itself, like if there was no intent to use a hardware offload in the first place. Your code does m->l2_len = L2_HDR_SIZE;, which, as I presume, only counts for Ethernet header. When your code prepends a VLAN header, this variable has to be updated accordingly:

    m->l2_len += sizeof(struct rte_vlan_hdr);