|
@@ -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;
|
|
|
|