[Intel-wired-lan] [PATCH V3] ixgbe: Handle extended IPv6 headers in tx path

Mark D Rustad mark.d.rustad at intel.com
Tue Nov 17 23:07:14 UTC 2015


Check for and handle IPv6 extended headers so that tx checksum
offload can be done. Also use skb_checksum_help for unexpected
cases. Thanks to Tom Herbert for noticing these problems. Thanks
to Alexander Duyck for recognizing problems with the first version
of this patch.

Reported-by: Tom Herbert <tom at herbertland.com>
Signed-off-by: Mark Rustad <mark.d.rustad at intel.com>
---
Changed in V2:
- Use ipv6_skip_exthdr instead of ipv6_find_hdr
- Move code into L3 processing and avoid any possible loop
- Handle encapsulated IPv6 extended headers correctly
Changed in V3:
- Call skb_checksum_help for unexpected cases
- Move unlikely() calls to more appropriate places
- Reaarange terms in call to ipv6_skip_exthdr to reduce line count
- Combined 2 unlikely error cases into one
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |   23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 1ffbe85eab7b..c058ce616b28 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -7229,6 +7229,8 @@ static void ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
 			struct tcphdr *tcphdr;
 			u8 *raw;
 		} transport_hdr;
+		__be16 frag_off;
+		int rc;
 
 		if (skb->encapsulation) {
 			network_hdr.raw = skb_inner_network_header(skb);
@@ -7252,6 +7254,21 @@ static void ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
 		case 6:
 			vlan_macip_lens |= transport_hdr.raw - network_hdr.raw;
 			l4_hdr = network_hdr.ipv6->nexthdr;
+			if (likely((transport_hdr.raw - network_hdr.raw) ==
+				   sizeof(struct ipv6hdr)))
+				break;
+			rc = ipv6_skip_exthdr(skb, network_hdr.raw - skb->data +
+						   sizeof(struct ipv6hdr),
+					      &l4_hdr, &frag_off);
+			if (unlikely(rc < 0 || frag_off)) {
+				if (net_ratelimit()) {
+					dev_warn(tx_ring->dev,
+						 "ipv6_skip_exthdr returns %d\n",
+						 rc);
+				}
+				skb_checksum_help(skb);
+				goto no_csum;
+			}
 			break;
 		default:
 			if (unlikely(net_ratelimit())) {
@@ -7259,6 +7276,8 @@ static void ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
 					 "partial checksum but version=%d\n",
 					 network_hdr.ipv4->version);
 			}
+			skb_checksum_help(skb);
+			goto no_csum;
 		}
 
 		switch (l4_hdr) {
@@ -7282,13 +7301,15 @@ static void ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
 				 "partial checksum but l4 proto=%x!\n",
 				 l4_hdr);
 			}
-			break;
+			skb_checksum_help(skb);
+			goto no_csum;
 		}
 
 		/* update TX checksum flag */
 		first->tx_flags |= IXGBE_TX_FLAGS_CSUM;
 	}
 
+no_csum:
 	/* vlan_macip_lens: MACLEN, VLAN tag */
 	vlan_macip_lens |= first->tx_flags & IXGBE_TX_FLAGS_VLAN_MASK;
 



More information about the Intel-wired-lan mailing list