@@ -683,13 +683,30 @@ int nft_init(struct nft_handle *h, struct builtin_table *t)
return 0;
}
-static void flush_rule_cache(struct nft_handle *h)
+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);
+ }
+
+ return 0;
+}
+
+static void flush_rule_cache(struct nft_handle *h, const char *tablename)
{
if (!h->rule_cache)
return;
- nftnl_rule_list_free(h->rule_cache);
- h->rule_cache = NULL;
+ 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;
+ }
}
static int __flush_chain_cache(struct nftnl_chain *c, void *data)
@@ -721,7 +738,7 @@ static void flush_chain_cache(struct nft_handle *h, const char *tablename)
void nft_fini(struct nft_handle *h)
{
flush_chain_cache(h, NULL);
- flush_rule_cache(h);
+ flush_rule_cache(h, NULL);
mnl_socket_close(h->nl);
}
@@ -1038,6 +1055,8 @@ err:
return NULL;
}
+static struct nftnl_rule_list *nft_rule_list_get(struct nft_handle *h);
+
int
nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
void *data, uint64_t handle, bool verbose)
@@ -1064,7 +1083,10 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
if (batch_rule_add(h, type, r) < 0)
nftnl_rule_free(r);
- flush_rule_cache(h);
+ nft_rule_list_get(h);
+
+ nftnl_rule_list_add_tail(r, h->rule_cache);
+
return 1;
}
@@ -1407,9 +1429,9 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table)
next:
c = nftnl_chain_list_iter_next(iter);
}
+ flush_rule_cache(h, table);
nftnl_chain_list_iter_destroy(iter);
- flush_rule_cache(h);
err:
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
@@ -1715,6 +1737,7 @@ 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);
+ flush_rule_cache(h, table);
return 0;
}
@@ -1755,6 +1778,10 @@ next:
t = nftnl_table_list_iter_next(iter);
}
+ 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:
@@ -1866,12 +1893,10 @@ int nft_rule_delete(struct nft_handle *h, const char *chain,
} else
errno = ENOENT;
- flush_rule_cache(h);
-
return ret;
}
-static int
+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)
@@ -1880,25 +1905,24 @@ nft_rule_add(struct nft_handle *h, const char *chain,
r = nft_rule_new(h, chain, table, cs);
if (r == NULL)
- return 0;
+ 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 0;
+ return NULL;
}
- flush_rule_cache(h);
- return 1;
+ 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_list *list;
- struct nftnl_rule *r;
uint64_t handle = 0;
/* If built-in chains don't exist for this table, create them */
@@ -1919,11 +1943,9 @@ int nft_rule_insert(struct nft_handle *h, const char *chain,
*/
r = nft_rule_find(h, list, chain, table, data,
rulenum - 1);
- if (r != NULL) {
- flush_rule_cache(h);
+ if (r != NULL)
return nft_rule_append(h, chain, table, data,
0, verbose);
- }
errno = ENOENT;
goto err;
@@ -1931,13 +1953,21 @@ 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);
-
- flush_rule_cache(h);
+ } else {
+ nft_rule_list_get(h);
}
- return nft_rule_add(h, chain, table, data, handle, verbose);
+ new_rule = nft_rule_add(h, chain, table, data, handle, verbose);
+ if (!new_rule)
+ goto err;
+
+ if (handle)
+ nftnl_rule_list_insert_at(new_rule, r);
+ else
+ nftnl_rule_list_add(new_rule, h->rule_cache);
+
+ return 1;
err:
- flush_rule_cache(h);
return 0;
}
@@ -1965,8 +1995,6 @@ int nft_rule_delete_num(struct nft_handle *h, const char *chain,
} else
errno = ENOENT;
- flush_rule_cache(h);
-
return ret;
}
@@ -1989,14 +2017,14 @@ int nft_rule_replace(struct nft_handle *h, const char *chain,
(unsigned long long)
nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE));
+ nftnl_rule_list_del(r);
+
ret = nft_rule_append(h, chain, table, data,
nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE),
verbose);
} else
errno = ENOENT;
- flush_rule_cache(h);
-
return ret;
}
@@ -2277,8 +2305,6 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
false);
error:
- flush_rule_cache(h);
-
return ret;
}
@@ -2316,7 +2342,6 @@ static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type,
type, h->family, flags, seq);
nftnl_rule_nlmsg_build_payload(nlh, rule);
nft_rule_print_debug(rule, nlh);
- nftnl_rule_free(rule);
}
static int nft_action(struct nft_handle *h, int action)
Perform incremental tracking on rule cache updates, instead of flushing and resynchronizing with the kernel over and over again. Note that there is no need to call flush_rule_cache() from nft_rule_delete() and nft_rule_delete_num(), since __nft_rule_del() already deletes the rule from the list. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> --- iptables/nft.c | 81 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 28 deletions(-)