This patch allows you to specify multiple netdevices to be bound to the
netdev basechain, eg.

 # nft add chain netdev x y { \
        type filter hook ingress devices = { eth0, eth1 } priority 0\; }

json codebase has been updated to support for one single device with the
existing representation, no support for multidevice is included in this
patch.

Signed-off-by: Pablo Neira Ayuso <pa...@netfilter.org>
---
 include/rule.h     |  4 +++-
 src/json.c         | 17 +++++++++++++----
 src/mnl.c          | 29 ++++++++++++++++++++++++-----
 src/netlink.c      | 20 +++++++++++++++++---
 src/parser_bison.y | 26 ++++++++++++++++++++------
 src/parser_json.c  | 18 +++++++++++++++---
 src/rule.c         | 22 +++++++++++++++++-----
 7 files changed, 109 insertions(+), 27 deletions(-)

diff --git a/include/rule.h b/include/rule.h
index 2708cbebc9f8..ba40db8806fc 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -208,7 +208,9 @@ struct chain {
        struct prio_spec        priority;
        struct expr             *policy;
        const char              *type;
-       const char              *dev;
+       const char              **dev_array;
+       struct expr             *dev_expr;
+       int                     dev_array_len;
        struct scope            scope;
        struct list_head        rules;
 };
diff --git a/src/json.c b/src/json.c
index 13a064249d90..56b20549bd73 100644
--- a/src/json.c
+++ b/src/json.c
@@ -222,9 +222,9 @@ static json_t *rule_print_json(struct output_ctx *octx,
 
 static json_t *chain_print_json(const struct chain *chain)
 {
+       int priority, policy, n = 0;
+       struct expr *dev, *expr;
        json_t *root, *tmp;
-       int priority;
-       int policy;
 
        root = json_pack("{s:s, s:s, s:s, s:I}",
                         "family", family2str(chain->handle.family),
@@ -243,8 +243,17 @@ static json_t *chain_print_json(const struct chain *chain)
                                                    chain->hooknum),
                                "prio", priority,
                                "policy", chain_policy2str(policy));
-               if (chain->dev)
-                       json_object_set_new(tmp, "dev", 
json_string(chain->dev));
+               if (chain->dev_expr) {
+                       list_for_each_entry(expr, 
&chain->dev_expr->expressions, list) {
+                               dev = expr;
+                               n++;
+                       }
+               }
+
+               if (n == 1) {
+                       json_object_set_new(tmp, "dev",
+                                           json_string(dev->identifier));
+               }
                json_object_update(root, tmp);
                json_decref(tmp);
        }
diff --git a/src/mnl.c b/src/mnl.c
index 75ab07b045aa..ee5d0a1a2a15 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -526,10 +526,12 @@ err:
 int mnl_nft_chain_add(struct netlink_ctx *ctx, const struct cmd *cmd,
                      unsigned int flags)
 {
+       int priority, policy, i = 0;
        struct nftnl_chain *nlc;
+       const char **dev_array;
        struct nlmsghdr *nlh;
-       int priority;
-       int policy;
+       struct expr *expr;
+       int dev_array_len;
 
        nlc = nftnl_chain_alloc();
        if (nlc == NULL)
@@ -555,9 +557,26 @@ int mnl_nft_chain_add(struct netlink_ctx *ctx, const 
struct cmd *cmd,
                                        BYTEORDER_HOST_ENDIAN, sizeof(int));
                        nftnl_chain_set_u32(nlc, NFTNL_CHAIN_POLICY, policy);
                }
-               if (cmd->chain->dev != NULL)
-                       nftnl_chain_set_str(nlc, NFTNL_CHAIN_DEV,
-                                           cmd->chain->dev);
+               if (cmd->chain->dev_expr) {
+                       dev_array = xmalloc(sizeof(char *) * 8);
+                       dev_array_len = 8;
+                       list_for_each_entry(expr, 
&cmd->chain->dev_expr->expressions, list) {
+                               dev_array[i++] = expr->identifier;
+                               if (i == dev_array_len) {
+                                       dev_array_len *= 2;
+                                       dev_array = xrealloc(dev_array,
+                                                            dev_array_len);
+                               }
+                       }
+
+                       dev_array[i] = NULL;
+                       if (i == 1)
+                               nftnl_chain_set_str(nlc, NFTNL_CHAIN_DEV, 
dev_array[0]);
+                       else if (i > 1)
+                               nftnl_chain_set(nlc, NFTNL_CHAIN_DEVICES, 
dev_array);
+
+                       xfree(dev_array);
+               }
        }
        netlink_dump_chain(nlc, ctx);
 
