summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/cache.h1
-rw-r--r--include/mnl.h3
-rw-r--r--src/cache.c55
-rw-r--r--src/mnl.c14
-rw-r--r--src/netlink.c3
-rwxr-xr-xtests/shell/testcases/listing/0020flowtable_051
6 files changed, 103 insertions, 24 deletions
diff --git a/include/cache.h b/include/cache.h
index 3a9a5e81..d185f3cf 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -54,6 +54,7 @@ struct nft_cache_filter {
const char *table;
const char *chain;
const char *set;
+ const char *ft;
} list;
struct {
diff --git a/include/mnl.h b/include/mnl.h
index 8659879c..b006192c 100644
--- a/include/mnl.h
+++ b/include/mnl.h
@@ -77,7 +77,8 @@ int mnl_nft_obj_add(struct netlink_ctx *ctx, struct cmd *cmd,
int mnl_nft_obj_del(struct netlink_ctx *ctx, struct cmd *cmd, int type);
struct nftnl_flowtable_list *
-mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family, const char *table);
+mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family,
+ const char *table, const char *ft);
int mnl_nft_flowtable_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags);
diff --git a/src/cache.c b/src/cache.c
index 38a34ee3..6494e474 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -229,6 +229,15 @@ static unsigned int evaluate_cache_list(struct nft_ctx *nft, struct cmd *cmd,
case CMD_OBJ_MAPS:
flags |= NFT_CACHE_TABLE | NFT_CACHE_SET;
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;
@@ -681,10 +690,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;
@@ -693,6 +711,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;
}
@@ -708,13 +728,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;
- ft_list = mnl_nft_flowtable_dump(ctx, table->handle.family,
- table->handle.table.name);
+ if (filter) {
+ family = filter->list.family;
+ table = filter->list.table;
+ ft = filter->list.ft;
+ }
+
+ ft_list = mnl_nft_flowtable_dump(ctx, family, table, ft);
if (!ft_list) {
if (errno == EINTR)
return NULL;
@@ -801,6 +829,13 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
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) {
@@ -849,15 +884,7 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
}
}
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;
goto cache_fails;
@@ -903,6 +930,8 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
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);
diff --git a/src/mnl.c b/src/mnl.c
index 47b3ca61..5413f865 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -1826,11 +1826,13 @@ err_free:
}
struct nftnl_flowtable_list *
-mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family, const char *table)
+mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family,
+ const char *table, const char *ft)
{
struct nftnl_flowtable_list *nln_list;
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nftnl_flowtable *n;
+ int flags = NLM_F_DUMP;
struct nlmsghdr *nlh;
int ret;
@@ -1838,10 +1840,14 @@ mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family, const char *table)
if (n == NULL)
memory_allocation_error();
- nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETFLOWTABLE, family,
- NLM_F_DUMP, ctx->seqnum);
if (table != NULL)
nftnl_flowtable_set_str(n, NFTNL_FLOWTABLE_TABLE, table);
+ if (ft) {
+ nftnl_flowtable_set_str(n, NFTNL_FLOWTABLE_NAME, ft);
+ flags = NLM_F_ACK;
+ }
+ nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETFLOWTABLE, family,
+ flags, ctx->seqnum);
nftnl_flowtable_nlmsg_build_payload(nlh, n);
nftnl_flowtable_free(n);
@@ -1850,7 +1856,7 @@ mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family, const char *table)
memory_allocation_error();
ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, flowtable_cb, nln_list);
- if (ret < 0)
+ if (ret < 0 && errno != ENOENT)
goto err;
return nln_list;
diff --git a/src/netlink.c b/src/netlink.c
index f74c0383..359d801c 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1721,7 +1721,8 @@ int netlink_list_flowtables(struct netlink_ctx *ctx, const struct handle *h)
struct nftnl_flowtable_list *flowtable_cache;
int err;
- flowtable_cache = mnl_nft_flowtable_dump(ctx, h->family, h->table.name);
+ flowtable_cache = mnl_nft_flowtable_dump(ctx, h->family,
+ h->table.name, NULL);
if (flowtable_cache == NULL) {
if (errno == EINTR)
return -1;
diff --git a/tests/shell/testcases/listing/0020flowtable_0 b/tests/shell/testcases/listing/0020flowtable_0
index 2f0a98d1..47488d8e 100755
--- a/tests/shell/testcases/listing/0020flowtable_0
+++ b/tests/shell/testcases/listing/0020flowtable_0
@@ -2,19 +2,60 @@
# list only the flowtable asked for with table
+FLOWTABLES="flowtable f {
+ hook ingress priority filter
+ devices = { lo }
+}
+flowtable f2 {
+ hook ingress priority filter
+ devices = { d0 }
+}"
+
+RULESET="table inet filter {
+ $FLOWTABLES
+}
+table ip filter {
+ $FLOWTABLES
+}"
+
EXPECTED="table inet filter {
flowtable f {
hook ingress priority filter
devices = { lo }
}
}"
+EXPECTED2="table ip filter {
+ flowtable f2 {
+ hook ingress priority filter
+ devices = { d0 }
+ }
+}"
+EXPECTED3="table ip filter {
+ flowtable f {
+ hook ingress priority filter
+ devices = { lo }
+ }
+ flowtable f2 {
+ hook ingress priority filter
+ devices = { d0 }
+ }
+}"
+
+ip link add d0 type dummy || {
+ echo "Skipping, no dummy interface available"
+ exit 0
+}
+trap "ip link del d0" EXIT
set -e
-$NFT -f - <<< "$EXPECTED"
+$NFT -f - <<< "$RULESET"
GET="$($NFT list flowtable inet filter f)"
-if [ "$EXPECTED" != "$GET" ] ; then
- $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
- exit 1
-fi
+$DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+
+GET="$($NFT list flowtable ip filter f2)"
+$DIFF -u <(echo "$EXPECTED2") <(echo "$GET")
+
+GET="$($NFT list flowtables ip)"
+$DIFF -u <(echo "$EXPECTED3") <(echo "$GET")