]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
xtables-restore: support atomic commit
authorPablo Neira Ayuso <pablo@netfilter.org>
Sun, 20 Jan 2013 19:19:20 +0000 (20:19 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 30 Dec 2013 22:50:23 +0000 (23:50 +0100)
Use new services in nf_tables to support atomic commit.

Commit per table, although we support global commit at once,
call commit for each table to emulate iptables-restore
behaviour by now.

Keep table dormant/wake up code in iptables/nft.c as it can
be used in the future.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/linux/netfilter/nf_tables.h
iptables/nft.c
iptables/nft.h
iptables/xtables-restore.c
iptables/xtables-standalone.c

index bdab3f2e998e312f3b67c8bed63bc9f24251124f..5385bf32f4de0a4c8eb5a3bc3d2e7e557ab844bf 100644 (file)
@@ -35,6 +35,8 @@ enum nf_tables_msg_types {
        NFT_MSG_NEWSETELEM,
        NFT_MSG_GETSETELEM,
        NFT_MSG_DELSETELEM,
+       NFT_MSG_COMMIT,
+       NFT_MSG_ABORT,
        NFT_MSG_MAX,
 };
 
@@ -83,12 +85,18 @@ enum nft_chain_attributes {
 };
 #define NFTA_CHAIN_MAX         (__NFTA_CHAIN_MAX - 1)
 
+enum {
+       NFT_RULE_F_COMMIT       = (1 << 0),
+       NFT_RULE_F_MASK         = NFT_RULE_F_COMMIT,
+};
+
 enum nft_rule_attributes {
        NFTA_RULE_UNSPEC,
        NFTA_RULE_TABLE,
        NFTA_RULE_CHAIN,
        NFTA_RULE_HANDLE,
        NFTA_RULE_EXPRESSIONS,
+       NFTA_RULE_FLAGS,
        __NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX          (__NFTA_RULE_MAX - 1)
index fd19ff5502b040d253ce9b81fca55c4a5a5ce147..f42e43774e29d46e440b881d1f2c45fceeda9d44 100644 (file)
@@ -946,6 +946,10 @@ nft_rule_add(struct nft_handle *h, const char *chain, const char *table,
                flags |= NLM_F_REPLACE;
        }
 
+       if (h->commit) {
+               nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FLAGS,
+                                     NFT_RULE_F_COMMIT);
+       }
        nlh = nft_rule_nlmsg_build_hdr(buf, NFT_MSG_NEWRULE,
                                       h->family, flags, h->seq);
 
@@ -1626,6 +1630,11 @@ __nft_rule_flush(struct nft_handle *h, const char *table, const char *chain)
        nft_rule_attr_set(r, NFT_RULE_ATTR_TABLE, (char *)table);
        nft_rule_attr_set(r, NFT_RULE_ATTR_CHAIN, (char *)chain);
 
+       if (h->commit) {
+               nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FLAGS,
+                                        NFT_RULE_F_COMMIT);
+       }
+
        /* Delete all rules in this table + chain */
        nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_DELRULE, h->family,
                                        NLM_F_ACK, h->seq);
@@ -2773,6 +2782,10 @@ int nft_rule_delete(struct nft_handle *h, const char *chain,
        if (r != NULL) {
                ret = 1;
 
+               if (h->commit) {
+                       nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FLAGS,
+                                                NFT_RULE_F_COMMIT);
+               }
                DEBUGP("deleting rule\n");
                __nft_rule_del(h, r);
        } else
@@ -2802,6 +2815,10 @@ int nft_rule_delete_num(struct nft_handle *h, const char *chain,
        if (r != NULL) {
                ret = 1;
 
+               if (h->commit) {
+                       nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FLAGS,
+                                                NFT_RULE_F_COMMIT);
+               }
                DEBUGP("deleting rule by number %d\n", rulenum);
                __nft_rule_del(h, r);
        } else
@@ -2834,6 +2851,10 @@ int nft_rule_replace(struct nft_handle *h, const char *chain,
                        (unsigned long long)
                        nft_rule_attr_get_u64(r, NFT_RULE_ATTR_HANDLE));
 
+               if (h->commit) {
+                       nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FLAGS,
+                                                NFT_RULE_F_COMMIT);
+               }
                ret = nft_rule_add(h, chain, table, cs, true,
                                   nft_rule_attr_get_u64(r, NFT_RULE_ATTR_HANDLE),
                                   verbose);
@@ -3435,6 +3456,41 @@ next:
        return 1;
 }
 
