mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 12:00:58 +07:00
udp6: Fix udp fragmentation for tunnel traffic.
udp6 over GRE tunnel does not work after to GRE tso changes. GRE
tso handler passes inner packet but keeps track of outer header
start in SKB_GSO_CB(skb)->mac_offset. udp6 fragment need to
take care of outer header, which start at the mac_offset, while
adding fragment header.
This bug is introduced by commit 68c3316311
(GRE: Add TCP
segmentation offload for GRE).
Reported-by: Dmitry Kravkov <dkravkov@gmail.com>
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Tested-by: Dmitry Kravkov <dmitry@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
b190a50875
commit
1e2bd517c1
@ -2852,6 +2852,21 @@ static inline int skb_tnl_header_len(const struct sk_buff *inner_skb)
|
||||
SKB_GSO_CB(inner_skb)->mac_offset;
|
||||
}
|
||||
|
||||
static inline int gso_pskb_expand_head(struct sk_buff *skb, int extra)
|
||||
{
|
||||
int new_headroom, headroom;
|
||||
int ret;
|
||||
|
||||
headroom = skb_headroom(skb);
|
||||
ret = pskb_expand_head(skb, extra, 0, GFP_ATOMIC);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
new_headroom = skb_headroom(skb);
|
||||
SKB_GSO_CB(skb)->mac_offset += (new_headroom - headroom);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool skb_is_gso(const struct sk_buff *skb)
|
||||
{
|
||||
return skb_shinfo(skb)->gso_size;
|
||||
|
@ -46,11 +46,12 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
|
||||
unsigned int mss;
|
||||
unsigned int unfrag_ip6hlen, unfrag_len;
|
||||
struct frag_hdr *fptr;
|
||||
u8 *mac_start, *prevhdr;
|
||||
u8 *packet_start, *prevhdr;
|
||||
u8 nexthdr;
|
||||
u8 frag_hdr_sz = sizeof(struct frag_hdr);
|
||||
int offset;
|
||||
__wsum csum;
|
||||
int tnl_hlen;
|
||||
|
||||
mss = skb_shinfo(skb)->gso_size;
|
||||
if (unlikely(skb->len <= mss))
|
||||
@ -83,9 +84,11 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
|
||||
/* Check if there is enough headroom to insert fragment header. */
|
||||
if ((skb_mac_header(skb) < skb->head + frag_hdr_sz) &&
|
||||
pskb_expand_head(skb, frag_hdr_sz, 0, GFP_ATOMIC))
|
||||
goto out;
|
||||
tnl_hlen = skb_tnl_header_len(skb);
|
||||
if (skb_headroom(skb) < (tnl_hlen + frag_hdr_sz)) {
|
||||
if (gso_pskb_expand_head(skb, tnl_hlen + frag_hdr_sz))
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Find the unfragmentable header and shift it left by frag_hdr_sz
|
||||
* bytes to insert fragment header.
|
||||
@ -93,11 +96,12 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
|
||||
unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
|
||||
nexthdr = *prevhdr;
|
||||
*prevhdr = NEXTHDR_FRAGMENT;
|
||||
unfrag_len = skb_network_header(skb) - skb_mac_header(skb) +
|
||||
unfrag_ip6hlen;
|
||||
mac_start = skb_mac_header(skb);
|
||||
memmove(mac_start-frag_hdr_sz, mac_start, unfrag_len);
|
||||
unfrag_len = (skb_network_header(skb) - skb_mac_header(skb)) +
|
||||
unfrag_ip6hlen + tnl_hlen;
|
||||
packet_start = (u8 *) skb->head + SKB_GSO_CB(skb)->mac_offset;
|
||||
memmove(packet_start-frag_hdr_sz, packet_start, unfrag_len);
|
||||
|
||||
SKB_GSO_CB(skb)->mac_offset -= frag_hdr_sz;
|
||||
skb->mac_header -= frag_hdr_sz;
|
||||
skb->network_header -= frag_hdr_sz;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user