[dpdk-dev] [PATCH v1] net/ixgbe: fix UDP zero checksum error for Arm NEON path

Feifei Wang feifei.wang2 at arm.com
Mon Feb 8 10:07:04 CET 2021


There is an 82599 errata that UDP frames with a zero checksum are
incorrectly marked as checksum invalid by the hardware.  This was
leading to misleading PKT_RX_L4_CKSUM_BAD flag.

To fix it for the NEON path in Arm platform, change the bad UDP checksum to
unknown, and then let software application to recompute the checksum.

This patch depends on:
http://patches.dpdk.org/patch/87750/

NICs: 82599(igb)
Driver: ixgbe(vector)
Architecture: arm64
$:./app/dpdk-testpmd -c 0x3 -w 0002:f9:00.0 -- -i
--port-topology=chained --enable-rx-cksum
test-pmd> set fwd rxonly
test-pmd> set verbose 1
test-pmd> start

1. UDP Test:
Package: (Ether()/IP()/UDP(checksum=0)
ol_flags: PKT_RX_L4_CKSUM_UNKNOWN PKT_RX_IP_CKSUM_GOOD

2. TCP Test:
Package: (Ether()/IP()/TCP(checksum=0)
ol_flags: PKT_RX_L4_CKSUM_BAD PKT_RX_IP_CKSUM_GOOD

Bugzilla ID: 629
Fixes: af75078fece3 ("first public release")
Cc: stable at dpdk.org

Reported-by: Paolo Valerio <pvalerio at redhat.com>
Signed-off-by: Feifei Wang <feifei.wang2 at arm.com>
Reviewed-by: Ruifeng Wang <ruifeng.wang at arm.com>
---
 drivers/net/ixgbe/ixgbe_rxtx_vec_neon.c | 46 +++++++++++++++++++++++--
 1 file changed, 43 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_rxtx_vec_neon.c b/drivers/net/ixgbe/ixgbe_rxtx_vec_neon.c
index f83b800ad..c541f537c 100644
--- a/drivers/net/ixgbe/ixgbe_rxtx_vec_neon.c
+++ b/drivers/net/ixgbe/ixgbe_rxtx_vec_neon.c
@@ -83,9 +83,12 @@ ixgbe_rxq_rearm(struct ixgbe_rx_queue *rxq)
 
 static inline void
 desc_to_olflags_v(uint8x16x2_t sterr_tmp1, uint8x16x2_t sterr_tmp2,
-		  uint8x16_t staterr, uint8_t vlan_flags, struct rte_mbuf **rx_pkts)
+		  uint8x16_t staterr, uint8_t vlan_flags, uint16_t udp_p_flag,
+		  struct rte_mbuf **rx_pkts)
 {
-	uint8x16_t ptype;
+	uint16_t udp_p_flag_hi;
+	uint8x16_t ptype, udp_csum_skip;
+	uint32x4_t temp_udp_csum_skip = {0, 0, 0, 0};
 	uint8x16_t vtag_lo, vtag_hi, vtag;
 	uint8x16_t temp_csum;
 	uint32x4_t csum = {0, 0, 0, 0};
@@ -139,7 +142,31 @@ desc_to_olflags_v(uint8x16x2_t sterr_tmp1, uint8x16x2_t sterr_tmp2,
 			PKT_RX_L4_CKSUM_GOOD >> sizeof(uint8_t), 0,
 			0, 0, 0, 0};
 
+	/* change mask from 0x200(IXGBE_RXDADV_PKTTYPE_UDP) to 0x2 */
+	udp_p_flag_hi = udp_p_flag >> 8;
+
+	/* mask everything except UDP header present if specified */
+	const uint8x16_t udp_hdr_p_msk = {
+			0, 0, 0, 0,
+			udp_p_flag_hi, udp_p_flag_hi, udp_p_flag_hi, udp_p_flag_hi,
+			0, 0, 0, 0,
+			0, 0, 0, 0};
+
+	const uint8x16_t udp_csum_bad_shuf = {
+			0xFF, ~(uint8_t)PKT_RX_L4_CKSUM_BAD, 0, 0,
+			0, 0, 0, 0,
+			0, 0, 0, 0,
+			0, 0, 0, 0};
+
 	ptype = vzipq_u8(sterr_tmp1.val[0], sterr_tmp2.val[0]).val[0];
+
+	/* save the UDP header present information */
+	udp_csum_skip = vandq_u8(ptype, udp_hdr_p_msk);
+
+	/* move UDP header present information to low 32bits */
+	temp_udp_csum_skip = vcopyq_laneq_u32(temp_udp_csum_skip, 0,
+				vreinterpretq_u32_u8(udp_csum_skip), 1);
+
 	ptype = vandq_u8(ptype, rsstype_msk);
 	ptype = vqtbl1q_u8(rss_flags, ptype);
 
@@ -166,6 +193,15 @@ desc_to_olflags_v(uint8x16x2_t sterr_tmp1, uint8x16x2_t sterr_tmp2,
 	vtag_lo = vqtbl1q_u8(vlan_csum_map_lo, vtag);
 	vtag_lo = vorrq_u8(ptype, vtag_lo);
 
+	/* convert the UDP header present 0x2 to 0x1 for aligning with each
+	 * PKT_RX_L4_CKSUM_BAD value in low byte of 8 bits word ol_flag in
+	 * vtag_lo (4x8). Then mask out the bad checksum value by shuffle and
+	 * bit-mask.
+	 */
+	udp_csum_skip = vshrq_n_u8(vreinterpretq_u8_u32(temp_udp_csum_skip), 1);
+	udp_csum_skip = vqtbl1q_u8(udp_csum_bad_shuf, udp_csum_skip);
+	vtag_lo = vandq_u8(vtag_lo, udp_csum_skip);
+
 	vtag = vzipq_u8(vtag_lo, vtag_hi).val[0];
 	vol.word = vgetq_lane_u64(vreinterpretq_u64_u8(vtag), 0);
 
@@ -267,6 +303,7 @@ _recv_raw_pkts_vec(struct ixgbe_rx_queue *rxq, struct rte_mbuf **rx_pkts,
 	uint16x8_t crc_adjust = {0, 0, rxq->crc_len, 0,
 				 rxq->crc_len, 0, 0, 0};
 	uint8_t vlan_flags;
+	uint16_t udp_p_flag = 0; /* Rx Descriptor UDP header present */
 
 	/* nb_pkts has to be floor-aligned to RTE_IXGBE_DESCS_PER_LOOP */
 	nb_pkts = RTE_ALIGN_FLOOR(nb_pkts, RTE_IXGBE_DESCS_PER_LOOP);
@@ -291,6 +328,9 @@ _recv_raw_pkts_vec(struct ixgbe_rx_queue *rxq, struct rte_mbuf **rx_pkts,
 				rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD)))
 		return 0;
 
+	if (rxq->rx_udp_csum_zero_err)
+		udp_p_flag = IXGBE_RXDADV_PKTTYPE_UDP;
+
 	/* Cache is empty -> need to scan the buffer rings, but first move
 	 * the next 'n' mbufs into the cache
 	 */
@@ -362,7 +402,7 @@ _recv_raw_pkts_vec(struct ixgbe_rx_queue *rxq, struct rte_mbuf **rx_pkts,
 
 		/* set ol_flags with vlan packet type */
 		desc_to_olflags_v(sterr_tmp1, sterr_tmp2, staterr, vlan_flags,
-				  &rx_pkts[pos]);
+				  udp_p_flag, &rx_pkts[pos]);
 
 		/* D.2 pkt 3,4 set in_port/nb_seg and remove crc */
 		tmp = vsubq_u16(vreinterpretq_u16_u8(pkt_mb4), crc_adjust);
-- 
2.25.1



More information about the dev mailing list