summaryrefslogtreecommitdiffstats
path: root/iptables
diff options
context:
space:
mode:
authorPhil Sutter <phil@nwl.cc>2020-03-18 17:08:31 +0100
committerPhil Sutter <phil@nwl.cc>2020-05-11 14:28:28 +0200
commit13b351c9ba01751c693df68f657d19e8c3d267ce (patch)
treed3710e31d4ab080bee1d3dc0ee658989401b60dc /iptables
parent6d1d5aa5c93eca890e28b508ef426b7844caf2b7 (diff)
nft-cache: Fetch cache per table
Restore per-table operation of cache routines as initially implemented in commit e2883c5531e6e ("nft-cache: Support partial cache per table"). As before, this doesn't limit fetching of tables (their number is supposed to be low) but instead limits fetching of sets, chains and rules to the specified table. For this to behave correctly when restoring without flushing over multiple tables, cache must be freed fully after each commit - otherwise the previous table's cache level is reused for the current one. The exception being fake cache, used for flushing restore: NFT_CL_FAKE is set just once at program startup, so it must stay set otherwise consecutive tables cause pointless cache fetching. The sole use-case requiring a multi-table cache, iptables-save, is indicated by req->table being NULL. Therefore, req->table assignment is a bit sloppy: All calls to nft_cache_level_set() are assumed to set the same table value, collision detection exists merely to catch programming mistakes. Make nft_fini() call nft_release_cache() instead of flush_chain_cache(), the former does a full cache deinit including cache_req contents. Signed-off-by: Phil Sutter <phil@nwl.cc>
Diffstat (limited to 'iptables')
-rw-r--r--iptables/nft-cache.c40
-rw-r--r--iptables/nft-cache.h4
-rw-r--r--iptables/nft-cmd.c57
-rw-r--r--iptables/nft.c2
-rw-r--r--iptables/nft.h1
-rw-r--r--iptables/xtables-restore.c2
-rw-r--r--iptables/xtables-save.c2
7 files changed, 64 insertions, 44 deletions
diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c
index 305f2c12..61184653 100644
--- a/iptables/nft-cache.c
+++ b/iptables/nft-cache.c
@@ -11,6 +11,7 @@
#include <assert.h>
#include <errno.h>
+#include <stdlib.h>
#include <string.h>
#include <xtables.h>
@@ -24,14 +25,21 @@
#include "nft.h"
#include "nft-cache.h"
-void nft_cache_level_set(struct nft_handle *h, int level)
+void nft_cache_level_set(struct nft_handle *h, int level,
+ const struct nft_cmd *cmd)
{
struct nft_cache_req *req = &h->cache_req;
- if (level <= req->level)
+ if (level > req->level)
+ req->level = level;
+
+ if (!cmd)
return;
- req->level = level;
+ if (!req->table)
+ req->table = strdup(cmd->table);
+ else
+ assert(!strcmp(req->table, cmd->table));
}
static int genid_cb(const struct nlmsghdr *nlh, void *data)
@@ -435,10 +443,14 @@ static void
__nft_build_cache(struct nft_handle *h)
{
struct nft_cache_req *req = &h->cache_req;
+ const struct builtin_table *t = NULL;
if (h->cache_init)
return;
+ if (req->table)
+ t = nft_table_builtin_find(h, req->table);
+
h->cache_init = true;
mnl_genid_get(h, &h->nft_genid);
@@ -447,11 +459,11 @@ __nft_build_cache(struct nft_handle *h)
if (req->level == NFT_CL_FAKE)
return;
if (req->level >= NFT_CL_CHAINS)
- fetch_chain_cache(h, NULL, NULL);
+ fetch_chain_cache(h, t, NULL);
if (req->level >= NFT_CL_SETS)
- fetch_set_cache(h, NULL, NULL);
+ fetch_set_cache(h, t, NULL);
if (req->level >= NFT_CL_RULES)
- fetch_rule_cache(h, NULL);
+ fetch_rule_cache(h, t);
}
static void __nft_flush_cache(struct nft_handle *h)
@@ -575,14 +587,20 @@ void nft_cache_build(struct nft_handle *h)
void nft_release_cache(struct nft_handle *h)
{
- if (!h->cache_index)
- return;
+ struct nft_cache_req *req = &h->cache_req;
+ while (h->cache_index)
+ flush_cache(h, &h->__cache[h->cache_index--], NULL);
flush_cache(h, &h->__cache[0], NULL);
- memcpy(&h->__cache[0], &h->__cache[1], sizeof(h->__cache[0]));
- memset(&h->__cache[1], 0, sizeof(h->__cache[1]));
- h->cache_index = 0;
h->cache = &h->__cache[0];
+ h->cache_init = false;
+
+ if (req->level != NFT_CL_FAKE)
+ req->level = NFT_CL_TABLES;
+ if (req->table) {
+ free(req->table);
+ req->table = NULL;
+ }
}
struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h)
diff --git a/iptables/nft-cache.h b/iptables/nft-cache.h
index 01dd15e1..f4291180 100644
--- a/iptables/nft-cache.h
+++ b/iptables/nft-cache.h
@@ -2,8 +2,10 @@
#define _NFT_CACHE_H_
struct nft_handle;
+struct nft_cmd;
-void nft_cache_level_set(struct nft_handle *h, int level);
+void nft_cache_level_set(struct nft_handle *h, int level,
+ const struct nft_cmd *cmd);
void nft_rebuild_cache(struct nft_handle *h);
void nft_release_cache(struct nft_handle *h);
void flush_chain_cache(struct nft_handle *h, const char *tablename);
diff --git a/iptables/nft-cmd.c b/iptables/nft-cmd.c
index 8bf361a6..23f2761f 100644
--- a/iptables/nft-cmd.c
+++ b/iptables/nft-cmd.c
@@ -71,12 +71,11 @@ void nft_cmd_free(struct nft_cmd *cmd)
free(cmd);
}
-static void nft_cmd_rule_bridge(struct nft_handle *h, const char *chain,
- const char *table)
+static void nft_cmd_rule_bridge(struct nft_handle *h, const struct nft_cmd *cmd)
{
const struct builtin_table *t;
- t = nft_table_builtin_find(h, table);
+ t = nft_table_builtin_find(h, cmd->table);
if (!t)
return;
@@ -84,10 +83,10 @@ static void nft_cmd_rule_bridge(struct nft_handle *h, const char *chain,
* rule in nftables, rule cache is required here to treat them right.
*/
if (h->family == NFPROTO_BRIDGE &&
- !nft_chain_builtin_find(t, chain))
- nft_cache_level_set(h, NFT_CL_RULES);
+ !nft_chain_builtin_find(t, cmd->chain))
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
else
- nft_cache_level_set(h, NFT_CL_CHAINS);
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
}
int nft_cmd_rule_append(struct nft_handle *h, const char *chain,
@@ -96,13 +95,13 @@ int nft_cmd_rule_append(struct nft_handle *h, const char *chain,
{
struct nft_cmd *cmd;
- nft_cmd_rule_bridge(h, chain, table);
-
cmd = nft_cmd_new(h, NFT_COMPAT_RULE_APPEND, table, chain, state, -1,
verbose);
if (!cmd)
return 0;
+ nft_cmd_rule_bridge(h, cmd);
+
return 1;
}
@@ -112,17 +111,17 @@ int nft_cmd_rule_insert(struct nft_handle *h, const char *chain,
{
struct nft_cmd *cmd;
- nft_cmd_rule_bridge(h, chain, table);
-
cmd = nft_cmd_new(h, NFT_COMPAT_RULE_INSERT, table, chain, state,
rulenum, verbose);
if (!cmd)
return 0;
+ nft_cmd_rule_bridge(h, cmd);
+
if (cmd->rulenum > 0)
- nft_cache_level_set(h, NFT_CL_RULES);
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
else
- nft_cache_level_set(h, NFT_CL_CHAINS);
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
return 1;
}
@@ -138,7 +137,7 @@ int nft_cmd_rule_delete(struct nft_handle *h, const char *chain,
if (!cmd)
return 0;
- nft_cache_level_set(h, NFT_CL_RULES);
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
return 1;
}
@@ -153,7 +152,7 @@ int nft_cmd_rule_delete_num(struct nft_handle *h, const char *chain,
if (!cmd)
return 0;
- nft_cache_level_set(h, NFT_CL_RULES);
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
return 1;
}
@@ -168,7 +167,7 @@ int nft_cmd_rule_flush(struct nft_handle *h, const char *chain,
if (!cmd)
return 0;
- nft_cache_level_set(h, NFT_CL_CHAINS);
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
return 1;
}
@@ -183,7 +182,7 @@ int nft_cmd_chain_zero_counters(struct nft_handle *h, const char *chain,
if (!cmd)
return 0;
- nft_cache_level_set(h, NFT_CL_CHAINS);
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
return 1;
}
@@ -198,7 +197,7 @@ int nft_cmd_chain_user_add(struct nft_handle *h, const char *chain,
if (!cmd)
return 0;
- nft_cache_level_set(h, NFT_CL_CHAINS);
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
return 1;
}
@@ -217,9 +216,9 @@ int nft_cmd_chain_user_del(struct nft_handle *h, const char *chain,
* rule cache.
*/
if (h->family == NFPROTO_BRIDGE)
- nft_cache_level_set(h, NFT_CL_RULES);
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
else
- nft_cache_level_set(h, NFT_CL_CHAINS);
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
return 1;
}
@@ -236,7 +235,7 @@ int nft_cmd_chain_user_rename(struct nft_handle *h,const char *chain,
cmd->rename = strdup(newname);
- nft_cache_level_set(h, NFT_CL_CHAINS);
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
return 1;
}
@@ -253,7 +252,7 @@ int nft_cmd_rule_list(struct nft_handle *h, const char *chain,
cmd->format = format;
- nft_cache_level_set(h, NFT_CL_RULES);
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
return 1;
}
@@ -269,7 +268,7 @@ int nft_cmd_rule_replace(struct nft_handle *h, const char *chain,
if (!cmd)
return 0;
- nft_cache_level_set(h, NFT_CL_RULES);
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
return 1;
}
@@ -284,7 +283,7 @@ int nft_cmd_rule_check(struct nft_handle *h, const char *chain,
if (!cmd)
return 0;
- nft_cache_level_set(h, NFT_CL_RULES);
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
return 1;
}
@@ -304,7 +303,7 @@ int nft_cmd_chain_set(struct nft_handle *h, const char *table,
if (counters)
cmd->counters = *counters;
- nft_cache_level_set(h, NFT_CL_CHAINS);
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
return 1;
}
@@ -318,7 +317,7 @@ int nft_cmd_table_flush(struct nft_handle *h, const char *table)
if (!cmd)
return 0;
- nft_cache_level_set(h, NFT_CL_TABLES);
+ nft_cache_level_set(h, NFT_CL_TABLES, cmd);
return 1;
}
@@ -333,7 +332,7 @@ int nft_cmd_chain_restore(struct nft_handle *h, const char *chain,
if (!cmd)
return 0;
- nft_cache_level_set(h, NFT_CL_CHAINS);
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
return 1;
}
@@ -348,7 +347,7 @@ int nft_cmd_rule_zero_counters(struct nft_handle *h, const char *chain,
if (!cmd)
return 0;
- nft_cache_level_set(h, NFT_CL_RULES);
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
return 1;
}
@@ -365,7 +364,7 @@ int nft_cmd_rule_list_save(struct nft_handle *h, const char *chain,
cmd->counters_save = counters;
- nft_cache_level_set(h, NFT_CL_RULES);
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
return 1;
}
@@ -382,7 +381,7 @@ int ebt_cmd_user_chain_policy(struct nft_handle *h, const char *table,
cmd->policy = strdup(policy);
- nft_cache_level_set(h, NFT_CL_RULES);
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
return 1;
}
diff --git a/iptables/nft.c b/iptables/nft.c
index f9e53316..daf08604 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -816,7 +816,7 @@ void nft_fini(struct nft_handle *h)
list_for_each_entry_safe(cmd, next, &h->cmd_list, head)
nft_cmd_free(cmd);
- flush_chain_cache(h, NULL);
+ nft_release_cache(h);
mnl_socket_close(h->nl);
}
diff --git a/iptables/nft.h b/iptables/nft.h
index c6aece7d..4eaaa77f 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -73,6 +73,7 @@ enum obj_update_type {
struct nft_cache_req {
enum nft_cache_level level;
+ char *table;
};
struct nft_handle {
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index 28ef366c..418a7400 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -261,7 +261,7 @@ void xtables_restore_parse(struct nft_handle *h,
char buffer[10240] = {};
if (!h->noflush)
- nft_cache_level_set(h, NFT_CL_FAKE);
+ nft_cache_level_set(h, NFT_CL_FAKE, NULL);
line = 0;
while (fgets(buffer, sizeof(buffer), p->in)) {
diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c
index f927aa6e..0ce66e5d 100644
--- a/iptables/xtables-save.c
+++ b/iptables/xtables-save.c
@@ -239,7 +239,7 @@ xtables_save_main(int family, int argc, char *argv[],
exit(EXIT_FAILURE);
}
- nft_cache_level_set(&h, NFT_CL_RULES);
+ nft_cache_level_set(&h, NFT_CL_RULES, NULL);
nft_cache_build(&h);
ret = do_output(&h, tablename, &d);