]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
mnl: flowtable support for extended netlink error reporting
authorPablo Neira Ayuso <pablo@netfilter.org>
Wed, 19 Apr 2023 13:38:04 +0000 (15:38 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 24 Apr 2023 20:48:42 +0000 (22:48 +0200)
This patch extends existing flowtable support to improve error
reporting:

 # nft add flowtable inet x y '{ devices = { x } ; }'
 Error: Could not process rule: No such file or directory
 add flowtable inet x y { devices = { x } ; }
                                      ^
 # nft delete flowtable inet x y '{ devices = { x } ; }'
 Error: Could not process rule: No such file or directory
 delete flowtable inet x y { devices = { x } ; }
                                         ^
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/mnl.c

index ce9e4ee1c0598e4c1560cee1d664cd5ffd92b551..4c16facaccab5972a3aac4ecffd4897b495d339b 100644 (file)
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -718,6 +718,51 @@ err:
 /*
  * Chain
  */
+
+struct nft_dev {
+       const char      *ifname;
+       struct location *location;
+};
+
+static struct nft_dev *nft_dev_array(const struct expr *dev_expr, int *num_devs)
+{
+       struct nft_dev *dev_array;
+       unsigned int ifname_len;
+       char ifname[IFNAMSIZ];
+       int i = 0, len = 1;
+       struct expr *expr;
+
+       list_for_each_entry(expr, &dev_expr->expressions, list)
+               len++;
+
+       dev_array = xmalloc(sizeof(struct nft_dev) * len);
+
+       list_for_each_entry(expr, &dev_expr->expressions, list) {
+               ifname_len = div_round_up(expr->len, BITS_PER_BYTE);
+               memset(ifname, 0, sizeof(ifname));
+               mpz_export_data(ifname, expr->value, BYTEORDER_HOST_ENDIAN,
+                               ifname_len);
+               dev_array[i].ifname = xstrdup(ifname);
+               dev_array[i].location = &expr->location;
+               i++;
+       }
+
+       dev_array[i].ifname = NULL;
+       *num_devs = i;
+
+       return dev_array;
+}
+
+static void nft_dev_array_free(const struct nft_dev *dev_array)
+{
+       int i = 0;
+
+       while (dev_array[i].ifname != NULL)
+               xfree(dev_array[i++].ifname);
+
+       xfree(dev_array);
+}
+
 int mnl_nft_chain_add(struct netlink_ctx *ctx, struct cmd *cmd,
                      unsigned int flags)
 {
@@ -1907,48 +1952,30 @@ err:
        return NULL;
 }
 
-static const char **nft_flowtable_dev_array(struct cmd *cmd)
+static void mnl_nft_ft_devs_build(struct nlmsghdr *nlh, struct cmd *cmd)
 {
-       unsigned int ifname_len;
-       const char **dev_array;
-       char ifname[IFNAMSIZ];
-       int i = 0, len = 1;
-       struct expr *expr;
+       const struct expr *dev_expr = cmd->flowtable->dev_expr;
+       const struct nft_dev *dev_array;
+       struct nlattr *nest_dev;
+       int i, num_devs= 0;
 
-       list_for_each_entry(expr, &cmd->flowtable->dev_expr->expressions, list)
-               len++;
-
-       dev_array = xmalloc(sizeof(char *) * len);
-
-       list_for_each_entry(expr, &cmd->flowtable->dev_expr->expressions, list) {
-               ifname_len = div_round_up(expr->len, BITS_PER_BYTE);
-               memset(ifname, 0, sizeof(ifname));
-               mpz_export_data(ifname, expr->value, BYTEORDER_HOST_ENDIAN,
-                               ifname_len);
-               dev_array[i++] = xstrdup(ifname);
+       dev_array = nft_dev_array(dev_expr, &num_devs);
+       nest_dev = mnl_attr_nest_start(nlh, NFTA_FLOWTABLE_HOOK_DEVS);
+       for (i = 0; i < num_devs; i++) {
+               cmd_add_loc(cmd, nlh->nlmsg_len, dev_array[i].location);
+               mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME, dev_array[i].ifname);
        }
 
-       dev_array[i] = NULL;
-
-       return dev_array;
-}
-
-static void nft_flowtable_dev_array_free(const char **dev_array)
-{
-       int i = 0;
-
-       while (dev_array[i] != NULL)
-               xfree(dev_array[i++]);
-
-       free(dev_array);
+       mnl_attr_nest_end(nlh, nest_dev);
+       nft_dev_array_free(dev_array);
 }
 
 int mnl_nft_flowtable_add(struct netlink_ctx *ctx, struct cmd *cmd,
                          unsigned int flags)
 {
        struct nftnl_flowtable *flo;
-       const char **dev_array;
        struct nlmsghdr *nlh;
+       struct nlattr *nest;
        int priority;
 
        flo = nftnl_flowtable_alloc();
@@ -1958,24 +1985,6 @@ int mnl_nft_flowtable_add(struct netlink_ctx *ctx, struct cmd *cmd,
        nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_FAMILY,
                                cmd->handle.family);
 
-       if (cmd->flowtable->hook.name) {
-               nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_HOOKNUM,
-                                       cmd->flowtable->hook.num);
-               mpz_export_data(&priority, cmd->flowtable->priority.expr->value,
-                               BYTEORDER_HOST_ENDIAN, sizeof(int));
-               nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_PRIO, priority);
-       } else {
-               nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_HOOKNUM, 0);
-               nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_PRIO, 0);
-       }
-
-       if (cmd->flowtable->dev_expr) {
-               dev_array = nft_flowtable_dev_array(cmd);
-               nftnl_flowtable_set_data(flo, NFTNL_FLOWTABLE_DEVICES,
-                                        dev_array, 0);
-               nft_flowtable_dev_array_free(dev_array);
-       }
-
        nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_FLAGS,
                                cmd->flowtable->flags);
 
