netfilter: nf_tables: extend NFT_MSG_DELTABLE to support flushing the ruleset
authorArturo Borrero <arturo.borrero.glez@gmail.com>
Tue, 2 Sep 2014 14:42:26 +0000 (16:42 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 9 Sep 2014 14:31:26 +0000 (16:31 +0200)
This patch extend the NFT_MSG_DELTABLE call to support flushing the entire
ruleset.

The options now are:
 * No family speficied, no table specified: flush all the ruleset.
 * Family specified, no table specified: flush all tables in the AF.
 * Family specified, table specified: flush the given table.

Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/nf_tables_api.c

index 3ce5cfa34935d283729bf0ca3ce96d620723b3b1..82374601577e538750ae822c793ae51af628a0da 100644 (file)
@@ -707,6 +707,67 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
        return 0;
 }
 
+static int nft_flush_table(struct nft_ctx *ctx)
+{
+       int err;
+       struct nft_chain *chain, *nc;
+       struct nft_set *set, *ns;
+
+       list_for_each_entry_safe(chain, nc, &ctx->table->chains, list) {
+               ctx->chain = chain;
+
+               err = nft_delrule_by_chain(ctx);
+               if (err < 0)
+                       goto out;
+
+               err = nft_delchain(ctx);
+               if (err < 0)
+                       goto out;
+       }
+
+       list_for_each_entry_safe(set, ns, &ctx->table->sets, list) {
+               if (set->flags & NFT_SET_ANONYMOUS &&
+                   !list_empty(&set->bindings))
+                       continue;
+
+               err = nft_delset(ctx, set);
+               if (err < 0)
+                       goto out;
+       }
+
+       err = nft_deltable(ctx);
+out:
+       return err;
+}
+
+static int nft_flush(struct nft_ctx *ctx, int family)
+{
+       struct nft_af_info *afi;
+       struct nft_table *table, *nt;
+       const struct nlattr * const *nla = ctx->nla;
+       int err = 0;
+
+       list_for_each_entry(afi, &ctx->net->nft.af_info, list) {
+               if (family != AF_UNSPEC && afi->family != family)
+                       continue;
+
+               ctx->afi = afi;
+               list_for_each_entry_safe(table, nt, &afi->tables, list) {
+                       if (nla[NFTA_TABLE_NAME] &&
+                           nla_strcmp(nla[NFTA_TABLE_NAME], table->name) != 0)
+                               continue;
+
+                       ctx->table = table;
+
+                       err = nft_flush_table(ctx);
+                       if (err < 0)
+                               goto out;
+               }
+       }
+out:
+       return err;
+}
+
 static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb,
                              const struct nlmsghdr *nlh,
                              const struct nlattr * const nla[])
@@ -718,6 +779,10 @@ static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb,
        int family = nfmsg->nfgen_family;
        struct nft_ctx ctx;
 
+       nft_ctx_init(&ctx, skb, nlh, NULL, NULL, NULL, nla);
+       if (family == AF_UNSPEC || nla[NFTA_TABLE_NAME] == NULL)
+               return nft_flush(&ctx, family);
+
        afi = nf_tables_afinfo_lookup(net, family, false);
        if (IS_ERR(afi))
                return PTR_ERR(afi);
@@ -727,12 +792,11 @@ static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb,
                return PTR_ERR(table);
        if (table->flags & NFT_TABLE_INACTIVE)
                return -ENOENT;
-       if (table->use > 0)
-               return -EBUSY;
 
-       nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
+       ctx.afi = afi;
+       ctx.table = table;
 
-       return nft_deltable(&ctx);
+       return nft_flush_table(&ctx);
 }
 
 static void nf_tables_table_destroy(struct nft_ctx *ctx)