1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <linux/kernel.h>
3 #include <linux/init.h>
4 #include <linux/module.h>
5 #include <linux/netfilter.h>
6 #include <linux/rhashtable.h>
7 #include <linux/netdevice.h>
8 #include <net/ip.h>
9 #include <net/ip6_route.h>
10 #include <net/netfilter/nf_tables.h>
11 #include <net/netfilter/nf_flow_table.h>
12 #include <net/netfilter/nf_conntrack.h>
13 #include <net/netfilter/nf_conntrack_core.h>
14 #include <net/netfilter/nf_conntrack_l4proto.h>
15 #include <net/netfilter/nf_conntrack_tuple.h>
16
17 static DEFINE_MUTEX(flowtable_lock);
18 static LIST_HEAD(flowtables);
19
20 static void
flow_offload_fill_dir(struct flow_offload * flow,enum flow_offload_tuple_dir dir)21 flow_offload_fill_dir(struct flow_offload *flow,
22 enum flow_offload_tuple_dir dir)
23 {
24 struct flow_offload_tuple *ft = &flow->tuplehash[dir].tuple;
25 struct nf_conntrack_tuple *ctt = &flow->ct->tuplehash[dir].tuple;
26
27 ft->dir = dir;
28
29 switch (ctt->src.l3num) {
30 case NFPROTO_IPV4:
31 ft->src_v4 = ctt->src.u3.in;
32 ft->dst_v4 = ctt->dst.u3.in;
33 break;
34 case NFPROTO_IPV6:
35 ft->src_v6 = ctt->src.u3.in6;
36 ft->dst_v6 = ctt->dst.u3.in6;
37 break;
38 }
39
40 ft->l3proto = ctt->src.l3num;
41 ft->l4proto = ctt->dst.protonum;
42
43 switch (ctt->dst.protonum) {
44 case IPPROTO_TCP:
45 case IPPROTO_UDP:
46 ft->src_port = ctt->src.u.tcp.port;
47 ft->dst_port = ctt->dst.u.tcp.port;
48 break;
49 }
50 }
51
flow_offload_alloc(struct nf_conn * ct)52 struct flow_offload *flow_offload_alloc(struct nf_conn *ct)
53 {
54 struct flow_offload *flow;
55
56 if (unlikely(nf_ct_is_dying(ct)))
57 return NULL;
58
59 flow = kzalloc(sizeof(*flow), GFP_ATOMIC);
60 if (!flow)
61 return NULL;
62
63 refcount_inc(&ct->ct_general.use);
64 flow->ct = ct;
65
66 flow_offload_fill_dir(flow, FLOW_OFFLOAD_DIR_ORIGINAL);
67 flow_offload_fill_dir(flow, FLOW_OFFLOAD_DIR_REPLY);
68
69 if (ct->status & IPS_SRC_NAT)
70 __set_bit(NF_FLOW_SNAT, &flow->flags);
71 if (ct->status & IPS_DST_NAT)
72 __set_bit(NF_FLOW_DNAT, &flow->flags);
73
74 return flow;
75 }
76 EXPORT_SYMBOL_GPL(flow_offload_alloc);
77
flow_offload_dst_cookie(struct flow_offload_tuple * flow_tuple)78 static u32 flow_offload_dst_cookie(struct flow_offload_tuple *flow_tuple)
79 {
80 if (flow_tuple->l3proto == NFPROTO_IPV6)
81 return rt6_get_cookie(dst_rt6_info(flow_tuple->dst_cache));
82
83 return 0;
84 }
85
nft_route_dst_fetch(struct nf_flow_route * route,enum flow_offload_tuple_dir dir)86 static struct dst_entry *nft_route_dst_fetch(struct nf_flow_route *route,
87 enum flow_offload_tuple_dir dir)
88 {
89 struct dst_entry *dst = route->tuple[dir].dst;
90
91 route->tuple[dir].dst = NULL;
92
93 return dst;
94 }
95
flow_offload_fill_route(struct flow_offload * flow,struct nf_flow_route * route,enum flow_offload_tuple_dir dir)96 static int flow_offload_fill_route(struct flow_offload *flow,
97 struct nf_flow_route *route,
98 enum flow_offload_tuple_dir dir)
99 {
100 struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple;
101 struct dst_entry *dst = nft_route_dst_fetch(route, dir);
102 int i, j = 0;
103
104 switch (flow_tuple->l3proto) {
105 case NFPROTO_IPV4:
106 flow_tuple->mtu = ip_dst_mtu_maybe_forward(dst, true);
107 break;
108 case NFPROTO_IPV6:
109 flow_tuple->mtu = ip6_dst_mtu_maybe_forward(dst, true);
110 break;
111 }
112
113 flow_tuple->iifidx = route->tuple[dir].in.ifindex;
114 for (i = route->tuple[dir].in.num_encaps - 1; i >= 0; i--) {
115 flow_tuple->encap[j].id = route->tuple[dir].in.encap[i].id;
116 flow_tuple->encap[j].proto = route->tuple[dir].in.encap[i].proto;
117 if (route->tuple[dir].in.ingress_vlans & BIT(i))
118 flow_tuple->in_vlan_ingress |= BIT(j);
119 j++;
120 }
121 flow_tuple->encap_num = route->tuple[dir].in.num_encaps;
122
123 switch (route->tuple[dir].xmit_type) {
124 case FLOW_OFFLOAD_XMIT_DIRECT:
125 memcpy(flow_tuple->out.h_dest, route->tuple[dir].out.h_dest,
126 ETH_ALEN);
127 memcpy(flow_tuple->out.h_source, route->tuple[dir].out.h_source,
128 ETH_ALEN);
129 flow_tuple->out.ifidx = route->tuple[dir].out.ifindex;
130 flow_tuple->out.hw_ifidx = route->tuple[dir].out.hw_ifindex;
131 dst_release(dst);
132 break;
133 case FLOW_OFFLOAD_XMIT_XFRM:
134 case FLOW_OFFLOAD_XMIT_NEIGH:
135 flow_tuple->dst_cache = dst;
136 flow_tuple->dst_cookie = flow_offload_dst_cookie(flow_tuple);
137 break;
138 default:
139 WARN_ON_ONCE(1);
140 break;
141 }
142 flow_tuple->xmit_type = route->tuple[dir].xmit_type;
143
144 return 0;
145 }
146
nft_flow_dst_release(struct flow_offload * flow,enum flow_offload_tuple_dir dir)147 static void nft_flow_dst_release(struct flow_offload *flow,
148 enum flow_offload_tuple_dir dir)
149 {
150 if (flow->tuplehash[dir].tuple.xmit_type == FLOW_OFFLOAD_XMIT_NEIGH ||
151 flow->tuplehash[dir].tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)
152 dst_release(flow->tuplehash[dir].tuple.dst_cache);
153 }
154
flow_offload_route_init(struct flow_offload * flow,struct nf_flow_route * route)155 void flow_offload_route_init(struct flow_offload *flow,
156 struct nf_flow_route *route)
157 {
158 flow_offload_fill_route(flow, route, FLOW_OFFLOAD_DIR_ORIGINAL);
159 flow_offload_fill_route(flow, route, FLOW_OFFLOAD_DIR_REPLY);
160 flow->type = NF_FLOW_OFFLOAD_ROUTE;
161 }
162 EXPORT_SYMBOL_GPL(flow_offload_route_init);
163
flow_offload_fixup_tcp(struct ip_ct_tcp * tcp)164 static void flow_offload_fixup_tcp(struct ip_ct_tcp *tcp)
165 {
166 tcp->seen[0].td_maxwin = 0;
167 tcp->seen[1].td_maxwin = 0;
168 }
169
flow_offload_fixup_ct(struct nf_conn * ct)170 static void flow_offload_fixup_ct(struct nf_conn *ct)
171 {
172 struct net *net = nf_ct_net(ct);
173 int l4num = nf_ct_protonum(ct);
174 s32 timeout;
175
176 if (l4num == IPPROTO_TCP) {
177 struct nf_tcp_net *tn = nf_tcp_pernet(net);
178
179 flow_offload_fixup_tcp(&ct->proto.tcp);
180
181 timeout = tn->timeouts[ct->proto.tcp.state];
182 timeout -= tn->offload_timeout;
183 } else if (l4num == IPPROTO_UDP) {
184 struct nf_udp_net *tn = nf_udp_pernet(net);
185 enum udp_conntrack state =
186 test_bit(IPS_SEEN_REPLY_BIT, &ct->status) ?
187 UDP_CT_REPLIED : UDP_CT_UNREPLIED;
188
189 timeout = tn->timeouts[state];
190 timeout -= tn->offload_timeout;
191 } else {
192 return;
193 }
194
195 if (timeout < 0)
196 timeout = 0;
197
198 if (nf_flow_timeout_delta(READ_ONCE(ct->timeout)) > (__s32)timeout)
199 WRITE_ONCE(ct->timeout, nfct_time_stamp + timeout);
200 }
201
flow_offload_route_release(struct flow_offload * flow)202 static void flow_offload_route_release(struct flow_offload *flow)
203 {
204 nft_flow_dst_release(flow, FLOW_OFFLOAD_DIR_ORIGINAL);
205 nft_flow_dst_release(flow, FLOW_OFFLOAD_DIR_REPLY);
206 }
207
flow_offload_free(struct flow_offload * flow)208 void flow_offload_free(struct flow_offload *flow)
209 {
210 switch (flow->type) {
211 case NF_FLOW_OFFLOAD_ROUTE:
212 flow_offload_route_release(flow);
213 break;
214 default:
215 break;
216 }
217 nf_ct_put(flow->ct);
218 kfree_rcu(flow, rcu_head);
219 }
220 EXPORT_SYMBOL_GPL(flow_offload_free);
221
flow_offload_hash(const void * data,u32 len,u32 seed)222 static u32 flow_offload_hash(const void *data, u32 len, u32 seed)
223 {
224 const struct flow_offload_tuple *tuple = data;
225
226 return jhash(tuple, offsetof(struct flow_offload_tuple, __hash), seed);
227 }
228
flow_offload_hash_obj(const void * data,u32 len,u32 seed)229 static u32 flow_offload_hash_obj(const void *data, u32 len, u32 seed)
230 {
231 const struct flow_offload_tuple_rhash *tuplehash = data;
232
233 return jhash(&tuplehash->tuple, offsetof(struct flow_offload_tuple, __hash), seed);
234 }
235
flow_offload_hash_cmp(struct rhashtable_compare_arg * arg,const void * ptr)236 static int flow_offload_hash_cmp(struct rhashtable_compare_arg *arg,
237 const void *ptr)
238 {
239 const struct flow_offload_tuple *tuple = arg->key;
240 const struct flow_offload_tuple_rhash *x = ptr;
241
242 if (memcmp(&x->tuple, tuple, offsetof(struct flow_offload_tuple, __hash)))
243 return 1;
244
245 return 0;
246 }
247
248 static const struct rhashtable_params nf_flow_offload_rhash_params = {
249 .head_offset = offsetof(struct flow_offload_tuple_rhash, node),
250 .hashfn = flow_offload_hash,
251 .obj_hashfn = flow_offload_hash_obj,
252 .obj_cmpfn = flow_offload_hash_cmp,
253 .automatic_shrinking = true,
254 };
255
flow_offload_get_timeout(struct flow_offload * flow)256 unsigned long flow_offload_get_timeout(struct flow_offload *flow)
257 {
258 unsigned long timeout = NF_FLOW_TIMEOUT;
259 struct net *net = nf_ct_net(flow->ct);
260 int l4num = nf_ct_protonum(flow->ct);
261
262 if (l4num == IPPROTO_TCP) {
263 struct nf_tcp_net *tn = nf_tcp_pernet(net);
264
265 timeout = tn->offload_timeout;
266 } else if (l4num == IPPROTO_UDP) {
267 struct nf_udp_net *tn = nf_udp_pernet(net);
268
269 timeout = tn->offload_timeout;
270 }
271
272 return timeout;
273 }
274
flow_offload_add(struct nf_flowtable * flow_table,struct flow_offload * flow)275 int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
276 {
277 int err;
278
279 flow->timeout = nf_flowtable_time_stamp + flow_offload_get_timeout(flow);
280
281 err = rhashtable_insert_fast(&flow_table->rhashtable,
282 &flow->tuplehash[0].node,
283 nf_flow_offload_rhash_params);
284 if (err < 0)
285 return err;
286
287 err = rhashtable_insert_fast(&flow_table->rhashtable,
288 &flow->tuplehash[1].node,
289 nf_flow_offload_rhash_params);
290 if (err < 0) {
291 rhashtable_remove_fast(&flow_table->rhashtable,
292 &flow->tuplehash[0].node,
293 nf_flow_offload_rhash_params);
294 return err;
295 }
296
297 nf_ct_offload_timeout(flow->ct);
298
299 if (nf_flowtable_hw_offload(flow_table)) {
300 __set_bit(NF_FLOW_HW, &flow->flags);
301 nf_flow_offload_add(flow_table, flow);
302 }
303
304 return 0;
305 }
306 EXPORT_SYMBOL_GPL(flow_offload_add);
307
flow_offload_refresh(struct nf_flowtable * flow_table,struct flow_offload * flow,bool force)308 void flow_offload_refresh(struct nf_flowtable *flow_table,
309 struct flow_offload *flow, bool force)
310 {
311 u32 timeout;
312
313 timeout = nf_flowtable_time_stamp + flow_offload_get_timeout(flow);
314 if (force || timeout - READ_ONCE(flow->timeout) > HZ)
315 WRITE_ONCE(flow->timeout, timeout);
316 else
317 return;
318
319 if (likely(!nf_flowtable_hw_offload(flow_table)))
320 return;
321
322 nf_flow_offload_add(flow_table, flow);
323 }
324 EXPORT_SYMBOL_GPL(flow_offload_refresh);
325
nf_flow_has_expired(const struct flow_offload * flow)326 static inline bool nf_flow_has_expired(const struct flow_offload *flow)
327 {
328 return nf_flow_timeout_delta(flow->timeout) <= 0;
329 }
330
flow_offload_del(struct nf_flowtable * flow_table,struct flow_offload * flow)331 static void flow_offload_del(struct nf_flowtable *flow_table,
332 struct flow_offload *flow)
333 {
334 rhashtable_remove_fast(&flow_table->rhashtable,
335 &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].node,
336 nf_flow_offload_rhash_params);
337 rhashtable_remove_fast(&flow_table->rhashtable,
338 &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].node,
339 nf_flow_offload_rhash_params);
340 flow_offload_free(flow);
341 }
342
flow_offload_teardown(struct flow_offload * flow)343 void flow_offload_teardown(struct flow_offload *flow)
344 {
345 clear_bit(IPS_OFFLOAD_BIT, &flow->ct->status);
346 set_bit(NF_FLOW_TEARDOWN, &flow->flags);
347 flow_offload_fixup_ct(flow->ct);
348 }
349 EXPORT_SYMBOL_GPL(flow_offload_teardown);
350
351 struct flow_offload_tuple_rhash *
flow_offload_lookup(struct nf_flowtable * flow_table,struct flow_offload_tuple * tuple)352 flow_offload_lookup(struct nf_flowtable *flow_table,
353 struct flow_offload_tuple *tuple)
354 {
355 struct flow_offload_tuple_rhash *tuplehash;
356 struct flow_offload *flow;
357 int dir;
358
359 tuplehash = rhashtable_lookup(&flow_table->rhashtable, tuple,
360 nf_flow_offload_rhash_params);
361 if (!tuplehash)
362 return NULL;
363
364 dir = tuplehash->tuple.dir;
365 flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
366 if (test_bit(NF_FLOW_TEARDOWN, &flow->flags))
367 return NULL;
368
369 if (unlikely(nf_ct_is_dying(flow->ct)))
370 return NULL;
371
372 return tuplehash;
373 }
374 EXPORT_SYMBOL_GPL(flow_offload_lookup);
375
376 static int
nf_flow_table_iterate(struct nf_flowtable * flow_table,void (* iter)(struct nf_flowtable * flowtable,struct flow_offload * flow,void * data),void * data)377 nf_flow_table_iterate(struct nf_flowtable *flow_table,
378 void (*iter)(struct nf_flowtable *flowtable,
379 struct flow_offload *flow, void *data),
380 void *data)
381 {
382 struct flow_offload_tuple_rhash *tuplehash;
383 struct rhashtable_iter hti;
384 struct flow_offload *flow;
385 int err = 0;
386
387 rhashtable_walk_enter(&flow_table->rhashtable, &hti);
388 rhashtable_walk_start(&hti);
389
390 while ((tuplehash = rhashtable_walk_next(&hti))) {
391 if (IS_ERR(tuplehash)) {
392 if (PTR_ERR(tuplehash) != -EAGAIN) {
393 err = PTR_ERR(tuplehash);
394 break;
395 }
396 continue;
397 }
398 if (tuplehash->tuple.dir)
399 continue;
400
401 flow = container_of(tuplehash, struct flow_offload, tuplehash[0]);
402
403 iter(flow_table, flow, data);
404 }
405 rhashtable_walk_stop(&hti);
406 rhashtable_walk_exit(&hti);
407
408 return err;
409 }
410
nf_flow_custom_gc(struct nf_flowtable * flow_table,const struct flow_offload * flow)411 static bool nf_flow_custom_gc(struct nf_flowtable *flow_table,
412 const struct flow_offload *flow)
413 {
414 return flow_table->type->gc && flow_table->type->gc(flow);
415 }
416
nf_flow_offload_gc_step(struct nf_flowtable * flow_table,struct flow_offload * flow,void * data)417 static void nf_flow_offload_gc_step(struct nf_flowtable *flow_table,
418 struct flow_offload *flow, void *data)
419 {
420 if (nf_flow_has_expired(flow) ||
421 nf_ct_is_dying(flow->ct) ||
422 nf_flow_custom_gc(flow_table, flow))
423 flow_offload_teardown(flow);
424
425 if (test_bit(NF_FLOW_TEARDOWN, &flow->flags)) {
426 if (test_bit(NF_FLOW_HW, &flow->flags)) {
427 if (!test_bit(NF_FLOW_HW_DYING, &flow->flags))
428 nf_flow_offload_del(flow_table, flow);
429 else if (test_bit(NF_FLOW_HW_DEAD, &flow->flags))
430 flow_offload_del(flow_table, flow);
431 } else {
432 flow_offload_del(flow_table, flow);
433 }
434 } else if (test_bit(NF_FLOW_HW, &flow->flags)) {
435 nf_flow_offload_stats(flow_table, flow);
436 }
437 }
438
nf_flow_table_gc_run(struct nf_flowtable * flow_table)439 void nf_flow_table_gc_run(struct nf_flowtable *flow_table)
440 {
441 nf_flow_table_iterate(flow_table, nf_flow_offload_gc_step, NULL);
442 }
443
nf_flow_offload_work_gc(struct work_struct * work)444 static void nf_flow_offload_work_gc(struct work_struct *work)
445 {
446 struct nf_flowtable *flow_table;
447
448 flow_table = container_of(work, struct nf_flowtable, gc_work.work);
449 nf_flow_table_gc_run(flow_table);
450 queue_delayed_work(system_power_efficient_wq, &flow_table->gc_work, HZ);
451 }
452
nf_flow_nat_port_tcp(struct sk_buff * skb,unsigned int thoff,__be16 port,__be16 new_port)453 static void nf_flow_nat_port_tcp(struct sk_buff *skb, unsigned int thoff,
454 __be16 port, __be16 new_port)
455 {
456 struct tcphdr *tcph;
457
458 tcph = (void *)(skb_network_header(skb) + thoff);
459 inet_proto_csum_replace2(&tcph->check, skb, port, new_port, false);
460 }
461
nf_flow_nat_port_udp(struct sk_buff * skb,unsigned int thoff,__be16 port,__be16 new_port)462 static void nf_flow_nat_port_udp(struct sk_buff *skb, unsigned int thoff,
463 __be16 port, __be16 new_port)
464 {
465 struct udphdr *udph;
466
467 udph = (void *)(skb_network_header(skb) + thoff);
468 if (udph->check || skb->ip_summed == CHECKSUM_PARTIAL) {
469 inet_proto_csum_replace2(&udph->check, skb, port,
470 new_port, false);
471 if (!udph->check)
472 udph->check = CSUM_MANGLED_0;
473 }
474 }
475
nf_flow_nat_port(struct sk_buff * skb,unsigned int thoff,u8 protocol,__be16 port,__be16 new_port)476 static void nf_flow_nat_port(struct sk_buff *skb, unsigned int thoff,
477 u8 protocol, __be16 port, __be16 new_port)
478 {
479 switch (protocol) {
480 case IPPROTO_TCP:
481 nf_flow_nat_port_tcp(skb, thoff, port, new_port);
482 break;
483 case IPPROTO_UDP:
484 nf_flow_nat_port_udp(skb, thoff, port, new_port);
485 break;
486 }
487 }
488
nf_flow_snat_port(const struct flow_offload * flow,struct sk_buff * skb,unsigned int thoff,u8 protocol,enum flow_offload_tuple_dir dir)489 void nf_flow_snat_port(const struct flow_offload *flow,
490 struct sk_buff *skb, unsigned int thoff,
491 u8 protocol, enum flow_offload_tuple_dir dir)
492 {
493 struct flow_ports *hdr;
494 __be16 port, new_port;
495
496 hdr = (void *)(skb_network_header(skb) + thoff);
497
498 switch (dir) {
499 case FLOW_OFFLOAD_DIR_ORIGINAL:
500 port = hdr->source;
501 new_port = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_port;
502 hdr->source = new_port;
503 break;
504 case FLOW_OFFLOAD_DIR_REPLY:
505 port = hdr->dest;
506 new_port = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.src_port;
507 hdr->dest = new_port;
508 break;
509 }
510
511 nf_flow_nat_port(skb, thoff, protocol, port, new_port);
512 }
513 EXPORT_SYMBOL_GPL(nf_flow_snat_port);
514
nf_flow_dnat_port(const struct flow_offload * flow,struct sk_buff * skb,unsigned int thoff,u8 protocol,enum flow_offload_tuple_dir dir)515 void nf_flow_dnat_port(const struct flow_offload *flow, struct sk_buff *skb,
516 unsigned int thoff, u8 protocol,
517 enum flow_offload_tuple_dir dir)
518 {
519 struct flow_ports *hdr;
520 __be16 port, new_port;
521
522 hdr = (void *)(skb_network_header(skb) + thoff);
523
524 switch (dir) {
525 case FLOW_OFFLOAD_DIR_ORIGINAL:
526 port = hdr->dest;
527 new_port = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_port;
528 hdr->dest = new_port;
529 break;
530 case FLOW_OFFLOAD_DIR_REPLY:
531 port = hdr->source;
532 new_port = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_port;
533 hdr->source = new_port;
534 break;
535 }
536
537 nf_flow_nat_port(skb, thoff, protocol, port, new_port);
538 }
539 EXPORT_SYMBOL_GPL(nf_flow_dnat_port);
540
nf_flow_table_init(struct nf_flowtable * flowtable)541 int nf_flow_table_init(struct nf_flowtable *flowtable)
542 {
543 int err;
544
545 INIT_DELAYED_WORK(&flowtable->gc_work, nf_flow_offload_work_gc);
546 flow_block_init(&flowtable->flow_block);
547 init_rwsem(&flowtable->flow_block_lock);
548
549 err = rhashtable_init(&flowtable->rhashtable,
550 &nf_flow_offload_rhash_params);
551 if (err < 0)
552 return err;
553
554 queue_delayed_work(system_power_efficient_wq,
555 &flowtable->gc_work, HZ);
556
557 mutex_lock(&flowtable_lock);
558 list_add(&flowtable->list, &flowtables);
559 mutex_unlock(&flowtable_lock);
560
561 return 0;
562 }
563 EXPORT_SYMBOL_GPL(nf_flow_table_init);
564
nf_flow_table_do_cleanup(struct nf_flowtable * flow_table,struct flow_offload * flow,void * data)565 static void nf_flow_table_do_cleanup(struct nf_flowtable *flow_table,
566 struct flow_offload *flow, void *data)
567 {
568 struct net_device *dev = data;
569
570 if (!dev) {
571 flow_offload_teardown(flow);
572 return;
573 }
574
575 if (net_eq(nf_ct_net(flow->ct), dev_net(dev)) &&
576 (flow->tuplehash[0].tuple.iifidx == dev->ifindex ||
577 flow->tuplehash[1].tuple.iifidx == dev->ifindex))
578 flow_offload_teardown(flow);
579 }
580
nf_flow_table_gc_cleanup(struct nf_flowtable * flowtable,struct net_device * dev)581 void nf_flow_table_gc_cleanup(struct nf_flowtable *flowtable,
582 struct net_device *dev)
583 {
584 nf_flow_table_iterate(flowtable, nf_flow_table_do_cleanup, dev);
585 flush_delayed_work(&flowtable->gc_work);
586 nf_flow_table_offload_flush(flowtable);
587 }
588
nf_flow_table_cleanup(struct net_device * dev)589 void nf_flow_table_cleanup(struct net_device *dev)
590 {
591 struct nf_flowtable *flowtable;
592
593 mutex_lock(&flowtable_lock);
594 list_for_each_entry(flowtable, &flowtables, list)
595 nf_flow_table_gc_cleanup(flowtable, dev);
596 mutex_unlock(&flowtable_lock);
597 }
598 EXPORT_SYMBOL_GPL(nf_flow_table_cleanup);
599
nf_flow_table_free(struct nf_flowtable * flow_table)600 void nf_flow_table_free(struct nf_flowtable *flow_table)
601 {
602 mutex_lock(&flowtable_lock);
603 list_del(&flow_table->list);
604 mutex_unlock(&flowtable_lock);
605
606 cancel_delayed_work_sync(&flow_table->gc_work);
607 nf_flow_table_offload_flush(flow_table);
608 /* ... no more pending work after this stage ... */
609 nf_flow_table_iterate(flow_table, nf_flow_table_do_cleanup, NULL);
610 nf_flow_table_gc_run(flow_table);
611 nf_flow_table_offload_flush_cleanup(flow_table);
612 rhashtable_destroy(&flow_table->rhashtable);
613 }
614 EXPORT_SYMBOL_GPL(nf_flow_table_free);
615
nf_flow_table_init_net(struct net * net)616 static int nf_flow_table_init_net(struct net *net)
617 {
618 net->ft.stat = alloc_percpu(struct nf_flow_table_stat);
619 return net->ft.stat ? 0 : -ENOMEM;
620 }
621
nf_flow_table_fini_net(struct net * net)622 static void nf_flow_table_fini_net(struct net *net)
623 {
624 free_percpu(net->ft.stat);
625 }
626
nf_flow_table_pernet_init(struct net * net)627 static int nf_flow_table_pernet_init(struct net *net)
628 {
629 int ret;
630
631 ret = nf_flow_table_init_net(net);
632 if (ret < 0)
633 return ret;
634
635 ret = nf_flow_table_init_proc(net);
636 if (ret < 0)
637 goto out_proc;
638
639 return 0;
640
641 out_proc:
642 nf_flow_table_fini_net(net);
643 return ret;
644 }
645
nf_flow_table_pernet_exit(struct list_head * net_exit_list)646 static void nf_flow_table_pernet_exit(struct list_head *net_exit_list)
647 {
648 struct net *net;
649
650 list_for_each_entry(net, net_exit_list, exit_list) {
651 nf_flow_table_fini_proc(net);
652 nf_flow_table_fini_net(net);
653 }
654 }
655
656 static struct pernet_operations nf_flow_table_net_ops = {
657 .init = nf_flow_table_pernet_init,
658 .exit_batch = nf_flow_table_pernet_exit,
659 };
660
nf_flow_table_module_init(void)661 static int __init nf_flow_table_module_init(void)
662 {
663 int ret;
664
665 ret = register_pernet_subsys(&nf_flow_table_net_ops);
666 if (ret < 0)
667 return ret;
668
669 ret = nf_flow_table_offload_init();
670 if (ret)
671 goto out_offload;
672
673 ret = nf_flow_register_bpf();
674 if (ret)
675 goto out_bpf;
676
677 return 0;
678
679 out_bpf:
680 nf_flow_table_offload_exit();
681 out_offload:
682 unregister_pernet_subsys(&nf_flow_table_net_ops);
683 return ret;
684 }
685
nf_flow_table_module_exit(void)686 static void __exit nf_flow_table_module_exit(void)
687 {
688 nf_flow_table_offload_exit();
689 unregister_pernet_subsys(&nf_flow_table_net_ops);
690 }
691
692 module_init(nf_flow_table_module_init);
693 module_exit(nf_flow_table_module_exit);
694
695 MODULE_LICENSE("GPL");
696 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
697 MODULE_DESCRIPTION("Netfilter flow table module");
698