summaryrefslogtreecommitdiffstats
path: root/src/cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cache.c')
-rw-r--r--src/cache.c610
1 files changed, 499 insertions, 111 deletions
diff --git a/src/cache.c b/src/cache.c
index c602f93a..c000e32c 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -6,6 +6,8 @@
* later) as published by the Free Software Foundation.
*/
+#include <nft.h>
+
#include <expression.h>
#include <statement.h>
#include <rule.h>
@@ -16,9 +18,12 @@
#include <mnl.h>
#include <libnftnl/chain.h>
#include <linux/netfilter.h>
+#include <linux/netfilter/nf_tables.h>
static unsigned int evaluate_cache_add(struct cmd *cmd, unsigned int flags)
{
+ struct set *set;
+
switch (cmd->obj) {
case CMD_OBJ_TABLE:
if (!cmd->table)
@@ -29,6 +34,10 @@ static unsigned int evaluate_cache_add(struct cmd *cmd, unsigned int flags)
NFT_CACHE_SET |
NFT_CACHE_OBJECT |
NFT_CACHE_FLOWTABLE;
+ list_for_each_entry(set, &cmd->table->sets, list) {
+ if (set->automerge)
+ flags |= NFT_CACHE_SETELEM_MAYBE;
+ }
break;
case CMD_OBJ_CHAIN:
case CMD_OBJ_SET:
@@ -96,13 +105,74 @@ static unsigned int evaluate_cache_get(struct cmd *cmd, unsigned int flags)
return flags;
}
-static unsigned int evaluate_cache_flush(struct cmd *cmd, unsigned int flags)
+struct nft_cache_filter *nft_cache_filter_init(void)
+{
+ struct nft_cache_filter *filter;
+ int i;
+
+ filter = xzalloc(sizeof(struct nft_cache_filter));
+ memset(&filter->list, 0, sizeof(filter->list));
+ for (i = 0; i < NFT_CACHE_HSIZE; i++)
+ init_list_head(&filter->obj[i].head);
+
+ return filter;
+}
+
+void nft_cache_filter_fini(struct nft_cache_filter *filter)
+{
+ int i;
+
+ for (i = 0; i < NFT_CACHE_HSIZE; i++) {
+ struct nft_filter_obj *obj, *next;
+
+ list_for_each_entry_safe(obj, next, &filter->obj[i].head, list)
+ free(obj);
+ }
+ free(filter);
+}
+
+static void cache_filter_add(struct nft_cache_filter *filter,
+ const struct cmd *cmd)
+{
+ struct nft_filter_obj *obj;
+ uint32_t hash;
+
+ obj = xmalloc(sizeof(struct nft_filter_obj));
+ obj->family = cmd->handle.family;
+ obj->table = cmd->handle.table.name;
+ obj->set = cmd->handle.set.name;
+
+ hash = djb_hash(cmd->handle.set.name) % NFT_CACHE_HSIZE;
+ list_add_tail(&obj->list, &filter->obj[hash].head);
+}
+
+static bool cache_filter_find(const struct nft_cache_filter *filter,
+ const struct handle *handle)
+{
+ struct nft_filter_obj *obj;
+ uint32_t hash;
+
+ hash = djb_hash(handle->set.name) % NFT_CACHE_HSIZE;
+
+ list_for_each_entry(obj, &filter->obj[hash].head, list) {
+ if (obj->family == handle->family &&
+ !strcmp(obj->table, handle->table.name) &&
+ !strcmp(obj->set, handle->set.name))
+ return true;
+ }
+
+ return false;
+}
+
+static unsigned int evaluate_cache_flush(struct cmd *cmd, unsigned int flags,
+ struct nft_cache_filter *filter)
{
switch (cmd->obj) {
case CMD_OBJ_SET:
case CMD_OBJ_MAP:
case CMD_OBJ_METER:
flags |= NFT_CACHE_SET;
+ cache_filter_add(filter, cmd);
break;
case CMD_OBJ_RULESET:
flags |= NFT_CACHE_FLUSHED;
@@ -133,21 +203,39 @@ static unsigned int evaluate_cache_list(struct nft_ctx *nft, struct cmd *cmd,
{
switch (cmd->obj) {
case CMD_OBJ_TABLE:
- if (filter && cmd->handle.table.name)
- filter->table = cmd->handle.table.name;
-
- flags |= NFT_CACHE_FULL | NFT_CACHE_REFRESH;
+ if (filter)
+ filter->list.family = cmd->handle.family;
+ if (!cmd->handle.table.name) {
+ flags |= NFT_CACHE_TABLE;
+ break;
+ } else if (filter) {
+ filter->list.table = cmd->handle.table.name;
+ }
+ flags |= NFT_CACHE_FULL;
+ break;
+ case CMD_OBJ_CHAIN:
+ if (filter && cmd->handle.chain.name) {
+ filter->list.family = cmd->handle.family;
+ filter->list.table = cmd->handle.table.name;
+ filter->list.chain = cmd->handle.chain.name;
+ /* implicit terse listing to fetch content of anonymous
+ * sets only when chain name is specified.
+ */
+ flags |= NFT_CACHE_TERSE;
+ }
+ flags |= NFT_CACHE_FULL;
break;
case CMD_OBJ_SET:
case CMD_OBJ_MAP:
if (filter && cmd->handle.table.name && cmd->handle.set.name) {
- filter->table = cmd->handle.table.name;
- filter->set = cmd->handle.set.name;
+ filter->list.family = cmd->handle.family;
+ filter->list.table = cmd->handle.table.name;
+ filter->list.set = cmd->handle.set.name;
}
- if (nft_output_terse(&nft->output))
- flags |= (NFT_CACHE_FULL & ~NFT_CACHE_SETELEM) | NFT_CACHE_REFRESH;
+ if (filter->list.table && filter->list.set)
+ flags |= NFT_CACHE_TABLE | NFT_CACHE_SET | NFT_CACHE_SETELEM;
else
- flags |= NFT_CACHE_FULL | NFT_CACHE_REFRESH;
+ flags |= NFT_CACHE_FULL;
break;
case CMD_OBJ_CHAINS:
flags |= NFT_CACHE_TABLE | NFT_CACHE_CHAIN;
@@ -155,32 +243,182 @@ static unsigned int evaluate_cache_list(struct nft_ctx *nft, struct cmd *cmd,
case CMD_OBJ_SETS:
case CMD_OBJ_MAPS:
flags |= NFT_CACHE_TABLE | NFT_CACHE_SET;
+ if (!nft_output_terse(&nft->output))
+ flags |= NFT_CACHE_SETELEM;
break;
+ case CMD_OBJ_FLOWTABLE:
+ if (filter &&
+ cmd->handle.table.name &&
+ cmd->handle.flowtable.name) {
+ filter->list.family = cmd->handle.family;
+ filter->list.table = cmd->handle.table.name;
+ filter->list.ft = cmd->handle.flowtable.name;
+ }
+ /* fall through */
case CMD_OBJ_FLOWTABLES:
flags |= NFT_CACHE_TABLE | NFT_CACHE_FLOWTABLE;
break;
case CMD_OBJ_RULESET:
- if (nft_output_terse(&nft->output))
- flags |= (NFT_CACHE_FULL & ~NFT_CACHE_SETELEM) | NFT_CACHE_REFRESH;
- else
- flags |= NFT_CACHE_FULL | NFT_CACHE_REFRESH;
default:
- flags |= NFT_CACHE_FULL | NFT_CACHE_REFRESH;
+ flags |= NFT_CACHE_FULL;
+ break;
+ }
+ flags |= NFT_CACHE_REFRESH;
+
+ if (nft_output_terse(&nft->output))
+ flags |= NFT_CACHE_TERSE;
+
+ return flags;
+}
+
+static unsigned int evaluate_cache_reset(struct cmd *cmd, unsigned int flags,
+ struct nft_cache_filter *filter)
+{
+ switch (cmd->obj) {
+ case CMD_OBJ_RULES:
+ case CMD_OBJ_RULE:
+ if (filter) {
+ if (cmd->handle.table.name) {
+ filter->list.family = cmd->handle.family;
+ filter->list.table = cmd->handle.table.name;
+ }
+ if (cmd->handle.chain.name)
+ filter->list.chain = cmd->handle.chain.name;
+ }
+ flags |= NFT_CACHE_SET | NFT_CACHE_FLOWTABLE |
+ NFT_CACHE_OBJECT | NFT_CACHE_CHAIN;
+ break;
+ case CMD_OBJ_ELEMENTS:
+ case CMD_OBJ_SET:
+ case CMD_OBJ_MAP:
+ flags |= NFT_CACHE_SET;
+ break;
+ default:
+ flags |= NFT_CACHE_TABLE;
break;
}
return flags;
}
-unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds,
- struct nft_cache_filter *filter)
+static int nft_handle_validate(const struct cmd *cmd, struct list_head *msgs)
+{
+ const struct handle *h = &cmd->handle;
+ const struct location *loc;
+
+ switch (cmd->obj) {
+ case CMD_OBJ_TABLE:
+ if (h->table.name &&
+ strlen(h->table.name) > NFT_NAME_MAXLEN) {
+ loc = &h->table.location;
+ goto err_name_too_long;
+ }
+ break;
+ case CMD_OBJ_RULE:
+ case CMD_OBJ_RULES:
+ case CMD_OBJ_CHAIN:
+ case CMD_OBJ_CHAINS:
+ if (h->table.name &&
+ strlen(h->table.name) > NFT_NAME_MAXLEN) {
+ loc = &h->table.location;
+ goto err_name_too_long;
+ }
+ if (h->chain.name &&
+ strlen(h->chain.name) > NFT_NAME_MAXLEN) {
+ loc = &h->chain.location;
+ goto err_name_too_long;
+ }
+ break;
+ case CMD_OBJ_ELEMENTS:
+ case CMD_OBJ_SET:
+ case CMD_OBJ_SETS:
+ case CMD_OBJ_MAP:
+ case CMD_OBJ_MAPS:
+ case CMD_OBJ_METER:
+ case CMD_OBJ_METERS:
+ if (h->table.name &&
+ strlen(h->table.name) > NFT_NAME_MAXLEN) {
+ loc = &h->table.location;
+ goto err_name_too_long;
+ }
+ if (h->set.name &&
+ strlen(h->set.name) > NFT_NAME_MAXLEN) {
+ loc = &h->set.location;
+ goto err_name_too_long;
+ }
+ break;
+ case CMD_OBJ_FLOWTABLE:
+ case CMD_OBJ_FLOWTABLES:
+ if (h->table.name &&
+ strlen(h->table.name) > NFT_NAME_MAXLEN) {
+ loc = &h->table.location;
+ goto err_name_too_long;
+ }
+ if (h->flowtable.name &&
+ strlen(h->flowtable.name) > NFT_NAME_MAXLEN) {
+ loc = &h->flowtable.location;
+ goto err_name_too_long;
+ }
+ break;
+ case CMD_OBJ_INVALID:
+ case CMD_OBJ_EXPR:
+ case CMD_OBJ_RULESET:
+ case CMD_OBJ_MARKUP:
+ case CMD_OBJ_MONITOR:
+ case CMD_OBJ_SETELEMS:
+ case CMD_OBJ_HOOKS:
+ break;
+ case CMD_OBJ_COUNTER:
+ case CMD_OBJ_COUNTERS:
+ case CMD_OBJ_QUOTA:
+ case CMD_OBJ_QUOTAS:
+ case CMD_OBJ_LIMIT:
+ case CMD_OBJ_LIMITS:
+ case CMD_OBJ_SECMARK:
+ case CMD_OBJ_SECMARKS:
+ case CMD_OBJ_SYNPROXY:
+ case CMD_OBJ_SYNPROXYS:
+ case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_CT_HELPERS:
+ case CMD_OBJ_CT_TIMEOUT:
+ case CMD_OBJ_CT_TIMEOUTS:
+ case CMD_OBJ_CT_EXPECT:
+ case CMD_OBJ_CT_EXPECTATIONS:
+ if (h->table.name &&
+ strlen(h->table.name) > NFT_NAME_MAXLEN) {
+ loc = &h->table.location;
+ goto err_name_too_long;
+ }
+ if (h->obj.name &&
+ strlen(h->obj.name) > NFT_NAME_MAXLEN) {
+ loc = &h->obj.location;
+ goto err_name_too_long;
+ }
+ break;
+ }
+
+ return 0;
+
+err_name_too_long:
+ erec_queue(error(loc, "name too long, %d characters maximum allowed",
+ NFT_NAME_MAXLEN),
+ msgs);
+ return -1;
+}
+
+int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds,
+ struct list_head *msgs, struct nft_cache_filter *filter,
+ unsigned int *pflags)
{
unsigned int flags = NFT_CACHE_EMPTY;
struct cmd *cmd;
list_for_each_entry(cmd, cmds, list) {
- if (filter->table && cmd->op != CMD_LIST)
- memset(filter, 0, sizeof(*filter));
+ if (nft_handle_validate(cmd, msgs) < 0)
+ return -1;
+
+ if (filter->list.table && cmd->op != CMD_LIST)
+ memset(&filter->list, 0, sizeof(filter->list));
switch (cmd->op) {
case CMD_ADD:
@@ -194,6 +432,7 @@ unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds,
flags = NFT_CACHE_FULL;
break;
case CMD_DELETE:
+ case CMD_DESTROY:
flags |= NFT_CACHE_TABLE |
NFT_CACHE_CHAIN |
NFT_CACHE_SET |
@@ -206,7 +445,7 @@ unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds,
flags = evaluate_cache_get(cmd, flags);
break;
case CMD_RESET:
- flags |= NFT_CACHE_TABLE;
+ flags |= evaluate_cache_reset(cmd, flags, filter);
break;
case CMD_LIST:
flags |= evaluate_cache_list(nft, cmd, flags, filter);
@@ -215,7 +454,7 @@ unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds,
flags |= NFT_CACHE_FULL;
break;
case CMD_FLUSH:
- flags = evaluate_cache_flush(cmd, flags);
+ flags = evaluate_cache_flush(cmd, flags, filter);
break;
case CMD_RENAME:
flags = evaluate_cache_rename(cmd, flags);
@@ -228,8 +467,9 @@ unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds,
break;
}
}
+ *pflags = flags;
- return flags;
+ return 0;
}
void table_cache_add(struct table *table, struct nft_cache *cache)
@@ -277,13 +517,13 @@ static int chain_cache_cb(struct nftnl_chain *nlc, void *arg)
struct chain *chain;
table_name = nftnl_chain_get_str(nlc, NFTNL_CHAIN_TABLE);
- chain_name = nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME);
family = nftnl_chain_get_u32(nlc, NFTNL_CHAIN_FAMILY);
- if (strcmp(table_name, ctx->table->handle.table.name) ||
- family != ctx->table->handle.family)
+ if (family != ctx->table->handle.family ||
+ strcmp(table_name, ctx->table->handle.table.name))
return 0;
+ chain_name = nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME);
hash = djb_hash(chain_name) % NFT_CACHE_HSIZE;
chain = netlink_delinearize_chain(ctx->nlctx, nlc);
@@ -311,12 +551,22 @@ static int chain_cache_init(struct netlink_ctx *ctx, struct table *table,
return 0;
}
-static struct nftnl_chain_list *chain_cache_dump(struct netlink_ctx *ctx,
- int *err)
+static struct nftnl_chain_list *
+chain_cache_dump(struct netlink_ctx *ctx,
+ const struct nft_cache_filter *filter, int *err)
{
struct nftnl_chain_list *chain_list;
+ const char *table = NULL;
+ const char *chain = NULL;
+ int family = NFPROTO_UNSPEC;
+
+ if (filter && filter->list.table && filter->list.chain) {
+ family = filter->list.family;
+ table = filter->list.table;
+ chain = filter->list.chain;
+ }
- chain_list = mnl_nft_chain_dump(ctx, AF_UNSPEC);
+ chain_list = mnl_nft_chain_dump(ctx, family, table, chain);
if (chain_list == NULL) {
if (errno == EINTR) {
*err = -1;
@@ -329,6 +579,21 @@ static struct nftnl_chain_list *chain_cache_dump(struct netlink_ctx *ctx,
return chain_list;
}
+void nft_chain_cache_update(struct netlink_ctx *ctx, struct table *table,
+ const char *chain)
+{
+ struct nftnl_chain_list *chain_list;
+
+ chain_list = mnl_nft_chain_dump(ctx, table->handle.family,
+ table->handle.table.name, chain);
+ if (!chain_list)
+ return;
+
+ chain_cache_init(ctx, table, chain_list);
+
+ nftnl_chain_list_free(chain_list);
+}
+
void chain_cache_add(struct chain *chain, struct table *table)
{
uint32_t hash;
@@ -356,58 +621,124 @@ struct chain *chain_cache_find(const struct table *table, const char *name)
return NULL;
}
+static int list_rule_cb(struct nftnl_rule *nlr, void *data)
+{
+ struct netlink_ctx *ctx = data;
+ const struct handle *h = ctx->data;
+ const char *table, *chain;
+ struct rule *rule;
+ uint32_t family;
+
+ family = nftnl_rule_get_u32(nlr, NFTNL_RULE_FAMILY);
+ table = nftnl_rule_get_str(nlr, NFTNL_RULE_TABLE);
+ chain = nftnl_rule_get_str(nlr, NFTNL_RULE_CHAIN);
+
+ if ((h->family != NFPROTO_UNSPEC && h->family != family) ||
+ (h->table.name && strcmp(table, h->table.name) != 0) ||
+ (h->chain.name && strcmp(chain, h->chain.name) != 0))
+ return 0;
+
+ netlink_dump_rule(nlr, ctx);
+ rule = netlink_delinearize_rule(ctx, nlr);
+ assert(rule);
+ list_add_tail(&rule->list, &ctx->list);
+
+ return 0;
+}
+
+int rule_cache_dump(struct netlink_ctx *ctx, const struct handle *h,
+ const struct nft_cache_filter *filter,
+ bool dump, bool reset)
+{
+ struct nftnl_rule_list *rule_cache;
+ const char *table = NULL;
+ const char *chain = NULL;
+ uint64_t rule_handle = 0;
+
+ if (filter) {
+ table = filter->list.table;
+ chain = filter->list.chain;
+ rule_handle = filter->list.rule_handle;
+ }
+
+ rule_cache = mnl_nft_rule_dump(ctx, h->family,
+ table, chain, rule_handle, dump, reset);
+ if (rule_cache == NULL) {
+ if (errno == EINTR)
+ return -1;
+
+ return 0;
+ }
+
+ ctx->data = h;
+ nftnl_rule_list_foreach(rule_cache, list_rule_cb, ctx);
+ nftnl_rule_list_free(rule_cache);
+ return 0;
+}
+
struct set_cache_dump_ctx {
struct netlink_ctx *nlctx;
struct table *table;
- const struct nft_cache_filter *filter;
};
static int set_cache_cb(struct nftnl_set *nls, void *arg)
{
struct set_cache_dump_ctx *ctx = arg;
+ const char *set_table;
const char *set_name;
+ uint32_t set_family;
struct set *set;
uint32_t hash;
+ set_table = nftnl_set_get_str(nls, NFTNL_SET_TABLE);
+ set_family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY);
+
+ if (set_family != ctx->table->handle.family ||
+ strcmp(set_table, ctx->table->handle.table.name))
+ return 0;
+
set = netlink_delinearize_set(ctx->nlctx, nls);
if (!set)
return -1;
- if (ctx->filter && ctx->filter->set &&
- (strcmp(ctx->filter->set, set->handle.set.name))) {
- set_free(set);
- return 0;
- }
-
set_name = nftnl_set_get_str(nls, NFTNL_SET_NAME);
hash = djb_hash(set_name) % NFT_CACHE_HSIZE;
cache_add(&set->cache, &ctx->table->set_cache, hash);
+ nftnl_set_list_del(nls);
+ nftnl_set_free(nls);
return 0;
}
static int set_cache_init(struct netlink_ctx *ctx, struct table *table,
- struct nftnl_set_list *set_list,
- const struct nft_cache_filter *filter)
+ struct nftnl_set_list *set_list)
{
struct set_cache_dump_ctx dump_ctx = {
.nlctx = ctx,
.table = table,
- .filter = filter,
};
+
nftnl_set_list_foreach(set_list, set_cache_cb, &dump_ctx);
return 0;
}
-static struct nftnl_set_list *set_cache_dump(struct netlink_ctx *ctx,
- const struct table *table,
- int *err)
+static struct nftnl_set_list *
+set_cache_dump(struct netlink_ctx *ctx,
+ const struct nft_cache_filter *filter, int *err)
{
struct nftnl_set_list *set_list;
+ int family = NFPROTO_UNSPEC;
+ const char *table = NULL;
+ const char *set = NULL;
+
+ if (filter) {
+ family = filter->list.family;
+ table = filter->list.table;
+ set = filter->list.set;
+ }
- set_list = mnl_nft_set_dump(ctx, table->handle.family,
- table->handle.table.name);
+ set_list = mnl_nft_set_dump(ctx, family, table, set);
if (!set_list) {
if (errno == EINTR) {
*err = -1;
@@ -542,10 +873,19 @@ struct ft_cache_dump_ctx {
static int ft_cache_cb(struct nftnl_flowtable *nlf, void *arg)
{
struct ft_cache_dump_ctx *ctx = arg;
- const char *ft_name;
struct flowtable *ft;
+ const char *ft_table;
+ const char *ft_name;
+ uint32_t ft_family;
uint32_t hash;
+ ft_family = nftnl_flowtable_get_u32(nlf, NFTNL_FLOWTABLE_FAMILY);
+ ft_table = nftnl_flowtable_get_str(nlf, NFTNL_FLOWTABLE_TABLE);
+
+ if (ft_family != ctx->table->handle.family ||
+ strcmp(ft_table, ctx->table->handle.table.name))
+ return 0;
+
ft = netlink_delinearize_flowtable(ctx->nlctx, nlf);
if (!ft)
return -1;
@@ -554,6 +894,8 @@ static int ft_cache_cb(struct nftnl_flowtable *nlf, void *arg)
hash = djb_hash(ft_name) % NFT_CACHE_HSIZE;
cache_add(&ft->cache, &ctx->table->ft_cache, hash);
+ nftnl_flowtable_list_del(nlf);
+ nftnl_flowtable_free(nlf);
return 0;
}
@@ -569,13 +911,21 @@ static int ft_cache_init(struct netlink_ctx *ctx, struct table *table,
return 0;
}
-static struct nftnl_flowtable_list *ft_cache_dump(struct netlink_ctx *ctx,
- const struct table *table)
+static struct nftnl_flowtable_list *
+ft_cache_dump(struct netlink_ctx *ctx, const struct nft_cache_filter *filter)
{
struct nftnl_flowtable_list *ft_list;
+ int family = NFPROTO_UNSPEC;
+ const char *table = NULL;
+ const char *ft = NULL;
+
+ if (filter) {
+ family = filter->list.family;
+ table = filter->list.table;
+ ft = filter->list.ft;
+ }
- ft_list = mnl_nft_flowtable_dump(ctx, table->handle.family,
- table->handle.table.name);
+ ft_list = mnl_nft_flowtable_dump(ctx, family, table, ft);
if (!ft_list) {
if (errno == EINTR)
return NULL;
@@ -625,24 +975,68 @@ static int cache_init_tables(struct netlink_ctx *ctx, struct handle *h,
struct table *table, *next;
int ret;
- ret = netlink_list_tables(ctx, h);
+ ret = netlink_list_tables(ctx, h, filter);
if (ret < 0)
return -1;
list_for_each_entry_safe(table, next, &ctx->list, list) {
list_del(&table->list);
-
- if (filter && filter->table &&
- (strcmp(filter->table, table->handle.table.name))) {
- table_free(table);
- continue;
- }
table_cache_add(table, cache);
}
return 0;
}
+static int rule_init_cache(struct netlink_ctx *ctx, struct table *table,
+ const struct nft_cache_filter *filter)
+{
+ struct rule *rule, *nrule;
+ struct chain *chain;
+ int ret;
+
+ ret = rule_cache_dump(ctx, &table->handle, filter, true, false);
+
+ list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
+ chain = chain_cache_find(table, rule->handle.chain.name);
+ if (!chain)
+ chain = chain_binding_lookup(table,
+ rule->handle.chain.name);
+ if (!chain)
+ goto err_ctx_list;
+
+ list_move_tail(&rule->list, &chain->rules);
+ }
+
+ return ret;
+
+err_ctx_list:
+ list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
+ list_del(&rule->list);
+ rule_free(rule);
+ }
+ errno = EINTR;
+
+ return -1;
+}
+
+static int implicit_chain_cache(struct netlink_ctx *ctx, struct table *table,
+ const char *chain_name)
+{
+ struct nft_cache_filter filter;
+ struct chain *chain;
+ int ret = 0;
+
+ list_for_each_entry(chain, &table->chain_bindings, cache.list) {
+ filter.list = (typeof(filter.list)) {
+ .table = table->handle.table.name,
+ .chain = chain->handle.chain.name,
+ };
+ ret = rule_init_cache(ctx, table, &filter);
+ }
+
+ return ret;
+}
+
static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
const struct nft_cache_filter *filter)
{
@@ -650,77 +1044,72 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
struct nftnl_chain_list *chain_list = NULL;
struct nftnl_set_list *set_list = NULL;
struct nftnl_obj_list *obj_list;
- struct rule *rule, *nrule;
struct table *table;
- struct chain *chain;
struct set *set;
int ret = 0;
if (flags & NFT_CACHE_CHAIN_BIT) {
- chain_list = chain_cache_dump(ctx, &ret);
+ chain_list = chain_cache_dump(ctx, filter, &ret);
if (!chain_list)
return -1;
}
+ if (flags & NFT_CACHE_SET_BIT) {
+ set_list = set_cache_dump(ctx, filter, &ret);
+ if (!set_list) {
+ ret = -1;
+ goto cache_fails;
+ }
+ }
+ if (flags & NFT_CACHE_FLOWTABLE_BIT) {
+ ft_list = ft_cache_dump(ctx, filter);
+ if (!ft_list) {
+ ret = -1;
+ goto cache_fails;
+ }
+ }
list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
if (flags & NFT_CACHE_SET_BIT) {
- set_list = set_cache_dump(ctx, table, &ret);
- if (!set_list) {
- ret = -1;
- goto cache_fails;
- }
- ret = set_cache_init(ctx, table, set_list, filter);
-
- nftnl_set_list_free(set_list);
-
- if (ret < 0) {
- ret = -1;
+ ret = set_cache_init(ctx, table, set_list);
+ if (ret < 0)
goto cache_fails;
- }
}
if (flags & NFT_CACHE_SETELEM_BIT) {
list_for_each_entry(set, &table->set_cache.list, cache.list) {
+ if (cache_filter_find(filter, &set->handle))
+ continue;
+ if (!set_is_anonymous(set->flags) &&
+ flags & NFT_CACHE_TERSE)
+ continue;
+
ret = netlink_list_setelems(ctx, &set->handle,
- set);
- if (ret < 0) {
- ret = -1;
+ set, false);
+ if (ret < 0)
goto cache_fails;
- }
}
} else if (flags & NFT_CACHE_SETELEM_MAYBE) {
list_for_each_entry(set, &table->set_cache.list, cache.list) {
+ if (cache_filter_find(filter, &set->handle))
+ continue;
+
if (!set_is_non_concat_range(set))
continue;
ret = netlink_list_setelems(ctx, &set->handle,
- set);
- if (ret < 0) {
- ret = -1;
+ set, false);
+ if (ret < 0)
goto cache_fails;
- }
}
}
if (flags & NFT_CACHE_CHAIN_BIT) {
ret = chain_cache_init(ctx, table, chain_list);
- if (ret < 0) {
- ret = -1;
+ if (ret < 0)
goto cache_fails;
- }
}
if (flags & NFT_CACHE_FLOWTABLE_BIT) {
- ft_list = ft_cache_dump(ctx, table);
- if (!ft_list) {
- ret = -1;
- goto cache_fails;
- }
ret = ft_cache_init(ctx, table, ft_list);
-
- nftnl_flowtable_list_free(ft_list);
-
- if (ret < 0) {
- ret = -1;
+ if (ret < 0)
goto cache_fails;
- }
}
if (flags & NFT_CACHE_OBJECT_BIT) {
obj_list = obj_cache_dump(ctx, table);
@@ -732,34 +1121,29 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
nftnl_obj_list_free(obj_list);
- if (ret < 0) {
- ret = -1;
+ if (ret < 0)
goto cache_fails;
- }
}
if (flags & NFT_CACHE_RULE_BIT) {
- ret = netlink_list_rules(ctx, &table->handle);
- list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
- chain = chain_cache_find(table, rule->handle.chain.name);
- if (!chain)
- chain = chain_binding_lookup(table,
- rule->handle.chain.name);
- if (!chain) {
- ret = -1;
- goto cache_fails;
- }
-
- list_move_tail(&rule->list, &chain->rules);
- }
- if (ret < 0) {
- ret = -1;
+ ret = rule_init_cache(ctx, table, filter);
+ if (ret < 0)
goto cache_fails;
+
+ if (filter && filter->list.table && filter->list.chain) {
+ ret = implicit_chain_cache(ctx, table, filter->list.chain);
+ if (ret < 0)
+ goto cache_fails;
}
}
}
cache_fails:
+ if (set_list)
+ nftnl_set_list_free(set_list);
+ if (ft_list)
+ nftnl_flowtable_list_free(ft_list);
+
if (flags & NFT_CACHE_CHAIN_BIT)
nftnl_chain_list_free(chain_list);
@@ -846,7 +1230,11 @@ replay:
goto replay;
}
+ erec_queue(error(&netlink_location, "cache initialization failed: %s",
+ strerror(errno)),
+ msgs);
nft_cache_release(cache);
+
return -1;
}
@@ -891,7 +1279,7 @@ void cache_init(struct cache *cache)
void cache_free(struct cache *cache)
{
- xfree(cache->ht);
+ free(cache->ht);
}
void cache_add(struct cache_item *item, struct cache *cache, uint32_t hash)