diff --git a/src/netlink.c b/src/netlink.c
index 1e669e5dcaa1..c47771d3c801 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -378,9 +378,9 @@ void netlink_dump_chain(const struct nftnl_chain *nlc, 
struct netlink_ctx *ctx)
 struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx,
                                        const struct nftnl_chain *nlc)
 {
+       int priority, policy, len = 0, i;
+       const char * const *dev_array;
        struct chain *chain;
-       int priority;
-       int policy;
 
        chain = chain_alloc(nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME));
        chain->handle.family =
@@ -415,8 +415,22 @@ struct chain *netlink_delinearize_chain(struct netlink_ctx 
*ctx,
                                                    &policy);
                        nftnl_chain_get_u32(nlc, NFTNL_CHAIN_POLICY);
                if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_DEV)) {
-                       chain->dev      =
+                       chain->dev_array = xmalloc(sizeof(char *));
+                       chain->dev_array_len = 1;
+                       chain->dev_array[0] =
                                xstrdup(nftnl_chain_get_str(nlc, 
NFTNL_CHAIN_DEV));
+                       chain->dev_array[1] = NULL;
+               } else if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_DEVICES)) {
+                       dev_array = nftnl_chain_get(nlc, NFTNL_CHAIN_DEVICES);
+                       while (dev_array[len])
+                               len++;
+
+                       chain->dev_array = xmalloc(len * sizeof(char *));
+                       for (i = 0; i < len; i++)
+                               chain->dev_array[i] = xstrdup(dev_array[i]);
+
+                       chain->dev_array[i] = NULL;
+                       chain->dev_array_len = len;
                }
                chain->flags        |= CHAIN_F_BASECHAIN;
        }
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 11f0dc8b2153..7f9b1752f41d 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -564,11 +564,11 @@ int nft_lex(void *, void *, void *);
 %type <val>                    family_spec family_spec_explicit
 %type <val32>                  int_num chain_policy
 %type <prio_spec>              extended_prio_spec prio_spec
-%type <string>                 extended_prio_name
-%destructor { xfree($$); }     extended_prio_name
+%type <string>                 extended_prio_name quota_unit
+%destructor { xfree($$); }     extended_prio_name quota_unit
 
-%type <string>                 dev_spec quota_unit
-%destructor { xfree($$); }     dev_spec quota_unit
+%type <expr>                   dev_spec
+%destructor { xfree($$); }     dev_spec
 
 %type <table>                  table_block_alloc table_block
 %destructor { close_scope(state); table_free($$); }    table_block_alloc
@@ -1992,7 +1992,7 @@ hook_spec         :       TYPE            STRING          
HOOK            STRING          dev_spec        prio_spec
                                }
                                xfree($4);
 
-                               $<chain>0->dev          = $5;
+                               $<chain>0->dev_expr     = $5;
                                $<chain>0->priority     = $6;
                                $<chain>0->flags        |= CHAIN_F_BASECHAIN;
                        }
@@ -2072,7 +2072,21 @@ int_num                  :       NUM                     
{ $$ = $1; }
                        |       DASH    NUM             { $$ = -$2; }
                        ;
 
-dev_spec               :       DEVICE  string          { $$ = $2; }
+dev_spec               :       DEVICE  string
+                       {
+                               struct expr *expr;
+
+                               expr = constant_expr_alloc(&@$, &string_type,
+                                                          
BYTEORDER_HOST_ENDIAN,
+                                                          strlen($2) * 
BITS_PER_BYTE, $2);
+                               $$ = compound_expr_alloc(&@$, EXPR_LIST);
+                               compound_expr_add($$, expr);
+
+                       }
+                       |       DEVICES         '='     flowtable_expr
+                       {
+                               $$ = $3;
+                       }
                        |       /* empty */             { $$ = NULL; }
                        ;
 
