]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: flowtable: add support for named flowtable listing
authorEric Jallot <ejallot@gmail.com>
Wed, 30 Oct 2019 17:06:19 +0000 (18:06 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 31 Oct 2019 13:16:42 +0000 (14:16 +0100)
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 <ejallot@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
doc/libnftables-json.adoc
include/rule.h
src/evaluate.c
src/json.c
src/mnl.c
src/netlink.c
src/parser_bison.y
src/parser_json.c
src/rule.c
tests/shell/testcases/listing/0020flowtable_0 [new file with mode: 0755]

index 6877f0549db1f3405bcf1ba93eb7207d4781d874..871480b95ceb607b7f3b535f7876c37a4fe9d0e8 100644 (file)
@@ -117,7 +117,7 @@ ____
 *{ "add":* 'ADD_OBJECT' *}*
 
 'ADD_OBJECT' := 'TABLE' | 'CHAIN' | 'RULE' | 'SET' | 'MAP' | 'ELEMENT' |
-                'FLOWTABLE' | 'COUNTER | QUOTA' | 'CT_HELPER' | 'LIMIT' |
+                'FLOWTABLE' | 'COUNTER' | 'QUOTA' | 'CT_HELPER' | 'LIMIT' |
                'CT_TIMEOUT' | 'CT_EXPECTATION'
 ____
 
@@ -161,9 +161,9 @@ ____
 
 'LIST_OBJECT' := 'TABLE' | 'TABLES' | 'CHAIN' | 'CHAINS' | 'SET' | 'SETS' |
                  'MAP' | 'MAPS | COUNTER' | 'COUNTERS' | 'QUOTA' | 'QUOTAS' |
-                 'CT_HELPER' | 'CT_HELPERS' | 'LIMIT' | 'LIMITS | RULESET' |
-                 'METER' | 'METERS' | 'FLOWTABLES' | 'CT_TIMEOUT' |
-                 'CT_EXPECTATION'
+                 'CT_HELPER' | 'CT_HELPERS' | 'LIMIT' | 'LIMITS' | 'RULESET' |
+                 'METER' | 'METERS' | 'FLOWTABLE' | 'FLOWTABLES' |
+                 'CT_TIMEOUT' | 'CT_EXPECTATION'
 ____
 
 List ruleset elements. The plural forms are used to list all objects of that
index ba40db8806fc8c3e5e24f7a65c3592c222cf2278..a718923b14a36d7f818b54a2e67cf157232d3dc7 100644 (file)
@@ -45,6 +45,11 @@ struct set_spec {
        const char              *name;
 };
 
+struct flowtable_spec {
+       struct location         location;
+       const char              *name;
+};
+
 struct obj_spec {
        struct location         location;
        const char              *name;
@@ -69,7 +74,7 @@ struct handle {
        struct chain_spec       chain;
        struct set_spec         set;
        struct obj_spec         obj;
-       const char              *flowtable;
+       struct flowtable_spec   flowtable;
        struct handle_spec      handle;
        struct position_spec    position;
        struct position_spec    index;
@@ -470,6 +475,10 @@ extern struct flowtable *flowtable_alloc(const struct location *loc);
 extern struct flowtable *flowtable_get(struct flowtable *flowtable);
 extern void flowtable_free(struct flowtable *flowtable);
 extern void flowtable_add_hash(struct flowtable *flowtable, struct table *table);
+extern struct flowtable *flowtable_lookup(const struct table *table, const char *name);
+extern struct flowtable *flowtable_lookup_fuzzy(const char *ft_name,
+                                               const struct nft_cache *cache,
+                                               const struct table **table);
 
 void flowtable_print(const struct flowtable *n, struct output_ctx *octx);
 
@@ -535,7 +544,6 @@ enum cmd_ops {
  * @CMD_OBJ_QUOTAS:    multiple quotas
  * @CMD_OBJ_LIMIT:     limit
  * @CMD_OBJ_LIMITS:    multiple limits
- * @CMD_OBJ_FLOWTABLES:        flow tables
  * @CMD_OBJ_SECMARK:   secmark
  * @CMD_OBJ_SECMARKS:  multiple secmarks
  * @CMD_OBJ_SYNPROXY:  synproxy
index a56cd2a56e9906c3d802c2aaf59db4119edc03da..81230fc7f4be41fe4939c2605428ce76777f264e 100644 (file)
@@ -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);
index 56b20549bd73976473b54f85e9c17c9791465afd..d079da9ea9ebe00ddb1b2f640bedb7cc67798b15 100644 (file)
@@ -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;
index 933e18d97cbd80290681d33dd89333070fa61f50..36ccda58c2688b4eedab421a37777d21f9d753fb 100644 (file)
--- 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,
index c47771d3c801020ad15622f700a9bcf8056f8763..a727c7eb76b0e325c7a78dd07a968d0f36cedc7e 100644 (file)
@@ -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])
index 7f9b1752f41d40ad70148d6f0dc6935174e6f130..94494f6f5005ea3513368c22dbf3b26707921ec1 100644 (file)
@@ -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;
                        }
                        ;
 
index a9bcb84faf44e4d082345eb3042e9ebff9f50371..3b86a0ae543f98f098c8a6d1bdce47de9a6e823b 100644 (file)
@@ -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);
index c258f12e5c77ae97ec48aa349b33e05a815bfbc6..a2811d18fa31b5c20cc13c731f28ec5513b2cdca 100644 (file)
@@ -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:
diff --git a/tests/shell/testcases/listing/0020flowtable_0 b/tests/shell/testcases/listing/0020flowtable_0
new file mode 100755 (executable)
index 0000000..6f630f1
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# list only the flowtable asked for with table
+
+EXPECTED="table inet filter {
+       flowtable f {
+               hook ingress priority filter
+               devices = { lo }
+       }
+}"
+
+set -e
+
+$NFT -f - <<< "$EXPECTED"
+
+GET="$($NFT list flowtable inet filter f)"
+if [ "$EXPECTED" != "$GET" ] ; then
+       DIFF="$(which diff)"
+       [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+       exit 1
+fi