77aeaccbce771d4777d2bca032d381050ed2113c
[openwrt/staging/rmilecki.git] / target / linux / generic / pending-5.10 / 640-07-netfilter-flowtable-add-vlan-support.patch
1 From: Pablo Neira Ayuso <pablo@netfilter.org>
2 Date: Fri, 20 Nov 2020 13:49:20 +0100
3 Subject: [PATCH] netfilter: flowtable: add vlan support
4
5 Add the vlan id and protocol to the flow tuple to uniquely identify
6 flows from the receive path. For the transmit path, dev_hard_header() on
7 the vlan device push the headers. This patch includes support for two
8 VLAN headers (QinQ) from the ingress path.
9
10 Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
11 ---
12
13 --- a/include/net/netfilter/nf_flow_table.h
14 +++ b/include/net/netfilter/nf_flow_table.h
15 @@ -95,6 +95,8 @@ enum flow_offload_xmit_type {
16 FLOW_OFFLOAD_XMIT_DIRECT,
17 };
18
19 +#define NF_FLOW_TABLE_VLAN_MAX 2
20 +
21 struct flow_offload_tuple {
22 union {
23 struct in_addr src_v4;
24 @@ -113,13 +115,17 @@ struct flow_offload_tuple {
25
26 u8 l3proto;
27 u8 l4proto;
28 + struct {
29 + u16 id;
30 + __be16 proto;
31 + } in_vlan[NF_FLOW_TABLE_VLAN_MAX];
32
33 /* All members above are keys for lookups, see flow_offload_hash(). */
34 struct { } __hash;
35
36 - u8 dir:6,
37 - xmit_type:2;
38 -
39 + u8 dir:4,
40 + xmit_type:2,
41 + in_vlan_num:2;
42 u16 mtu;
43 union {
44 struct dst_entry *dst_cache;
45 @@ -174,6 +180,9 @@ struct nf_flow_route {
46 struct dst_entry *dst;
47 struct {
48 u32 ifindex;
49 + u16 vid[NF_FLOW_TABLE_VLAN_MAX];
50 + __be16 vproto[NF_FLOW_TABLE_VLAN_MAX];
51 + u8 num_vlans;
52 } in;
53 struct {
54 u32 ifindex;
55 --- a/net/netfilter/nf_flow_table_core.c
56 +++ b/net/netfilter/nf_flow_table_core.c
57 @@ -80,6 +80,7 @@ static int flow_offload_fill_route(struc
58 {
59 struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple;
60 struct dst_entry *dst = route->tuple[dir].dst;
61 + int i, j = 0;
62
63 switch (flow_tuple->l3proto) {
64 case NFPROTO_IPV4:
65 @@ -91,6 +92,12 @@ static int flow_offload_fill_route(struc
66 }
67
68 flow_tuple->iifidx = route->tuple[dir].in.ifindex;
69 + for (i = route->tuple[dir].in.num_vlans - 1; i >= 0; i--) {
70 + flow_tuple->in_vlan[j].id = route->tuple[dir].in.vid[i];
71 + flow_tuple->in_vlan[j].proto = route->tuple[dir].in.vproto[i];
72 + j++;
73 + }
74 + flow_tuple->in_vlan_num = route->tuple[dir].in.num_vlans;
75
76 switch (route->tuple[dir].xmit_type) {
77 case FLOW_OFFLOAD_XMIT_DIRECT:
78 --- a/net/netfilter/nf_flow_table_ip.c
79 +++ b/net/netfilter/nf_flow_table_ip.c
80 @@ -159,17 +159,35 @@ static bool ip_has_options(unsigned int
81 return thoff != sizeof(struct iphdr);
82 }
83
84 +static void nf_flow_tuple_vlan(struct sk_buff *skb,
85 + struct flow_offload_tuple *tuple)
86 +{
87 + if (skb_vlan_tag_present(skb)) {
88 + tuple->in_vlan[0].id = skb_vlan_tag_get(skb);
89 + tuple->in_vlan[0].proto = skb->vlan_proto;
90 + }
91 + if (skb->protocol == htons(ETH_P_8021Q)) {
92 + struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb);
93 +
94 + tuple->in_vlan[1].id = ntohs(veth->h_vlan_TCI);
95 + tuple->in_vlan[1].proto = skb->protocol;
96 + }
97 +}
98 +
99 static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
100 struct flow_offload_tuple *tuple)
101 {
102 - unsigned int thoff, hdrsize;
103 + unsigned int thoff, hdrsize, offset = 0;
104 struct flow_ports *ports;
105 struct iphdr *iph;
106
107 - if (!pskb_may_pull(skb, sizeof(*iph)))
108 + if (skb->protocol == htons(ETH_P_8021Q))
109 + offset += VLAN_HLEN;
110 +
111 + if (!pskb_may_pull(skb, sizeof(*iph) + offset))
112 return -1;
113
114 - iph = ip_hdr(skb);
115 + iph = (struct iphdr *)(skb_network_header(skb) + offset);
116 thoff = iph->ihl * 4;
117
118 if (ip_is_fragment(iph) ||
119 @@ -191,11 +209,11 @@ static int nf_flow_tuple_ip(struct sk_bu
120 return -1;
121
122 thoff = iph->ihl * 4;
123 - if (!pskb_may_pull(skb, thoff + hdrsize))
124 + if (!pskb_may_pull(skb, thoff + hdrsize + offset))
125 return -1;
126
127 - iph = ip_hdr(skb);
128 - ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
129 + iph = (struct iphdr *)(skb_network_header(skb) + offset);
130 + ports = (struct flow_ports *)(skb_network_header(skb) + thoff + offset);
131
132 tuple->src_v4.s_addr = iph->saddr;
133 tuple->dst_v4.s_addr = iph->daddr;
134 @@ -204,6 +222,7 @@ static int nf_flow_tuple_ip(struct sk_bu
135 tuple->l3proto = AF_INET;
136 tuple->l4proto = iph->protocol;
137 tuple->iifidx = dev->ifindex;
138 + nf_flow_tuple_vlan(skb, tuple);
139
140 return 0;
141 }
142 @@ -248,6 +267,37 @@ static unsigned int nf_flow_xmit_xfrm(st
143 return NF_STOLEN;
144 }
145
146 +static bool nf_flow_skb_vlan_protocol(const struct sk_buff *skb, __be16 proto)
147 +{
148 + if (skb->protocol == htons(ETH_P_8021Q)) {
149 + struct vlan_ethhdr *veth;
150 +
151 + veth = (struct vlan_ethhdr *)skb_mac_header(skb);
152 + if (veth->h_vlan_encapsulated_proto == proto)
153 + return true;
154 + }
155 +
156 + return false;
157 +}
158 +
159 +static void nf_flow_vlan_pop(struct sk_buff *skb,
160 + struct flow_offload_tuple_rhash *tuplehash)
161 +{
162 + struct vlan_hdr *vlan_hdr;
163 + int i;
164 +
165 + for (i = 0; i < tuplehash->tuple.in_vlan_num; i++) {
166 + if (skb_vlan_tag_present(skb)) {
167 + __vlan_hwaccel_clear_tag(skb);
168 + continue;
169 + }
170 + vlan_hdr = (struct vlan_hdr *)skb->data;
171 + __skb_pull(skb, VLAN_HLEN);
172 + vlan_set_encap_proto(skb, vlan_hdr);
173 + skb_reset_network_header(skb);
174 + }
175 +}
176 +
177 static unsigned int nf_flow_queue_xmit(struct net *net, struct sk_buff *skb,
178 const struct flow_offload_tuple_rhash *tuplehash,
179 unsigned short type)
180 @@ -280,9 +330,11 @@ nf_flow_offload_ip_hook(void *priv, stru
181 unsigned int thoff;
182 struct iphdr *iph;
183 __be32 nexthop;
184 + u32 offset = 0;
185 int ret;
186
187 - if (skb->protocol != htons(ETH_P_IP))
188 + if (skb->protocol != htons(ETH_P_IP) &&
189 + !nf_flow_skb_vlan_protocol(skb, htons(ETH_P_IP)))
190 return NF_ACCEPT;
191
192 if (nf_flow_tuple_ip(skb, state->in, &tuple) < 0)
193 @@ -298,11 +350,15 @@ nf_flow_offload_ip_hook(void *priv, stru
194 if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)))
195 return NF_ACCEPT;
196
197 - if (skb_try_make_writable(skb, sizeof(*iph)))
198 + if (skb->protocol == htons(ETH_P_8021Q))
199 + offset += VLAN_HLEN;
200 +
201 + if (skb_try_make_writable(skb, sizeof(*iph) + offset))
202 return NF_DROP;
203
204 - thoff = ip_hdr(skb)->ihl * 4;
205 - if (nf_flow_state_check(flow, ip_hdr(skb)->protocol, skb, thoff))
206 + iph = (struct iphdr *)(skb_network_header(skb) + offset);
207 + thoff = (iph->ihl * 4) + offset;
208 + if (nf_flow_state_check(flow, iph->protocol, skb, thoff))
209 return NF_ACCEPT;
210
211 flow_offload_refresh(flow_table, flow);
212 @@ -312,6 +368,9 @@ nf_flow_offload_ip_hook(void *priv, stru
213 return NF_ACCEPT;
214 }
215
216 + nf_flow_vlan_pop(skb, tuplehash);
217 + thoff -= offset;
218 +
219 if (nf_flow_nat_ip(flow, skb, thoff, dir) < 0)
220 return NF_DROP;
221
222 @@ -479,14 +538,17 @@ static int nf_flow_nat_ipv6(const struct
223 static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
224 struct flow_offload_tuple *tuple)
225 {
226 - unsigned int thoff, hdrsize;
227 + unsigned int thoff, hdrsize, offset = 0;
228 struct flow_ports *ports;
229 struct ipv6hdr *ip6h;
230
231 - if (!pskb_may_pull(skb, sizeof(*ip6h)))
232 + if (skb->protocol == htons(ETH_P_8021Q))
233 + offset += VLAN_HLEN;
234 +
235 + if (!pskb_may_pull(skb, sizeof(*ip6h) + offset))
236 return -1;
237
238 - ip6h = ipv6_hdr(skb);
239 + ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
240
241 switch (ip6h->nexthdr) {
242 case IPPROTO_TCP:
243 @@ -503,11 +565,11 @@ static int nf_flow_tuple_ipv6(struct sk_
244 return -1;
245
246 thoff = sizeof(*ip6h);
247 - if (!pskb_may_pull(skb, thoff + hdrsize))
248 + if (!pskb_may_pull(skb, thoff + hdrsize + offset))
249 return -1;
250
251 - ip6h = ipv6_hdr(skb);
252 - ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
253 + ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
254 + ports = (struct flow_ports *)(skb_network_header(skb) + thoff + offset);
255
256 tuple->src_v6 = ip6h->saddr;
257 tuple->dst_v6 = ip6h->daddr;
258 @@ -516,6 +578,7 @@ static int nf_flow_tuple_ipv6(struct sk_
259 tuple->l3proto = AF_INET6;
260 tuple->l4proto = ip6h->nexthdr;
261 tuple->iifidx = dev->ifindex;
262 + nf_flow_tuple_vlan(skb, tuple);
263
264 return 0;
265 }
266 @@ -533,9 +596,11 @@ nf_flow_offload_ipv6_hook(void *priv, st
267 struct net_device *outdev;
268 struct ipv6hdr *ip6h;
269 struct rt6_info *rt;
270 + u32 offset = 0;
271 int ret;
272
273 - if (skb->protocol != htons(ETH_P_IPV6))
274 + if (skb->protocol != htons(ETH_P_IPV6) &&
275 + !nf_flow_skb_vlan_protocol(skb, htons(ETH_P_IPV6)))
276 return NF_ACCEPT;
277
278 if (nf_flow_tuple_ipv6(skb, state->in, &tuple) < 0)
279 @@ -551,8 +616,11 @@ nf_flow_offload_ipv6_hook(void *priv, st
280 if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)))
281 return NF_ACCEPT;
282
283 - if (nf_flow_state_check(flow, ipv6_hdr(skb)->nexthdr, skb,
284 - sizeof(*ip6h)))
285 + if (skb->protocol == htons(ETH_P_8021Q))
286 + offset += VLAN_HLEN;
287 +
288 + ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
289 + if (nf_flow_state_check(flow, ip6h->nexthdr, skb, sizeof(*ip6h)))
290 return NF_ACCEPT;
291
292 flow_offload_refresh(flow_table, flow);
293 @@ -562,6 +630,8 @@ nf_flow_offload_ipv6_hook(void *priv, st
294 return NF_ACCEPT;
295 }
296
297 + nf_flow_vlan_pop(skb, tuplehash);
298 +
299 if (skb_try_make_writable(skb, sizeof(*ip6h)))
300 return NF_DROP;
301
302 --- a/net/netfilter/nft_flow_offload.c
303 +++ b/net/netfilter/nft_flow_offload.c
304 @@ -65,6 +65,9 @@ static int nft_dev_fill_forward_path(con
305
306 struct nft_forward_info {
307 const struct net_device *dev;
308 + __u16 vid[NF_FLOW_TABLE_VLAN_MAX];
309 + __be16 vproto[NF_FLOW_TABLE_VLAN_MAX];
310 + u8 num_vlans;
311 u8 h_source[ETH_ALEN];
312 u8 h_dest[ETH_ALEN];
313 enum flow_offload_xmit_type xmit_type;
314 @@ -83,9 +86,22 @@ static void nft_dev_path_info(const stru
315 path = &stack->path[i];
316 switch (path->type) {
317 case DEV_PATH_ETHERNET:
318 + case DEV_PATH_VLAN:
319 info->dev = path->dev;
320 if (is_zero_ether_addr(info->h_source))
321 memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
322 +
323 + if (path->type == DEV_PATH_ETHERNET)
324 + break;
325 +
326 + /* DEV_PATH_VLAN */
327 + if (info->num_vlans >= NF_FLOW_TABLE_VLAN_MAX) {
328 + info->dev = NULL;
329 + break;
330 + }
331 + info->vid[info->num_vlans] = path->vlan.id;
332 + info->vproto[info->num_vlans] = path->vlan.proto;
333 + info->num_vlans++;
334 break;
335 case DEV_PATH_BRIDGE:
336 if (is_zero_ether_addr(info->h_source))
337 @@ -93,7 +109,6 @@ static void nft_dev_path_info(const stru
338
339 info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
340 break;
341 - case DEV_PATH_VLAN:
342 default:
343 info->dev = NULL;
344 break;
345 @@ -127,6 +142,7 @@ static void nft_dev_forward_path(struct
346 struct net_device_path_stack stack;
347 struct nft_forward_info info = {};
348 unsigned char ha[ETH_ALEN];
349 + int i;
350
351 if (nft_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) >= 0)
352 nft_dev_path_info(&stack, &info, ha);
353 @@ -135,6 +151,11 @@ static void nft_dev_forward_path(struct
354 return;
355
356 route->tuple[!dir].in.ifindex = info.dev->ifindex;
357 + for (i = 0; i < info.num_vlans; i++) {
358 + route->tuple[!dir].in.vid[i] = info.vid[i];
359 + route->tuple[!dir].in.vproto[i] = info.vproto[i];
360 + }
361 + route->tuple[!dir].in.num_vlans = info.num_vlans;
362
363 if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) {
364 memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN);