netfilter: nf_tables: add support for multi family tables
authorPatrick McHardy <kaber@trash.net>
Fri, 3 Jan 2014 12:16:15 +0000 (12:16 +0000)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 7 Jan 2014 22:55:46 +0000 (23:55 +0100)
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>
include/net/netfilter/nf_tables.h
net/bridge/netfilter/nf_tables_bridge.c
net/ipv4/netfilter/nf_tables_arp.c
net/ipv4/netfilter/nf_tables_ipv4.c
net/ipv6/netfilter/nf_tables_ipv6.c
net/netfilter/nf_tables_api.c
net/netfilter/nft_compat.c

index c9e63167f9a211a951b0d22ac9f5f7c25f53adba..f066f252e5e5f462013d253c0051de40184883c7 100644 (file)
@@ -422,6 +422,8 @@ struct nft_stats {
        u64 pkts;
 };
 
+#define NFT_HOOK_OPS_MAX               2
+
 /**
  *     struct nft_base_chain - nf_tables base chain
  *
@@ -432,7 +434,7 @@ struct nft_stats {
  *     @chain: the chain
  */
 struct nft_base_chain {
-       struct nf_hook_ops              ops;
+       struct nf_hook_ops              ops[NFT_HOOK_OPS_MAX];
        enum nft_chain_type             type;
        u8                              policy;
        struct nft_stats __percpu       *stats;
@@ -476,6 +478,8 @@ struct nft_table {
  *     @nhooks: number of hooks in this family
  *     @owner: module owner
  *     @tables: used internally
+ *     @nops: number of hook ops in this family
+ *     @hook_ops_init: initialization function for chain hook ops
  *     @hooks: hookfn overrides for packet validation
  */
 struct nft_af_info {
@@ -484,6 +488,9 @@ struct nft_af_info {
        unsigned int                    nhooks;
        struct module                   *owner;
        struct list_head                tables;
+       unsigned int                    nops;
+       void                            (*hook_ops_init)(struct nf_hook_ops *,
+                                                        unsigned int);
        nf_hookfn                       *hooks[NF_MAX_HOOKS];
 };
 
index c5fdd9a693bedd8aab09f46b919810a8a6689cf6..003c1e9a8b0c29629740c6b6d0724d1850e202ed 100644 (file)
@@ -32,6 +32,7 @@ static struct nft_af_info nft_af_bridge __read_mostly = {
        .family         = NFPROTO_BRIDGE,
        .nhooks         = NF_BR_NUMHOOKS,
        .owner          = THIS_MODULE,
+       .nops           = 1,
        .hooks          = {
                [NF_BR_LOCAL_IN]        = nft_do_chain_bridge,
                [NF_BR_FORWARD]         = nft_do_chain_bridge,
index 31bb778cebb8944a93d4393f3b1a9289d2e480ea..36d27fc7e859eaeedd4f521f11cbfac43b6e42ec 100644 (file)
@@ -32,6 +32,7 @@ static struct nft_af_info nft_af_arp __read_mostly = {
        .family         = NFPROTO_ARP,
        .nhooks         = NF_ARP_NUMHOOKS,
        .owner          = THIS_MODULE,
+       .nops           = 1,
        .hooks          = {
                [NF_ARP_IN]             = nft_do_chain_arp,
                [NF_ARP_OUT]            = nft_do_chain_arp,
index ed7e15a934108af6f5c4b05a7c178ff68bd504bb..177c3bceb7ca68b3e3092a47b9fab6b04fa68b1a 100644 (file)
@@ -52,6 +52,7 @@ static struct nft_af_info nft_af_ipv4 __read_mostly = {
        .family         = NFPROTO_IPV4,
        .nhooks         = NF_INET_NUMHOOKS,
        .owner          = THIS_MODULE,
+       .nops           = 1,
        .hooks          = {
                [NF_INET_LOCAL_IN]      = nft_do_chain_ipv4,
                [NF_INET_LOCAL_OUT]     = nft_ipv4_output,
index 54a2bcdc8a17b937444a9f2637a20d3b8d141ba9..642280e44b652cbf0915626989f592a5b413b2b3 100644 (file)
@@ -51,6 +51,7 @@ static struct nft_af_info nft_af_ipv6 __read_mostly = {
        .family         = NFPROTO_IPV6,
        .nhooks         = NF_INET_NUMHOOKS,
        .owner          = THIS_MODULE,
+       .nops           = 1,
        .hooks          = {
                [NF_INET_LOCAL_IN]      = nft_do_chain_ipv6,
                [NF_INET_LOCAL_OUT]     = nft_ipv6_output,
index d568626bc0f9b124bcc3bec7728d264cd47b615f..572d88dd3e5fe027bf9beb4cc61438d9e10d737e 100644 (file)
@@ -307,7 +307,8 @@ err:
        return err;
 }
 
-static int nf_tables_table_enable(struct nft_table *table)
+static int nf_tables_table_enable(const struct nft_af_info *afi,
+                                 struct nft_table *table)
 {
        struct nft_chain *chain;
        int err, i = 0;
@@ -316,7 +317,7 @@ static int nf_tables_table_enable(struct nft_table *table)
                if (!(chain->flags & NFT_BASE_CHAIN))
                        continue;
 
-               err = nf_register_hook(&nft_base_chain(chain)->ops);
+               err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops);
                if (err < 0)
                        goto err;
 
@@ -331,18 +332,20 @@ err:
                if (i-- <= 0)
                        break;
 
-               nf_unregister_hook(&nft_base_chain(chain)->ops);
+               nf_unregister_hooks(nft_base_chain(chain)->ops, afi->nops);
        }
        return err;
 }
 
-static int nf_tables_table_disable(struct nft_table *table)
+static int nf_tables_table_disable(const struct nft_af_info *afi,
+                                  struct nft_table *table)
 {
        struct nft_chain *chain;
 
        list_for_each_entry(chain, &table->chains, list) {
                if (chain->flags & NFT_BASE_CHAIN)
-                       nf_unregister_hook(&nft_base_chain(chain)->ops);
+                       nf_unregister_hooks(nft_base_chain(chain)->ops,
+                                           afi->nops);
        }
 
        return 0;
@@ -365,12 +368,12 @@ static int nf_tables_updtable(struct sock *nlsk, struct sk_buff *skb,
 
                if ((flags & NFT_TABLE_F_DORMANT) &&
                    !(table->flags & NFT_TABLE_F_DORMANT)) {
-                       ret = nf_tables_table_disable(table);
+                       ret = nf_tables_table_disable(afi, table);
                        if (ret >= 0)
                                table->flags |= NFT_TABLE_F_DORMANT;
                } else if (!(flags & NFT_TABLE_F_DORMANT) &&
                           table->flags & NFT_TABLE_F_DORMANT) {
-                       ret = nf_tables_table_enable(table);
+                       ret = nf_tables_table_enable(afi, table);
                        if (ret >= 0)
                                table->flags &= ~NFT_TABLE_F_DORMANT;
                }
@@ -598,7 +601,7 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq,
 
        if (chain->flags & NFT_BASE_CHAIN) {
                const struct nft_base_chain *basechain = nft_base_chain(chain);
-               const struct nf_hook_ops *ops = &basechain->ops;
+               const struct nf_hook_ops *ops = &basechain->ops[0];
                struct nlattr *nest;
 
                nest = nla_nest_start(skb, NFTA_CHAIN_HOOK);
@@ -832,6 +835,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
        struct net *net = sock_net(skb->sk);
        int family = nfmsg->nfgen_family;
        u64 handle = 0;
+       unsigned int i;
        int err;
        bool create;
 
@@ -904,7 +908,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
        if (nla[NFTA_CHAIN_HOOK]) {
                struct nf_hook_ops *ops;
                nf_hookfn *hookfn;
-               u32 hooknum;
+               u32 hooknum, priority;
                int type = NFT_CHAIN_T_DEFAULT;
 
                if (nla[NFTA_CHAIN_TYPE]) {
@@ -926,6 +930,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
                hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM]));
                if (hooknum >= afi->nhooks)
                        return -EINVAL;
+               priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY]));
 
                if (!(chain_type[family][type]->hook_mask & (1 << hooknum)))
                        return -EOPNOTSUPP;
@@ -938,15 +943,19 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
                basechain->type = type;
                chain = &basechain->chain;
 
-               ops = &basechain->ops;
-               ops->pf         = family;
-               ops->owner      = afi->owner;
-               ops->hooknum    = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM]));
-               ops->priority   = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY]));
-               ops->priv       = chain;
-               ops->hook       = afi->hooks[ops->hooknum];
-               if (hookfn)
-                       ops->hook = hookfn;
+               for (i = 0; i < afi->nops; i++) {
+                       ops = &basechain->ops[i];
+                       ops->pf         = family;
+                       ops->owner      = afi->owner;
+                       ops->hooknum    = hooknum;
+                       ops->priority   = priority;
+                       ops->priv       = chain;
+                       ops->hook       = afi->hooks[ops->hooknum];
+                       if (hookfn)
+                               ops->hook = hookfn;
+                       if (afi->hook_ops_init)
+                               afi->hook_ops_init(ops, i);
+               }
 
                chain->flags |= NFT_BASE_CHAIN;
 
@@ -993,7 +1002,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
 
        if (!(table->flags & NFT_TABLE_F_DORMANT) &&
            chain->flags & NFT_BASE_CHAIN) {
-               err = nf_register_hook(&nft_base_chain(chain)->ops);
+               err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops);
                if (err < 0) {
                        free_percpu(basechain->stats);
                        kfree(basechain);
@@ -1052,7 +1061,7 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
 
        if (!(table->flags & NFT_TABLE_F_DORMANT) &&
            chain->flags & NFT_BASE_CHAIN)
-               nf_unregister_hook(&nft_base_chain(chain)->ops);
+               nf_unregister_hooks(nft_base_chain(chain)->ops, afi->nops);
 
        nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_DELCHAIN,
                               family);
index da0c1f4ada128d79c41d0425d4072641b7b34fe3..82cb8236f8a101d260a9f3cc6eb1c218e34163f3 100644 (file)
@@ -92,7 +92,7 @@ nft_target_set_tgchk_param(struct xt_tgchk_param *par,
        if (ctx->chain->flags & NFT_BASE_CHAIN) {
                const struct nft_base_chain *basechain =
                                                nft_base_chain(ctx->chain);
-               const struct nf_hook_ops *ops = &basechain->ops;
+               const struct nf_hook_ops *ops = &basechain->ops[0];
 
                par->hook_mask = 1 << ops->hooknum;
        }
@@ -253,7 +253,7 @@ static int nft_target_validate(const struct nft_ctx *ctx,
        if (ctx->chain->flags & NFT_BASE_CHAIN) {
                const struct nft_base_chain *basechain =
                                                nft_base_chain(ctx->chain);
-               const struct nf_hook_ops *ops = &basechain->ops;
+               const struct nf_hook_ops *ops = &basechain->ops[0];
 
                hook_mask = 1 << ops->hooknum;
                if (hook_mask & target->hooks)
@@ -323,7 +323,7 @@ nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx,
        if (ctx->chain->flags & NFT_BASE_CHAIN) {
                const struct nft_base_chain *basechain =
                                                nft_base_chain(ctx->chain);
-               const struct nf_hook_ops *ops = &basechain->ops;
+               const struct nf_hook_ops *ops = &basechain->ops[0];
 
                par->hook_mask = 1 << ops->hooknum;
        }
@@ -449,7 +449,7 @@ static int nft_match_validate(const struct nft_ctx *ctx,
        if (ctx->chain->flags & NFT_BASE_CHAIN) {
                const struct nft_base_chain *basechain =
                                                nft_base_chain(ctx->chain);
-               const struct nf_hook_ops *ops = &basechain->ops;
+               const struct nf_hook_ops *ops = &basechain->ops[0];
 
                hook_mask = 1 << ops->hooknum;
                if (hook_mask & match->hooks)