summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhil Sutter <phil@nwl.cc>2021-11-29 16:26:44 +0100
committerPhil Sutter <phil@nwl.cc>2021-12-03 12:50:18 +0100
commit17297d1acbbff0133f8614dbee6717edf55c39f8 (patch)
treed3d0f078888445061be8af50cdf4045b6e62f982
parent95781fcbddcd6524f67a3357c0cf91f13be24053 (diff)
cache: Filter chain list on kernel side
When operating on a specific chain, add payload to NFT_MSG_GETCHAIN so kernel returns only relevant data. Since ENOENT is an expected return code, do not treat this as error. While being at it, improve code in chain_cache_cb() a bit: - Check chain's family first, it is a less expensive check than comparing table names. - Do not extract chain name of uninteresting chains. Signed-off-by: Phil Sutter <phil@nwl.cc>
-rw-r--r--include/mnl.h3
-rw-r--r--src/cache.c38
-rw-r--r--src/mnl.c21
3 files changed, 39 insertions, 23 deletions
diff --git a/include/mnl.h b/include/mnl.h
index 19faa651..9d54aac8 100644
--- a/include/mnl.h
+++ b/include/mnl.h
@@ -43,7 +43,8 @@ int mnl_nft_chain_rename(struct netlink_ctx *ctx, const struct cmd *cmd,
const struct chain *chain);
struct nftnl_chain_list *mnl_nft_chain_dump(struct netlink_ctx *ctx,
- int family);
+ int family, const char *table,
+ const char *chain);
int mnl_nft_table_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags);
diff --git a/src/cache.c b/src/cache.c
index 484efdb9..1e98e6cf 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -342,31 +342,23 @@ struct table *table_cache_find(const struct cache *cache,
struct chain_cache_dump_ctx {
struct netlink_ctx *nlctx;
struct table *table;
- const struct nft_cache_filter *filter;
};
static int chain_cache_cb(struct nftnl_chain *nlc, void *arg)
{
struct chain_cache_dump_ctx *ctx = arg;
- const struct nft_cache_filter *filter = ctx->filter;
const char *chain_name, *table_name;
uint32_t hash, family;
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)
- return 0;
-
- if (filter && filter->list.table && filter->list.chain &&
- (filter->list.family != family ||
- strcmp(filter->list.table, table_name) ||
- strcmp(filter->list.chain, chain_name)))
+ 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);
@@ -383,25 +375,33 @@ static int chain_cache_cb(struct nftnl_chain *nlc, void *arg)
}
static int chain_cache_init(struct netlink_ctx *ctx, struct table *table,
- struct nftnl_chain_list *chain_list,
- const struct nft_cache_filter *filter)
+ struct nftnl_chain_list *chain_list)
{
struct chain_cache_dump_ctx dump_ctx = {
.nlctx = ctx,
.table = table,
- .filter = filter,
};
nftnl_chain_list_foreach(chain_list, chain_cache_cb, &dump_ctx);
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;
@@ -781,7 +781,7 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
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;
}
@@ -834,7 +834,7 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
}
}
if (flags & NFT_CACHE_CHAIN_BIT) {
- ret = chain_cache_init(ctx, table, chain_list, filter);
+ ret = chain_cache_init(ctx, table, chain_list);
if (ret < 0) {
ret = -1;
goto cache_fails;
diff --git a/src/mnl.c b/src/mnl.c
index 26f643fb..109c3dd8 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -906,10 +906,12 @@ err_free:
}
struct nftnl_chain_list *mnl_nft_chain_dump(struct netlink_ctx *ctx,
- int family)
+ int family, const char *table,
+ const char *chain)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nftnl_chain_list *nlc_list;
+ struct nftnl_chain *nlc = NULL;
struct nlmsghdr *nlh;
int ret;
@@ -917,11 +919,24 @@ struct nftnl_chain_list *mnl_nft_chain_dump(struct netlink_ctx *ctx,
if (nlc_list == NULL)
memory_allocation_error();
+ if (table && chain) {
+ nlc = nftnl_chain_alloc();
+ if (!nlc)
+ memory_allocation_error();
+
+ nftnl_chain_set_str(nlc, NFTNL_CHAIN_TABLE, table);
+ nftnl_chain_set_str(nlc, NFTNL_CHAIN_NAME, chain);
+ }
+
nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, family,
- NLM_F_DUMP, ctx->seqnum);
+ nlc ? NLM_F_ACK : NLM_F_DUMP, ctx->seqnum);
+ if (nlc) {
+ nftnl_chain_nlmsg_build_payload(nlh, nlc);
+ nftnl_chain_free(nlc);
+ }
ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, chain_cb, nlc_list);
- if (ret < 0)
+ if (ret < 0 && errno != ENOENT)
goto err;
return nlc_list;