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@xxxxxxxxxxxxx> --- iptables/nft.c | 81 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index 07801f973176..3cfd23c7cdab 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -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) -- 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