From patchwork Thu Dec 13 11:15:54 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Sutter X-Patchwork-Id: 1012794 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=nwl.cc Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43FrkC4yGSz9s4s for ; Thu, 13 Dec 2018 22:17:23 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728732AbeLMLRX (ORCPT ); Thu, 13 Dec 2018 06:17:23 -0500 Received: from orbyte.nwl.cc ([151.80.46.58]:58118 "EHLO orbyte.nwl.cc" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728517AbeLMLRX (ORCPT ); Thu, 13 Dec 2018 06:17:23 -0500 Received: from localhost ([::1]:42976 helo=tatos) by orbyte.nwl.cc with esmtp (Exim 4.91) (envelope-from ) id 1gXOzZ-00079c-OW; Thu, 13 Dec 2018 12:17:21 +0100 From: Phil Sutter To: Pablo Neira Ayuso Cc: netfilter-devel@vger.kernel.org Subject: [iptables PATCH v2 01/14] xtables: Review unclear return points Date: Thu, 13 Dec 2018 12:15:54 +0100 Message-Id: <20181213111607.5457-2-phil@nwl.cc> X-Mailer: git-send-email 2.19.0 In-Reply-To: <20181213111607.5457-1-phil@nwl.cc> References: <20181213111607.5457-1-phil@nwl.cc> MIME-Version: 1.0 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org When converting to per table chain caches, these two error returns were marked for review but apparently forgotten. Make sure error condition is propagated when returning at those points. Fixes: c58ecf9f8bcb7 ("xtables: Introduce per table chain caches") Signed-off-by: Phil Sutter --- iptables/nft.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index 7b6fb2b10686d..e7a56778f8004 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -2311,7 +2311,7 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, list = nft_chain_list_get(h, table); if (!list) - goto err; /* XXX: return 0 instead? */ + return 0; iter = nftnl_chain_list_iter_create(list); if (iter == NULL) @@ -2454,7 +2454,7 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain, list = nft_chain_list_get(h, table); if (!list) - goto err; /* XXX: correct? */ + goto err; /* Dump policies and custom chains first */ if (!rulenum) From patchwork Thu Dec 13 11:15:55 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Sutter X-Patchwork-Id: 1012786 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=nwl.cc Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43FrjN51qdz9s4s for ; Thu, 13 Dec 2018 22:16:40 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728728AbeLMLQk (ORCPT ); Thu, 13 Dec 2018 06:16:40 -0500 Received: from orbyte.nwl.cc ([151.80.46.58]:58070 "EHLO orbyte.nwl.cc" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728067AbeLMLQk (ORCPT ); Thu, 13 Dec 2018 06:16:40 -0500 Received: from localhost ([::1]:42928 helo=tatos) by orbyte.nwl.cc with esmtp (Exim 4.91) (envelope-from ) id 1gXOyt-000777-2C; Thu, 13 Dec 2018 12:16:39 +0100 From: Phil Sutter To: Pablo Neira Ayuso Cc: netfilter-devel@vger.kernel.org Subject: [iptables PATCH v2 02/14] xtables-restore: Review chain handling Date: Thu, 13 Dec 2018 12:15:55 +0100 Message-Id: <20181213111607.5457-3-phil@nwl.cc> X-Mailer: git-send-email 2.19.0 In-Reply-To: <20181213111607.5457-1-phil@nwl.cc> References: <20181213111607.5457-1-phil@nwl.cc> MIME-Version: 1.0 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org There is no need to "delete" (actually, remove from cache) a chain if noflush wasn't given: While handling the corresponding table line, 'table_flush' callback has already taken care of that. Streamlining the code further, move syntax checks to the top. If these concede, there are three cases to distinguish: A) Given chain name matches a builtin one in current table, so assume it exists already and just set policy and counters. B) Noflush was given and the (custom) chain exists already, flush it. C) Custom chain was either flushed (noflush not given) or didn't exist before, create it. Signed-off-by: Phil Sutter --- iptables/nft-shared.h | 2 -- iptables/xtables-restore.c | 68 +++++++++++--------------------------- 2 files changed, 19 insertions(+), 51 deletions(-) diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 388abb97303ab..019c1f20e2939 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -245,8 +245,6 @@ struct nft_xt_restore_cb { void (*table_new)(struct nft_handle *h, const char *table); struct nftnl_chain_list *(*chain_list)(struct nft_handle *h, const char *table); - void (*chain_del)(struct nftnl_chain_list *clist, const char *curtable, - const char *chain); int (*chain_user_flush)(struct nft_handle *h, struct nftnl_chain_list *clist, const char *table, const char *chain); diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index 642876d6c70ac..4e00ed86be06d 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -68,21 +68,6 @@ static struct nftnl_chain_list *get_chain_list(struct nft_handle *h, return chain_list; } -static void chain_delete(struct nftnl_chain_list *clist, const char *curtable, - const char *chain) -{ - struct nftnl_chain *chain_obj; - - chain_obj = nft_chain_list_find(clist, chain); - /* This chain has been found, delete from list. Later - * on, unvisited chains will be purged out. - */ - if (chain_obj != NULL) { - nftnl_chain_list_del(chain_obj); - nftnl_chain_free(chain_obj); - } -} - struct nft_xt_restore_cb restore_cb = { .chain_list = get_chain_list, .commit = nft_commit, @@ -90,7 +75,6 @@ struct nft_xt_restore_cb restore_cb = { .table_new = nft_table_new, .table_flush = nft_table_flush, .chain_user_flush = nft_chain_user_flush, - .chain_del = chain_delete, .do_command = do_commandx, .chain_set = nft_chain_set, .chain_user_add = nft_chain_user_add, @@ -183,7 +167,6 @@ void xtables_restore_parse(struct nft_handle *h, /* New chain. */ char *policy, *chain = NULL; struct xt_counters count = {}; - bool chain_exists = false; chain = strtok(buffer+1, " \t\n"); DEBUGP("line %u, chain '%s'\n", line, chain); @@ -194,21 +177,6 @@ void xtables_restore_parse(struct nft_handle *h, exit(1); } - if (noflush == 0) { - if (cb->chain_del) - cb->chain_del(chain_list, curtable->name, - chain); - } else if (nft_chain_list_find(chain_list, chain)) { - chain_exists = true; - /* Apparently -n still flushes existing user - * defined chains that are redefined. Otherwise, - * leave them as is. - */ - if (cb->chain_user_flush) - cb->chain_user_flush(h, chain_list, - curtable->name, chain); - } - if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN) xtables_error(PARAMETER_PROBLEM, "Invalid chain name `%s' " @@ -246,24 +214,28 @@ void xtables_restore_parse(struct nft_handle *h, } DEBUGP("Setting policy of chain %s to %s\n", chain, policy); - ret = 1; - } else { - if (!chain_exists && - cb->chain_user_add && - cb->chain_user_add(h, chain, - curtable->name) < 0) { - if (errno == EEXIST) - continue; + } else if (noflush && + nftnl_chain_list_lookup_byname(chain_list, chain)) { + /* Apparently -n still flushes existing user + * defined chains that are redefined. Otherwise, + * leave them as is. + */ + if (cb->chain_user_flush) + cb->chain_user_flush(h, chain_list, + curtable->name, chain); + } else if (cb->chain_user_add && + cb->chain_user_add(h, chain, + curtable->name) < 0) { + if (errno == EEXIST) + continue; - xtables_error(PARAMETER_PROBLEM, - "cannot create chain " - "'%s' (%s)\n", chain, - strerror(errno)); - } - continue; + xtables_error(PARAMETER_PROBLEM, + "cannot create chain " + "'%s' (%s)\n", chain, + strerror(errno)); } - + ret = 1; } else if (in_table) { int a; char *pcnt = NULL; @@ -496,7 +468,6 @@ struct nft_xt_restore_cb ebt_restore_cb = { .table_new = nft_table_new, .table_flush = nft_table_flush, .chain_user_flush = nft_chain_user_flush, - .chain_del = chain_delete, .do_command = do_commandeb, .chain_set = nft_chain_set, .chain_user_add = nft_chain_user_add, @@ -542,7 +513,6 @@ struct nft_xt_restore_cb arp_restore_cb = { .table_new = nft_table_new, .table_flush = nft_table_flush, .chain_user_flush = nft_chain_user_flush, - .chain_del = chain_delete, .do_command = do_commandarp, .chain_set = nft_chain_set, .chain_user_add = nft_chain_user_add, From patchwork Thu Dec 13 11:15:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Sutter X-Patchwork-Id: 1012796 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=nwl.cc Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43FrkQ46L6z9s4s for ; Thu, 13 Dec 2018 22:17:34 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728757AbeLMLRe (ORCPT ); Thu, 13 Dec 2018 06:17:34 -0500 Received: from orbyte.nwl.cc ([151.80.46.58]:58130 "EHLO orbyte.nwl.cc" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728716AbeLMLRe (ORCPT ); Thu, 13 Dec 2018 06:17:34 -0500 Received: from localhost ([::1]:42988 helo=tatos) by orbyte.nwl.cc with esmtp (Exim 4.91) (envelope-from ) id 1gXOzk-0007A1-ED; Thu, 13 Dec 2018 12:17:32 +0100 From: Phil Sutter To: Pablo Neira Ayuso Cc: netfilter-devel@vger.kernel.org Subject: [iptables PATCH v2 03/14] xtables: Implement per chain rule cache Date: Thu, 13 Dec 2018 12:15:56 +0100 Message-Id: <20181213111607.5457-4-phil@nwl.cc> X-Mailer: git-send-email 2.19.0 In-Reply-To: <20181213111607.5457-1-phil@nwl.cc> References: <20181213111607.5457-1-phil@nwl.cc> MIME-Version: 1.0 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Use recently introduced support for rules inside chains in libnftnl to introduce a rule cache per chain instead of a global one. A tricky bit is to decide if cache should be updated or not. Previously, the global rule cache was populated just once and then reused unless being flushed completely (via call to flush_rule_cache() with NULL-pointer table argument). Resemble this behaviour by introducing a boolean indicating cache status and fetch rules for all chains when updating the chain cache in nft_chain_list_get(). Signed-off-by: Phil Sutter --- Changes since v1: - Update rule cache only if required. --- iptables/nft.c | 599 +++++++++++++++++-------------------- iptables/nft.h | 5 +- iptables/xtables-restore.c | 5 +- iptables/xtables-save.c | 6 +- 4 files changed, 282 insertions(+), 333 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index e7a56778f8004..0869f2e222393 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -687,10 +687,11 @@ nft_chain_builtin_find(const struct builtin_table *t, const char *chain) static void nft_chain_builtin_init(struct nft_handle *h, const struct builtin_table *table) { - struct nftnl_chain_list *list = nft_chain_list_get(h, table->name); + struct nftnl_chain_list *list; struct nftnl_chain *c; int i; + list = nft_chain_list_get(h, table->name, false); if (!list) return; @@ -772,28 +773,15 @@ int nft_init(struct nft_handle *h, const struct builtin_table *t) static int __flush_rule_cache(struct nftnl_rule *r, void *data) { - const char *tablename = data; - - if (!strcmp(nftnl_rule_get_str(r, NFTNL_RULE_TABLE), tablename)) { - nftnl_rule_list_del(r); - nftnl_rule_free(r); - } + nftnl_rule_list_del(r); + nftnl_rule_free(r); return 0; } -static void flush_rule_cache(struct nft_handle *h, const char *tablename) +static void flush_rule_cache(struct nftnl_chain *c) { - if (!h->rule_cache) - return; - - if (tablename) { - nftnl_rule_list_foreach(h->rule_cache, __flush_rule_cache, - (void *)tablename); - } else { - nftnl_rule_list_free(h->rule_cache); - h->rule_cache = NULL; - } + nftnl_rule_foreach(c, __flush_rule_cache, NULL); } static int __flush_chain_cache(struct nftnl_chain *c, void *data) @@ -815,23 +803,27 @@ static void flush_chain_cache(struct nft_handle *h, const char *tablename) if (tablename && strcmp(h->tables[i].name, tablename)) continue; - if (h->table[i].chain_cache) { - if (tablename) { - nftnl_chain_list_foreach(h->table[i].chain_cache, - __flush_chain_cache, NULL); - break; - } else { - nftnl_chain_list_free(h->table[i].chain_cache); - h->table[i].chain_cache = NULL; - } + if (!h->table[i].chain_cache) { + if (tablename) + return; + continue; } + if (tablename) { + nftnl_chain_list_foreach(h->table[i].chain_cache, + __flush_chain_cache, NULL); + return; + } + + nftnl_chain_list_free(h->table[i].chain_cache); + h->table[i].chain_cache = NULL; } + h->have_cache = false; + h->have_rule_cache = false; } void nft_fini(struct nft_handle *h) { flush_chain_cache(h, NULL); - flush_rule_cache(h, NULL); mnl_socket_close(h->nl); } @@ -1191,12 +1183,15 @@ err: return NULL; } -static struct nftnl_rule_list *nft_rule_list_get(struct nft_handle *h); +static struct nftnl_chain * +nft_chain_find(struct nft_handle *h, const char *table, + const char *chain, bool need_rules); int nft_rule_append(struct nft_handle *h, const char *chain, const char *table, void *data, uint64_t handle, bool verbose) { + struct nftnl_chain *c; struct nftnl_rule *r; int type; @@ -1224,10 +1219,9 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table, if (verbose) h->ops->print_rule(r, 0, FMT_PRINT_RULE); - if (!nft_rule_list_get(h)) - return 0; - - nftnl_rule_list_add_tail(r, h->rule_cache); + c = nft_chain_find(h, table, chain, true); + if (c) + nftnl_chain_rule_add(r, c); return 1; } @@ -1282,12 +1276,6 @@ static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data) if (!t) goto out; - if (!h->table[t->type].chain_cache) { - h->table[t->type].chain_cache = nftnl_chain_list_alloc(); - if (!h->table[t->type].chain_cache) - goto out; - } - nftnl_chain_list_add_tail(c, h->table[t->type].chain_cache); return MNL_CB_OK; @@ -1297,33 +1285,60 @@ err: return MNL_CB_OK; } +static int nft_rule_list_update(struct nftnl_chain *c, void *data); + struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h, - const char *table) + const char *table, bool need_rules) { char buf[16536]; struct nlmsghdr *nlh; const struct builtin_table *t; int ret; + int i; t = nft_table_builtin_find(h, table); if (!t) return NULL; - if (h->table[t->type].chain_cache) + if (h->have_cache && (!need_rules || h->have_rule_cache)) return h->table[t->type].chain_cache; + + if (h->have_cache) + goto fetch_rules; + retry: + for (i = 0; i < NFT_TABLE_MAX; i++) { + enum nft_table_type type = h->tables[i].type; + + if (!h->tables[i].name) + continue; + + h->table[type].chain_cache = nftnl_chain_list_alloc(); + } nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family, NLM_F_DUMP, h->seq); ret = mnl_talk(h, nlh, nftnl_chain_list_cb, h); if (ret < 0 && errno == EINTR) { assert(nft_restart(h) >= 0); + flush_chain_cache(h, NULL); goto retry; } + h->have_cache = true; + if (!need_rules) + return h->table[t->type].chain_cache; - if (!h->table[t->type].chain_cache) - h->table[t->type].chain_cache = nftnl_chain_list_alloc(); +fetch_rules: + for (i = 0; i < NFT_TABLE_MAX; i++) { + enum nft_table_type type = h->tables[i].type; + + if (!h->tables[i].name) + continue; + nftnl_chain_list_foreach(h->table[type].chain_cache, + nft_rule_list_update, h); + } + h->have_rule_cache = true; return h->table[t->type].chain_cache; } @@ -1369,92 +1384,108 @@ int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list) static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data) { + struct nftnl_chain *c = data; struct nftnl_rule *r; - struct nftnl_rule_list *list = data; r = nftnl_rule_alloc(); if (r == NULL) - goto err; - - if (nftnl_rule_nlmsg_parse(nlh, r) < 0) - goto out; + return MNL_CB_OK; - nftnl_rule_list_add_tail(r, list); + if (nftnl_rule_nlmsg_parse(nlh, r) < 0) { + nftnl_rule_free(r); + return MNL_CB_OK; + } - return MNL_CB_OK; -out: - nftnl_rule_free(r); - nftnl_rule_list_free(list); -err: + nftnl_chain_rule_add(r, c); return MNL_CB_OK; } -static struct nftnl_rule_list *nft_rule_list_get(struct nft_handle *h) +static int nft_rule_list_update(struct nftnl_chain *c, void *data) { + struct nft_handle *h = data; char buf[16536]; struct nlmsghdr *nlh; - struct nftnl_rule_list *list; + struct nftnl_rule *rule; int ret; - if (h->rule_cache) - return h->rule_cache; + rule = nftnl_rule_alloc(); + if (!rule) + return false; -retry: - list = nftnl_rule_list_alloc(); - if (list == NULL) - return 0; + nftnl_rule_set(rule, NFTNL_RULE_TABLE, + nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE)); + nftnl_rule_set(rule, NFTNL_RULE_CHAIN, + nftnl_chain_get_str(c, NFTNL_CHAIN_NAME)); +retry: nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family, NLM_F_DUMP, h->seq); + nftnl_rule_nlmsg_build_payload(nlh, rule); - ret = mnl_talk(h, nlh, nftnl_rule_list_cb, list); + ret = mnl_talk(h, nlh, nftnl_rule_list_cb, c); if (ret < 0) { + flush_rule_cache(c); + if (errno == EINTR) { assert(nft_restart(h) >= 0); - nftnl_rule_list_free(list); goto retry; } - - nftnl_rule_list_free(list); - return NULL; + nftnl_rule_free(rule); + return false; } - h->rule_cache = list; - return list; + nftnl_rule_free(rule); + return true; } -int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format) +static int nft_chain_save_rules(struct nft_handle *h, + struct nftnl_chain *c, unsigned int format) { - struct nftnl_rule_list *list; - struct nftnl_rule_list_iter *iter; + struct nftnl_rule_iter *iter; struct nftnl_rule *r; - list = nft_rule_list_get(h); - if (list == NULL) - return 0; - - iter = nftnl_rule_list_iter_create(list); + iter = nftnl_rule_iter_create(c); if (iter == NULL) - return 0; + return 1; - r = nftnl_rule_list_iter_next(iter); + r = nftnl_rule_iter_next(iter); while (r != NULL) { - const char *rule_table = - nftnl_rule_get_str(r, NFTNL_RULE_TABLE); + nft_rule_print_save(r, NFT_RULE_APPEND, format); + r = nftnl_rule_iter_next(iter); + } - if (strcmp(table, rule_table) != 0) - goto next; + nftnl_rule_iter_destroy(iter); + return 0; +} - nft_rule_print_save(r, NFT_RULE_APPEND, format); +int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format) +{ + struct nftnl_chain_list_iter *iter; + struct nftnl_chain_list *list; + struct nftnl_chain *c; + int ret = 0; -next: - r = nftnl_rule_list_iter_next(iter); + list = nft_chain_list_get(h, table, true); + if (!list) + return 0; + + iter = nftnl_chain_list_iter_create(list); + if (!iter) + return 0; + + c = nftnl_chain_list_iter_next(iter); + while (c) { + ret = nft_chain_save_rules(h, c, format); + if (ret != 0) + break; + + c = nftnl_chain_list_iter_next(iter); } - nftnl_rule_list_iter_destroy(iter); + nftnl_chain_list_iter_destroy(iter); /* the core expects 1 for success and 0 for error */ - return 1; + return ret == 0 ? 1 : 0; } static void @@ -1529,7 +1560,7 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table, nft_fn = nft_rule_flush; - list = nft_chain_list_get(h, table); + list = nft_chain_list_get(h, table, false); if (list == NULL) { ret = 1; goto err; @@ -1553,6 +1584,7 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table, fprintf(stdout, "Flushing chain `%s'\n", chain_name); __nft_rule_flush(h, table, chain_name); + flush_rule_cache(c); if (chain != NULL) break; @@ -1560,7 +1592,6 @@ next: c = nftnl_chain_list_iter_next(iter); } nftnl_chain_list_iter_destroy(iter); - flush_rule_cache(h, table); err: /* the core expects 1 for success and 0 for error */ return ret == 0 ? 1 : 0; @@ -1587,7 +1618,7 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c); - list = nft_chain_list_get(h, table); + list = nft_chain_list_get(h, table, false); if (list) nftnl_chain_list_add(c, list); @@ -1611,7 +1642,7 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain, nft_fn = nft_chain_user_del; - list = nft_chain_list_get(h, table); + list = nft_chain_list_get(h, table, false); if (list == NULL) goto err; @@ -1689,11 +1720,12 @@ next: } static struct nftnl_chain * -nft_chain_find(struct nft_handle *h, const char *table, const char *chain) +nft_chain_find(struct nft_handle *h, const char *table, + const char *chain, bool need_rules) { struct nftnl_chain_list *list; - list = nft_chain_list_get(h, table); + list = nft_chain_list_get(h, table, need_rules); if (list == NULL) return NULL; @@ -1712,7 +1744,7 @@ bool nft_chain_exists(struct nft_handle *h, if (nft_chain_builtin_find(t, chain)) return true; - return !!nft_chain_find(h, table, chain); + return !!nft_chain_find(h, table, chain, false); } int nft_chain_user_rename(struct nft_handle *h,const char *chain, @@ -1732,7 +1764,7 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain, errno = 0; /* Find the old chain to be renamed */ - c = nft_chain_find(h, table, chain); + c = nft_chain_find(h, table, chain, false); if (c == NULL) { errno = ENOENT; return 0; @@ -1884,7 +1916,6 @@ static int __nft_table_flush(struct nft_handle *h, const char *table) h->table[_t->type].initialized = false; flush_chain_cache(h, table); - flush_rule_cache(h, table); return 0; } @@ -1925,12 +1956,6 @@ next: t = nftnl_table_list_iter_next(iter); } - if (!h->rule_cache) { - h->rule_cache = nftnl_rule_list_alloc(); - if (h->rule_cache == NULL) - return -1; - } - err_table_iter: nftnl_table_list_iter_destroy(iter); err_table_list: @@ -1946,8 +1971,7 @@ void nft_table_new(struct nft_handle *h, const char *table) nft_xt_builtin_init(h, table); } -static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule_list *list, - struct nftnl_rule *r) +static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r) { int ret; @@ -1962,31 +1986,19 @@ static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule_list *list, } static struct nftnl_rule * -nft_rule_find(struct nft_handle *h, struct nftnl_rule_list *list, - const char *chain, const char *table, void *data, int rulenum) +nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulenum) { struct nftnl_rule *r; - struct nftnl_rule_list_iter *iter; + struct nftnl_rule_iter *iter; int rule_ctr = 0; bool found = false; - iter = nftnl_rule_list_iter_create(list); + iter = nftnl_rule_iter_create(c); if (iter == NULL) return 0; - r = nftnl_rule_list_iter_next(iter); + r = nftnl_rule_iter_next(iter); while (r != NULL) { - const char *rule_table = - nftnl_rule_get_str(r, NFTNL_RULE_TABLE); - const char *rule_chain = - nftnl_rule_get_str(r, NFTNL_RULE_CHAIN); - - if (strcmp(table, rule_table) != 0 || - strcmp(chain, rule_chain) != 0) { - DEBUGP("different chain / table\n"); - goto next; - } - if (rulenum >= 0) { /* Delete by rule number case */ if (rule_ctr == rulenum) { @@ -1999,11 +2011,10 @@ nft_rule_find(struct nft_handle *h, struct nftnl_rule_list *list, break; } rule_ctr++; -next: - r = nftnl_rule_list_iter_next(iter); + r = nftnl_rule_iter_next(iter); } - nftnl_rule_list_iter_destroy(iter); + nftnl_rule_iter_destroy(iter); return found ? r : NULL; } @@ -2011,16 +2022,16 @@ next: int nft_rule_check(struct nft_handle *h, const char *chain, const char *table, void *data, bool verbose) { - struct nftnl_rule_list *list; + struct nftnl_chain *c; struct nftnl_rule *r; nft_fn = nft_rule_check; - list = nft_rule_list_get(h); - if (list == NULL) + c = nft_chain_find(h, table, chain, true); + if (!c) return 0; - r = nft_rule_find(h, list, chain, table, data, -1); + r = nft_rule_find(h, c, data, -1); if (r == NULL) { errno = ENOENT; return 0; @@ -2034,19 +2045,21 @@ int nft_rule_check(struct nft_handle *h, const char *chain, int nft_rule_delete(struct nft_handle *h, const char *chain, const char *table, void *data, bool verbose) { - int ret = 0; + struct nftnl_chain *c; struct nftnl_rule *r; - struct nftnl_rule_list *list; + int ret = 0; nft_fn = nft_rule_delete; - list = nft_rule_list_get(h); - if (list == NULL) + c = nft_chain_find(h, table, chain, true); + if (!c) { + errno = ENOENT; return 0; + } - r = nft_rule_find(h, list, chain, table, data, -1); + r = nft_rule_find(h, c, data, -1); if (r != NULL) { - ret =__nft_rule_del(h, list, r); + ret =__nft_rule_del(h, r); if (ret < 0) errno = ENOMEM; if (verbose) @@ -2086,7 +2099,7 @@ int nft_rule_insert(struct nft_handle *h, const char *chain, const char *table, void *data, int rulenum, bool verbose) { struct nftnl_rule *r, *new_rule; - struct nftnl_rule_list *list; + struct nftnl_chain *c; uint64_t handle = 0; /* If built-in chains don't exist for this table, create them */ @@ -2095,18 +2108,19 @@ int nft_rule_insert(struct nft_handle *h, const char *chain, nft_fn = nft_rule_insert; - if (rulenum > 0) { - list = nft_rule_list_get(h); - if (list == NULL) - goto err; + c = nft_chain_find(h, table, chain, true); + if (!c) { + errno = ENOENT; + goto err; + } - r = nft_rule_find(h, list, chain, table, data, rulenum); + if (rulenum > 0) { + r = nft_rule_find(h, c, data, rulenum); if (r == NULL) { /* special case: iptables allows to insert into * rule_count + 1 position. */ - r = nft_rule_find(h, list, chain, table, data, - rulenum - 1); + r = nft_rule_find(h, c, data, rulenum - 1); if (r != NULL) return nft_rule_append(h, chain, table, data, 0, verbose); @@ -2117,8 +2131,6 @@ int nft_rule_insert(struct nft_handle *h, const char *chain, handle = nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE); DEBUGP("adding after rule handle %"PRIu64"\n", handle); - } else { - nft_rule_list_get(h); } new_rule = nft_rule_add(h, chain, table, data, handle, verbose); @@ -2126,9 +2138,9 @@ int nft_rule_insert(struct nft_handle *h, const char *chain, goto err; if (handle) - nftnl_rule_list_insert_at(new_rule, r); + nftnl_chain_rule_insert_at(new_rule, r); else - nftnl_rule_list_add(new_rule, h->rule_cache); + nftnl_chain_rule_add(new_rule, c); return 1; err: @@ -2138,20 +2150,22 @@ err: int nft_rule_delete_num(struct nft_handle *h, const char *chain, const char *table, int rulenum, bool verbose) { - int ret = 0; + struct nftnl_chain *c; struct nftnl_rule *r; - struct nftnl_rule_list *list; + int ret = 0; nft_fn = nft_rule_delete_num; - list = nft_rule_list_get(h); - if (list == NULL) + c = nft_chain_find(h, table, chain, true); + if (!c) { + errno = ENOENT; return 0; + } - r = nft_rule_find(h, list, chain, table, NULL, rulenum); + r = nft_rule_find(h, c, NULL, rulenum); if (r != NULL) { DEBUGP("deleting rule by number %d\n", rulenum); - ret = __nft_rule_del(h, list, r); + ret = __nft_rule_del(h, r); if (ret < 0) errno = ENOMEM; } else @@ -2163,17 +2177,19 @@ int nft_rule_delete_num(struct nft_handle *h, const char *chain, int nft_rule_replace(struct nft_handle *h, const char *chain, const char *table, void *data, int rulenum, bool verbose) { - int ret = 0; + struct nftnl_chain *c; struct nftnl_rule *r; - struct nftnl_rule_list *list; + int ret = 0; nft_fn = nft_rule_replace; - list = nft_rule_list_get(h); - if (list == NULL) + c = nft_chain_find(h, table, chain, true); + if (!c) { + errno = ENOENT; return 0; + } - r = nft_rule_find(h, list, chain, table, data, rulenum); + r = nft_rule_find(h, c, data, rulenum); if (r != NULL) { DEBUGP("replacing rule with handle=%llu\n", (unsigned long long) @@ -2191,35 +2207,21 @@ int nft_rule_replace(struct nft_handle *h, const char *chain, } static int -__nft_rule_list(struct nft_handle *h, const char *chain, const char *table, +__nft_rule_list(struct nft_handle *h, struct nftnl_chain *c, int rulenum, unsigned int format, void (*cb)(struct nftnl_rule *r, unsigned int num, unsigned int format)) { - struct nftnl_rule_list *list; - struct nftnl_rule_list_iter *iter; + struct nftnl_rule_iter *iter; struct nftnl_rule *r; int rule_ctr = 0; - list = nft_rule_list_get(h); - if (list == NULL) - return 0; - - iter = nftnl_rule_list_iter_create(list); + iter = nftnl_rule_iter_create(c); if (iter == NULL) return 0; - r = nftnl_rule_list_iter_next(iter); + r = nftnl_rule_iter_next(iter); while (r != NULL) { - const char *rule_table = - nftnl_rule_get_str(r, NFTNL_RULE_TABLE); - const char *rule_chain = - nftnl_rule_get_str(r, NFTNL_RULE_CHAIN); - - if (strcmp(table, rule_table) != 0 || - strcmp(chain, rule_chain) != 0) - goto next; - rule_ctr++; if (rulenum > 0 && rule_ctr != rulenum) { @@ -2232,46 +2234,30 @@ __nft_rule_list(struct nft_handle *h, const char *chain, const char *table, break; next: - r = nftnl_rule_list_iter_next(iter); + r = nftnl_rule_iter_next(iter); } - nftnl_rule_list_iter_destroy(iter); + nftnl_rule_iter_destroy(iter); return 1; } -static int nft_rule_count(struct nft_handle *h, - const char *chain, const char *table) +static int nft_rule_count(struct nft_handle *h, struct nftnl_chain *c) { - struct nftnl_rule_list_iter *iter; - struct nftnl_rule_list *list; + struct nftnl_rule_iter *iter; struct nftnl_rule *r; int rule_ctr = 0; - list = nft_rule_list_get(h); - if (list == NULL) - return 0; - - iter = nftnl_rule_list_iter_create(list); + iter = nftnl_rule_iter_create(c); if (iter == NULL) return 0; - r = nftnl_rule_list_iter_next(iter); + r = nftnl_rule_iter_next(iter); while (r != NULL) { - const char *rule_table = - nftnl_rule_get_str(r, NFTNL_RULE_TABLE); - const char *rule_chain = - nftnl_rule_get_str(r, NFTNL_RULE_CHAIN); - - if (strcmp(table, rule_table) != 0 || - strcmp(chain, rule_chain) != 0) - goto next; - rule_ctr++; -next: - r = nftnl_rule_list_iter_next(iter); + r = nftnl_rule_iter_next(iter); } - nftnl_rule_list_iter_destroy(iter); + nftnl_rule_iter_destroy(iter); return rule_ctr; } @@ -2304,8 +2290,11 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, } if (chain && rulenum) { - __nft_rule_list(h, chain, table, - rulenum, format, ops->print_rule); + c = nft_chain_find(h, table, chain, true); + if (!c) + return 0; + + __nft_rule_list(h, c, rulenum, format, ops->print_rule); return 1; } @@ -2348,12 +2337,11 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, if (found) printf("\n"); - entries = nft_rule_count(h, chain_name, table); + entries = nft_rule_count(h, c); ops->print_header(format, chain_name, policy_name[policy], &ctrs, basechain, refs - entries, entries); - __nft_rule_list(h, chain_name, table, - rulenum, format, ops->print_rule); + __nft_rule_list(h, c, rulenum, format, ops->print_rule); found = true; @@ -2452,7 +2440,7 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain, return 0; } - list = nft_chain_list_get(h, table); + list = nft_chain_list_get(h, table, true); if (!list) goto err; @@ -2478,8 +2466,7 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain, if (chain && strcmp(chain, chain_name) != 0) goto next; - ret = __nft_rule_list(h, chain_name, table, rulenum, - format, list_save); + ret = __nft_rule_list(h, c, rulenum, format, list_save); /* we printed the chain we wanted, stop processing. */ if (chain) @@ -2497,17 +2484,17 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain, const char *table, int rulenum) { struct iptables_command_state cs = {}; - struct nftnl_rule_list *list; + struct nftnl_chain *c; struct nftnl_rule *r; int ret = 0; nft_fn = nft_rule_delete; - list = nft_rule_list_get(h); - if (list == NULL) + c = nft_chain_find(h, table, chain, true); + if (!c) return 0; - r = nft_rule_find(h, list, chain, table, NULL, rulenum); + r = nft_rule_find(h, c, NULL, rulenum); if (r == NULL) { errno = ENOENT; ret = 1; @@ -2976,38 +2963,19 @@ int nft_xtables_config_load(struct nft_handle *h, const char *filename, static void nft_chain_zero_rule_counters(struct nft_handle *h, struct nftnl_chain *c) { - struct nftnl_rule_list_iter *iter; - struct nftnl_rule_list *list; - const char *table_name; - const char *chain_name; + struct nftnl_rule_iter *iter; struct nftnl_rule *r; - list = nft_rule_list_get(h); - if (list == NULL) - return; - iter = nftnl_rule_list_iter_create(list); + iter = nftnl_rule_iter_create(c); if (iter == NULL) return; - table_name = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); - chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); - - r = nftnl_rule_list_iter_next(iter); + r = nftnl_rule_iter_next(iter); while (r != NULL) { struct nftnl_expr_iter *ei; - const char *table_chain; - const char *rule_chain; struct nftnl_expr *e; bool zero_needed; - table_chain = nftnl_rule_get_str(r, NFTNL_RULE_TABLE); - if (strcmp(table_chain, table_name)) - goto next; - - rule_chain = nftnl_rule_get_str(r, NFTNL_RULE_CHAIN); - if (strcmp(rule_chain, chain_name)) - goto next; - ei = nftnl_expr_iter_create(r); if (!ei) break; @@ -3038,11 +3006,10 @@ static void nft_chain_zero_rule_counters(struct nft_handle *h, nftnl_rule_unset(r, NFTNL_RULE_POSITION); batch_rule_add(h, NFT_COMPAT_RULE_REPLACE, r); } -next: - r = nftnl_rule_list_iter_next(iter); + r = nftnl_rule_iter_next(iter); } - nftnl_rule_list_iter_destroy(iter); + nftnl_rule_iter_destroy(iter); } int nft_chain_zero_counters(struct nft_handle *h, const char *chain, @@ -3053,7 +3020,7 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain, struct nftnl_chain *c; int ret = 0; - list = nft_chain_list_get(h, table); + list = nft_chain_list_get(h, table, true); if (list == NULL) goto err; @@ -3119,29 +3086,29 @@ static const char *supported_exprs[NFT_COMPAT_EXPR_MAX] = { }; -static int nft_is_expr_compatible(const struct nftnl_expr *expr) +static bool nft_is_expr_compatible(const struct nftnl_expr *expr) { const char *name = nftnl_expr_get_str(expr, NFTNL_EXPR_NAME); int i; for (i = 0; i < NFT_COMPAT_EXPR_MAX; i++) { if (strcmp(supported_exprs[i], name) == 0) - return 0; + return true; } if (!strcmp(name, "limit") && nftnl_expr_get_u32(expr, NFTNL_EXPR_LIMIT_TYPE) == NFT_LIMIT_PKTS && nftnl_expr_get_u32(expr, NFTNL_EXPR_LIMIT_FLAGS) == 0) - return 0; + return true; - return 1; + return false; } static bool nft_is_rule_compatible(struct nftnl_rule *rule) { struct nftnl_expr_iter *iter; struct nftnl_expr *expr; - bool compatible = false; + bool compatible = true; iter = nftnl_expr_iter_create(rule); if (iter == NULL) @@ -3149,123 +3116,101 @@ static bool nft_is_rule_compatible(struct nftnl_rule *rule) expr = nftnl_expr_iter_next(iter); while (expr != NULL) { - if (nft_is_expr_compatible(expr) == 0) { - expr = nftnl_expr_iter_next(iter); - continue; + if (!nft_is_expr_compatible(expr)) { + compatible = false; + break; } - - compatible = true; - break; + expr = nftnl_expr_iter_next(iter); } nftnl_expr_iter_destroy(iter); return compatible; } -static int nft_is_chain_compatible(const struct nft_handle *h, - const struct nftnl_chain *chain) +static bool nft_are_rules_compatible(struct nft_handle *h, struct nftnl_chain *c) { - const char *table, *name, *type, *cur_table; - const struct builtin_chain *chains; - int i, j, prio; - enum nf_inet_hooks hook; - - table = nftnl_chain_get(chain, NFTNL_CHAIN_TABLE); - name = nftnl_chain_get(chain, NFTNL_CHAIN_NAME); - type = nftnl_chain_get(chain, NFTNL_CHAIN_TYPE); - prio = nftnl_chain_get_u32(chain, NFTNL_CHAIN_PRIO); - hook = nftnl_chain_get_u32(chain, NFTNL_CHAIN_HOOKNUM); - - for (i = 0; i < NFT_TABLE_MAX; i++) { - cur_table = h->tables[i].name; - chains = h->tables[i].chains; - - if (!cur_table || strcmp(table, cur_table) != 0) - continue; + struct nftnl_rule_iter *iter; + struct nftnl_rule *rule; + bool compatible = true; - for (j = 0; j < NF_INET_NUMHOOKS && chains[j].name; j++) { - if (strcmp(name, chains[j].name) != 0) - continue; + iter = nftnl_rule_iter_create(c); + if (iter == NULL) + return false; - if (strcmp(type, chains[j].type) == 0 && - prio == chains[j].prio && - hook == chains[j].hook) - return 0; + rule = nftnl_rule_iter_next(iter); + while (rule != NULL) { + if (!nft_is_rule_compatible(rule)) { + compatible = false; break; } + rule = nftnl_rule_iter_next(iter); } - - return 1; + nftnl_rule_iter_destroy(iter); + return compatible; } -static int nft_are_chains_compatible(struct nft_handle *h, const char *tablename) +static int nft_is_chain_compatible(struct nftnl_chain *c, void *data) { - struct nftnl_chain_list *list; - struct nftnl_chain_list_iter *iter; - struct nftnl_chain *chain; - int ret = 0; + const struct builtin_chain *chains = NULL, *chain = NULL; + const char *table, *name, *type; + struct nft_handle *h = data; + enum nf_inet_hooks hook; + int i, prio; - list = nft_chain_list_get(h, tablename); - if (list == NULL) + if (!nft_are_rules_compatible(h, c)) return -1; - iter = nftnl_chain_list_iter_create(list); - if (iter == NULL) + if (!nft_chain_builtin(c)) + return 0; + + /* find chain's table in builtin tables */ + table = nftnl_chain_get(c, NFTNL_CHAIN_TABLE); + for (i = 0; i < NFT_TABLE_MAX; i++) { + const char *cur_table = h->tables[i].name; + + if (!cur_table || strcmp(table, cur_table) != 0) + continue; + + chains = h->tables[i].chains; + break; + } + if (!chains) return -1; - chain = nftnl_chain_list_iter_next(iter); - while (chain != NULL) { - if (!nft_chain_builtin(chain)) - goto next; + /* find chain in builtin chain list */ + name = nftnl_chain_get(c, NFTNL_CHAIN_NAME); + for (i = 0; i < NF_INET_NUMHOOKS && chains[i].name; i++) { + if (strcmp(name, chains[i].name) != 0) + continue; - ret = nft_is_chain_compatible(h, chain); - if (ret != 0) - break; -next: - chain = nftnl_chain_list_iter_next(iter); + chain = &chains[i]; + break; } + if (!chain) + return -1; - nftnl_chain_list_iter_destroy(iter); + /* compare properties */ + type = nftnl_chain_get(c, NFTNL_CHAIN_TYPE); + prio = nftnl_chain_get_u32(c, NFTNL_CHAIN_PRIO); + hook = nftnl_chain_get_u32(c, NFTNL_CHAIN_HOOKNUM); + if (strcmp(type, chains[i].type) == 0 && + prio == chains[i].prio && + hook == chains[i].hook) + return 0; - return ret; + return -1; } bool nft_is_table_compatible(struct nft_handle *h, const char *tablename) { - struct nftnl_rule_list *list; - struct nftnl_rule_list_iter *iter; - struct nftnl_rule *rule; - int ret = 0; + struct nftnl_chain_list *list; - if (!nft_table_builtin_find(h, tablename)) + list = nft_chain_list_get(h, tablename, true); + if (!list) return false; - ret = nft_are_chains_compatible(h, tablename); - if (ret != 0) + if (nftnl_chain_list_foreach(list, nft_is_chain_compatible, h)) return false; - list = nft_rule_list_get(h); - if (list == NULL) - return true; - - iter = nftnl_rule_list_iter_create(list); - if (iter == NULL) - return true; - - rule = nftnl_rule_list_iter_next(iter); - while (rule != NULL) { - const char *table = nftnl_rule_get_str(rule, NFTNL_RULE_TABLE); - - if (strcmp(table, tablename)) - goto next_rule; - - ret = nft_is_rule_compatible(rule); - if (ret != 0) - break; -next_rule: - rule = nftnl_rule_list_iter_next(iter); - } - - nftnl_rule_list_iter_destroy(iter); - return ret == 0; + return true; } diff --git a/iptables/nft.h b/iptables/nft.h index bf60ab3943659..af46afc789773 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -42,7 +42,8 @@ struct nft_handle { struct nftnl_chain_list *chain_cache; bool initialized; } table[NFT_TABLE_MAX]; - struct nftnl_rule_list *rule_cache; + bool have_cache; + bool have_rule_cache; bool restore; int8_t config_done; @@ -82,7 +83,7 @@ struct nftnl_chain; int nft_chain_set(struct nft_handle *h, const char *table, const char *chain, const char *policy, const struct xt_counters *counters); struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h, - const char *table); + const char *table, bool need_rules); struct nftnl_chain *nft_chain_list_find(struct nftnl_chain_list *list, const char *chain); int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list); diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index 4e00ed86be06d..0aaeec0764426 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -61,7 +61,7 @@ static struct nftnl_chain_list *get_chain_list(struct nft_handle *h, { struct nftnl_chain_list *chain_list; - chain_list = nft_chain_list_get(h, table); + chain_list = nft_chain_list_get(h, table, false); if (chain_list == NULL) xtables_error(OTHER_PROBLEM, "cannot retrieve chain list\n"); @@ -155,6 +155,9 @@ void xtables_restore_parse(struct nft_handle *h, table); if (cb->table_flush) cb->table_flush(h, table); + /* fake rule cache presence so that we don't populate + * the cache later with rules just flushed here */ + h->have_rule_cache = true; } ret = 1; diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c index 414a864b6196b..4451c9ce15557 100644 --- a/iptables/xtables-save.c +++ b/iptables/xtables-save.c @@ -73,7 +73,7 @@ __do_output(struct nft_handle *h, const char *tablename, bool counters) return 0; } - chain_list = nft_chain_list_get(h, tablename); + chain_list = nft_chain_list_get(h, tablename, false); if (!chain_list) return 0; @@ -259,7 +259,7 @@ static int __ebt_save(struct nft_handle *h, const char *tablename, bool counters return 0; } - chain_list = nft_chain_list_get(h, tablename); + chain_list = nft_chain_list_get(h, tablename, false); if (first) { now = time(NULL); @@ -401,7 +401,7 @@ int xtables_arp_save_main(int argc, char **argv) } printf("*filter\n"); - nft_chain_save(&h, nft_chain_list_get(&h, "filter")); + nft_chain_save(&h, nft_chain_list_get(&h, "filter", false)); nft_rule_save(&h, "filter", show_counters ? 0 : FMT_NOCOUNTS); printf("\n"); nft_fini(&h); From patchwork Thu Dec 13 11:15:57 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Sutter X-Patchwork-Id: 1012784 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=nwl.cc Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43FrjB4QjFz9s4s for ; Thu, 13 Dec 2018 22:16:30 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728647AbeLMLQ3 (ORCPT ); Thu, 13 Dec 2018 06:16:29 -0500 Received: from orbyte.nwl.cc ([151.80.46.58]:58058 "EHLO orbyte.nwl.cc" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728625AbeLMLQ3 (ORCPT ); Thu, 13 Dec 2018 06:16:29 -0500 Received: from localhost ([::1]:42916 helo=tatos) by orbyte.nwl.cc with esmtp (Exim 4.91) (envelope-from ) id 1gXOyi-00076F-AP; Thu, 13 Dec 2018 12:16:28 +0100 From: Phil Sutter To: Pablo Neira Ayuso Cc: netfilter-devel@vger.kernel.org Subject: [iptables PATCH v2 04/14] nft: Simplify nftnl_rule_list_chain_save() Date: Thu, 13 Dec 2018 12:15:57 +0100 Message-Id: <20181213111607.5457-5-phil@nwl.cc> X-Mailer: git-send-email 2.19.0 In-Reply-To: <20181213111607.5457-1-phil@nwl.cc> References: <20181213111607.5457-1-phil@nwl.cc> MIME-Version: 1.0 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Since there are per table chain caches, The chain list passed to that function is comprised of chains belonging to the right table only. Therefore the table name check can safely be skipped. Signed-off-by: Phil Sutter --- iptables/nft.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index 0869f2e222393..8c53dae7138ec 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -2369,8 +2369,7 @@ list_save(struct nftnl_rule *r, unsigned int num, unsigned int format) static int nftnl_rule_list_chain_save(struct nft_handle *h, const char *chain, - const char *table, struct nftnl_chain_list *list, - int counters) + struct nftnl_chain_list *list, int counters) { struct nftnl_chain_list_iter *iter; struct nftnl_chain *c; @@ -2381,15 +2380,12 @@ nftnl_rule_list_chain_save(struct nft_handle *h, const char *chain, c = nftnl_chain_list_iter_next(iter); while (c != NULL) { - const char *chain_table = - nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); uint32_t policy = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY); - if (strcmp(table, chain_table) != 0 || - (chain && strcmp(chain, chain_name) != 0)) + if (chain && strcmp(chain, chain_name) != 0) goto next; /* this is a base chain */ @@ -2446,7 +2442,7 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain, /* Dump policies and custom chains first */ if (!rulenum) - nftnl_rule_list_chain_save(h, chain, table, list, counters); + nftnl_rule_list_chain_save(h, chain, list, counters); /* Now dump out rules in this table */ iter = nftnl_chain_list_iter_create(list); From patchwork Thu Dec 13 11:15:58 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Sutter X-Patchwork-Id: 1012791 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=nwl.cc Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43Frjv1dFDz9s4s for ; Thu, 13 Dec 2018 22:17:07 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728751AbeLMLRH (ORCPT ); Thu, 13 Dec 2018 06:17:07 -0500 Received: from orbyte.nwl.cc ([151.80.46.58]:58100 "EHLO orbyte.nwl.cc" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728067AbeLMLRG (ORCPT ); Thu, 13 Dec 2018 06:17:06 -0500 Received: from localhost ([::1]:42958 helo=tatos) by orbyte.nwl.cc with esmtp (Exim 4.91) (envelope-from ) id 1gXOzJ-00078e-PP; Thu, 13 Dec 2018 12:17:05 +0100 From: Phil Sutter To: Pablo Neira Ayuso Cc: netfilter-devel@vger.kernel.org Subject: [iptables PATCH v2 05/14] xtables: Drop nft_chain_list_find() Date: Thu, 13 Dec 2018 12:15:58 +0100 Message-Id: <20181213111607.5457-6-phil@nwl.cc> X-Mailer: git-send-email 2.19.0 In-Reply-To: <20181213111607.5457-1-phil@nwl.cc> References: <20181213111607.5457-1-phil@nwl.cc> MIME-Version: 1.0 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Replace the function by nftnl_chain_list_lookup_byname() as provided by libnftnl. Signed-off-by: Phil Sutter --- iptables/nft.c | 31 ++----------------------------- iptables/nft.h | 2 -- 2 files changed, 2 insertions(+), 31 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index 8c53dae7138ec..a440bb015386e 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -698,7 +698,7 @@ static void nft_chain_builtin_init(struct nft_handle *h, /* Initialize built-in chains if they don't exist yet */ for (i=0; i < NF_INET_NUMHOOKS && table->chains[i].name != NULL; i++) { - c = nft_chain_list_find(list, table->chains[i].name); + c = nftnl_chain_list_lookup_byname(list, table->chains[i].name); if (c != NULL) continue; @@ -1692,33 +1692,6 @@ err: return ret == 0 ? 1 : 0; } -struct nftnl_chain * -nft_chain_list_find(struct nftnl_chain_list *list, const char *chain) -{ - struct nftnl_chain_list_iter *iter; - struct nftnl_chain *c; - - iter = nftnl_chain_list_iter_create(list); - if (iter == NULL) - return NULL; - - c = nftnl_chain_list_iter_next(iter); - while (c != NULL) { - const char *chain_name = - nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); - - if (strcmp(chain, chain_name) != 0) - goto next; - - nftnl_chain_list_iter_destroy(iter); - return c; -next: - c = nftnl_chain_list_iter_next(iter); - } - nftnl_chain_list_iter_destroy(iter); - return NULL; -} - static struct nftnl_chain * nft_chain_find(struct nft_handle *h, const char *table, const char *chain, bool need_rules) @@ -1729,7 +1702,7 @@ nft_chain_find(struct nft_handle *h, const char *table, if (list == NULL) return NULL; - return nft_chain_list_find(list, chain); + return nftnl_chain_list_lookup_byname(list, chain); } bool nft_chain_exists(struct nft_handle *h, diff --git a/iptables/nft.h b/iptables/nft.h index af46afc789773..5cf3cd9315add 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -84,8 +84,6 @@ struct nftnl_chain; int nft_chain_set(struct nft_handle *h, const char *table, const char *chain, const char *policy, const struct xt_counters *counters); struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h, const char *table, bool need_rules); -struct nftnl_chain *nft_chain_list_find(struct nftnl_chain_list *list, - const char *chain); int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list); int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table); int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *table, bool verbose); From patchwork Thu Dec 13 11:15:59 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Sutter X-Patchwork-Id: 1012782 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=nwl.cc Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43Frj11Tjvz9s4s for ; Thu, 13 Dec 2018 22:16:21 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727904AbeLMLQU (ORCPT ); Thu, 13 Dec 2018 06:16:20 -0500 Received: from orbyte.nwl.cc ([151.80.46.58]:58046 "EHLO orbyte.nwl.cc" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727544AbeLMLQT (ORCPT ); Thu, 13 Dec 2018 06:16:19 -0500 Received: from localhost ([::1]:42904 helo=tatos) by orbyte.nwl.cc with esmtp (Exim 4.91) (envelope-from ) id 1gXOyX-00075X-M0; Thu, 13 Dec 2018 12:16:17 +0100 From: Phil Sutter To: Pablo Neira Ayuso Cc: netfilter-devel@vger.kernel.org Subject: [iptables PATCH v2 06/14] xtables: Optimize flushing a specific chain Date: Thu, 13 Dec 2018 12:15:59 +0100 Message-Id: <20181213111607.5457-7-phil@nwl.cc> X-Mailer: git-send-email 2.19.0 In-Reply-To: <20181213111607.5457-1-phil@nwl.cc> References: <20181213111607.5457-1-phil@nwl.cc> MIME-Version: 1.0 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org If a chain name is given to nft_rule_flush(), make use of nftnl_chain_list_lookup_byname(). Signed-off-by: Phil Sutter --- iptables/nft.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index a440bb015386e..846e34f88ccbd 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1489,10 +1489,14 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format) } static void -__nft_rule_flush(struct nft_handle *h, const char *table, const char *chain) +__nft_rule_flush(struct nft_handle *h, const char *table, + const char *chain, bool verbose) { struct nftnl_rule *r; + if (verbose) + fprintf(stdout, "Flushing chain `%s'\n", chain); + r = nftnl_rule_alloc(); if (r == NULL) return; @@ -1526,7 +1530,7 @@ static int __nft_chain_user_flush(struct nftnl_chain *c, void *data) return 0; if (!nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) - __nft_rule_flush(h, table, chain); + __nft_rule_flush(h, table, chain, false); return 0; } @@ -1566,6 +1570,16 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table, goto err; } + if (chain) { + c = nftnl_chain_list_lookup_byname(list, chain); + if (!c) + return 0; + + __nft_rule_flush(h, table, chain, verbose); + flush_rule_cache(c); + return 1; + } + iter = nftnl_chain_list_iter_create(list); if (iter == NULL) { ret = 1; @@ -1577,18 +1591,8 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table, const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); - if (chain != NULL && strcmp(chain, chain_name) != 0) - goto next; - - if (verbose) - fprintf(stdout, "Flushing chain `%s'\n", chain_name); - - __nft_rule_flush(h, table, chain_name); + __nft_rule_flush(h, table, chain_name, verbose); flush_rule_cache(c); - - if (chain != NULL) - break; -next: c = nftnl_chain_list_iter_next(iter); } nftnl_chain_list_iter_destroy(iter); From patchwork Thu Dec 13 11:16:00 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Sutter X-Patchwork-Id: 1012787 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=nwl.cc Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43FrjV44FZz9s4s for ; Thu, 13 Dec 2018 22:16:46 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728742AbeLMLQq (ORCPT ); Thu, 13 Dec 2018 06:16:46 -0500 Received: from orbyte.nwl.cc ([151.80.46.58]:58076 "EHLO orbyte.nwl.cc" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728067AbeLMLQq (ORCPT ); Thu, 13 Dec 2018 06:16:46 -0500 Received: from localhost ([::1]:42934 helo=tatos) by orbyte.nwl.cc with esmtp (Exim 4.91) (envelope-from ) id 1gXOyy-00077Q-ER; Thu, 13 Dec 2018 12:16:44 +0100 From: Phil Sutter To: Pablo Neira Ayuso Cc: netfilter-devel@vger.kernel.org Subject: [iptables PATCH v2 07/14] xtables: Optimize nft_chain_zero_counters() Date: Thu, 13 Dec 2018 12:16:00 +0100 Message-Id: <20181213111607.5457-8-phil@nwl.cc> X-Mailer: git-send-email 2.19.0 In-Reply-To: <20181213111607.5457-1-phil@nwl.cc> References: <20181213111607.5457-1-phil@nwl.cc> MIME-Version: 1.0 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org If a chain name was given, make use of nftnl_chain_list_lookup_byname(). Streamline nft_chain_zero_rule_counters() to be suitable for calling from nftnl_chain_list_foreach(). There is an unrelated optimization in here, too: Add batch job NFT_COMPAT_CHAIN_ZERO only if it is a base chain. Since user-defined chains don't have counters, there is no need to do anything for them. Signed-off-by: Phil Sutter --- iptables/nft.c | 72 +++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index 846e34f88ccbd..c85fb724e3cd6 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -2933,15 +2933,36 @@ int nft_xtables_config_load(struct nft_handle *h, const char *filename, return h->config_done; } -static void nft_chain_zero_rule_counters(struct nft_handle *h, - struct nftnl_chain *c) +struct chain_zero_data { + struct nft_handle *handle; + bool verbose; +}; + +static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data) { + struct chain_zero_data *d = data; + struct nft_handle *h = d->handle; struct nftnl_rule_iter *iter; struct nftnl_rule *r; + int ret = 0; + + if (d->verbose) + fprintf(stdout, "Zeroing chain `%s'\n", + nftnl_chain_get_str(c, NFTNL_CHAIN_NAME)); + + if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) { + /* zero base chain counters. */ + nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, 0); + nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, 0); + nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE); + ret = batch_chain_add(h, NFT_COMPAT_CHAIN_ZERO, c); + if (ret) + return -1; + } iter = nftnl_rule_iter_create(c); if (iter == NULL) - return; + return -1; r = nftnl_rule_iter_next(iter); while (r != NULL) { @@ -2983,13 +3004,17 @@ static void nft_chain_zero_rule_counters(struct nft_handle *h, } nftnl_rule_iter_destroy(iter); + return 0; } int nft_chain_zero_counters(struct nft_handle *h, const char *chain, const char *table, bool verbose) { struct nftnl_chain_list *list; - struct nftnl_chain_list_iter *iter; + struct chain_zero_data d = { + .handle = h, + .verbose = verbose, + }; struct nftnl_chain *c; int ret = 0; @@ -2997,41 +3022,16 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain, if (list == NULL) goto err; - iter = nftnl_chain_list_iter_create(list); - if (iter == NULL) - goto err; - - c = nftnl_chain_list_iter_next(iter); - while (c != NULL) { - const char *chain_name = - nftnl_chain_get(c, NFTNL_CHAIN_NAME); - - if (chain != NULL && strcmp(chain, chain_name) != 0) - goto next; - - if (verbose) - fprintf(stdout, "Zeroing chain `%s'\n", chain_name); - - if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) { - /* zero base chain counters. */ - nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, 0); - nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, 0); - } - - nft_chain_zero_rule_counters(h, c); - - nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE); - - ret = batch_chain_add(h, NFT_COMPAT_CHAIN_ZERO, c); + if (chain) { + c = nftnl_chain_list_lookup_byname(list, chain); + if (!c) + return 0; - if (chain != NULL) - break; -next: - c = nftnl_chain_list_iter_next(iter); + ret = __nft_chain_zero_counters(c, &d); + goto err; } - nftnl_chain_list_iter_destroy(iter); - + ret = nftnl_chain_list_foreach(list, __nft_chain_zero_counters, &d); err: /* the core expects 1 for success and 0 for error */ return ret == 0 ? 1 : 0; From patchwork Thu Dec 13 11:16:01 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Sutter X-Patchwork-Id: 1012788 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=nwl.cc Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43Frjb1knsz9s4s for ; Thu, 13 Dec 2018 22:16:51 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728744AbeLMLQv (ORCPT ); Thu, 13 Dec 2018 06:16:51 -0500 Received: from orbyte.nwl.cc ([151.80.46.58]:58082 "EHLO orbyte.nwl.cc" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728067AbeLMLQu (ORCPT ); Thu, 13 Dec 2018 06:16:50 -0500 Received: from localhost ([::1]:42940 helo=tatos) by orbyte.nwl.cc with esmtp (Exim 4.91) (envelope-from ) id 1gXOz3-00077j-Oe; Thu, 13 Dec 2018 12:16:49 +0100 From: Phil Sutter To: Pablo Neira Ayuso Cc: netfilter-devel@vger.kernel.org Subject: [iptables PATCH v2 08/14] tests: Extend verbose output and return code tests Date: Thu, 13 Dec 2018 12:16:01 +0100 Message-Id: <20181213111607.5457-9-phil@nwl.cc> X-Mailer: git-send-email 2.19.0 In-Reply-To: <20181213111607.5457-1-phil@nwl.cc> References: <20181213111607.5457-1-phil@nwl.cc> MIME-Version: 1.0 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Recent changes to chain flush and zero routines incorporate proper error propagation so trying to flush or zero a non-existent chain results in an error. This is consistent with iptables-legacy, extend tests to make sure it stays this way. Also extend verbose output test to make these recent changes didn't mess it up. Signed-off-by: Phil Sutter --- .../shell/testcases/iptables/0002-verbose-output_0 | 13 +++++++++---- .../shell/testcases/iptables/0004-return-codes_0 | 6 ++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 b/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 index 2e8059536ea7b..b1ef91f61f481 100755 --- a/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 +++ b/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 @@ -29,23 +29,28 @@ Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables -v -n -L) +[[ -z $($XT_MULTI iptables -v -N foobar) ]] || exit 1 + diff -u -Z <(echo -e "$VOUT1") <($XT_MULTI iptables -v -D FORWARD $RULE1) diff -u -Z <(echo -e "$VOUT2") <($XT_MULTI iptables -v -D FORWARD $RULE2) EXPECT="Flushing chain \`INPUT' Flushing chain \`FORWARD' -Flushing chain \`OUTPUT'" +Flushing chain \`OUTPUT' +Flushing chain \`foobar'" diff -u <(echo -e "$EXPECT") <($XT_MULTI iptables -v -F) EXPECT="Zeroing chain \`INPUT' Zeroing chain \`FORWARD' -Zeroing chain \`OUTPUT'" +Zeroing chain \`OUTPUT' +Zeroing chain \`foobar'" diff -u <(echo -e "$EXPECT") <($XT_MULTI iptables -v -Z) diff -u <(echo "Flushing chain \`OUTPUT'") <($XT_MULTI iptables -v -F OUTPUT) diff -u <(echo "Zeroing chain \`OUTPUT'") <($XT_MULTI iptables -v -Z OUTPUT) +diff -u <(echo "Flushing chain \`foobar'") <($XT_MULTI iptables -v -F foobar) +diff -u <(echo "Zeroing chain \`foobar'") <($XT_MULTI iptables -v -Z foobar) -$XT_MULTI iptables -N foo -diff -u <(echo "Deleting chain \`foo'") <($XT_MULTI iptables -v -X foo) +diff -u <(echo "Deleting chain \`foobar'") <($XT_MULTI iptables -v -X foobar) diff --git a/iptables/tests/shell/testcases/iptables/0004-return-codes_0 b/iptables/tests/shell/testcases/iptables/0004-return-codes_0 index 5b6e1f6f1bc7a..9d2493992bd69 100755 --- a/iptables/tests/shell/testcases/iptables/0004-return-codes_0 +++ b/iptables/tests/shell/testcases/iptables/0004-return-codes_0 @@ -23,6 +23,12 @@ cmd 1 iptables -N foo # iptables-nft allows this - bug or feature? #cmd 2 iptables -N "invalid name" +# test chain flushing/zeroing +cmd 0 iptables -F foo +cmd 0 iptables -Z foo +cmd 1 iptables -F bar +cmd 1 iptables -Z bar + # test chain rename cmd 0 iptables -E foo bar cmd 1 iptables -E foo bar From patchwork Thu Dec 13 11:16:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Sutter X-Patchwork-Id: 1012790 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=nwl.cc Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43Frjn6fZ1z9s4s for ; Thu, 13 Dec 2018 22:17:01 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728749AbeLMLRB (ORCPT ); Thu, 13 Dec 2018 06:17:01 -0500 Received: from orbyte.nwl.cc ([151.80.46.58]:58094 "EHLO orbyte.nwl.cc" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728067AbeLMLRB (ORCPT ); Thu, 13 Dec 2018 06:17:01 -0500 Received: from localhost ([::1]:42952 helo=tatos) by orbyte.nwl.cc with esmtp (Exim 4.91) (envelope-from ) id 1gXOzE-00078L-DK; Thu, 13 Dec 2018 12:17:00 +0100 From: Phil Sutter To: Pablo Neira Ayuso Cc: netfilter-devel@vger.kernel.org Subject: [iptables PATCH v2 09/14] xtables: Optimize nft_chain_user_del() Date: Thu, 13 Dec 2018 12:16:02 +0100 Message-Id: <20181213111607.5457-10-phil@nwl.cc> X-Mailer: git-send-email 2.19.0 In-Reply-To: <20181213111607.5457-1-phil@nwl.cc> References: <20181213111607.5457-1-phil@nwl.cc> MIME-Version: 1.0 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Make use of nftnl_chain_list_lookup_byname() if a chain name was given. Move the actual chain deleting code into a callback suitable for passing to nftnl_chain_list_foreach(). Signed-off-by: Phil Sutter --- iptables/nft.c | 89 ++++++++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index c85fb724e3cd6..69f351f8e2972 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1635,63 +1635,66 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl #define NLM_F_NONREC 0x100 /* Do not delete recursively */ #endif +struct chain_user_del_data { + struct nft_handle *handle; + bool verbose; + int builtin_err; +}; + +static int __nft_chain_user_del(struct nftnl_chain *c, void *data) +{ + struct chain_user_del_data *d = data; + struct nft_handle *h = d->handle; + int ret; + + /* don't delete built-in chain */ + if (nft_chain_builtin(c)) + return d->builtin_err; + + if (d->verbose) + fprintf(stdout, "Deleting chain `%s'\n", + nftnl_chain_get_str(c, NFTNL_CHAIN_NAME)); + + ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c); + if (ret) + return -1; + + nftnl_chain_list_del(c); + return 0; +} + int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *table, bool verbose) { + struct chain_user_del_data d = { + .handle = h, + .verbose = verbose, + }; struct nftnl_chain_list *list; - struct nftnl_chain_list_iter *iter; struct nftnl_chain *c; int ret = 0; - int deleted_ctr = 0; nft_fn = nft_chain_user_del; list = nft_chain_list_get(h, table, false); if (list == NULL) - goto err; - - iter = nftnl_chain_list_iter_create(list); - if (iter == NULL) - goto err; - - c = nftnl_chain_list_iter_next(iter); - while (c != NULL) { - const char *chain_name = - nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); - - /* don't delete built-in chain */ - if (nft_chain_builtin(c)) - goto next; - - if (chain != NULL && strcmp(chain, chain_name) != 0) - goto next; - - if (verbose) - fprintf(stdout, "Deleting chain `%s'\n", chain); - - ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c); - - if (ret < 0) - break; - - deleted_ctr++; - nftnl_chain_list_del(c); - - if (chain != NULL) - break; -next: - c = nftnl_chain_list_iter_next(iter); - } - - nftnl_chain_list_iter_destroy(iter); -err: + return 0; - /* chain not found */ - if (chain != NULL && deleted_ctr == 0) { - ret = -1; - errno = ENOENT; + if (chain) { + c = nftnl_chain_list_lookup_byname(list, chain); + if (!c) { + errno = ENOENT; + return 0; + } + d.builtin_err = -2; + ret = __nft_chain_user_del(c, &d); + if (ret == -2) + errno = EINVAL; + goto out; } + ret = nftnl_chain_list_foreach(list, __nft_chain_user_del, &d); +out: /* the core expects 1 for success and 0 for error */ return ret == 0 ? 1 : 0; } From patchwork Thu Dec 13 11:16:03 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Sutter X-Patchwork-Id: 1012793 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=nwl.cc Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43Frk63txYz9s4s for ; Thu, 13 Dec 2018 22:17:18 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728514AbeLMLRS (ORCPT ); Thu, 13 Dec 2018 06:17:18 -0500 Received: from orbyte.nwl.cc ([151.80.46.58]:58112 "EHLO orbyte.nwl.cc" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728067AbeLMLRS (ORCPT ); Thu, 13 Dec 2018 06:17:18 -0500 Received: from localhost ([::1]:42970 helo=tatos) by orbyte.nwl.cc with esmtp (Exim 4.91) (envelope-from ) id 1gXOzU-00079G-Dt; Thu, 13 Dec 2018 12:17:16 +0100 From: Phil Sutter To: Pablo Neira Ayuso Cc: netfilter-devel@vger.kernel.org Subject: [iptables PATCH v2 10/14] xtables: Optimize nft_rule_list() Date: Thu, 13 Dec 2018 12:16:03 +0100 Message-Id: <20181213111607.5457-11-phil@nwl.cc> X-Mailer: git-send-email 2.19.0 In-Reply-To: <20181213111607.5457-1-phil@nwl.cc> References: <20181213111607.5457-1-phil@nwl.cc> MIME-Version: 1.0 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Make use of nftnl_chain_list_lookup_byname() even if not listing a specific rule. Introduce __nft_print_header() to consolidate chain value extraction for printing with ops->print_header(). Signed-off-by: Phil Sutter --- iptables/nft.c | 78 +++++++++++++++++++++----------------------------- 1 file changed, 32 insertions(+), 46 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index 69f351f8e2972..40aedfb74fc70 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -2241,6 +2241,24 @@ static int nft_rule_count(struct nft_handle *h, struct nftnl_chain *c) return rule_ctr; } +static void __nft_print_header(struct nft_handle *h, + const struct nft_family_ops *ops, + struct nftnl_chain *c, unsigned int format) +{ + const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); + uint32_t policy = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY); + bool basechain = !!nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM); + uint32_t refs = nftnl_chain_get_u32(c, NFTNL_CHAIN_USE); + uint32_t entries = nft_rule_count(h, c); + struct xt_counters ctrs = { + .pcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS), + .bcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES), + }; + + ops->print_header(format, chain_name, policy_name[policy], + &ctrs, basechain, refs - entries, entries); +} + int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, int rulenum, unsigned int format) { @@ -2269,75 +2287,43 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, return 0; } - if (chain && rulenum) { - c = nft_chain_find(h, table, chain, true); + list = nft_chain_list_get(h, table, true); + if (!list) + return 0; + + if (chain) { + c = nftnl_chain_list_lookup_byname(list, chain); if (!c) return 0; + if (!rulenum) { + if (ops->print_table_header) + ops->print_table_header(table); + __nft_print_header(h, ops, c, format); + } __nft_rule_list(h, c, rulenum, format, ops->print_rule); return 1; } - list = nft_chain_list_get(h, table); - if (!list) - return 0; - iter = nftnl_chain_list_iter_create(list); if (iter == NULL) - goto err; + return 0; - if (!chain && ops->print_table_header) + if (ops->print_table_header) ops->print_table_header(table); c = nftnl_chain_list_iter_next(iter); while (c != NULL) { - const char *chain_name = - nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); - uint32_t policy = - nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY); - uint32_t refs = - nftnl_chain_get_u32(c, NFTNL_CHAIN_USE); - struct xt_counters ctrs = { - .pcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS), - .bcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES), - }; - bool basechain = false; - uint32_t entries; - - if (nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM)) - basechain = true; - - if (chain) { - if (strcmp(chain, chain_name) != 0) - goto next; - else if (ops->print_table_header) - ops->print_table_header(table); - } - if (found) printf("\n"); - entries = nft_rule_count(h, c); - ops->print_header(format, chain_name, policy_name[policy], - &ctrs, basechain, refs - entries, entries); - + __nft_print_header(h, ops, c, format); __nft_rule_list(h, c, rulenum, format, ops->print_rule); found = true; - - /* we printed the chain we wanted, stop processing. */ - if (chain) - break; - -next: c = nftnl_chain_list_iter_next(iter); } - nftnl_chain_list_iter_destroy(iter); -err: - if (chain && !found) - return 0; - return 1; } From patchwork Thu Dec 13 11:16:04 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Sutter X-Patchwork-Id: 1012789 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=nwl.cc Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43Frjh483yz9s4s for ; Thu, 13 Dec 2018 22:16:56 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728747AbeLMLQ4 (ORCPT ); Thu, 13 Dec 2018 06:16:56 -0500 Received: from orbyte.nwl.cc ([151.80.46.58]:58088 "EHLO orbyte.nwl.cc" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728067AbeLMLQ4 (ORCPT ); Thu, 13 Dec 2018 06:16:56 -0500 Received: from localhost ([::1]:42946 helo=tatos) by orbyte.nwl.cc with esmtp (Exim 4.91) (envelope-from ) id 1gXOz9-000782-2x; Thu, 13 Dec 2018 12:16:55 +0100 From: Phil Sutter To: Pablo Neira Ayuso Cc: netfilter-devel@vger.kernel.org Subject: [iptables PATCH v2 11/14] xtables: Optimize nft_rule_list_save() Date: Thu, 13 Dec 2018 12:16:04 +0100 Message-Id: <20181213111607.5457-12-phil@nwl.cc> X-Mailer: git-send-email 2.19.0 In-Reply-To: <20181213111607.5457-1-phil@nwl.cc> References: <20181213111607.5457-1-phil@nwl.cc> MIME-Version: 1.0 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org If a chain name was given, make use of nftnl_chain_list_lookup_byname(). Likewise in nftnl_rule_list_chain_save(), but introduce __nftnl_rule_list_chain_save() suitable for passing to nftnl_chain_list_foreach(). Signed-off-by: Phil Sutter --- iptables/nft.c | 93 +++++++++++++++++++++++--------------------------- 1 file changed, 43 insertions(+), 50 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index 40aedfb74fc70..be57aae297f50 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -2333,46 +2333,44 @@ list_save(struct nftnl_rule *r, unsigned int num, unsigned int format) nft_rule_print_save(r, NFT_RULE_APPEND, format); } +static int __nftnl_rule_list_chain_save(struct nftnl_chain *c, void *data) +{ + const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); + uint32_t policy = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY); + int *counters = data; + + if (!nft_chain_builtin(c)) { + printf("-N %s\n", chain_name); + return 0; + } + + /* this is a base chain */ + + printf("-P %s %s", chain_name, policy_name[policy]); + if (*counters) + printf(" -c %"PRIu64" %"PRIu64, + nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS), + nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES)); + printf("\n"); + return 0; +} + static int nftnl_rule_list_chain_save(struct nft_handle *h, const char *chain, struct nftnl_chain_list *list, int counters) { - struct nftnl_chain_list_iter *iter; struct nftnl_chain *c; - iter = nftnl_chain_list_iter_create(list); - if (iter == NULL) - return 0; - - c = nftnl_chain_list_iter_next(iter); - while (c != NULL) { - const char *chain_name = - nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); - uint32_t policy = - nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY); - - if (chain && strcmp(chain, chain_name) != 0) - goto next; + if (chain) { + c = nftnl_chain_list_lookup_byname(list, chain); + if (!c) + return 0; - /* this is a base chain */ - if (nft_chain_builtin(c)) { - printf("-P %s %s", chain_name, policy_name[policy]); - - if (counters) { - printf(" -c %"PRIu64" %"PRIu64"\n", - nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS), - nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES)); - } else - printf("\n"); - } else { - printf("-N %s\n", chain_name); - } -next: - c = nftnl_chain_list_iter_next(iter); + __nftnl_rule_list_chain_save(c, &counters); + return 1; } - nftnl_chain_list_iter_destroy(iter); - + nftnl_chain_list_foreach(list, __nftnl_rule_list_chain_save, &counters); return 1; } @@ -2404,41 +2402,36 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain, list = nft_chain_list_get(h, table, true); if (!list) - goto err; + return 0; /* Dump policies and custom chains first */ if (!rulenum) nftnl_rule_list_chain_save(h, chain, list, counters); - /* Now dump out rules in this table */ - iter = nftnl_chain_list_iter_create(list); - if (iter == NULL) - goto err; - if (counters < 0) format = FMT_C_COUNTS; else if (counters == 0) format = FMT_NOCOUNTS; - c = nftnl_chain_list_iter_next(iter); - while (c != NULL) { - const char *chain_name = - nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); + if (chain) { + c = nftnl_chain_list_lookup_byname(list, chain); + if (!c) + return 0; - if (chain && strcmp(chain, chain_name) != 0) - goto next; + return __nft_rule_list(h, c, rulenum, format, list_save); + } - ret = __nft_rule_list(h, c, rulenum, format, list_save); + /* Now dump out rules in this table */ + iter = nftnl_chain_list_iter_create(list); + if (iter == NULL) + return 0; - /* we printed the chain we wanted, stop processing. */ - if (chain) - break; -next: + c = nftnl_chain_list_iter_next(iter); + while (c != NULL) { + ret = __nft_rule_list(h, c, rulenum, format, list_save); c = nftnl_chain_list_iter_next(iter); } - nftnl_chain_list_iter_destroy(iter); -err: return ret; } From patchwork Thu Dec 13 11:16:05 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Sutter X-Patchwork-Id: 1012785 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=nwl.cc Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43FrjH5995z9s5c for ; Thu, 13 Dec 2018 22:16:35 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728677AbeLMLQe (ORCPT ); Thu, 13 Dec 2018 06:16:34 -0500 Received: from orbyte.nwl.cc ([151.80.46.58]:58064 "EHLO orbyte.nwl.cc" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728067AbeLMLQe (ORCPT ); Thu, 13 Dec 2018 06:16:34 -0500 Received: from localhost ([::1]:42922 helo=tatos) by orbyte.nwl.cc with esmtp (Exim 4.91) (envelope-from ) id 1gXOyn-00076n-NC; Thu, 13 Dec 2018 12:16:33 +0100 From: Phil Sutter To: Pablo Neira Ayuso Cc: netfilter-devel@vger.kernel.org Subject: [iptables PATCH v2 12/14] xtables: Make use of nftnl_rule_lookup_byindex() Date: Thu, 13 Dec 2018 12:16:05 +0100 Message-Id: <20181213111607.5457-13-phil@nwl.cc> X-Mailer: git-send-email 2.19.0 In-Reply-To: <20181213111607.5457-1-phil@nwl.cc> References: <20181213111607.5457-1-phil@nwl.cc> MIME-Version: 1.0 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Use the function where suitable to potentially speedup rule cache lookup by rule number. Signed-off-by: Phil Sutter --- iptables/nft.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index be57aae297f50..3e2fa30650c26 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1970,27 +1970,21 @@ nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulen { struct nftnl_rule *r; struct nftnl_rule_iter *iter; - int rule_ctr = 0; bool found = false; + if (rulenum >= 0) + /* Delete by rule number case */ + return nftnl_rule_lookup_byindex(c, rulenum); + iter = nftnl_rule_iter_create(c); if (iter == NULL) return 0; r = nftnl_rule_iter_next(iter); while (r != NULL) { - if (rulenum >= 0) { - /* Delete by rule number case */ - if (rule_ctr == rulenum) { - found = true; - break; - } - } else { - found = h->ops->rule_find(h->ops, r, data); - if (found) - break; - } - rule_ctr++; + found = h->ops->rule_find(h->ops, r, data); + if (found) + break; r = nftnl_rule_iter_next(iter); } @@ -2196,6 +2190,16 @@ __nft_rule_list(struct nft_handle *h, struct nftnl_chain *c, struct nftnl_rule *r; int rule_ctr = 0; + if (rulenum > 0) { + r = nftnl_rule_lookup_byindex(c, rulenum - 1); + if (!r) + /* iptables-legacy returns 0 when listing for + * valid chain but invalid rule number */ + return 1; + cb(r, rulenum, format); + return 1; + } + iter = nftnl_rule_iter_create(c); if (iter == NULL) return 0; From patchwork Thu Dec 13 11:16:06 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Sutter X-Patchwork-Id: 1012795 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=nwl.cc Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43FrkK3kZbz9s4s for ; Thu, 13 Dec 2018 22:17:29 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728756AbeLMLR3 (ORCPT ); Thu, 13 Dec 2018 06:17:29 -0500 Received: from orbyte.nwl.cc ([151.80.46.58]:58124 "EHLO orbyte.nwl.cc" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728517AbeLMLR3 (ORCPT ); Thu, 13 Dec 2018 06:17:29 -0500 Received: from localhost ([::1]:42982 helo=tatos) by orbyte.nwl.cc with esmtp (Exim 4.91) (envelope-from ) id 1gXOzf-00079v-1o; Thu, 13 Dec 2018 12:17:27 +0100 From: Phil Sutter To: Pablo Neira Ayuso Cc: netfilter-devel@vger.kernel.org Subject: [iptables PATCH v2 13/14] xtables: Fix for inserting rule at wrong position Date: Thu, 13 Dec 2018 12:16:06 +0100 Message-Id: <20181213111607.5457-14-phil@nwl.cc> X-Mailer: git-send-email 2.19.0 In-Reply-To: <20181213111607.5457-1-phil@nwl.cc> References: <20181213111607.5457-1-phil@nwl.cc> MIME-Version: 1.0 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org iptables-restore allows to insert rules at a certain position which is problematic for iptables-nft to realize since rule position is not determined by number but handle of previous or following rule. To fix this, make use of the rule cache (which holds in-kernel rules with their associated handle already). Insert new rules at the right position into that cache, then at commit time (i.e., in nft_action()) traverse each chain's rule list for new rules to add: * New rules at beginning of list are inserted in reverse order without reference of another rule, so that each consecutive rule is added before all previous ones. * Each time an "old" (i.e., in-kernel) rule is encountered, its handle is stored (overwriting any previous ones'). * New rules following an old one are appended to the old one (by specifying its handle) in reverse order, so that each consecutive rule is inserted between the old one and previously appended ones. For this to function, built-in chains need to be in cache. Consequently, batch jobs with type NFT_COMPAT_CHAIN_ADD must not delete their payload. A nice side-effect of that is when initializing builtin tables/chains, no explicit call to nft_commit() is required anymore. Signed-off-by: Phil Sutter --- iptables/nft.c | 181 +++++++++++------- .../ipt-restore/0003-restore-ordering_0 | 94 +++++++++ .../testcases/iptables/0005-rule-replace_0 | 38 ++++ 3 files changed, 241 insertions(+), 72 deletions(-) create mode 100755 iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0 create mode 100755 iptables/tests/shell/testcases/iptables/0005-rule-replace_0 diff --git a/iptables/nft.c b/iptables/nft.c index 3e2fa30650c26..733e3b5823672 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -644,6 +644,7 @@ static void nft_chain_builtin_add(struct nft_handle *h, return; batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c); + nftnl_chain_list_add_tail(c, h->table[table->type].chain_cache); } /* find if built-in table already exists */ @@ -1193,7 +1194,6 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table, { struct nftnl_chain *c; struct nftnl_rule *r; - int type; /* If built-in chains don't exist for this table, create them */ if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) @@ -1207,21 +1207,18 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table, if (handle > 0) { nftnl_rule_set(r, NFTNL_RULE_HANDLE, &handle); - type = NFT_COMPAT_RULE_REPLACE; - } else - type = NFT_COMPAT_RULE_APPEND; - - if (batch_rule_add(h, type, r) < 0) { - nftnl_rule_free(r); - return 0; + if (batch_rule_add(h, NFT_COMPAT_RULE_REPLACE, r) < 0) { + nftnl_rule_free(r); + return 0; + } } if (verbose) h->ops->print_rule(r, 0, FMT_PRINT_RULE); c = nft_chain_find(h, table, chain, true); - if (c) - nftnl_chain_rule_add(r, c); + assert(c); + nftnl_chain_rule_add_tail(r, c); return 1; } @@ -1396,7 +1393,7 @@ static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data) return MNL_CB_OK; } - nftnl_chain_rule_add(r, c); + nftnl_chain_rule_add_tail(r, c); return MNL_CB_OK; } @@ -2044,37 +2041,11 @@ int nft_rule_delete(struct nft_handle *h, const char *chain, return ret; } -static struct nftnl_rule * -nft_rule_add(struct nft_handle *h, const char *chain, - const char *table, struct iptables_command_state *cs, - uint64_t handle, bool verbose) -{ - struct nftnl_rule *r; - - r = nft_rule_new(h, chain, table, cs); - if (r == NULL) - return NULL; - - if (handle > 0) - nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, handle); - - if (batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r) < 0) { - nftnl_rule_free(r); - return NULL; - } - - if (verbose) - h->ops->print_rule(r, 0, FMT_PRINT_RULE); - - return r; -} - int nft_rule_insert(struct nft_handle *h, const char *chain, const char *table, void *data, int rulenum, bool verbose) { - struct nftnl_rule *r, *new_rule; + struct nftnl_rule *r = NULL, *new_rule; struct nftnl_chain *c; - uint64_t handle = 0; /* If built-in chains don't exist for this table, create them */ if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) @@ -2089,31 +2060,23 @@ int nft_rule_insert(struct nft_handle *h, const char *chain, } if (rulenum > 0) { - r = nft_rule_find(h, c, data, rulenum); + r = nft_rule_find(h, c, data, rulenum - 1); if (r == NULL) { - /* special case: iptables allows to insert into - * rule_count + 1 position. - */ - r = nft_rule_find(h, c, data, rulenum - 1); - if (r != NULL) - return nft_rule_append(h, chain, table, data, - 0, verbose); - errno = ENOENT; goto err; } - - handle = nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE); - DEBUGP("adding after rule handle %"PRIu64"\n", handle); } - new_rule = nft_rule_add(h, chain, table, data, handle, verbose); + new_rule = nft_rule_new(h, chain, table, data); if (!new_rule) goto err; - if (handle) + if (verbose) + h->ops->print_rule(new_rule, 0, FMT_PRINT_RULE); + + if (r) /* insert new rule after r */ nftnl_chain_rule_insert_at(new_rule, r); - else + else /* insert new rule at beginning of list */ nftnl_chain_rule_add(new_rule, c); return 1; @@ -2273,16 +2236,8 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, bool found = false; /* If built-in chains don't exist for this table, create them */ - if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) { + if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) nft_xt_builtin_init(h, table); - /* Force table and chain creation, otherwise first iptables -L - * lists no table/chains. - */ - if (!list_empty(&h->obj_list)) { - nft_commit(h); - flush_chain_cache(h, NULL); - } - } ops = nft_family_ops_lookup(h->family); @@ -2388,16 +2343,8 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain, int ret = 0; /* If built-in chains don't exist for this table, create them */ - if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) { + if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) nft_xt_builtin_init(h, table); - /* Force table and chain creation, otherwise first iptables -L - * lists no table/chains. - */ - if (!list_empty(&h->obj_list)) { - nft_commit(h); - flush_chain_cache(h, NULL); - } - } if (!nft_is_table_compatible(h, table)) { xtables_error(OTHER_PROBLEM, "table `%s' is incompatible, use 'nft' tool.\n", table); @@ -2516,8 +2463,8 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o) break; case NFT_COMPAT_CHAIN_ZERO: case NFT_COMPAT_CHAIN_USER_ADD: - break; case NFT_COMPAT_CHAIN_ADD: + break; case NFT_COMPAT_CHAIN_USER_DEL: case NFT_COMPAT_CHAIN_USER_FLUSH: case NFT_COMPAT_CHAIN_UPDATE: @@ -2538,6 +2485,78 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o) free(o); } +struct rule_stack_data { + struct nft_handle *h; + uint64_t handle; + uint32_t seq; +}; + +static int rule_stack_cb(struct nftnl_rule *r, void *data) +{ + struct rule_stack_data *rsd = data; + uint16_t flags = NLM_F_CREATE; + + if (rsd->handle) { + /* append rule to previous in-kernel one */ + flags |= NLM_F_APPEND; + nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, rsd->handle); + } + nft_compat_rule_batch_add(rsd->h, NFT_MSG_NEWRULE, + flags, rsd->seq++, r); + mnl_nft_batch_continue(rsd->h->batch); + nftnl_rule_list_del(r); + nftnl_rule_free(r); + return 0; +} + +struct batch_from_chain_cache_data { + struct nft_handle *handle; + uint32_t seq; +}; + +static int batch_from_chain_cache(struct nftnl_chain *c, void *data) +{ + struct batch_from_chain_cache_data *d = data; + struct rule_stack_data rsd = { + .h = d->handle, + .seq = d->seq, + }; + struct nftnl_rule_list *stack; + struct nftnl_rule_iter *iter; + struct nftnl_rule *r; + + stack = nftnl_rule_list_alloc(); + if (!stack) + return -1; + + iter = nftnl_rule_iter_create(c); + if (!iter) + return -1; + + r = nftnl_rule_iter_next(iter); + while (r) { + uint64_t handle = nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE); + + if (!handle) { + /* new rule to be added, put onto stack */ + nftnl_rule_list_del(r); + nftnl_rule_list_add(r, stack); + } else { + /* rule in kernel already, handle rules in stack */ + nftnl_rule_list_foreach(stack, rule_stack_cb, &rsd); + d->seq = rsd.seq; + rsd.handle = handle; + } + r = nftnl_rule_iter_next(iter); + } + nftnl_rule_iter_destroy(iter); + + nftnl_rule_list_foreach(stack, rule_stack_cb, &rsd); + nftnl_rule_list_free(stack); + d->seq = rsd.seq; + return 0; +} + static int nft_action(struct nft_handle *h, int action) { struct obj_update *n, *tmp; @@ -2621,6 +2640,24 @@ static int nft_action(struct nft_handle *h, int action) mnl_nft_batch_continue(h->batch); } + if (h->have_cache) { + struct batch_from_chain_cache_data d = { + .handle = h, + .seq = seq, + }; + + for (i = 0; i < NFT_TABLE_MAX; i++) { + const char *cur_table = h->tables[i].name; + + if (!cur_table) + continue; + + nftnl_chain_list_foreach(h->table[i].chain_cache, + batch_from_chain_cache, &d); + } + seq = d.seq; + } + switch (action) { case NFT_COMPAT_COMMIT: mnl_batch_end(h->batch, seq++); diff --git a/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0 b/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0 new file mode 100755 index 0000000000000..44ee796ef44df --- /dev/null +++ b/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0 @@ -0,0 +1,94 @@ +#!/bin/bash + +# Make sure iptables-restore does the right thing +# when encountering INSERT rules with index. + +set -e + +# show rules, drop uninteresting policy settings +ipt_show() { + $XT_MULTI iptables -S | grep -v '^-P' +} + +# basic issue reproducer + +$XT_MULTI iptables-restore < X-Patchwork-Id: 1012783 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=nwl.cc Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43Frj43Vpmz9s4s for ; Thu, 13 Dec 2018 22:16:24 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728364AbeLMLQY (ORCPT ); Thu, 13 Dec 2018 06:16:24 -0500 Received: from orbyte.nwl.cc ([151.80.46.58]:58052 "EHLO orbyte.nwl.cc" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727544AbeLMLQY (ORCPT ); Thu, 13 Dec 2018 06:16:24 -0500 Received: from localhost ([::1]:42910 helo=tatos) by orbyte.nwl.cc with esmtp (Exim 4.91) (envelope-from ) id 1gXOyc-00075w-W1; Thu, 13 Dec 2018 12:16:23 +0100 From: Phil Sutter To: Pablo Neira Ayuso Cc: netfilter-devel@vger.kernel.org Subject: [iptables PATCH v2 14/14] xtables: Do not change ruleset while listing Date: Thu, 13 Dec 2018 12:16:07 +0100 Message-Id: <20181213111607.5457-15-phil@nwl.cc> X-Mailer: git-send-email 2.19.0 In-Reply-To: <20181213111607.5457-1-phil@nwl.cc> References: <20181213111607.5457-1-phil@nwl.cc> MIME-Version: 1.0 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org When only listing rules, avoid to create the basic ruleset. Initializing the latter is still needed so that a completely empty ruleset does not lead to no output. But with builtin chains being added to cache immediately, there is no need to push the changes to the kernel anymore. Avoid this by calling nft_abort() in the right spots. Signed-off-by: Phil Sutter --- iptables/xtables-arp.c | 1 + iptables/xtables-eb.c | 1 + iptables/xtables.c | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index 2f369d9aadb01..10cc4c9fbc875 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -1366,6 +1366,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, options&OPT_NUMERIC, /*options&OPT_EXPANDED*/0, options&OPT_LINENUMBERS); + nft_abort(h); break; case CMD_FLUSH: ret = nft_rule_flush(h, chain, *table, options & OPT_VERBOSE); diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index efc1f16ac6364..51730ed8f0d94 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -1289,6 +1289,7 @@ print_zero: /*flags&OPT_EXPANDED*/0, flags&LIST_N, flags&LIST_C); + nft_abort(h); } if (flags & OPT_ZERO) { ret = nft_chain_zero_counters(h, chain, *table, 0); diff --git a/iptables/xtables.c b/iptables/xtables.c index 24a6e234bcf4b..e58d9ae2d562f 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -1143,6 +1143,8 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, cs.options & OPT_NUMERIC, cs.options & OPT_EXPANDED, cs.options & OPT_LINENUMBERS); + if (p.command == CMD_LIST) + nft_abort(h); if (ret && (p.command & CMD_ZERO)) { ret = nft_chain_zero_counters(h, p.chain, p.table, cs.options & OPT_VERBOSE); @@ -1158,6 +1160,8 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, case CMD_LIST_RULES|CMD_ZERO_NUM: ret = list_rules(h, p.chain, p.table, p.rulenum, cs.options & OPT_VERBOSE); + if (p.command == CMD_LIST_RULES) + nft_abort(h); if (ret && (p.command & CMD_ZERO)) { ret = nft_chain_zero_counters(h, p.chain, p.table, cs.options & OPT_VERBOSE);