@@ -1991,6 +2000,21 @@ int mnl_nft_flowtable_add(struct netlink_ctx *ctx, struct cmd *cmd,
        mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_NAME, cmd->handle.flowtable.name);
 
        nftnl_flowtable_nlmsg_build_payload(nlh, flo);
+
+       nest = mnl_attr_nest_start(nlh, NFTA_FLOWTABLE_HOOK);
+
+       if (cmd->flowtable && cmd->flowtable->priority.expr) {
+               mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_HOOK_NUM, htonl(cmd->flowtable->hook.num));
+               mpz_export_data(&priority, cmd->flowtable->priority.expr->value,
+                               BYTEORDER_HOST_ENDIAN, sizeof(int));
+               mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_HOOK_PRIORITY, htonl(priority));
+       }
+
+       if (cmd->flowtable->dev_expr)
+               mnl_nft_ft_devs_build(nlh, cmd);
+
+       mnl_attr_nest_end(nlh, nest);
+
        nftnl_flowtable_free(flo);
 
        mnl_nft_batch_continue(ctx->batch);
@@ -2002,8 +2026,8 @@ int mnl_nft_flowtable_del(struct netlink_ctx *ctx, struct cmd *cmd)
 {
        enum nf_tables_msg_types msg_type = NFT_MSG_DELFLOWTABLE;
        struct nftnl_flowtable *flo;
-       const char **dev_array;
        struct nlmsghdr *nlh;
+       struct nlattr *nest;
 
        flo = nftnl_flowtable_alloc();
        if (!flo)
@@ -2012,16 +2036,6 @@ int mnl_nft_flowtable_del(struct netlink_ctx *ctx, struct cmd *cmd)
        nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_FAMILY,
                                cmd->handle.family);
 
-       if (cmd->flowtable && cmd->flowtable->dev_expr) {
-               nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_HOOKNUM, 0);
-               nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_PRIO, 0);
-
-               dev_array = nft_flowtable_dev_array(cmd);
-               nftnl_flowtable_set_data(flo, NFTNL_FLOWTABLE_DEVICES,
-                                        dev_array, 0);
-               nft_flowtable_dev_array_free(dev_array);
-       }
-
        if (cmd->op == CMD_DESTROY)
                msg_type = NFT_MSG_DESTROYFLOWTABLE;
 
@@ -2044,6 +2058,14 @@ int mnl_nft_flowtable_del(struct netlink_ctx *ctx, struct cmd *cmd)
        }
 
        nftnl_flowtable_nlmsg_build_payload(nlh, flo);
+
+       if (cmd->op == CMD_DELETE &&
+           cmd->flowtable && cmd->flowtable->dev_expr) {
+               nest = mnl_attr_nest_start(nlh, NFTA_FLOWTABLE_HOOK);
+               mnl_nft_ft_devs_build(nlh, cmd);
+               mnl_attr_nest_end(nlh, nest);
+       }
+
        nftnl_flowtable_free(flo);
 
        mnl_nft_batch_continue(ctx->batch);