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
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.
10 Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
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,
19 +#define NF_FLOW_TABLE_VLAN_MAX 2
21 struct flow_offload_tuple {
23 struct in_addr src_v4;
24 @@ -113,13 +115,17 @@ struct flow_offload_tuple {
31 + } in_vlan[NF_FLOW_TABLE_VLAN_MAX];
33 /* All members above are keys for lookups, see flow_offload_hash(). */
44 struct dst_entry *dst_cache;
45 @@ -174,6 +180,9 @@ struct nf_flow_route {
46 struct dst_entry *dst;
49 + u16 vid[NF_FLOW_TABLE_VLAN_MAX];
50 + __be16 vproto[NF_FLOW_TABLE_VLAN_MAX];
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
59 struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple;
60 struct dst_entry *dst = route->tuple[dir].dst;
63 switch (flow_tuple->l3proto) {
65 @@ -91,6 +92,12 @@ static int flow_offload_fill_route(struc
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];
74 + flow_tuple->in_vlan_num = route->tuple[dir].in.num_vlans;
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);
84 +static void nf_flow_tuple_vlan(struct sk_buff *skb,
85 + struct flow_offload_tuple *tuple)
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;
91 + if (skb->protocol == htons(ETH_P_8021Q)) {
92 + struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb);
94 + tuple->in_vlan[1].id = ntohs(veth->h_vlan_TCI);
95 + tuple->in_vlan[1].proto = skb->protocol;
99 static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
100 struct flow_offload_tuple *tuple)
102 - unsigned int thoff, hdrsize;
103 + unsigned int thoff, hdrsize, offset = 0;
104 struct flow_ports *ports;
107 - if (!pskb_may_pull(skb, sizeof(*iph)))
108 + if (skb->protocol == htons(ETH_P_8021Q))
109 + offset += VLAN_HLEN;
111 + if (!pskb_may_pull(skb, sizeof(*iph) + offset))
115 + iph = (struct iphdr *)(skb_network_header(skb) + offset);
116 thoff = iph->ihl * 4;
118 if (ip_is_fragment(iph) ||
119 @@ -191,11 +209,11 @@ static int nf_flow_tuple_ip(struct sk_bu
122 thoff = iph->ihl * 4;
123 - if (!pskb_may_pull(skb, thoff + hdrsize))
124 + if (!pskb_may_pull(skb, thoff + hdrsize + offset))
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);
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);
142 @@ -248,6 +267,37 @@ static unsigned int nf_flow_xmit_xfrm(st
146 +static bool nf_flow_skb_vlan_protocol(const struct sk_buff *skb, __be16 proto)
148 + if (skb->protocol == htons(ETH_P_8021Q)) {
149 + struct vlan_ethhdr *veth;
151 + veth = (struct vlan_ethhdr *)skb_mac_header(skb);
152 + if (veth->h_vlan_encapsulated_proto == proto)
159 +static void nf_flow_vlan_pop(struct sk_buff *skb,
160 + struct flow_offload_tuple_rhash *tuplehash)
162 + struct vlan_hdr *vlan_hdr;
165 + for (i = 0; i < tuplehash->tuple.in_vlan_num; i++) {
166 + if (skb_vlan_tag_present(skb)) {
167 + __vlan_hwaccel_clear_tag(skb);
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);
177 static unsigned int nf_flow_queue_xmit(struct net *net, struct sk_buff *skb,
178 const struct flow_offload_tuple_rhash *tuplehash,
180 @@ -280,9 +330,11 @@ nf_flow_offload_ip_hook(void *priv, stru
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)))
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)))
197 - if (skb_try_make_writable(skb, sizeof(*iph)))
198 + if (skb->protocol == htons(ETH_P_8021Q))
199 + offset += VLAN_HLEN;
201 + if (skb_try_make_writable(skb, sizeof(*iph) + offset))
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))
211 flow_offload_refresh(flow_table, flow);
212 @@ -312,6 +368,9 @@ nf_flow_offload_ip_hook(void *priv, stru
216 + nf_flow_vlan_pop(skb, tuplehash);
219 if (nf_flow_nat_ip(flow, skb, thoff, dir) < 0)
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)
226 - unsigned int thoff, hdrsize;
227 + unsigned int thoff, hdrsize, offset = 0;
228 struct flow_ports *ports;
229 struct ipv6hdr *ip6h;
231 - if (!pskb_may_pull(skb, sizeof(*ip6h)))
232 + if (skb->protocol == htons(ETH_P_8021Q))
233 + offset += VLAN_HLEN;
235 + if (!pskb_may_pull(skb, sizeof(*ip6h) + offset))
238 - ip6h = ipv6_hdr(skb);
239 + ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
241 switch (ip6h->nexthdr) {
243 @@ -503,11 +565,11 @@ static int nf_flow_tuple_ipv6(struct sk_
246 thoff = sizeof(*ip6h);
247 - if (!pskb_may_pull(skb, thoff + hdrsize))
248 + if (!pskb_may_pull(skb, thoff + hdrsize + offset))
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);
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);
266 @@ -533,9 +596,11 @@ nf_flow_offload_ipv6_hook(void *priv, st
267 struct net_device *outdev;
268 struct ipv6hdr *ip6h;
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)))
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)))
283 - if (nf_flow_state_check(flow, ipv6_hdr(skb)->nexthdr, skb,
285 + if (skb->protocol == htons(ETH_P_8021Q))
286 + offset += VLAN_HLEN;
288 + ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
289 + if (nf_flow_state_check(flow, ip6h->nexthdr, skb, sizeof(*ip6h)))
292 flow_offload_refresh(flow_table, flow);
293 @@ -562,6 +630,8 @@ nf_flow_offload_ipv6_hook(void *priv, st
297 + nf_flow_vlan_pop(skb, tuplehash);
299 if (skb_try_make_writable(skb, sizeof(*ip6h)))
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
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];
311 u8 h_source[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);
323 + if (path->type == DEV_PATH_ETHERNET)
326 + /* DEV_PATH_VLAN */
327 + if (info->num_vlans >= NF_FLOW_TABLE_VLAN_MAX) {
331 + info->vid[info->num_vlans] = path->vlan.id;
332 + info->vproto[info->num_vlans] = path->vlan.proto;
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
339 info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
341 - case DEV_PATH_VLAN:
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];
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
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];
361 + route->tuple[!dir].in.num_vlans = info.num_vlans;
363 if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) {
364 memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN);