Commit 115a60b173af0170e0db26b9a3fd6a911fba70a3

Authored by Patrick McHardy
Committed by Pablo Neira Ayuso
1 parent c9484874e7

netfilter: nf_tables: add support for multi family tables

Add support to register chains to multiple hooks for different address
families for mixed IPv4/IPv6 tables.

Signed-off-by: Patrick McHardy <kaber@trash.net>

Showing 7 changed files with 45 additions and 25 deletions Side-by-side Diff

include/net/netfilter/nf_tables.h
... ... @@ -422,6 +422,8 @@
422 422 u64 pkts;
423 423 };
424 424  
  425 +#define NFT_HOOK_OPS_MAX 2
  426 +
425 427 /**
426 428 * struct nft_base_chain - nf_tables base chain
427 429 *
... ... @@ -432,7 +434,7 @@
432 434 * @chain: the chain
433 435 */
434 436 struct nft_base_chain {
435   - struct nf_hook_ops ops;
  437 + struct nf_hook_ops ops[NFT_HOOK_OPS_MAX];
436 438 enum nft_chain_type type;
437 439 u8 policy;
438 440 struct nft_stats __percpu *stats;
... ... @@ -476,6 +478,8 @@
476 478 * @nhooks: number of hooks in this family
477 479 * @owner: module owner
478 480 * @tables: used internally
  481 + * @nops: number of hook ops in this family
  482 + * @hook_ops_init: initialization function for chain hook ops
479 483 * @hooks: hookfn overrides for packet validation
480 484 */
481 485 struct nft_af_info {
... ... @@ -484,6 +488,9 @@
484 488 unsigned int nhooks;
485 489 struct module *owner;
486 490 struct list_head tables;
  491 + unsigned int nops;
  492 + void (*hook_ops_init)(struct nf_hook_ops *,
  493 + unsigned int);
487 494 nf_hookfn *hooks[NF_MAX_HOOKS];
488 495 };
489 496  
net/bridge/netfilter/nf_tables_bridge.c
... ... @@ -32,6 +32,7 @@
32 32 .family = NFPROTO_BRIDGE,
33 33 .nhooks = NF_BR_NUMHOOKS,
34 34 .owner = THIS_MODULE,
  35 + .nops = 1,
35 36 .hooks = {
36 37 [NF_BR_LOCAL_IN] = nft_do_chain_bridge,
37 38 [NF_BR_FORWARD] = nft_do_chain_bridge,
net/ipv4/netfilter/nf_tables_arp.c
... ... @@ -32,6 +32,7 @@
32 32 .family = NFPROTO_ARP,
33 33 .nhooks = NF_ARP_NUMHOOKS,
34 34 .owner = THIS_MODULE,
  35 + .nops = 1,
35 36 .hooks = {
36 37 [NF_ARP_IN] = nft_do_chain_arp,
37 38 [NF_ARP_OUT] = nft_do_chain_arp,
net/ipv4/netfilter/nf_tables_ipv4.c
... ... @@ -52,6 +52,7 @@
52 52 .family = NFPROTO_IPV4,
53 53 .nhooks = NF_INET_NUMHOOKS,
54 54 .owner = THIS_MODULE,
  55 + .nops = 1,
55 56 .hooks = {
56 57 [NF_INET_LOCAL_IN] = nft_do_chain_ipv4,
57 58 [NF_INET_LOCAL_OUT] = nft_ipv4_output,
net/ipv6/netfilter/nf_tables_ipv6.c
... ... @@ -51,6 +51,7 @@
51 51 .family = NFPROTO_IPV6,
52 52 .nhooks = NF_INET_NUMHOOKS,
53 53 .owner = THIS_MODULE,
  54 + .nops = 1,
54 55 .hooks = {
55 56 [NF_INET_LOCAL_IN] = nft_do_chain_ipv6,
56 57 [NF_INET_LOCAL_OUT] = nft_ipv6_output,
net/netfilter/nf_tables_api.c
... ... @@ -307,7 +307,8 @@
307 307 return err;
308 308 }
309 309  
310   -static int nf_tables_table_enable(struct nft_table *table)
  310 +static int nf_tables_table_enable(const struct nft_af_info *afi,
  311 + struct nft_table *table)
311 312 {
312 313 struct nft_chain *chain;
313 314 int err, i = 0;
... ... @@ -316,7 +317,7 @@
316 317 if (!(chain->flags & NFT_BASE_CHAIN))
317 318 continue;
318 319  
319   - err = nf_register_hook(&nft_base_chain(chain)->ops);
  320 + err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops);
320 321 if (err < 0)
321 322 goto err;
322 323  
323 324  
324 325  
... ... @@ -331,18 +332,20 @@
331 332 if (i-- <= 0)
332 333 break;
333 334  
334   - nf_unregister_hook(&nft_base_chain(chain)->ops);
  335 + nf_unregister_hooks(nft_base_chain(chain)->ops, afi->nops);
335 336 }
336 337 return err;
337 338 }
338 339  
339   -static int nf_tables_table_disable(struct nft_table *table)
  340 +static int nf_tables_table_disable(const struct nft_af_info *afi,
  341 + struct nft_table *table)
340 342 {
341 343 struct nft_chain *chain;
342 344  
343 345 list_for_each_entry(chain, &table->chains, list) {
344 346 if (chain->flags & NFT_BASE_CHAIN)
345   - nf_unregister_hook(&nft_base_chain(chain)->ops);
  347 + nf_unregister_hooks(nft_base_chain(chain)->ops,
  348 + afi->nops);
346 349 }
347 350  
348 351 return 0;
349 352  
... ... @@ -365,12 +368,12 @@
365 368  
366 369 if ((flags & NFT_TABLE_F_DORMANT) &&
367 370 !(table->flags & NFT_TABLE_F_DORMANT)) {
368   - ret = nf_tables_table_disable(table);
  371 + ret = nf_tables_table_disable(afi, table);
369 372 if (ret >= 0)
370 373 table->flags |= NFT_TABLE_F_DORMANT;
371 374 } else if (!(flags & NFT_TABLE_F_DORMANT) &&
372 375 table->flags & NFT_TABLE_F_DORMANT) {
373   - ret = nf_tables_table_enable(table);
  376 + ret = nf_tables_table_enable(afi, table);
374 377 if (ret >= 0)
375 378 table->flags &= ~NFT_TABLE_F_DORMANT;
376 379 }
... ... @@ -598,7 +601,7 @@
598 601  
599 602 if (chain->flags & NFT_BASE_CHAIN) {
600 603 const struct nft_base_chain *basechain = nft_base_chain(chain);
601   - const struct nf_hook_ops *ops = &basechain->ops;
  604 + const struct nf_hook_ops *ops = &basechain->ops[0];
602 605 struct nlattr *nest;
603 606  
604 607 nest = nla_nest_start(skb, NFTA_CHAIN_HOOK);
... ... @@ -832,6 +835,7 @@
832 835 struct net *net = sock_net(skb->sk);
833 836 int family = nfmsg->nfgen_family;
834 837 u64 handle = 0;
  838 + unsigned int i;
835 839 int err;
836 840 bool create;
837 841  
... ... @@ -904,7 +908,7 @@
904 908 if (nla[NFTA_CHAIN_HOOK]) {
905 909 struct nf_hook_ops *ops;
906 910 nf_hookfn *hookfn;
907   - u32 hooknum;
  911 + u32 hooknum, priority;
908 912 int type = NFT_CHAIN_T_DEFAULT;
909 913  
910 914 if (nla[NFTA_CHAIN_TYPE]) {
... ... @@ -926,6 +930,7 @@
926 930 hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM]));
927 931 if (hooknum >= afi->nhooks)
928 932 return -EINVAL;
  933 + priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY]));
929 934  
930 935 if (!(chain_type[family][type]->hook_mask & (1 << hooknum)))
931 936 return -EOPNOTSUPP;
... ... @@ -938,15 +943,19 @@
938 943 basechain->type = type;
939 944 chain = &basechain->chain;
940 945  
941   - ops = &basechain->ops;
942   - ops->pf = family;
943   - ops->owner = afi->owner;
944   - ops->hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM]));
945   - ops->priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY]));
946   - ops->priv = chain;
947   - ops->hook = afi->hooks[ops->hooknum];
948   - if (hookfn)
949   - ops->hook = hookfn;
  946 + for (i = 0; i < afi->nops; i++) {
  947 + ops = &basechain->ops[i];
  948 + ops->pf = family;
  949 + ops->owner = afi->owner;
  950 + ops->hooknum = hooknum;
  951 + ops->priority = priority;
  952 + ops->priv = chain;
  953 + ops->hook = afi->hooks[ops->hooknum];
  954 + if (hookfn)
  955 + ops->hook = hookfn;
  956 + if (afi->hook_ops_init)
  957 + afi->hook_ops_init(ops, i);
  958 + }
950 959  
951 960 chain->flags |= NFT_BASE_CHAIN;
952 961  
... ... @@ -993,7 +1002,7 @@
993 1002  
994 1003 if (!(table->flags & NFT_TABLE_F_DORMANT) &&
995 1004 chain->flags & NFT_BASE_CHAIN) {
996   - err = nf_register_hook(&nft_base_chain(chain)->ops);
  1005 + err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops);
997 1006 if (err < 0) {
998 1007 free_percpu(basechain->stats);
999 1008 kfree(basechain);
... ... @@ -1052,7 +1061,7 @@
1052 1061  
1053 1062 if (!(table->flags & NFT_TABLE_F_DORMANT) &&
1054 1063 chain->flags & NFT_BASE_CHAIN)
1055   - nf_unregister_hook(&nft_base_chain(chain)->ops);
  1064 + nf_unregister_hooks(nft_base_chain(chain)->ops, afi->nops);
1056 1065  
1057 1066 nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_DELCHAIN,
1058 1067 family);
net/netfilter/nft_compat.c
... ... @@ -92,7 +92,7 @@
92 92 if (ctx->chain->flags & NFT_BASE_CHAIN) {
93 93 const struct nft_base_chain *basechain =
94 94 nft_base_chain(ctx->chain);
95   - const struct nf_hook_ops *ops = &basechain->ops;
  95 + const struct nf_hook_ops *ops = &basechain->ops[0];
96 96  
97 97 par->hook_mask = 1 << ops->hooknum;
98 98 }
... ... @@ -253,7 +253,7 @@
253 253 if (ctx->chain->flags & NFT_BASE_CHAIN) {
254 254 const struct nft_base_chain *basechain =
255 255 nft_base_chain(ctx->chain);
256   - const struct nf_hook_ops *ops = &basechain->ops;
  256 + const struct nf_hook_ops *ops = &basechain->ops[0];
257 257  
258 258 hook_mask = 1 << ops->hooknum;
259 259 if (hook_mask & target->hooks)
... ... @@ -323,7 +323,7 @@
323 323 if (ctx->chain->flags & NFT_BASE_CHAIN) {
324 324 const struct nft_base_chain *basechain =
325 325 nft_base_chain(ctx->chain);
326   - const struct nf_hook_ops *ops = &basechain->ops;
  326 + const struct nf_hook_ops *ops = &basechain->ops[0];
327 327  
328 328 par->hook_mask = 1 << ops->hooknum;
329 329 }
... ... @@ -449,7 +449,7 @@
449 449 if (ctx->chain->flags & NFT_BASE_CHAIN) {
450 450 const struct nft_base_chain *basechain =
451 451 nft_base_chain(ctx->chain);
452   - const struct nf_hook_ops *ops = &basechain->ops;
  452 + const struct nf_hook_ops *ops = &basechain->ops[0];
453 453  
454 454 hook_mask = 1 << ops->hooknum;
455 455 if (hook_mask & match->hooks)