浏览代码

i40e/i40evf: Handle IPv6 extension headers in checksum offload

This patch adds support for IPv6 extension headers in setting up the Tx
checksum.  Without this patch extension headers would cause IPv6 traffic to
fail as the transport protocol could not be identified.

Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Alexander Duyck 9 年之前
父节点
当前提交
a3fd9d8876
共有 2 个文件被更改,包括 26 次插入2 次删除
  1. 13 1
      drivers/net/ethernet/intel/i40e/i40e_txrx.c
  2. 13 1
      drivers/net/ethernet/intel/i40evf/i40e_txrx.c

+ 13 - 1
drivers/net/ethernet/intel/i40e/i40e_txrx.c

@@ -2402,7 +2402,9 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
 		struct udphdr *udp;
 		struct udphdr *udp;
 		unsigned char *hdr;
 		unsigned char *hdr;
 	} l4;
 	} l4;
+	unsigned char *exthdr;
 	u32 l4_tunnel = 0;
 	u32 l4_tunnel = 0;
+	__be16 frag_off;
 	u8 l4_proto = 0;
 	u8 l4_proto = 0;
 
 
 	ip.hdr = skb_network_header(skb);
 	ip.hdr = skb_network_header(skb);
@@ -2419,7 +2421,12 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
 			l4_proto = ip.v4->protocol;
 			l4_proto = ip.v4->protocol;
 		} else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
 		} else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
 			*cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
 			*cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
+
+			exthdr = ip.hdr + sizeof(*ip.v6);
 			l4_proto = ip.v6->nexthdr;
 			l4_proto = ip.v6->nexthdr;
+			if (l4.hdr != exthdr)
+				ipv6_skip_exthdr(skb, exthdr - skb->data,
+						 &l4_proto, &frag_off);
 		}
 		}
 
 
 		/* define outer transport */
 		/* define outer transport */
@@ -2469,8 +2476,13 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
 			*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4;
 			*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4;
 		}
 		}
 	} else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
 	} else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
-		l4_proto = ip.v6->nexthdr;
 		*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV6;
 		*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV6;
+
+		exthdr = ip.hdr + sizeof(*ip.v6);
+		l4_proto = ip.v6->nexthdr;
+		if (l4.hdr != exthdr)
+			ipv6_skip_exthdr(skb, exthdr - skb->data,
+					 &l4_proto, &frag_off);
 	}
 	}
 
 
 	/* Now set the td_offset for IP header length */
 	/* Now set the td_offset for IP header length */

+ 13 - 1
drivers/net/ethernet/intel/i40evf/i40e_txrx.c

@@ -1619,7 +1619,9 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
 		struct udphdr *udp;
 		struct udphdr *udp;
 		unsigned char *hdr;
 		unsigned char *hdr;
 	} l4;
 	} l4;
+	unsigned char *exthdr;
 	u32 l4_tunnel = 0;
 	u32 l4_tunnel = 0;
+	__be16 frag_off;
 	u8 l4_proto = 0;
 	u8 l4_proto = 0;
 
 
 	ip.hdr = skb_network_header(skb);
 	ip.hdr = skb_network_header(skb);
@@ -1636,7 +1638,12 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
 			l4_proto = ip.v4->protocol;
 			l4_proto = ip.v4->protocol;
 		} else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
 		} else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
 			*cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
 			*cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
+
+			exthdr = ip.hdr + sizeof(*ip.v6);
 			l4_proto = ip.v6->nexthdr;
 			l4_proto = ip.v6->nexthdr;
+			if (l4.hdr != exthdr)
+				ipv6_skip_exthdr(skb, exthdr - skb->data,
+						 &l4_proto, &frag_off);
 		}
 		}
 
 
 		/* define outer transport */
 		/* define outer transport */
@@ -1686,8 +1693,13 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
 			*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4;
 			*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4;
 		}
 		}
 	} else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
 	} else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
-		l4_proto = ip.v6->nexthdr;
 		*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV6;
 		*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV6;
+
+		exthdr = ip.hdr + sizeof(*ip.v6);
+		l4_proto = ip.v6->nexthdr;
+		if (l4.hdr != exthdr)
+			ipv6_skip_exthdr(skb, exthdr - skb->data,
+					 &l4_proto, &frag_off);
 	}
 	}
 
 
 	/* Now set the td_offset for IP header length */
 	/* Now set the td_offset for IP header length */