v1.5 branch refresh based upon upstream master @ c8677ca89e53e3be7988d54280fce166cc894a7e
[librecmc/librecmc.git] / target / linux / generic / backport-4.14 / 337-v4.16-netfilter-nf_tables-get-rid-of-pernet-families.patch
1 From: Pablo Neira Ayuso <pablo@netfilter.org>
2 Date: Tue, 9 Jan 2018 02:42:11 +0100
3 Subject: [PATCH] netfilter: nf_tables: get rid of pernet families
4
5 Now that we have a single table list for each netns, we can get rid of
6 one pointer per family and the global afinfo list, thus, shrinking
7 struct netns for nftables that now becomes 64 bytes smaller.
8
9 And call __nft_release_afinfo() from __net_exit path accordingly to
10 release netnamespace objects on removal.
11
12 Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
13 ---
14
15 --- a/include/net/netfilter/nf_tables.h
16 +++ b/include/net/netfilter/nf_tables.h
17 @@ -969,8 +969,8 @@ struct nft_af_info {
18         struct module                   *owner;
19  };
20  
21 -int nft_register_afinfo(struct net *, struct nft_af_info *);
22 -void nft_unregister_afinfo(struct net *, struct nft_af_info *);
23 +int nft_register_afinfo(struct nft_af_info *);
24 +void nft_unregister_afinfo(struct nft_af_info *);
25  
26  int nft_register_chain_type(const struct nf_chain_type *);
27  void nft_unregister_chain_type(const struct nf_chain_type *);
28 --- a/include/net/netns/nftables.h
29 +++ b/include/net/netns/nftables.h
30 @@ -7,15 +7,8 @@
31  struct nft_af_info;
32  
33  struct netns_nftables {
34 -       struct list_head        af_info;
35         struct list_head        tables;
36         struct list_head        commit_list;
37 -       struct nft_af_info      *ipv4;
38 -       struct nft_af_info      *ipv6;
39 -       struct nft_af_info      *inet;
40 -       struct nft_af_info      *arp;
41 -       struct nft_af_info      *bridge;
42 -       struct nft_af_info      *netdev;
43         unsigned int            base_seq;
44         u8                      gencursor;
45  };
46 --- a/net/bridge/netfilter/nf_tables_bridge.c
47 +++ b/net/bridge/netfilter/nf_tables_bridge.c
48 @@ -47,34 +47,6 @@ static struct nft_af_info nft_af_bridge
49         .owner          = THIS_MODULE,
50  };
51  
52 -static int nf_tables_bridge_init_net(struct net *net)
53 -{
54 -       net->nft.bridge = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
55 -       if (net->nft.bridge == NULL)
56 -               return -ENOMEM;
57 -
58 -       memcpy(net->nft.bridge, &nft_af_bridge, sizeof(nft_af_bridge));
59 -
60 -       if (nft_register_afinfo(net, net->nft.bridge) < 0)
61 -               goto err;
62 -
63 -       return 0;
64 -err:
65 -       kfree(net->nft.bridge);
66 -       return -ENOMEM;
67 -}
68 -
69 -static void nf_tables_bridge_exit_net(struct net *net)
70 -{
71 -       nft_unregister_afinfo(net, net->nft.bridge);
72 -       kfree(net->nft.bridge);
73 -}
74 -
75 -static struct pernet_operations nf_tables_bridge_net_ops = {
76 -       .init   = nf_tables_bridge_init_net,
77 -       .exit   = nf_tables_bridge_exit_net,
78 -};
79 -
80  static const struct nf_chain_type filter_bridge = {
81         .name           = "filter",
82         .type           = NFT_CHAIN_T_DEFAULT,
83 @@ -98,17 +70,17 @@ static int __init nf_tables_bridge_init(
84  {
85         int ret;
86  
87 -       ret = nft_register_chain_type(&filter_bridge);
88 +       ret = nft_register_afinfo(&nft_af_bridge);
89         if (ret < 0)
90                 return ret;
91  
92 -       ret = register_pernet_subsys(&nf_tables_bridge_net_ops);
93 +       ret = nft_register_chain_type(&filter_bridge);
94         if (ret < 0)
95 -               goto err_register_subsys;
96 +               goto err_register_chain;
97  
98         return ret;
99  
100 -err_register_subsys:
101 +err_register_chain:
102         nft_unregister_chain_type(&filter_bridge);
103  
104         return ret;
105 @@ -116,8 +88,8 @@ err_register_subsys:
106  
107  static void __exit nf_tables_bridge_exit(void)
108  {
109 -       unregister_pernet_subsys(&nf_tables_bridge_net_ops);
110         nft_unregister_chain_type(&filter_bridge);
111 +       nft_unregister_afinfo(&nft_af_bridge);
112  }
113  
114  module_init(nf_tables_bridge_init);
115 --- a/net/ipv4/netfilter/nf_tables_arp.c
116 +++ b/net/ipv4/netfilter/nf_tables_arp.c
117 @@ -32,34 +32,6 @@ static struct nft_af_info nft_af_arp __r
118         .owner          = THIS_MODULE,
119  };
120  
121 -static int nf_tables_arp_init_net(struct net *net)
122 -{
123 -       net->nft.arp = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
124 -       if (net->nft.arp== NULL)
125 -               return -ENOMEM;
126 -
127 -       memcpy(net->nft.arp, &nft_af_arp, sizeof(nft_af_arp));
128 -
129 -       if (nft_register_afinfo(net, net->nft.arp) < 0)
130 -               goto err;
131 -
132 -       return 0;
133 -err:
134 -       kfree(net->nft.arp);
135 -       return -ENOMEM;
136 -}
137 -
138 -static void nf_tables_arp_exit_net(struct net *net)
139 -{
140 -       nft_unregister_afinfo(net, net->nft.arp);
141 -       kfree(net->nft.arp);
142 -}
143 -
144 -static struct pernet_operations nf_tables_arp_net_ops = {
145 -       .init   = nf_tables_arp_init_net,
146 -       .exit   = nf_tables_arp_exit_net,
147 -};
148 -
149  static const struct nf_chain_type filter_arp = {
150         .name           = "filter",
151         .type           = NFT_CHAIN_T_DEFAULT,
152 @@ -77,21 +49,26 @@ static int __init nf_tables_arp_init(voi
153  {
154         int ret;
155  
156 -       ret = nft_register_chain_type(&filter_arp);
157 +       ret = nft_register_afinfo(&nft_af_arp);
158         if (ret < 0)
159                 return ret;
160  
161 -       ret = register_pernet_subsys(&nf_tables_arp_net_ops);
162 +       ret = nft_register_chain_type(&filter_arp);
163         if (ret < 0)
164 -               nft_unregister_chain_type(&filter_arp);
165 +               goto err_register_chain;
166 +
167 +       return 0;
168 +
169 +err_register_chain:
170 +       nft_unregister_chain_type(&filter_arp);
171  
172         return ret;
173  }
174  
175  static void __exit nf_tables_arp_exit(void)
176  {
177 -       unregister_pernet_subsys(&nf_tables_arp_net_ops);
178         nft_unregister_chain_type(&filter_arp);
179 +       nft_unregister_afinfo(&nft_af_arp);
180  }
181  
182  module_init(nf_tables_arp_init);
183 --- a/net/ipv4/netfilter/nf_tables_ipv4.c
184 +++ b/net/ipv4/netfilter/nf_tables_ipv4.c
185 @@ -35,34 +35,6 @@ static struct nft_af_info nft_af_ipv4 __
186         .owner          = THIS_MODULE,
187  };
188  
189 -static int nf_tables_ipv4_init_net(struct net *net)
190 -{
191 -       net->nft.ipv4 = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
192 -       if (net->nft.ipv4 == NULL)
193 -               return -ENOMEM;
194 -
195 -       memcpy(net->nft.ipv4, &nft_af_ipv4, sizeof(nft_af_ipv4));
196 -
197 -       if (nft_register_afinfo(net, net->nft.ipv4) < 0)
198 -               goto err;
199 -
200 -       return 0;
201 -err:
202 -       kfree(net->nft.ipv4);
203 -       return -ENOMEM;
204 -}
205 -
206 -static void nf_tables_ipv4_exit_net(struct net *net)
207 -{
208 -       nft_unregister_afinfo(net, net->nft.ipv4);
209 -       kfree(net->nft.ipv4);
210 -}
211 -
212 -static struct pernet_operations nf_tables_ipv4_net_ops = {
213 -       .init   = nf_tables_ipv4_init_net,
214 -       .exit   = nf_tables_ipv4_exit_net,
215 -};
216 -
217  static const struct nf_chain_type filter_ipv4 = {
218         .name           = "filter",
219         .type           = NFT_CHAIN_T_DEFAULT,
220 @@ -86,21 +58,25 @@ static int __init nf_tables_ipv4_init(vo
221  {
222         int ret;
223  
224 -       ret = nft_register_chain_type(&filter_ipv4);
225 +       ret = nft_register_afinfo(&nft_af_ipv4);
226         if (ret < 0)
227                 return ret;
228  
229 -       ret = register_pernet_subsys(&nf_tables_ipv4_net_ops);
230 +       ret = nft_register_chain_type(&filter_ipv4);
231         if (ret < 0)
232 -               nft_unregister_chain_type(&filter_ipv4);
233 +               goto err_register_chain;
234 +
235 +       return 0;
236  
237 +err_register_chain:
238 +       nft_unregister_afinfo(&nft_af_ipv4);
239         return ret;
240  }
241  
242  static void __exit nf_tables_ipv4_exit(void)
243  {
244 -       unregister_pernet_subsys(&nf_tables_ipv4_net_ops);
245         nft_unregister_chain_type(&filter_ipv4);
246 +       nft_unregister_afinfo(&nft_af_ipv4);
247  }
248  
249  module_init(nf_tables_ipv4_init);
250 --- a/net/ipv6/netfilter/nf_tables_ipv6.c
251 +++ b/net/ipv6/netfilter/nf_tables_ipv6.c
252 @@ -33,34 +33,6 @@ static struct nft_af_info nft_af_ipv6 __
253         .owner          = THIS_MODULE,
254  };
255  
256 -static int nf_tables_ipv6_init_net(struct net *net)
257 -{
258 -       net->nft.ipv6 = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
259 -       if (net->nft.ipv6 == NULL)
260 -               return -ENOMEM;
261 -
262 -       memcpy(net->nft.ipv6, &nft_af_ipv6, sizeof(nft_af_ipv6));
263 -
264 -       if (nft_register_afinfo(net, net->nft.ipv6) < 0)
265 -               goto err;
266 -
267 -       return 0;
268 -err:
269 -       kfree(net->nft.ipv6);
270 -       return -ENOMEM;
271 -}
272 -
273 -static void nf_tables_ipv6_exit_net(struct net *net)
274 -{
275 -       nft_unregister_afinfo(net, net->nft.ipv6);
276 -       kfree(net->nft.ipv6);
277 -}
278 -
279 -static struct pernet_operations nf_tables_ipv6_net_ops = {
280 -       .init   = nf_tables_ipv6_init_net,
281 -       .exit   = nf_tables_ipv6_exit_net,
282 -};
283 -
284  static const struct nf_chain_type filter_ipv6 = {
285         .name           = "filter",
286         .type           = NFT_CHAIN_T_DEFAULT,
287 @@ -84,20 +56,24 @@ static int __init nf_tables_ipv6_init(vo
288  {
289         int ret;
290  
291 -       ret = nft_register_chain_type(&filter_ipv6);
292 +       ret = nft_register_afinfo(&nft_af_ipv6);
293         if (ret < 0)
294                 return ret;
295  
296 -       ret = register_pernet_subsys(&nf_tables_ipv6_net_ops);
297 +       ret = nft_register_chain_type(&filter_ipv6);
298         if (ret < 0)
299 -               nft_unregister_chain_type(&filter_ipv6);
300 +               goto err_register_chain;
301 +
302 +       return 0;
303  
304 +err_register_chain:
305 +       nft_unregister_afinfo(&nft_af_ipv6);
306         return ret;
307  }
308  
309  static void __exit nf_tables_ipv6_exit(void)
310  {
311 -       unregister_pernet_subsys(&nf_tables_ipv6_net_ops);
312 +       nft_unregister_afinfo(&nft_af_ipv6);
313         nft_unregister_chain_type(&filter_ipv6);
314  }
315  
316 --- a/net/netfilter/nf_tables_api.c
317 +++ b/net/netfilter/nf_tables_api.c
318 @@ -26,6 +26,7 @@
319  static LIST_HEAD(nf_tables_expressions);
320  static LIST_HEAD(nf_tables_objects);
321  static LIST_HEAD(nf_tables_flowtables);
322 +static LIST_HEAD(nf_tables_af_info);
323  
324  /**
325   *     nft_register_afinfo - register nf_tables address family info
326 @@ -35,17 +36,15 @@ static LIST_HEAD(nf_tables_flowtables);
327   *     Register the address family for use with nf_tables. Returns zero on
328   *     success or a negative errno code otherwise.
329   */
330 -int nft_register_afinfo(struct net *net, struct nft_af_info *afi)
331 +int nft_register_afinfo(struct nft_af_info *afi)
332  {
333         nfnl_lock(NFNL_SUBSYS_NFTABLES);
334 -       list_add_tail_rcu(&afi->list, &net->nft.af_info);
335 +       list_add_tail_rcu(&afi->list, &nf_tables_af_info);
336         nfnl_unlock(NFNL_SUBSYS_NFTABLES);
337         return 0;
338  }
339  EXPORT_SYMBOL_GPL(nft_register_afinfo);
340  
341 -static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi);
342 -
343  /**
344   *     nft_unregister_afinfo - unregister nf_tables address family info
345   *
346 @@ -53,10 +52,9 @@ static void __nft_release_afinfo(struct
347   *
348   *     Unregister the address family for use with nf_tables.
349   */
350 -void nft_unregister_afinfo(struct net *net, struct nft_af_info *afi)
351 +void nft_unregister_afinfo(struct nft_af_info *afi)
352  {
353         nfnl_lock(NFNL_SUBSYS_NFTABLES);
354 -       __nft_release_afinfo(net, afi);
355         list_del_rcu(&afi->list);
356         nfnl_unlock(NFNL_SUBSYS_NFTABLES);
357  }
358 @@ -66,7 +64,7 @@ static struct nft_af_info *nft_afinfo_lo
359  {
360         struct nft_af_info *afi;
361  
362 -       list_for_each_entry(afi, &net->nft.af_info, list) {
363 +       list_for_each_entry(afi, &nf_tables_af_info, list) {
364                 if (afi->family == family)
365                         return afi;
366         }
367 @@ -4975,15 +4973,12 @@ void nft_flow_table_iterate(struct net *
368                             void *data)
369  {
370         struct nft_flowtable *flowtable;
371 -       const struct nft_af_info *afi;
372         const struct nft_table *table;
373  
374         rcu_read_lock();
375 -       list_for_each_entry_rcu(afi, &net->nft.af_info, list) {
376 -               list_for_each_entry_rcu(table, &net->nft.tables, list) {
377 -                       list_for_each_entry_rcu(flowtable, &table->flowtables, list) {
378 -                               iter(&flowtable->data, data);
379 -                       }
380 +       list_for_each_entry_rcu(table, &net->nft.tables, list) {
381 +               list_for_each_entry_rcu(flowtable, &table->flowtables, list) {
382 +                       iter(&flowtable->data, data);
383                 }
384         }
385         rcu_read_unlock();
386 @@ -6468,21 +6463,6 @@ int nft_data_dump(struct sk_buff *skb, i
387  }
388  EXPORT_SYMBOL_GPL(nft_data_dump);
389  
390 -static int __net_init nf_tables_init_net(struct net *net)
391 -{
392 -       INIT_LIST_HEAD(&net->nft.af_info);
393 -       INIT_LIST_HEAD(&net->nft.tables);
394 -       INIT_LIST_HEAD(&net->nft.commit_list);
395 -       net->nft.base_seq = 1;
396 -       return 0;
397 -}
398 -
399 -static void __net_exit nf_tables_exit_net(struct net *net)
400 -{
401 -       WARN_ON_ONCE(!list_empty(&net->nft.af_info));
402 -       WARN_ON_ONCE(!list_empty(&net->nft.commit_list));
403 -}
404 -
405  int __nft_release_basechain(struct nft_ctx *ctx)
406  {
407         struct nft_rule *rule, *nr;
408 @@ -6503,8 +6483,7 @@ int __nft_release_basechain(struct nft_c
409  }
410  EXPORT_SYMBOL_GPL(__nft_release_basechain);
411  
412 -/* Called by nft_unregister_afinfo() from __net_exit path, nfnl_lock is held. */
413 -static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi)
414 +static void __nft_release_afinfo(struct net *net)
415  {
416         struct nft_flowtable *flowtable, *nf;
417         struct nft_table *table, *nt;
418 @@ -6514,10 +6493,11 @@ static void __nft_release_afinfo(struct
419         struct nft_set *set, *ns;
420         struct nft_ctx ctx = {
421                 .net    = net,
422 -               .family = afi->family,
423         };
424  
425         list_for_each_entry_safe(table, nt, &net->nft.tables, list) {
426 +               ctx.family = table->afi->family;
427 +
428                 list_for_each_entry(chain, &table->chains, list)
429                         nf_tables_unregister_hook(net, table, chain);
430                 list_for_each_entry(flowtable, &table->flowtables, list)
431 @@ -6558,6 +6538,21 @@ static void __nft_release_afinfo(struct
432         }
433  }
434  
435 +static int __net_init nf_tables_init_net(struct net *net)
436 +{
437 +       INIT_LIST_HEAD(&net->nft.tables);
438 +       INIT_LIST_HEAD(&net->nft.commit_list);
439 +       net->nft.base_seq = 1;
440 +       return 0;
441 +}
442 +
443 +static void __net_exit nf_tables_exit_net(struct net *net)
444 +{
445 +       __nft_release_afinfo(net);
446 +       WARN_ON_ONCE(!list_empty(&net->nft.tables));
447 +       WARN_ON_ONCE(!list_empty(&net->nft.commit_list));
448 +}
449 +
450  static struct pernet_operations nf_tables_net_ops = {
451         .init   = nf_tables_init_net,
452         .exit   = nf_tables_exit_net,
453 --- a/net/netfilter/nf_tables_inet.c
454 +++ b/net/netfilter/nf_tables_inet.c
455 @@ -43,34 +43,6 @@ static struct nft_af_info nft_af_inet __
456         .owner          = THIS_MODULE,
457  };
458  
459 -static int __net_init nf_tables_inet_init_net(struct net *net)
460 -{
461 -       net->nft.inet = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
462 -       if (net->nft.inet == NULL)
463 -               return -ENOMEM;
464 -       memcpy(net->nft.inet, &nft_af_inet, sizeof(nft_af_inet));
465 -
466 -       if (nft_register_afinfo(net, net->nft.inet) < 0)
467 -               goto err;
468 -
469 -       return 0;
470 -
471 -err:
472 -       kfree(net->nft.inet);
473 -       return -ENOMEM;
474 -}
475 -
476 -static void __net_exit nf_tables_inet_exit_net(struct net *net)
477 -{
478 -       nft_unregister_afinfo(net, net->nft.inet);
479 -       kfree(net->nft.inet);
480 -}
481 -
482 -static struct pernet_operations nf_tables_inet_net_ops = {
483 -       .init   = nf_tables_inet_init_net,
484 -       .exit   = nf_tables_inet_exit_net,
485 -};
486 -
487  static const struct nf_chain_type filter_inet = {
488         .name           = "filter",
489         .type           = NFT_CHAIN_T_DEFAULT,
490 @@ -94,21 +66,24 @@ static int __init nf_tables_inet_init(vo
491  {
492         int ret;
493  
494 -       ret = nft_register_chain_type(&filter_inet);
495 -       if (ret < 0)
496 +       if (nft_register_afinfo(&nft_af_inet) < 0)
497                 return ret;
498  
499 -       ret = register_pernet_subsys(&nf_tables_inet_net_ops);
500 +       ret = nft_register_chain_type(&filter_inet);
501         if (ret < 0)
502 -               nft_unregister_chain_type(&filter_inet);
503 +               goto err_register_chain;
504 +
505 +       return ret;
506  
507 +err_register_chain:
508 +       nft_unregister_afinfo(&nft_af_inet);
509         return ret;
510  }
511  
512  static void __exit nf_tables_inet_exit(void)
513  {
514 -       unregister_pernet_subsys(&nf_tables_inet_net_ops);
515         nft_unregister_chain_type(&filter_inet);
516 +       nft_unregister_afinfo(&nft_af_inet);
517  }
518  
519  module_init(nf_tables_inet_init);
520 --- a/net/netfilter/nf_tables_netdev.c
521 +++ b/net/netfilter/nf_tables_netdev.c
522 @@ -43,34 +43,6 @@ static struct nft_af_info nft_af_netdev
523         .owner          = THIS_MODULE,
524  };
525  
526 -static int nf_tables_netdev_init_net(struct net *net)
527 -{
528 -       net->nft.netdev = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
529 -       if (net->nft.netdev == NULL)
530 -               return -ENOMEM;
531 -
532 -       memcpy(net->nft.netdev, &nft_af_netdev, sizeof(nft_af_netdev));
533 -
534 -       if (nft_register_afinfo(net, net->nft.netdev) < 0)
535 -               goto err;
536 -
537 -       return 0;
538 -err:
539 -       kfree(net->nft.netdev);
540 -       return -ENOMEM;
541 -}
542 -
543 -static void nf_tables_netdev_exit_net(struct net *net)
544 -{
545 -       nft_unregister_afinfo(net, net->nft.netdev);
546 -       kfree(net->nft.netdev);
547 -}
548 -
549 -static struct pernet_operations nf_tables_netdev_net_ops = {
550 -       .init   = nf_tables_netdev_init_net,
551 -       .exit   = nf_tables_netdev_exit_net,
552 -};
553 -
554  static const struct nf_chain_type nft_filter_chain_netdev = {
555         .name           = "filter",
556         .type           = NFT_CHAIN_T_DEFAULT,
557 @@ -145,32 +117,32 @@ static int __init nf_tables_netdev_init(
558  {
559         int ret;
560  
561 -       ret = nft_register_chain_type(&nft_filter_chain_netdev);
562 -       if (ret)
563 +       if (nft_register_afinfo(&nft_af_netdev) < 0)
564                 return ret;
565  
566 -       ret = register_pernet_subsys(&nf_tables_netdev_net_ops);
567 +       ret = nft_register_chain_type(&nft_filter_chain_netdev);
568         if (ret)
569 -               goto err1;
570 +               goto err_register_chain_type;
571  
572         ret = register_netdevice_notifier(&nf_tables_netdev_notifier);
573         if (ret)
574 -               goto err2;
575 +               goto err_register_netdevice_notifier;
576  
577         return 0;
578  
579 -err2:
580 -       unregister_pernet_subsys(&nf_tables_netdev_net_ops);
581 -err1:
582 +err_register_netdevice_notifier:
583         nft_unregister_chain_type(&nft_filter_chain_netdev);
584 +err_register_chain_type:
585 +       nft_unregister_afinfo(&nft_af_netdev);
586 +
587         return ret;
588  }
589  
590  static void __exit nf_tables_netdev_exit(void)
591  {
592         unregister_netdevice_notifier(&nf_tables_netdev_notifier);
593 -       unregister_pernet_subsys(&nf_tables_netdev_net_ops);
594         nft_unregister_chain_type(&nft_filter_chain_netdev);
595 +       nft_unregister_afinfo(&nft_af_netdev);
596  }
597  
598  module_init(nf_tables_netdev_init);