+static int nft_action(struct nft_handle *h, int type)
+{
+       char buf[MNL_SOCKET_BUFFER_SIZE];
+       struct nlmsghdr *nlh;
+       uint32_t seq;
+       int ret;
+
+       nlh = mnl_nlmsg_put_header(buf);
+       nlh->nlmsg_type = (NFNL_SUBSYS_NFTABLES<< 8) | type;
+       nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+       nlh->nlmsg_seq = seq = time(NULL);
+
+       struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+       nfg->nfgen_family = AF_INET;
+       nfg->version = NFNETLINK_V0;
+       nfg->res_id = 0;
+
+       ret = mnl_talk(h, nlh, NULL, NULL);
+       if (ret < 0) {
+               if (errno != EEXIST)
+                       perror("mnl-talk:nft_commit");
+       }
+       return ret;
+}
+
+int nft_commit(struct nft_handle *h)
+{
+       return nft_action(h, NFT_MSG_COMMIT);
+}
+
+int nft_abort(struct nft_handle *h)
+{
+       return nft_action(h, NFT_MSG_ABORT);
+}
+
 int nft_compatible_revision(const char *name, uint8_t rev, int opt)
 {
        struct mnl_socket *nl;
index f7ed0a388da2276685dd7660f8de1bb7782d1190..834fff0d93d4158ac83a76d23f8aa2c59bde6d11 100644 (file)
@@ -8,6 +8,7 @@ struct nft_handle {
        struct mnl_socket       *nl;
        uint32_t                portid;
        uint32_t                seq;
+       bool                    commit;
 };
 
 int nft_init(struct nft_handle *h);
@@ -55,6 +56,12 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain, const char *tabl
 int nft_rule_save(struct nft_handle *h, const char *table, bool counters);
 int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table);
 
+/*
+ * global commit and abort
+ */
+int nft_commit(struct nft_handle *h);
+int nft_abort(struct nft_handle *h);
+
 /*
  * revision compatibility.
  */
index 9778a9f7b656ee0aa66094352eb0278428c73f2f..ca9e0c05c50b72462439b0ec63022140e83bf415 100644 (file)
@@ -164,6 +164,7 @@ xtables_restore_main(int argc, char *argv[])
 {
        struct nft_handle h = {
                .family = AF_INET,      /* default to IPv4 */
+               .commit = true,
        };
        char buffer[10240];
        int c;
@@ -253,10 +254,14 @@ xtables_restore_main(int argc, char *argv[])
                        continue;
                } else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) {
                        if (!testing) {
-                               if (nft_table_wake_dormant(&h, curtable) < 0) {
-                                       fprintf(stderr, "Failed to wake up "
-                                               "dormant table `%s'\n",
-                                               curtable);
+                               /* Commit per table, although we support
+                                * global commit at once, stick by now to
+                                * the existing behaviour.
+                                */
+                               if (nft_commit(&h)) {
+                                       fprintf(stderr, "Failed to commit "
+                                                       "table %s\n",
+                                                       curtable);
                                }
                                DEBUGP("Calling commit\n");
                                ret = 1;
@@ -288,7 +293,6 @@ xtables_restore_main(int argc, char *argv[])
                        if (tablename && (strcmp(tablename, table) != 0))
                                continue;
 
-                       nft_table_set_dormant(&h, table);
                        if (noflush == 0) {
                                DEBUGP("Cleaning all chains of table '%s'\n",
                                        table);
@@ -426,6 +430,14 @@ xtables_restore_main(int argc, char *argv[])
                                DEBUGP("argv[%u]: %s\n", a, newargv[a]);
 
                        ret = do_commandx(&h, newargc, newargv, &newargv[2]);
+                       if (ret < 0) {
+                               ret = nft_abort(&h);
+                               if (ret < 0) {
+                                       fprintf(stderr, "failed to abort "
+                                                       "commit operation\n");
+                               }
+                               exit(1);
+                       }
 
                        free_argv();
                        fflush(stdout);
index f746c9027c071714a81bd7dd459b57c34668a670..284161174cca2a7ea786c9d3558e4f788505573d 100644 (file)
@@ -46,6 +46,8 @@ xtables_main(int argc, char *argv[])
        char *table = "filter";
        struct nft_handle h;
 
+       memset(&h, 0, sizeof(h));
+
        iptables_globals.program_name = "xtables";
        ret = xtables_init_all(&xtables_globals, NFPROTO_IPV4);
        if (ret < 0) {