1 From: Felix Fietkau <nbd@nbd.name>
2 Date: Wed, 10 Feb 2021 19:39:23 +0100
3 Subject: [PATCH] netfilter: flowtable: rework ingress vlan matching
5 When dealing with bridges with VLAN filtering and DSA/switchdev offload,
6 the hardware could offload adding a VLAN tag configured in the bridge.
7 Since there doesn't seem to be an easy way to detect that, this patch
8 reworks the code to optionally match the last VLAN tag that would otherwise
9 be inserted by the bridge.
10 This matters when bypassing the bridge and attaching an ingress hook on
13 Signed-off-by: Felix Fietkau <nbd@nbd.name>
16 --- a/include/net/netfilter/nf_flow_table.h
17 +++ b/include/net/netfilter/nf_flow_table.h
18 @@ -115,14 +115,15 @@ struct flow_offload_tuple {
25 - } in_vlan[NF_FLOW_TABLE_VLAN_MAX];
27 /* All members above are keys for lookups, see flow_offload_hash(). */
33 + } in_vlan[NF_FLOW_TABLE_VLAN_MAX], in_pvid;
38 --- a/net/netfilter/nf_flow_table_ip.c
39 +++ b/net/netfilter/nf_flow_table_ip.c
40 @@ -281,12 +281,13 @@ static bool nf_flow_skb_vlan_protocol(co
43 static void nf_flow_vlan_pop(struct sk_buff *skb,
44 - struct flow_offload_tuple_rhash *tuplehash)
45 + struct flow_offload_tuple_rhash *tuplehash,
48 struct vlan_hdr *vlan_hdr;
51 - for (i = 0; i < tuplehash->tuple.in_vlan_num; i++) {
52 + for (i = 0; i < tuplehash->tuple.in_vlan_num + strip_pvid; i++) {
53 if (skb_vlan_tag_present(skb)) {
54 __vlan_hwaccel_clear_tag(skb);
56 @@ -316,6 +317,31 @@ static unsigned int nf_flow_queue_xmit(s
61 +nf_flow_offload_check_vlan(struct flow_offload_tuple *tuple,
62 + struct flow_offload_tuple *flow_tuple,
67 + if (flow_tuple->in_pvid.proto &&
68 + !memcmp(&tuple->in_vlan[0], &flow_tuple->in_pvid,
69 + sizeof(tuple->in_vlan[0])))
74 + for (i = 0; i < flow_tuple->in_vlan_num; i++, cur++) {
75 + if (!memcmp(&tuple->in_vlan[cur], &flow_tuple->in_vlan[i],
76 + sizeof(tuple->in_vlan[0])))
86 nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
87 const struct nf_hook_state *state)
88 @@ -329,6 +355,7 @@ nf_flow_offload_ip_hook(void *priv, stru
96 @@ -344,6 +371,10 @@ nf_flow_offload_ip_hook(void *priv, stru
97 if (tuplehash == NULL)
100 + if (!nf_flow_offload_check_vlan(&tuple, &tuplehash->tuple,
104 dir = tuplehash->tuple.dir;
105 flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
107 @@ -368,7 +399,7 @@ nf_flow_offload_ip_hook(void *priv, stru
111 - nf_flow_vlan_pop(skb, tuplehash);
112 + nf_flow_vlan_pop(skb, tuplehash, strip_pvid);
115 if (nf_flow_nat_ip(flow, skb, thoff, dir) < 0)
116 @@ -596,6 +627,7 @@ nf_flow_offload_ipv6_hook(void *priv, st
117 struct net_device *outdev;
118 struct ipv6hdr *ip6h;
124 @@ -610,6 +642,10 @@ nf_flow_offload_ipv6_hook(void *priv, st
125 if (tuplehash == NULL)
128 + if (!nf_flow_offload_check_vlan(&tuple, &tuplehash->tuple,
132 dir = tuplehash->tuple.dir;
133 flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
135 @@ -630,7 +666,7 @@ nf_flow_offload_ipv6_hook(void *priv, st
139 - nf_flow_vlan_pop(skb, tuplehash);
140 + nf_flow_vlan_pop(skb, tuplehash, strip_pvid);
142 if (skb_try_make_writable(skb, sizeof(*ip6h)))