Skip to content

Commit

Permalink
skbuff: allow 'slow_gro' for skb carring sock reference
Browse files Browse the repository at this point in the history
This change leverages the infrastructure introduced by the previous
patches to allow soft devices passing to the GRO engine owned skbs
without impacting the fast-path.

It's up to the GRO caller ensuring the slow_gro bit validity before
invoking the GRO engine. The new helper skb_prepare_for_gro() is
introduced for that goal.

On slow_gro, skbs are aggregated only with equal sk.
Additionally, skb truesize on GRO recycle and free is correctly
updated so that sk wmem is not changed by the GRO processing.

rfc-> v1:
 - fixed bad truesize on dev_gro_receive NAPI_FREE
 - use the existing state bit

Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Paolo Abeni authored and davem330 committed Jul 29, 2021
1 parent 9efb4b5 commit 5e10da5
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 4 deletions.
9 changes: 9 additions & 0 deletions include/net/sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -2249,6 +2249,15 @@ static inline __must_check bool skb_set_owner_sk_safe(struct sk_buff *skb, struc
return false;
}

static inline void skb_prepare_for_gro(struct sk_buff *skb)
{
if (skb->destructor != sock_wfree) {
skb_orphan(skb);
return;
}
skb->slow_gro = 1;
}

void sk_reset_timer(struct sock *sk, struct timer_list *timer,
unsigned long expires);

Expand Down
2 changes: 2 additions & 0 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -6034,6 +6034,7 @@ static void gro_list_prepare(const struct list_head *head,
struct tc_skb_ext *p_ext;
#endif

diffs |= p->sk != skb->sk;
diffs |= skb_metadata_dst_cmp(p, skb);
diffs |= skb_get_nfct(p) ^ skb_get_nfct(skb);

Expand Down Expand Up @@ -6311,6 +6312,7 @@ static void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb)
skb_shinfo(skb)->gso_type = 0;
skb->truesize = SKB_TRUESIZE(skb_end_offset(skb));
if (unlikely(skb->slow_gro)) {
skb_orphan(skb);
skb_ext_reset(skb);
nf_reset_ct(skb);
skb->slow_gro = 0;
Expand Down
17 changes: 13 additions & 4 deletions net/core/skbuff.c
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,7 @@ void napi_skb_free_stolen_head(struct sk_buff *skb)
nf_reset_ct(skb);
skb_dst_drop(skb);
skb_ext_put(skb);
skb_orphan(skb);
skb->slow_gro = 0;
}
napi_skb_cache_put(skb);
Expand Down Expand Up @@ -3892,6 +3893,9 @@ int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb)
NAPI_GRO_CB(p)->last = skb;
NAPI_GRO_CB(p)->count++;
p->data_len += skb->len;

/* sk owenrship - if any - completely transferred to the aggregated packet */
skb->destructor = NULL;
p->truesize += skb->truesize;
p->len += skb->len;

Expand Down Expand Up @@ -4259,6 +4263,7 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb)
unsigned int headlen = skb_headlen(skb);
unsigned int len = skb_gro_len(skb);
unsigned int delta_truesize;
unsigned int new_truesize;
struct sk_buff *lp;

if (unlikely(p->len + len >= 65536 || NAPI_GRO_CB(skb)->flush))
Expand Down Expand Up @@ -4290,10 +4295,10 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb)
skb_frag_size_sub(frag, offset);

/* all fragments truesize : remove (head size + sk_buff) */
delta_truesize = skb->truesize -
SKB_TRUESIZE(skb_end_offset(skb));
new_truesize = SKB_TRUESIZE(skb_end_offset(skb));
delta_truesize = skb->truesize - new_truesize;

skb->truesize -= skb->data_len;
skb->truesize = new_truesize;
skb->len -= skb->data_len;
skb->data_len = 0;

Expand Down Expand Up @@ -4322,12 +4327,16 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb)
memcpy(frag + 1, skbinfo->frags, sizeof(*frag) * skbinfo->nr_frags);
/* We dont need to clear skbinfo->nr_frags here */

delta_truesize = skb->truesize - SKB_DATA_ALIGN(sizeof(struct sk_buff));
new_truesize = SKB_TRUESIZE(sizeof(struct sk_buff));
delta_truesize = skb->truesize - new_truesize;
skb->truesize = new_truesize;
NAPI_GRO_CB(skb)->free = NAPI_GRO_FREE_STOLEN_HEAD;
goto done;
}

merge:
/* sk owenrship - if any - completely transferred to the aggregated packet */
skb->destructor = NULL;
delta_truesize = skb->truesize;
if (offset > headlen) {
unsigned int eat = offset - headlen;
Expand Down

0 comments on commit 5e10da5

Please sign in to comment.