From: Ivan Malov Date: Tue, 2 Feb 2021 15:23:45 +0000 (+0300) Subject: net/sfc: fix TSO and checksum offloads for EF10 X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=be56d20ff17fdba2568a56e35abf1706cb48bb85;p=dpdk.git net/sfc: fix TSO and checksum offloads for EF10 This is workaround for 8000-series EF10 hardware TSO bug. Innermost IP length and outer UDP datagram length must be greater than or equal to the corresponding values derived from the MSS; otherwise, the checksum offloads will break. Fixes: c1ce2ba218f8 ("net/sfc: support tunnel TSO on EF10 native Tx datapath") Fixes: 6bc985e41155 ("net/sfc: support TSO in EF10 Tx datapath") Fixes: fec33d5bb3eb ("net/sfc: support firmware-assisted TSO") Cc: stable@dpdk.org Signed-off-by: Ivan Malov Reviewed-by: Andrew Rybchenko Reviewed-by: Andy Moreton --- diff --git a/drivers/net/sfc/sfc_ef10_tx.c b/drivers/net/sfc/sfc_ef10_tx.c index 87fa40f3eb..33d2d637c2 100644 --- a/drivers/net/sfc/sfc_ef10_tx.c +++ b/drivers/net/sfc/sfc_ef10_tx.c @@ -481,6 +481,25 @@ sfc_ef10_xmit_tso_pkt(struct sfc_ef10_txq * const txq, struct rte_mbuf *m_seg, needed_desc--; } + /* + * 8000-series EF10 hardware requires that innermost IP length + * be greater than or equal to the value which each segment is + * supposed to have; otherwise, TCP checksum will be incorrect. + * + * The same concern applies to outer UDP datagram length field. + */ + switch (m_seg->ol_flags & PKT_TX_TUNNEL_MASK) { + case PKT_TX_TUNNEL_VXLAN: + /* FALLTHROUGH */ + case PKT_TX_TUNNEL_GENEVE: + sfc_tso_outer_udp_fix_len(first_m_seg, hdr_addr); + break; + default: + break; + } + + sfc_tso_innermost_ip_fix_len(first_m_seg, hdr_addr, iph_off); + /* * Tx prepare has debug-only checks that offload flags are correctly * filled in in TSO mbuf. Use zero IPID if there is no IPv4 flag. diff --git a/drivers/net/sfc/sfc_tso.c b/drivers/net/sfc/sfc_tso.c index d6f1119890..b090ef14db 100644 --- a/drivers/net/sfc/sfc_tso.c +++ b/drivers/net/sfc/sfc_tso.c @@ -140,6 +140,13 @@ sfc_efx_tso_do(struct sfc_efx_txq *txq, unsigned int idx, tsoh = rte_pktmbuf_mtod(m, uint8_t *); } + /* + * 8000-series EF10 hardware requires that innermost IP length + * be greater than or equal to the value which each segment is + * supposed to have; otherwise, TCP checksum will be incorrect. + */ + sfc_tso_innermost_ip_fix_len(m, tsoh, nh_off); + /* * Handle IP header. Tx prepare has debug-only checks that offload flags * are correctly filled in in TSO mbuf. Use zero IPID if there is no diff --git a/drivers/net/sfc/sfc_tso.h b/drivers/net/sfc/sfc_tso.h index 8597c2868a..361aa22192 100644 --- a/drivers/net/sfc/sfc_tso.h +++ b/drivers/net/sfc/sfc_tso.h @@ -38,6 +38,36 @@ sfc_tso_ip4_get_ipid(const uint8_t *pkt_hdrp, size_t ip_hdr_off) return rte_be_to_cpu_16(ipid); } +static inline void +sfc_tso_outer_udp_fix_len(const struct rte_mbuf *m, uint8_t *tsoh) +{ + rte_be16_t len = rte_cpu_to_be_16(m->l2_len + m->l3_len + m->l4_len + + m->tso_segsz); + + rte_memcpy(tsoh + m->outer_l2_len + m->outer_l3_len + + offsetof(struct rte_udp_hdr, dgram_len), + &len, sizeof(len)); +} + +static inline void +sfc_tso_innermost_ip_fix_len(const struct rte_mbuf *m, uint8_t *tsoh, + size_t iph_ofst) +{ + size_t ip_payload_len = m->l4_len + m->tso_segsz; + size_t field_ofst; + rte_be16_t len; + + if (m->ol_flags & PKT_TX_IPV4) { + field_ofst = offsetof(struct rte_ipv4_hdr, total_length); + len = rte_cpu_to_be_16(m->l3_len + ip_payload_len); + } else { + field_ofst = offsetof(struct rte_ipv6_hdr, payload_len); + len = rte_cpu_to_be_16(ip_payload_len); + } + + rte_memcpy(tsoh + iph_ofst + field_ofst, &len, sizeof(len)); +} + unsigned int sfc_tso_prepare_header(uint8_t *tsoh, size_t header_len, struct rte_mbuf **in_seg, size_t *in_off);