Prior to this commit IP/UDP/TCP checksum offload calculations were skipped in case of a multi segments packet. This commit enables TAP checksum calculations for multi segments packets. The only restriction is that the first segment must contain all headers of layers 2, 3 and 4 (where layer 4 header size equals TCP header size).
Signed-off-by: Ophir Munk <ophi...@mellanox.com> --- drivers/net/tap/rte_eth_tap.c | 54 ++++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c index 61d6465..df23c4d 100644 --- a/drivers/net/tap/rte_eth_tap.c +++ b/drivers/net/tap/rte_eth_tap.c @@ -509,6 +509,10 @@ pmd_tx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) char m_copy[mbuf->data_len]; int n; int j; + int k; /* first index in iovecs for copying segments */ + uint16_t l234_len; /* length of layers 2,3,4 headers */ + uint16_t seg_len; /* length of first segment */ + uint16_t nb_segs; /* stats.errs will be incremented */ if (rte_pktmbuf_pkt_len(mbuf) > max_size) @@ -529,30 +533,52 @@ pmd_tx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) if (j & (0x40 | 0x60)) pi.proto = (j == 0x40) ? 0x0008 : 0xdd86; - iovecs[0].iov_base = π - iovecs[0].iov_len = sizeof(pi); - for (j = 1; j <= mbuf->nb_segs; j++) { - iovecs[j].iov_len = rte_pktmbuf_data_len(seg); - iovecs[j].iov_base = - rte_pktmbuf_mtod(seg, void *); - seg = seg->next; - } + k = 0; + iovecs[k].iov_base = π + iovecs[k].iov_len = sizeof(pi); + k++; + nb_segs = mbuf->nb_segs; if (txq->csum && ((mbuf->ol_flags & (PKT_TX_IP_CKSUM | PKT_TX_IPV4) || (mbuf->ol_flags & PKT_TX_L4_MASK) == PKT_TX_UDP_CKSUM || (mbuf->ol_flags & PKT_TX_L4_MASK) == PKT_TX_TCP_CKSUM))) { - /* Support only packets with all data in the same seg */ - if (mbuf->nb_segs > 1) + /* Support only packets with at least layer 4 + * header included in the first segment + */ + seg_len = rte_pktmbuf_data_len(mbuf); + l234_len = mbuf->l2_len + mbuf->l3_len + + sizeof(struct tcp_hdr); + if (seg_len < l234_len) break; - /* To change checksums, work on a copy of data. */ + + /* To change checksums, work on a + * copy of l2, l3 l4 headers. + */ rte_memcpy(m_copy, rte_pktmbuf_mtod(mbuf, void *), - rte_pktmbuf_data_len(mbuf)); + l234_len); tap_tx_offload(m_copy, mbuf->ol_flags, mbuf->l2_len, mbuf->l3_len); - iovecs[1].iov_base = m_copy; + iovecs[k].iov_base = m_copy; + iovecs[k].iov_len = l234_len; + k++; + /* Update next iovecs[] beyond l2, l3, l4 headers */ + if (seg_len > l234_len) { + iovecs[k].iov_len = seg_len - l234_len; + iovecs[k].iov_base = + rte_pktmbuf_mtod(seg, char *) + + l234_len; + k++; + } + nb_segs--; + seg = seg->next; + } + for (j = k; j <= nb_segs; j++) { + iovecs[j].iov_len = rte_pktmbuf_data_len(seg); + iovecs[j].iov_base = rte_pktmbuf_mtod(seg, void *); + seg = seg->next; } /* copy the tx frame data */ - n = writev(txq->fd, iovecs, mbuf->nb_segs + 1); + n = writev(txq->fd, iovecs, j); if (n <= 0) break; -- 2.7.4