From 3fdc7541fba079f9626bcb1605368a7da3a8d81a Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 26 Oct 2019 13:15:10 +0200 Subject: src: add multidevice support for netdev chain 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 --- 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 2708cbeb..ba40db88 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 13a06424..56b20549 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 75ab07b0..492381da 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 * sizeof(char *)); + } + } + + 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 1e669e5d..c47771d3 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 11f0dc8b..7f9b1752 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -564,11 +564,11 @@ int nft_lex(void *, void *, void *); %type family_spec family_spec_explicit %type int_num chain_policy %type extended_prio_spec prio_spec -%type extended_prio_name -%destructor { xfree($$); } extended_prio_name +%type extended_prio_name quota_unit +%destructor { xfree($$); } extended_prio_name quota_unit -%type dev_spec quota_unit -%destructor { xfree($$); } dev_spec quota_unit +%type dev_spec +%destructor { xfree($$); } dev_spec %type 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); - $0->dev = $5; + $0->dev_expr = $5; $0->priority = $6; $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 fe0c5df9..a9bcb84f 100644 --- a/src/parser_json.c +++ b/src/parser_json.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -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) { diff --git a/src/rule.c b/src/rule.c index 64756bce..c258f12e 100644 --- a/src/rule.c +++ b/src/rule.c @@ -814,6 +814,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; @@ -822,8 +823,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); @@ -1102,7 +1105,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)) @@ -1111,8 +1114,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, -- cgit v1.2.3