i40e/i40evf: Enable support for SKB_GSO_UDP_TUNNEL_CSUM
authorAlexander Duyck <aduyck@mirantis.com>
Mon, 25 Jan 2016 05:17:29 +0000 (21:17 -0800)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Thu, 18 Feb 2016 22:46:23 +0000 (14:46 -0800)
The XL722 has support for providing the outer UDP tunnel checksum on
transmits.  Make use of this feature to support segmenting UDP tunnels with
outer checksums enabled.

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>
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40evf/i40e_txrx.c

index ded73c021510eb0f22b2c70ceeaf48e011a83595..1955c849a45277e421a945abf2b847539f4f1b9a 100644 (file)
@@ -2272,6 +2272,7 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
        } ip;
        union {
                struct tcphdr *tcp;
+               struct udphdr *udp;
                unsigned char *hdr;
        } l4;
        u32 paylen, l4_offset;
@@ -2298,7 +2299,18 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
                ip.v6->payload_len = 0;
        }
 
-       if (skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL | SKB_GSO_GRE)) {
+       if (skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL | SKB_GSO_GRE |
+                                        SKB_GSO_UDP_TUNNEL_CSUM)) {
+               if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM) {
+                       /* determine offset of outer transport header */
+                       l4_offset = l4.hdr - skb->data;
+
+                       /* remove payload length from outer checksum */
+                       paylen = (__force u16)l4.udp->check;
+                       paylen += ntohs(1) * (u16)~(skb->len - l4_offset);
+                       l4.udp->check = ~csum_fold((__force __wsum)paylen);
+               }
+
                /* reset pointers to inner headers */
                ip.hdr = skb_inner_network_header(skb);
                l4.hdr = skb_inner_transport_header(skb);
@@ -2460,6 +2472,11 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
                tunnel |= ((ip.hdr - l4.hdr) / 2) <<
                          I40E_TXD_CTX_QW0_NATLEN_SHIFT;
 
+               /* indicate if we need to offload outer UDP header */
+               if ((*tx_flags & I40E_TX_FLAGS_TSO) &&
+                   (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM))
+                       tunnel |= I40E_TXD_CTX_QW0_L4T_CS_MASK;
+
                /* record tunnel offload values */
                *cd_tunneling |= tunnel;
 
index 3f40e0e260661d51801578db596c49d7e2f69271..6d66fcdc6122d3c9b00bc5d74fc723b7965b62ce 100644 (file)
@@ -1532,6 +1532,7 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
        } ip;
        union {
                struct tcphdr *tcp;
+               struct udphdr *udp;
                unsigned char *hdr;
        } l4;
        u32 paylen, l4_offset;
@@ -1558,7 +1559,18 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
                ip.v6->payload_len = 0;
        }
 
-       if (skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL | SKB_GSO_GRE)) {
+       if (skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL | SKB_GSO_GRE |
+                                        SKB_GSO_UDP_TUNNEL_CSUM)) {
+               if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM) {
+                       /* determine offset of outer transport header */
+                       l4_offset = l4.hdr - skb->data;
+
+                       /* remove payload length from outer checksum */
+                       paylen = (__force u16)l4.udp->check;
+                       paylen += ntohs(1) * (u16)~(skb->len - l4_offset);
+                       l4.udp->check = ~csum_fold((__force __wsum)paylen);
+               }
+
                /* reset pointers to inner headers */
                ip.hdr = skb_inner_network_header(skb);
                l4.hdr = skb_inner_transport_header(skb);
@@ -1678,6 +1690,11 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
                tunnel |= ((ip.hdr - l4.hdr) / 2) <<
                          I40E_TXD_CTX_QW0_NATLEN_SHIFT;
 
+               /* indicate if we need to offload outer UDP header */
+               if ((*tx_flags & I40E_TX_FLAGS_TSO) &&
+                   (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM))
+                       tunnel |= I40E_TXD_CTX_QW0_L4T_CS_MASK;
+
                /* record tunnel offload values */
                *cd_tunneling |= tunnel;