]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
i40e/i40evf: Add support for IPv4 encapsulated in IPv6
authorAlexander Duyck <aduyck@mirantis.com>
Mon, 25 Jan 2016 05:16:48 +0000 (21:16 -0800)
committerChuck Anderson <chuck.anderson@oracle.com>
Thu, 10 Mar 2016 16:37:37 +0000 (08:37 -0800)
Orabug: 22342532

This patch fixes two issues.  First was the fact that iphdr(skb)->protocl
was being used to test for the outer transport protocol.  This completely
breaks IPv6 support.  Second was the fact that we cleared the flag for v4
going to v6, but we didn't take care of txflags going the other way.  As
such we would have the v6 flag still set even if the inner header was v4.

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>
(cherry picked from commit a0064728f8a34f7a5afd9df86d9cdd8210977c8d)
Signed-off-by: Brian Maly <brian.maly@oracle.com>
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40evf/i40e_txrx.c

index fce195107f030df5a3d14f2b0de20737cf57d65c..7f2fce74cf1ea3c9530777930aa1a43107a99d64 100644 (file)
@@ -2408,13 +2408,28 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
        l4.hdr = skb_transport_header(skb);
 
        if (skb->encapsulation) {
-               switch (ip_hdr(skb)->protocol) {
+               /* define outer network header type */
+               if (*tx_flags & I40E_TX_FLAGS_IPV4) {
+                       if (*tx_flags & I40E_TX_FLAGS_TSO)
+                               *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV4;
+                       else
+                               *cd_tunneling |=
+                                        I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
+                       l4_proto = ip.v4->protocol;
+               } else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
+                       *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
+                       l4_proto = ip.v6->nexthdr;
+               }
+
+               /* define outer transport */
+               switch (l4_proto) {
                case IPPROTO_UDP:
                        l4_tunnel = I40E_TXD_CTX_UDP_TUNNELING;
                        *tx_flags |= I40E_TX_FLAGS_UDP_TUNNEL;
                        break;
                case IPPROTO_GRE:
                        l4_tunnel = I40E_TXD_CTX_GRE_TUNNELING;
+                       *tx_flags |= I40E_TX_FLAGS_UDP_TUNNEL;
                        break;
                default:
                        return;
@@ -2423,17 +2438,7 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
                /* switch L4 header pointer from outer to inner */
                ip.hdr = skb_inner_network_header(skb);
                l4.hdr = skb_inner_transport_header(skb);
-
-               if (*tx_flags & I40E_TX_FLAGS_IPV4) {
-                       if (*tx_flags & I40E_TX_FLAGS_TSO) {
-                               *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV4;
-                       } else {
-                               *cd_tunneling |=
-                                        I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
-                       }
-               } else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
-                       *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
-               }
+               l4_proto = 0;
 
                /* Now set the ctx descriptor fields */
                *cd_tunneling |= (skb_network_header_len(skb) >> 2) <<
@@ -2442,10 +2447,13 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
                                   ((skb_inner_network_offset(skb) -
                                        skb_transport_offset(skb)) >> 1) <<
                                   I40E_TXD_CTX_QW0_NATLEN_SHIFT;
-               if (ip.v6->version == 6) {
-                       *tx_flags &= ~I40E_TX_FLAGS_IPV4;
+
+               /* reset type as we transition from outer to inner headers */
+               *tx_flags &= ~(I40E_TX_FLAGS_IPV4 | I40E_TX_FLAGS_IPV6);
+               if (ip.v4->version == 4)
+                       *tx_flags |= I40E_TX_FLAGS_IPV4;
+               if (ip.v6->version == 6)
                        *tx_flags |= I40E_TX_FLAGS_IPV6;
-               }
        }
 
        /* Enable IP checksum offloads */
index 3592067c7a83580e64ecbeeae7f364b0e1b5b7c1..b8a78a2dd011f0df728a43e993ead2b73c2423eb 100644 (file)
@@ -1625,11 +1625,29 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
        l4.hdr = skb_transport_header(skb);
 
        if (skb->encapsulation) {
-               switch (ip_hdr(skb)->protocol) {
+               /* define outer network header type */
+               if (*tx_flags & I40E_TX_FLAGS_IPV4) {
+                       if (*tx_flags & I40E_TX_FLAGS_TSO)
+                               *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV4;
+                       else
+                               *cd_tunneling |=
+                                        I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
+                       l4_proto = ip.v4->protocol;
+               } else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
+                       *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
+                       l4_proto = ip.v6->nexthdr;
+               }
+
+               /* define outer transport */
+               switch (l4_proto) {
                case IPPROTO_UDP:
                        l4_tunnel = I40E_TXD_CTX_UDP_TUNNELING;
                        *tx_flags |= I40E_TX_FLAGS_VXLAN_TUNNEL;
                        break;
+               case IPPROTO_GRE:
+                       l4_tunnel = I40E_TXD_CTX_GRE_TUNNELING;
+                       *tx_flags |= I40E_TX_FLAGS_VXLAN_TUNNEL;
+                       break;
                default:
                        return;
                }
@@ -1637,17 +1655,7 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
                /* switch L4 header pointer from outer to inner */
                ip.hdr = skb_inner_network_header(skb);
                l4.hdr = skb_inner_transport_header(skb);
-
-               if (*tx_flags & I40E_TX_FLAGS_IPV4) {
-                       if (*tx_flags & I40E_TX_FLAGS_TSO) {
-                               *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV4;
-                       } else {
-                               *cd_tunneling |=
-                                        I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
-                       }
-               } else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
-                       *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
-               }
+               l4_proto = 0;
 
                /* Now set the ctx descriptor fields */
                *cd_tunneling |= (skb_network_header_len(skb) >> 2) <<
@@ -1656,10 +1664,13 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
                                   ((skb_inner_network_offset(skb) -
                                        skb_transport_offset(skb)) >> 1) <<
                                   I40E_TXD_CTX_QW0_NATLEN_SHIFT;
-               if (ip.v6->version == 6) {
-                       *tx_flags &= ~I40E_TX_FLAGS_IPV4;
+
+               /* reset type as we transition from outer to inner headers */
+               *tx_flags &= ~(I40E_TX_FLAGS_IPV4 | I40E_TX_FLAGS_IPV6);
+               if (ip.v4->version == 4)
+                       *tx_flags |= I40E_TX_FLAGS_IPV4;
+               if (ip.v6->version == 6)
                        *tx_flags |= I40E_TX_FLAGS_IPV6;
-               }
        }
 
        /* Enable IP checksum offloads */