@@ -894,8 +894,10 @@ static void flush_chain_cache(struct nft_handle *h, const char *tablename)
if (!h->have_chain_cache)
return;
- if (flush_cache(h->cache, h->tables, tablename))
+ if (flush_cache(h->cache, h->tables, tablename)) {
h->have_chain_cache = false;
+ h->have_rule_cache = false;
+ }
}
void nft_fini(struct nft_handle *h)
@@ -1276,6 +1278,14 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
nft_xt_builtin_init(h, table);
+ /* Since ebtables user-defined chain policies are implemented as last
+ * rule in nftables, rule cache is required here to treat them right. */
+ if (h->family == NFPROTO_BRIDGE) {
+ c = nft_chain_find(h, table, chain);
+ if (c && !nft_chain_builtin(c))
+ nft_build_rule_cache(h);
+ }
+
nft_fn = nft_rule_append;
r = nft_rule_new(h, chain, table, data);
@@ -1602,6 +1612,7 @@ retry:
fetch_chain_cache(h);
fetch_rule_cache(h);
h->have_chain_cache = true;
+ h->have_rule_cache = true;
mnl_genid_get(h, &genid_stop);
if (genid_start != genid_stop) {
@@ -1618,11 +1629,19 @@ void nft_build_cache(struct nft_handle *h)
__nft_build_cache(h);
}
+void nft_build_rule_cache(struct nft_handle *h)
+{
+ if (!h->have_rule_cache) {
+ fetch_rule_cache(h);
+ h->have_rule_cache = true;
+ }
+}
+
void nft_fake_cache(struct nft_handle *h)
{
int i;
- if (h->have_chain_cache)
+ if (h->have_chain_cache && h->have_rule_cache)
return;
/* fetch tables so conditional table delete logic works */
@@ -1636,10 +1655,14 @@ void nft_fake_cache(struct nft_handle *h)
h->cache->table[type].chains)
continue;
+ if (h->cache->table[type].chains)
+ continue;
+
h->cache->table[type].chains = nftnl_chain_list_alloc();
}
mnl_genid_get(h, &h->nft_genid);
h->have_chain_cache = true;
+ h->have_rule_cache = true;
}
static void __nft_flush_cache(struct nft_handle *h)
@@ -1675,7 +1698,10 @@ struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h,
if (!t)
return NULL;
- nft_build_cache(h);
+ if (!h->have_chain_cache) {
+ fetch_chain_cache(h);
+ h->have_chain_cache = true;
+ }
return h->cache->table[t->type].chains;
}
@@ -1760,6 +1786,8 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
if (!list)
return 0;
+ nft_build_rule_cache(h);
+
iter = nftnl_chain_list_iter_create(list);
if (!iter)
return 0;
@@ -1981,6 +2009,10 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain,
if (list == NULL)
return 0;
+ /* This triggers required policy rule deletion. */
+ if (h->family == NFPROTO_BRIDGE)
+ nft_build_rule_cache(h);
+
if (chain) {
c = nftnl_chain_list_lookup_byname(list, chain);
if (!c) {
@@ -2242,6 +2274,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);
+
if (rulenum >= 0)
/* Delete by rule number case */
return nftnl_rule_lookup_byindex(c, rulenum);
@@ -3062,6 +3096,8 @@ int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
if (!c)
return 0;
+ nft_build_rule_cache(h);
+
if (!strcmp(policy, "DROP"))
pval = NF_DROP;
else if (!strcmp(policy, "ACCEPT"))
@@ -3339,6 +3375,8 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
if (list == NULL)
goto err;
+ nft_build_rule_cache(h);
+
if (chain) {
c = nftnl_chain_list_lookup_byname(list, chain);
if (!c) {
@@ -3445,6 +3483,8 @@ bool nft_is_table_compatible(struct nft_handle *h, const char *tablename)
if (clist == NULL)
return false;
+ nft_build_rule_cache(h);
+
if (nftnl_chain_list_foreach(clist, nft_is_chain_compatible, h))
return false;
@@ -54,6 +54,7 @@ struct nft_handle {
struct nft_cache __cache[2];
struct nft_cache *cache;
bool have_chain_cache;
+ bool have_rule_cache;
bool restore;
bool noflush;
int8_t config_done;
@@ -74,6 +75,7 @@ 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_fake_cache(struct nft_handle *h);
/*
Introduce boolean have_rule_cache to indicate whether rules have been fetched or not. Introduce nft_build_rule_cache() to trigger explicit rule cache population. In a ruleset with many rules, this largely improves performance of commands which don't need to access the rules themselves. E.g., appending a rule to a large chain is now two magnitudes faster than before and even one magnitude faster than legacy iptables. Signed-off-by: Phil Sutter <phil@nwl.cc> --- iptables/nft.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- iptables/nft.h | 2 ++ 2 files changed, 45 insertions(+), 3 deletions(-)