Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ce87fc6c authored by Jesse Gross's avatar Jesse Gross Committed by David S. Miller
Browse files

gro: Make GRO aware of lightweight tunnels.



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: default avatarJohn <john.phillips5@hpe.com>
Fixes: 2e15ea39 ("ip_gre: Add support to collect tunnel metadata.")
Signed-off-by: default avatarJesse Gross <jesse@kernel.org>
Acked-by: default avatarEric Dumazet <edumazet@google.com>
Acked-by: default avatarThomas Graf <tgraf@suug.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5f2f3cad
Loading
Loading
Loading
Loading
+18 −0
Original line number Original line Diff line number Diff line
@@ -44,6 +44,24 @@ static inline bool skb_valid_dst(const struct sk_buff *skb)
	return dst && !(dst->flags & DST_METADATA);
	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 *metadata_dst_alloc(u8 optslen, gfp_t flags);
struct metadata_dst __percpu *metadata_dst_alloc_percpu(u8 optslen, gfp_t flags);
struct metadata_dst __percpu *metadata_dst_alloc_percpu(u8 optslen, gfp_t flags);


+5 −2
Original line number Original line Diff line number Diff line
@@ -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 = (unsigned long)p->dev ^ (unsigned long)skb->dev;
		diffs |= p->vlan_tci ^ skb->vlan_tci;
		diffs |= p->vlan_tci ^ skb->vlan_tci;
		diffs |= skb_metadata_dst_cmp(p, skb);
		if (maclen == ETH_HLEN)
		if (maclen == ETH_HLEN)
			diffs |= compare_ether_header(skb_mac_header(p),
			diffs |= compare_ether_header(skb_mac_header(p),
						      skb_mac_header(skb));
						      skb_mac_header(skb));
@@ -4548,10 +4549,12 @@ static gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb)
		break;
		break;


	case GRO_MERGED_FREE:
	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);
			kmem_cache_free(skbuff_head_cache, skb);
		else
		} else {
			__kfree_skb(skb);
			__kfree_skb(skb);
		}
		break;
		break;


	case GRO_HELD:
	case GRO_HELD: