Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions net/core/filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -3481,13 +3481,20 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 off, u32 len_diff,
if (skb_is_gso(skb)) {
struct skb_shared_info *shinfo = skb_shinfo(skb);

/* Due to header grow, MSS needs to be downgraded. */
if (!(flags & BPF_F_ADJ_ROOM_FIXED_GSO))
skb_decrease_gso_size(shinfo, len_diff);

/* Header must be checked, and gso_segs recomputed. */
shinfo->gso_type |= gso_type;
shinfo->gso_segs = 0;

/* Due to header growth, MSS needs to be downgraded.
* There is a BUG_ON() when segmenting the frag_list with
* head_frag true, so linearize the skb after downgrading
* the MSS.
*/
if (!(flags & BPF_F_ADJ_ROOM_FIXED_GSO)) {
skb_decrease_gso_size(shinfo, len_diff);
if (shinfo->frag_list)
return skb_linearize(skb);
}
}

return 0;
Expand Down
27 changes: 25 additions & 2 deletions net/ipv4/udp_offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,32 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
bool copy_dtor;
__sum16 check;
__be16 newlen;
int ret = 0;

if (skb_shinfo(gso_skb)->gso_type & SKB_GSO_FRAGLIST)
return __udp_gso_segment_list(gso_skb, features, is_ipv6);
if (skb_shinfo(gso_skb)->gso_type & SKB_GSO_FRAGLIST) {
/* Detect modified geometry and pass those to skb_segment. */
if (skb_pagelen(gso_skb) - sizeof(*uh) == skb_shinfo(gso_skb)->gso_size)
return __udp_gso_segment_list(gso_skb, features, is_ipv6);

ret = __skb_linearize(gso_skb);
if (ret)
return ERR_PTR(ret);

/* Setup csum, as fraglist skips this in udp4_gro_receive. */
gso_skb->csum_start = skb_transport_header(gso_skb) - gso_skb->head;
gso_skb->csum_offset = offsetof(struct udphdr, check);
gso_skb->ip_summed = CHECKSUM_PARTIAL;

uh = udp_hdr(gso_skb);
if (is_ipv6)
uh->check = ~udp_v6_check(gso_skb->len,
&ipv6_hdr(gso_skb)->saddr,
&ipv6_hdr(gso_skb)->daddr, 0);
else
uh->check = ~udp_v4_check(gso_skb->len,
ip_hdr(gso_skb)->saddr,
ip_hdr(gso_skb)->daddr, 0);
}

mss = skb_shinfo(gso_skb)->gso_size;
if (gso_skb->len <= sizeof(*uh) + mss)
Expand Down