Skip to content

Commit

Permalink
gro: Make GRO aware of lightweight tunnels.
Browse files Browse the repository at this point in the history
GRO is currently not aware of tunnel metadata generated by lightweight
tunnels and stored in the dst. This leads to two possible problems:
 * Incorrectly merging two frames that have different metadata.
 * Leaking of allocated metadata from merged frames.

This avoids those problems by comparing the tunnel information before
merging, similar to how we handle other metadata (such as vlan tags),
and releasing any state when we are done.

Reported-by: John <[email protected]>
Fixes: 2e15ea3 ("ip_gre: Add support to collect tunnel metadata.")
Signed-off-by: Jesse Gross <[email protected]>
Acked-by: Eric Dumazet <[email protected]>
Acked-by: Thomas Graf <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
jessegross authored and davem330 committed Jan 21, 2016
1 parent 5f2f3ca commit ce87fc6
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 2 deletions.
18 changes: 18 additions & 0 deletions include/net/dst_metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,24 @@ static inline bool skb_valid_dst(const struct sk_buff *skb)
return dst && !(dst->flags & DST_METADATA);
}

static inline int skb_metadata_dst_cmp(const struct sk_buff *skb_a,
const struct sk_buff *skb_b)
{
const struct metadata_dst *a, *b;

if (!(skb_a->_skb_refdst | skb_b->_skb_refdst))
return 0;

a = (const struct metadata_dst *) skb_dst(skb_a);
b = (const struct metadata_dst *) skb_dst(skb_b);

if (!a != !b || a->u.tun_info.options_len != b->u.tun_info.options_len)
return 1;

return memcmp(&a->u.tun_info, &b->u.tun_info,
sizeof(a->u.tun_info) + a->u.tun_info.options_len);
}

struct metadata_dst *metadata_dst_alloc(u8 optslen, gfp_t flags);
struct metadata_dst __percpu *metadata_dst_alloc_percpu(u8 optslen, gfp_t flags);

Expand Down
7 changes: 5 additions & 2 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -4351,6 +4351,7 @@ static void gro_list_prepare(struct napi_struct *napi, struct sk_buff *skb)

diffs = (unsigned long)p->dev ^ (unsigned long)skb->dev;
diffs |= p->vlan_tci ^ skb->vlan_tci;
diffs |= skb_metadata_dst_cmp(p, skb);
if (maclen == ETH_HLEN)
diffs |= compare_ether_header(skb_mac_header(p),
skb_mac_header(skb));
Expand Down Expand Up @@ -4548,10 +4549,12 @@ static gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb)
break;

case GRO_MERGED_FREE:
if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD)
if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD) {
skb_dst_drop(skb);
kmem_cache_free(skbuff_head_cache, skb);
else
} else {
__kfree_skb(skb);
}
break;

case GRO_HELD:
Expand Down

0 comments on commit ce87fc6

Please sign in to comment.