So we don't have to dump the chain cache content over and over again. Moreover, perform incremental updates on the chain cache to add and to delete non-base chains. Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> --- iptables/nft.c | 82 ++++++++++++++++++++++++++++------------------ iptables/nft.h | 3 +- iptables/xtables-restore.c | 5 +-- iptables/xtables-save.c | 2 +- 4 files changed, 54 insertions(+), 38 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index a04aa350a074..07801f973176 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -604,7 +604,7 @@ static void nft_chain_builtin_init(struct nft_handle *h, struct builtin_table *table) { int i; - struct nftnl_chain_list *list = nft_chain_dump(h, NULL); + struct nftnl_chain_list *list = nft_chain_dump(h); struct nftnl_chain *c; /* Initialize built-in chains if they don't exist yet */ @@ -617,8 +617,6 @@ static void nft_chain_builtin_init(struct nft_handle *h, nft_chain_builtin_add(h, table, &table->chains[i]); } - - nftnl_chain_list_free(list); } static int nft_xt_builtin_init(struct nft_handle *h, const char *table) @@ -694,8 +692,35 @@ static void flush_rule_cache(struct nft_handle *h) h->rule_cache = NULL; } +static int __flush_chain_cache(struct nftnl_chain *c, void *data) +{ + const char *tablename = data; + + if (!strcmp(nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), tablename)) { + nftnl_chain_list_del(c); + nftnl_chain_free(c); + } + + return 0; +} + +static void flush_chain_cache(struct nft_handle *h, const char *tablename) +{ + if (!h->chain_cache) + return; + + if (tablename) { + nftnl_chain_list_foreach(h->chain_cache, __flush_chain_cache, + (void *)tablename); + } else { + nftnl_chain_list_free(h->chain_cache); + h->chain_cache = NULL; + } +} + void nft_fini(struct nft_handle *h) { + flush_chain_cache(h, NULL); flush_rule_cache(h); mnl_socket_close(h->nl); } @@ -1093,14 +1118,15 @@ err: return MNL_CB_OK; } -static struct nftnl_chain_list *nftnl_chain_list_get(struct nft_handle *h, - const char *tablename) +static struct nftnl_chain_list *nftnl_chain_list_get(struct nft_handle *h) { char buf[16536]; struct nlmsghdr *nlh; struct nftnl_chain_list *list; int ret; + if (h->chain_cache) + return h->chain_cache; retry: list = nftnl_chain_list_alloc(); if (list == NULL) { @@ -1110,15 +1136,6 @@ retry: nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family, NLM_F_DUMP, h->seq); - if (tablename) { - struct nftnl_chain *t = nftnl_chain_alloc(); - - if (t) { - nftnl_chain_set(t, NFTNL_CHAIN_TABLE, tablename); - nftnl_chain_nlmsg_build_payload(nlh, t); - nftnl_chain_free(t); - } - } ret = mnl_talk(h, nlh, nftnl_chain_list_cb, list); if (ret < 0 && errno == EINTR) { @@ -1127,12 +1144,14 @@ retry: goto retry; } + h->chain_cache = list; + return list; } -struct nftnl_chain_list *nft_chain_dump(struct nft_handle *h, const char *tablename) +struct nftnl_chain_list *nft_chain_dump(struct nft_handle *h) { - return nftnl_chain_list_get(h, tablename); + return nftnl_chain_list_get(h); } static const char *policy_name[NF_ACCEPT+1] = { @@ -1186,7 +1205,6 @@ next: } nftnl_chain_list_iter_destroy(iter); - nftnl_chain_list_free(list); return 1; } @@ -1359,7 +1377,7 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table) nft_fn = nft_rule_flush; - list = nftnl_chain_list_get(h, table); + list = nftnl_chain_list_get(h); if (list == NULL) { ret = 0; goto err; @@ -1393,8 +1411,6 @@ next: nftnl_chain_list_iter_destroy(iter); flush_rule_cache(h); err: - nftnl_chain_list_free(list); - /* the core expects 1 for success and 0 for error */ return ret == 0 ? 1 : 0; } @@ -1419,6 +1435,10 @@ 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); + nft_chain_dump(h); + + nftnl_chain_list_add(c, h->chain_cache); + /* the core expects 1 for success and 0 for error */ return ret == 0 ? 1 : 0; } @@ -1438,7 +1458,7 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *tabl nft_fn = nft_chain_user_del; - list = nftnl_chain_list_get(h, table); + list = nftnl_chain_list_get(h); if (list == NULL) goto err; @@ -1469,6 +1489,7 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *tabl break; deleted_ctr++; + nftnl_chain_list_del(c); if (chain != NULL) break; @@ -1527,7 +1548,7 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain) { struct nftnl_chain_list *list; - list = nftnl_chain_list_get(h, table); + list = nftnl_chain_list_get(h); if (list == NULL) return NULL; @@ -1693,6 +1714,8 @@ static int __nft_table_flush(struct nft_handle *h, const char *table) batch_table_add(h, NFT_COMPAT_TABLE_FLUSH, t); + flush_chain_cache(h, table); + return 0; } @@ -2064,7 +2087,7 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, return 1; } - list = nft_chain_dump(h, table); + list = nft_chain_dump(h); iter = nftnl_chain_list_iter_create(list); if (iter == NULL) @@ -2118,8 +2141,6 @@ next: nftnl_chain_list_iter_destroy(iter); err: - nftnl_chain_list_free(list); - return 1; } @@ -2188,7 +2209,7 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain, struct nftnl_chain *c; int ret = 1; - list = nft_chain_dump(h, table); + list = nft_chain_dump(h); /* Dump policies and custom chains first */ if (!rulenum) @@ -2223,8 +2244,6 @@ next: nftnl_chain_list_iter_destroy(iter); err: - nftnl_chain_list_free(list); - return ret; } @@ -2285,7 +2304,6 @@ static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type, type, h->family, flags, seq); nftnl_chain_nlmsg_build_payload(nlh, chain); nft_chain_print_debug(chain, nlh); - nftnl_chain_free(chain); } static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type, @@ -2654,7 +2672,7 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain, struct nftnl_chain *c; int ret = 0; - list = nftnl_chain_list_get(h, table); + list = nftnl_chain_list_get(h); if (list == NULL) goto err; @@ -2799,7 +2817,7 @@ static int nft_are_chains_compatible(struct nft_handle *h, const char *tablename struct nftnl_chain *chain; int ret = 0; - list = nftnl_chain_list_get(h, tablename); + list = nftnl_chain_list_get(h); if (list == NULL) return -1; @@ -2820,7 +2838,7 @@ next: } nftnl_chain_list_iter_destroy(iter); - nftnl_chain_list_free(list); + return ret; } diff --git a/iptables/nft.h b/iptables/nft.h index 515832d7e37b..7a775a8db7a2 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -36,6 +36,7 @@ struct nft_handle { struct list_head err_list; struct nft_family_ops *ops; struct builtin_table *tables; + struct nftnl_chain_list *chain_cache; struct nftnl_rule_list *rule_cache; bool restore; }; @@ -67,7 +68,7 @@ int nft_table_flush(struct nft_handle *h, const char *table); 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_dump(struct nft_handle *h, const char *table); +struct nftnl_chain_list *nft_chain_dump(struct nft_handle *h); struct nftnl_chain *nft_chain_list_find(struct nftnl_chain_list *list, const char *table, const char *chain); int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list, const char *table); int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table); diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index d977dabfae50..db199218027b 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -169,7 +169,7 @@ static struct nftnl_chain_list *get_chain_list(struct nft_handle *h) { struct nftnl_chain_list *chain_list; - chain_list = nft_chain_dump(h, NULL); + chain_list = nft_chain_dump(h); if (chain_list == NULL) xtables_error(OTHER_PROBLEM, "cannot retrieve chain list\n"); @@ -447,9 +447,6 @@ void xtables_restore_parse(struct nft_handle *h, xt_params->program_name, line + 1); exit(1); } - - if (chain_list) - nftnl_chain_list_free(chain_list); } static int diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c index be98b8350aaa..8bcc31fd9d48 100644 --- a/iptables/xtables-save.c +++ b/iptables/xtables-save.c @@ -57,7 +57,7 @@ do_output(struct nft_handle *h, const char *tablename, bool counters) return 0; } - chain_list = nft_chain_dump(h, tablename); + chain_list = nft_chain_dump(h); time_t now = time(NULL); -- 2.11.0 -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html