From 81c51fc1ab699fb6e417ada77221657ca34efd0b Mon Sep 17 00:00:00 2001 From: Eric Jallot Date: Wed, 30 Oct 2019 18:06:19 +0100 Subject: src: flowtable: add support for named flowtable listing This patch allows you to dump a named flowtable. # nft list flowtable inet t f table inet t { flowtable f { hook ingress priority filter + 10 devices = { eth0, eth1 } } } Also: libnftables-json.adoc: fix missing quotes. Fixes: db0697ce7f60 ("src: support for flowtable listing") Fixes: 872f373dc50f ("doc: Add JSON schema documentation") Signed-off-by: Eric Jallot Signed-off-by: Pablo Neira Ayuso --- src/evaluate.c | 29 +++++++++++++++++++++++++ src/json.c | 20 ++++++++++++++++- src/mnl.c | 4 ++-- src/netlink.c | 2 +- src/parser_bison.y | 12 +++++++--- src/parser_json.c | 4 ++-- src/rule.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 7 files changed, 122 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/evaluate.c b/src/evaluate.c index a56cd2a5..81230fc7 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -218,6 +218,23 @@ static int set_not_found(struct eval_ctx *ctx, const struct location *loc, table->handle.table.name); } +static int flowtable_not_found(struct eval_ctx *ctx, const struct location *loc, + const char *ft_name) +{ + const struct table *table; + struct flowtable *ft; + + ft = flowtable_lookup_fuzzy(ft_name, &ctx->nft->cache, &table); + if (ft == NULL) + return cmd_error(ctx, loc, "%s", strerror(ENOENT)); + + return cmd_error(ctx, loc, + "%s; did you mean flowtable ā€˜%sā€™ in table %s ā€˜%sā€™?", + strerror(ENOENT), ft->handle.flowtable.name, + family2str(ft->handle.family), + table->handle.table.name); +} + /* * Symbol expression: parse symbol and evaluate resulting expression. */ @@ -3834,6 +3851,7 @@ static int cmd_evaluate_list_obj(struct eval_ctx *ctx, const struct cmd *cmd, static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd) { + struct flowtable *ft; struct table *table; struct set *set; @@ -3898,6 +3916,17 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd) if (chain_lookup(table, &cmd->handle) == NULL) return chain_not_found(ctx); + return 0; + case CMD_OBJ_FLOWTABLE: + table = table_lookup(&cmd->handle, &ctx->nft->cache); + if (table == NULL) + return table_not_found(ctx); + + ft = flowtable_lookup(table, cmd->handle.flowtable.name); + if (ft == NULL) + return flowtable_not_found(ctx, &ctx->cmd->handle.flowtable.location, + ctx->cmd->handle.flowtable.name); + return 0; case CMD_OBJ_QUOTA: return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_QUOTA); diff --git a/src/json.c b/src/json.c index 56b20549..d079da9e 100644 --- a/src/json.c +++ b/src/json.c @@ -412,7 +412,7 @@ static json_t *flowtable_print_json(const struct flowtable *ftable) BYTEORDER_HOST_ENDIAN, sizeof(int)); root = json_pack("{s:s, s:s, s:s, s:s, s:i}", "family", family2str(ftable->handle.family), - "name", ftable->handle.flowtable, + "name", ftable->handle.flowtable.name, "table", ftable->handle.table.name, "hook", hooknum2str(NFPROTO_NETDEV, ftable->hooknum), "prio", priority); @@ -1724,6 +1724,21 @@ static json_t *do_list_obj_json(struct netlink_ctx *ctx, return root; } +static json_t *do_list_flowtable_json(struct netlink_ctx *ctx, + struct cmd *cmd, struct table *table) +{ + json_t *root = json_array(); + struct flowtable *ft; + + ft = flowtable_lookup(table, cmd->handle.flowtable.name); + if (ft == NULL) + return json_null(); + + json_array_append_new(root, flowtable_print_json(ft)); + + return root; +} + static json_t *do_list_flowtables_json(struct netlink_ctx *ctx, struct cmd *cmd) { json_t *root = json_array(), *tmp; @@ -1815,6 +1830,9 @@ int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd) case CMD_OBJ_SECMARKS: root = do_list_obj_json(ctx, cmd, NFT_OBJECT_SECMARK); break; + case CMD_OBJ_FLOWTABLE: + root = do_list_flowtable_json(ctx, cmd, table); + break; case CMD_OBJ_FLOWTABLES: root = do_list_flowtables_json(ctx, cmd); break; diff --git a/src/mnl.c b/src/mnl.c index 933e18d9..36ccda58 100644 --- a/src/mnl.c +++ b/src/mnl.c @@ -1429,7 +1429,7 @@ int mnl_nft_flowtable_add(struct netlink_ctx *ctx, const struct cmd *cmd, nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_TABLE, cmd->handle.table.name); nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_NAME, - cmd->handle.flowtable); + cmd->handle.flowtable.name); nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_HOOKNUM, cmd->flowtable->hooknum); mpz_export_data(&priority, cmd->flowtable->priority.expr->value, @@ -1475,7 +1475,7 @@ int mnl_nft_flowtable_del(struct netlink_ctx *ctx, const struct cmd *cmd) nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_TABLE, cmd->handle.table.name); nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_NAME, - cmd->handle.flowtable); + cmd->handle.flowtable.name); nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch), NFT_MSG_DELFLOWTABLE, cmd->handle.family, diff --git a/src/netlink.c b/src/netlink.c index c47771d3..a727c7eb 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -1131,7 +1131,7 @@ netlink_delinearize_flowtable(struct netlink_ctx *ctx, nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_FAMILY); flowtable->handle.table.name = xstrdup(nftnl_flowtable_get_str(nlo, NFTNL_FLOWTABLE_TABLE)); - flowtable->handle.flowtable = + flowtable->handle.flowtable.name = xstrdup(nftnl_flowtable_get_str(nlo, NFTNL_FLOWTABLE_NAME)); dev_array = nftnl_flowtable_get(nlo, NFTNL_FLOWTABLE_DEVICES); while (dev_array[len]) diff --git a/src/parser_bison.y b/src/parser_bison.y index 7f9b1752..94494f6f 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -1315,6 +1315,10 @@ list_cmd : TABLE table_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_FLOWTABLES, &$2, &@$, NULL); } + | FLOWTABLE flowtable_spec + { + $$ = cmd_alloc(CMD_LIST, CMD_OBJ_FLOWTABLE, &$2, &@$, NULL); + } | MAPS ruleset_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_MAPS, &$2, &@$, NULL); @@ -2224,15 +2228,17 @@ set_identifier : identifier flowtable_spec : table_spec identifier { - $$ = $1; - $$.flowtable = $2; + $$ = $1; + $$.flowtable.name = $2; + $$.flowtable.location = @2; } ; flowtable_identifier : identifier { memset(&$$, 0, sizeof($$)); - $$.flowtable = $1; + $$.flowtable.name = $1; + $$.flowtable.location = @1; } ; diff --git a/src/parser_json.c b/src/parser_json.c index a9bcb84f..3b86a0ae 100644 --- a/src/parser_json.c +++ b/src/parser_json.c @@ -2967,7 +2967,7 @@ static struct cmd *json_parse_cmd_add_flowtable(struct json_ctx *ctx, if (json_unpack_err(ctx, root, "{s:s, s:s, s:s}", "family", &family, "table", &h.table.name, - "name", &h.flowtable)) + "name", &h.flowtable.name)) return NULL; if (parse_family(family, &h.family)) { @@ -2975,7 +2975,7 @@ static struct cmd *json_parse_cmd_add_flowtable(struct json_ctx *ctx, return NULL; } h.table.name = xstrdup(h.table.name); - h.flowtable = xstrdup(h.flowtable); + h.flowtable.name = xstrdup(h.flowtable.name); if (op == CMD_DELETE) return cmd_alloc(op, cmd_obj, &h, int_loc, NULL); diff --git a/src/rule.c b/src/rule.c index c258f12e..a2811d18 100644 --- a/src/rule.c +++ b/src/rule.c @@ -105,7 +105,7 @@ void handle_free(struct handle *h) xfree(h->table.name); xfree(h->chain.name); xfree(h->set.name); - xfree(h->flowtable); + xfree(h->flowtable.name); xfree(h->obj.name); } @@ -125,8 +125,8 @@ void handle_merge(struct handle *dst, const struct handle *src) dst->set.name = xstrdup(src->set.name); dst->set.location = src->set.location; } - if (dst->flowtable == NULL && src->flowtable != NULL) - dst->flowtable = xstrdup(src->flowtable); + if (dst->flowtable.name == NULL && src->flowtable.name != NULL) + dst->flowtable.name = xstrdup(src->flowtable.name); if (dst->obj.name == NULL && src->obj.name != NULL) dst->obj.name = xstrdup(src->obj.name); if (dst->handle.id == 0) @@ -2156,7 +2156,7 @@ static void flowtable_print_declaration(const struct flowtable *flowtable, if (opts->table != NULL) nft_print(octx, " %s", opts->table); - nft_print(octx, " %s {%s", flowtable->handle.flowtable, opts->nl); + nft_print(octx, " %s {%s", flowtable->handle.flowtable.name, opts->nl); nft_print(octx, "%s%shook %s priority %s%s", opts->tab, opts->tab, @@ -2193,6 +2193,60 @@ void flowtable_print(const struct flowtable *s, struct output_ctx *octx) do_flowtable_print(s, &opts, octx); } +struct flowtable *flowtable_lookup(const struct table *table, const char *name) +{ + struct flowtable *ft; + + list_for_each_entry(ft, &table->flowtables, list) { + if (!strcmp(ft->handle.flowtable.name, name)) + return ft; + } + return NULL; +} + +struct flowtable *flowtable_lookup_fuzzy(const char *ft_name, + const struct nft_cache *cache, + const struct table **t) +{ + struct string_misspell_state st; + struct table *table; + struct flowtable *ft; + + string_misspell_init(&st); + + list_for_each_entry(table, &cache->list, list) { + list_for_each_entry(ft, &table->flowtables, list) { + if (!strcmp(ft->handle.flowtable.name, ft_name)) { + *t = table; + return ft; + } + if (string_misspell_update(ft->handle.flowtable.name, + ft_name, ft, &st)) + *t = table; + } + } + return st.obj; +} + +static int do_list_flowtable(struct netlink_ctx *ctx, struct cmd *cmd, + struct table *table) +{ + struct flowtable *ft; + + ft = flowtable_lookup(table, cmd->handle.flowtable.name); + if (ft == NULL) + return -1; + + nft_print(&ctx->nft->output, "table %s %s {\n", + family2str(table->handle.family), + table->handle.table.name); + + flowtable_print(ft, &ctx->nft->output); + nft_print(&ctx->nft->output, "}\n"); + + return 0; +} + static int do_list_flowtables(struct netlink_ctx *ctx, struct cmd *cmd) { struct print_fmt_options opts = { @@ -2388,6 +2442,8 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd) case CMD_OBJ_SYNPROXY: case CMD_OBJ_SYNPROXYS: return do_list_obj(ctx, cmd, NFT_OBJECT_SYNPROXY); + case CMD_OBJ_FLOWTABLE: + return do_list_flowtable(ctx, cmd, table); case CMD_OBJ_FLOWTABLES: return do_list_flowtables(ctx, cmd); default: -- cgit v1.2.3