diff --git a/src/parser_json.c b/src/parser_json.c
index 55dbc177cc98..0c79189ec526 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -17,6 +17,7 @@
 #include <netinet/icmp6.h>
 #include <netinet/ip.h>
 #include <netinet/ip_icmp.h>
+#include <net/if.h>
 #include <linux/xfrm.h>
 
 #include <linux/netfilter.h>
@@ -2581,8 +2582,9 @@ static struct cmd *json_parse_cmd_add_chain(struct 
json_ctx *ctx, json_t *root,
                .table.location = *int_loc,
        };
        const char *family = "", *policy = "", *type, *hookstr;
-       int prio;
+       const char name[IFNAMSIZ];
        struct chain *chain;
+       int prio;
 
        if (json_unpack_err(ctx, root, "{s:s, s:s}",
                            "family", &family,
@@ -2626,8 +2628,18 @@ static struct cmd *json_parse_cmd_add_chain(struct 
json_ctx *ctx, json_t *root,
                return NULL;
        }
 
-       if (!json_unpack(root, "{s:s}", "dev", &chain->dev))
-               chain->dev = xstrdup(chain->dev);
+       if (!json_unpack(root, "{s:s}", "dev", &name)) {
+               struct expr *dev_expr, *expr;
+
+               dev_expr = compound_expr_alloc(int_loc, EXPR_LIST);
+               expr = constant_expr_alloc(int_loc, &integer_type,
+                                          BYTEORDER_HOST_ENDIAN,
+                                          strlen(name) * BITS_PER_BYTE,
+                                          name);
+               compound_expr_add(dev_expr, expr);
+               chain->dev_expr = dev_expr;
+       }
+
        if (!json_unpack(root, "{s:s}", "policy", &policy)) {
                chain->policy = parse_policy(policy);
                if (chain->policy < 0) {
diff --git a/src/rule.c b/src/rule.c
index 55894cbdb766..ec7bcb97425e 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -813,6 +813,7 @@ struct chain *chain_get(struct chain *chain)
 void chain_free(struct chain *chain)
 {
        struct rule *rule, *next;
+       int i;
 
        if (--chain->refcnt > 0)
                return;
@@ -821,8 +822,10 @@ void chain_free(struct chain *chain)
        handle_free(&chain->handle);
        scope_release(&chain->scope);
        xfree(chain->type);
-       if (chain->dev != NULL)
-               xfree(chain->dev);
+       expr_free(chain->dev_expr);
+       for (i = 0; i < chain->dev_array_len; i++)
+               xfree(chain->dev_array[i]);
+       xfree(chain->dev_array);
        expr_free(chain->priority.expr);
        expr_free(chain->policy);
        xfree(chain);
@@ -1101,7 +1104,7 @@ static void chain_print_declaration(const struct chain 
*chain,
                                    struct output_ctx *octx)
 {
        char priobuf[STD_PRIO_BUFSIZE];
-       int policy;
+       int policy, i;
 
        nft_print(octx, "\tchain %s {", chain->handle.chain.name);
        if (nft_output_handle(octx))
@@ -1110,8 +1113,17 @@ static void chain_print_declaration(const struct chain 
*chain,
        if (chain->flags & CHAIN_F_BASECHAIN) {
                nft_print(octx, "\t\ttype %s hook %s", chain->type,
                          hooknum2str(chain->handle.family, chain->hooknum));
-               if (chain->dev != NULL)
-                       nft_print(octx, " device \"%s\"", chain->dev);
+               if (chain->dev_array_len == 1) {
+                       nft_print(octx, " device \"%s\"", chain->dev_array[0]);
+               } else if (chain->dev_array_len > 1) {
+                       nft_print(octx, " devices = { ");
+                       for (i = 0; i < chain->dev_array_len; i++) {
+                               nft_print(octx, "%s", chain->dev_array[i]);
+                                       if (i + 1 != chain->dev_array_len)
+                                               nft_print(octx, ", ");
+                       }
+                       nft_print(octx, " }");
+               }
                nft_print(octx, " priority %s;",
                          prio2str(octx, priobuf, sizeof(priobuf),
                                   chain->handle.family, chain->hooknum,
-- 
2.11.0

Reply via email to