u8 *hdr_len, u64 *cd_type_cmd_tso_mss)
 {
        u64 cd_cmd, cd_tso_len, cd_mss;
-       struct ipv6hdr *ipv6h;
-       struct iphdr *iph;
+       union {
+               struct iphdr *v4;
+               struct ipv6hdr *v6;
+               unsigned char *hdr;
+       } ip;
        union {
                struct tcphdr *tcp;
                unsigned char *hdr;
        if (err < 0)
                return err;
 
-       iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
-       ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb);
-       l4.hdr = skb->encapsulation ? skb_inner_transport_header(skb) :
-                                     skb_transport_header(skb);
+       ip.hdr = skb_network_header(skb);
+       l4.hdr = skb_transport_header(skb);
 
-       if (iph->version == 4) {
-               iph->tot_len = 0;
-               iph->check = 0;
+       /* initialize outer IP header fields */
+       if (ip.v4->version == 4) {
+               ip.v4->tot_len = 0;
+               ip.v4->check = 0;
        } else {
-               ipv6h->payload_len = 0;
+               ip.v6->payload_len = 0;
+       }
+
+       if (skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL | SKB_GSO_GRE)) {
+               /* reset pointers to inner headers */
+               ip.hdr = skb_inner_network_header(skb);
+               l4.hdr = skb_inner_transport_header(skb);
+
+               /* initialize inner IP header fields */
+               if (ip.v4->version == 4) {
+                       ip.v4->tot_len = 0;
+                       ip.v4->check = 0;
+               } else {
+                       ip.v6->payload_len = 0;
+               }
        }
 
        /* determine offset of inner transport header */
        struct iphdr *this_ip_hdr;
        u32 network_hdr_len;
        u8 l4_hdr = 0;
-       struct udphdr *oudph = NULL;
-       struct iphdr *oiph = NULL;
        u32 l4_tunnel = 0;
 
        if (skb->encapsulation) {
                switch (ip_hdr(skb)->protocol) {
                case IPPROTO_UDP:
-                       oudph = udp_hdr(skb);
-                       oiph = ip_hdr(skb);
                        l4_tunnel = I40E_TXD_CTX_UDP_TUNNELING;
                        *tx_flags |= I40E_TX_FLAGS_UDP_TUNNEL;
                        break;
                if (*tx_flags & I40E_TX_FLAGS_IPV4) {
                        if (*tx_flags & I40E_TX_FLAGS_TSO) {
                                *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV4;
-                               ip_hdr(skb)->check = 0;
                        } 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;
-                       if (*tx_flags & I40E_TX_FLAGS_TSO)
-                               ip_hdr(skb)->check = 0;
                }
 
                /* Now set the ctx descriptor fields */
                 */
                if (*tx_flags & I40E_TX_FLAGS_TSO) {
                        *td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4_CSUM;
-                       this_ip_hdr->check = 0;
                } else {
                        *td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4;
                }
 
                    u8 *hdr_len, u64 *cd_type_cmd_tso_mss)
 {
        u64 cd_cmd, cd_tso_len, cd_mss;
-       struct ipv6hdr *ipv6h;
-       struct iphdr *iph;
+       union {
+               struct iphdr *v4;
+               struct ipv6hdr *v6;
+               unsigned char *hdr;
+       } ip;
        union {
                struct tcphdr *tcp;
                unsigned char *hdr;
        if (err < 0)
                return err;
 
-       iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
-       ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb);
-       l4.hdr = skb->encapsulation ? skb_inner_transport_header(skb) :
-                                     skb_transport_header(skb);
+       ip.hdr = skb_network_header(skb);
+       l4.hdr = skb_transport_header(skb);
 
-       if (iph->version == 4) {
-               iph->tot_len = 0;
-               iph->check = 0;
+       /* initialize outer IP header fields */
+       if (ip.v4->version == 4) {
+               ip.v4->tot_len = 0;
+               ip.v4->check = 0;
        } else {
-               ipv6h->payload_len = 0;
+               ip.v6->payload_len = 0;
+       }
+
+       if (skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL | SKB_GSO_GRE)) {
+               /* reset pointers to inner headers */
+               ip.hdr = skb_inner_network_header(skb);
+               l4.hdr = skb_inner_transport_header(skb);
+
+               /* initialize inner IP header fields */
+               if (ip.v4->version == 4) {
+                       ip.v4->tot_len = 0;
+                       ip.v4->check = 0;
+               } else {
+                       ip.v6->payload_len = 0;
+               }
        }
 
        /* determine offset of inner transport header */
        struct iphdr *this_ip_hdr;
        u32 network_hdr_len;
        u8 l4_hdr = 0;
-       struct udphdr *oudph;
-       struct iphdr *oiph;
        u32 l4_tunnel = 0;
 
        if (skb->encapsulation) {
                switch (ip_hdr(skb)->protocol) {
                case IPPROTO_UDP:
-                       oudph = udp_hdr(skb);
-                       oiph = ip_hdr(skb);
                        l4_tunnel = I40E_TXD_CTX_UDP_TUNNELING;
                        *tx_flags |= I40E_TX_FLAGS_VXLAN_TUNNEL;
                        break;
                if (*tx_flags & I40E_TX_FLAGS_IPV4) {
                        if (*tx_flags & I40E_TX_FLAGS_TSO) {
                                *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV4;
-                               ip_hdr(skb)->check = 0;
                        } 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;
-                       if (*tx_flags & I40E_TX_FLAGS_TSO)
-                               ip_hdr(skb)->check = 0;
                }
 
                /* Now set the ctx descriptor fields */
                 */
                if (*tx_flags & I40E_TX_FLAGS_TSO) {
                        *td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4_CSUM;
-                       this_ip_hdr->check = 0;
                } else {
                        *td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4;
                }