Just like with single chain fetching, pass optional table and chain names to nft_build_rule_cache() to restrict its effect onto those. This effectively makes iptables-nft ignore other tables and other chains of the same table even if rule cache is needed for an operation affecting a single chain only. Signed-off-by: Phil Sutter <phil@xxxxxx> --- iptables/nft.c | 52 ++++++++++++++++++++++++++++------------- iptables/nft.h | 6 +++-- iptables/xtables-save.c | 2 +- 3 files changed, 41 insertions(+), 19 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index 46c7be372a10f..294cb306700d0 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1283,7 +1283,7 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table, if (h->family == NFPROTO_BRIDGE) { c = nft_chain_find(h, table, chain); if (c && !nft_chain_builtin(c)) - nft_build_rule_cache(h); + nft_build_rule_cache(h, table, chain); } nft_fn = nft_rule_append; @@ -1610,7 +1610,7 @@ static int nft_rule_list_update(struct nftnl_chain *c, void *data) return 0; } -static int fetch_rule_cache(struct nft_handle *h) +static int fetch_rule_cache(struct nft_handle *h, const char *table, const char *chain) { int i; @@ -1623,9 +1623,25 @@ static int fetch_rule_cache(struct nft_handle *h) if (!h->cache->table[type].chains) continue; + if (table && strcmp(h->tables[i].name, table)) + continue; + + if (chain) { + struct nftnl_chain_list *clist; + struct nftnl_chain *c; + + clist = h->cache->table[type].chains; + c = nftnl_chain_list_lookup_byname(clist, chain); + + return c ? nft_rule_list_update(c, h) : -1; + } + if (nftnl_chain_list_foreach(h->cache->table[type].chains, nft_rule_list_update, h)) return -1; + + if (table) + break; } return 0; } @@ -1637,7 +1653,7 @@ static void __nft_build_cache(struct nft_handle *h) retry: mnl_genid_get(h, &genid_start); fetch_chain_cache(h, NULL, NULL); - fetch_rule_cache(h); + fetch_rule_cache(h, NULL, NULL); h->have_chain_cache = true; h->have_rule_cache = true; mnl_genid_get(h, &genid_stop); @@ -1656,11 +1672,13 @@ void nft_build_cache(struct nft_handle *h) __nft_build_cache(h); } -void nft_build_rule_cache(struct nft_handle *h) +void nft_build_rule_cache(struct nft_handle *h, + const char *table, const char *chain) { if (!h->have_rule_cache) { - fetch_rule_cache(h); - h->have_rule_cache = true; + fetch_rule_cache(h, table, chain); + if (!table && !chain) + h->have_rule_cache = true; } } @@ -1814,7 +1832,7 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format) if (!list) return 0; - nft_build_rule_cache(h); + nft_build_rule_cache(h, table, NULL); iter = nftnl_chain_list_iter_create(list); if (!iter) @@ -2039,7 +2057,7 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain, /* This triggers required policy rule deletion. */ if (h->family == NFPROTO_BRIDGE) - nft_build_rule_cache(h); + nft_build_rule_cache(h, table, chain); if (chain) { c = nftnl_chain_list_lookup_byname(list, chain); @@ -2302,7 +2320,8 @@ nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulen struct nftnl_rule_iter *iter; bool found = false; - nft_build_rule_cache(h); + nft_build_rule_cache(h, nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), + nftnl_chain_get_str(c, NFTNL_CHAIN_NAME)); if (rulenum >= 0) /* Delete by rule number case */ @@ -2607,7 +2626,7 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, ops = nft_family_ops_lookup(h->family); - if (!nft_is_table_compatible(h, table)) { + if (!nft_is_table_compatible(h, table, chain)) { xtables_error(OTHER_PROBLEM, "table `%s' is incompatible, use 'nft' tool.\n", table); return 0; } @@ -2710,7 +2729,7 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain, nft_xt_builtin_init(h, table); - if (!nft_is_table_compatible(h, table)) { + if (!nft_is_table_compatible(h, table, chain)) { xtables_error(OTHER_PROBLEM, "table `%s' is incompatible, use 'nft' tool.\n", table); return 0; } @@ -3124,7 +3143,7 @@ int ebt_set_user_chain_policy(struct nft_handle *h, const char *table, if (!c) return 0; - nft_build_rule_cache(h); + nft_build_rule_cache(h, table, chain); if (!strcmp(policy, "DROP")) pval = NF_DROP; @@ -3403,7 +3422,7 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain, if (list == NULL) goto err; - nft_build_rule_cache(h); + nft_build_rule_cache(h, table, chain); if (chain) { c = nftnl_chain_list_lookup_byname(list, chain); @@ -3503,15 +3522,16 @@ static int nft_is_chain_compatible(struct nftnl_chain *c, void *data) return 0; } -bool nft_is_table_compatible(struct nft_handle *h, const char *tablename) +bool nft_is_table_compatible(struct nft_handle *h, + const char *tablename, const char *chainname) { struct nftnl_chain_list *clist; - clist = nft_chain_list_get(h, tablename, NULL); + clist = nft_chain_list_get(h, tablename, chainname); if (clist == NULL) return false; - nft_build_rule_cache(h); + nft_build_rule_cache(h, tablename, chainname); if (nftnl_chain_list_foreach(clist, nft_is_chain_compatible, h)) return false; diff --git a/iptables/nft.h b/iptables/nft.h index 4b1c191effbd6..e6bfdf34103b1 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -75,7 +75,8 @@ int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh, int nft_init(struct nft_handle *h, const struct builtin_table *t); void nft_fini(struct nft_handle *h); void nft_build_cache(struct nft_handle *h); -void nft_build_rule_cache(struct nft_handle *h); +void nft_build_rule_cache(struct nft_handle *h, + const char *table, const char *chain); void nft_fake_cache(struct nft_handle *h); /* @@ -202,7 +203,8 @@ int nft_arp_rule_insert(struct nft_handle *h, const char *chain, void nft_rule_to_arpt_entry(struct nftnl_rule *r, struct arpt_entry *fw); -bool nft_is_table_compatible(struct nft_handle *h, const char *name); +bool nft_is_table_compatible(struct nft_handle *h, + const char *table, const char *chain); int ebt_set_user_chain_policy(struct nft_handle *h, const char *table, const char *chain, const char *policy); diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c index 503ae401737c5..000104d3b51ae 100644 --- a/iptables/xtables-save.c +++ b/iptables/xtables-save.c @@ -76,7 +76,7 @@ __do_output(struct nft_handle *h, const char *tablename, void *data) if (!nft_table_builtin_find(h, tablename)) return 0; - if (!nft_is_table_compatible(h, tablename)) { + if (!nft_is_table_compatible(h, tablename, NULL)) { printf("# Table `%s' is incompatible, use 'nft' tool.\n", tablename); return 0; -- 2.23.0