This patch enables the user to specify a comment when adding a chain. Relies on kernel space supporting userdata for chains. > nft add table ip filter > nft add chain ip filter input { comment "test"\; type filter hook input priority 0\; policy accept\; } > list ruleset table ip filter { chain input { comment "test" type filter hook input priority filter; policy accept; } } Signed-off-by: Jose M. Guisado Gomez <guigom@xxxxxxxxxx> --- include/rule.h | 1 + src/mnl.c | 11 +++++++ src/netlink.c | 32 +++++++++++++++++++ src/parser_bison.y | 8 +++++ src/rule.c | 3 ++ .../testcases/optionals/comments_chain_0 | 12 +++++++ .../optionals/dumps/comments_chain_0.nft | 5 +++ 7 files changed, 72 insertions(+) create mode 100755 tests/shell/testcases/optionals/comments_chain_0 create mode 100644 tests/shell/testcases/optionals/dumps/comments_chain_0.nft diff --git a/include/rule.h b/include/rule.h index 837005b1..ffe8daab 100644 --- a/include/rule.h +++ b/include/rule.h @@ -225,6 +225,7 @@ struct chain { struct location location; unsigned int refcnt; uint32_t flags; + const char *comment; struct { struct location loc; struct prio_spec priority; diff --git a/src/mnl.c b/src/mnl.c index ca4f4b2a..3e0de103 100644 --- a/src/mnl.c +++ b/src/mnl.c @@ -612,6 +612,7 @@ err: int mnl_nft_chain_add(struct netlink_ctx *ctx, struct cmd *cmd, unsigned int flags) { + struct nftnl_udata_buf *udbuf; int priority, policy, i = 0; struct nftnl_chain *nlc; unsigned int ifname_len; @@ -672,6 +673,16 @@ int mnl_nft_chain_add(struct netlink_ctx *ctx, struct cmd *cmd, xfree(dev_array); } + if (cmd->chain->comment) { + udbuf = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN); + if (!udbuf) + memory_allocation_error(); + if (!nftnl_udata_put_strz(udbuf, NFTNL_UDATA_CHAIN_COMMENT, cmd->chain->comment)) + memory_allocation_error(); + nftnl_chain_set_data(nlc, NFTNL_CHAIN_USERDATA, nftnl_udata_buf_data(udbuf), + nftnl_udata_buf_len(udbuf)); + nftnl_udata_buf_free(udbuf); + } } netlink_dump_chain(nlc, ctx); diff --git a/src/netlink.c b/src/netlink.c index 6912b018..f8ac2b9e 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -472,12 +472,34 @@ void netlink_dump_chain(const struct nftnl_chain *nlc, struct netlink_ctx *ctx) fprintf(fp, "\n"); } +static int chain_parse_udata_cb(const struct nftnl_udata *attr, void *data) +{ + unsigned char *value = nftnl_udata_get(attr); + uint8_t type = nftnl_udata_type(attr); + const struct nftnl_udata **tb = data; + uint8_t len = nftnl_udata_len(attr); + + switch (type) { + case NFTNL_UDATA_CHAIN_COMMENT: + if (value[len - 1] != '\0') + return -1; + break; + default: + return 0; + } + tb[type] = attr; + return 0; +} + struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx, const struct nftnl_chain *nlc) { + const struct nftnl_udata *ud[NFTNL_UDATA_OBJ_MAX + 1] = {}; int priority, policy, len = 0, i; const char * const *dev_array; struct chain *chain; + const char *udata; + uint32_t ulen; chain = chain_alloc(nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME)); chain->handle.family = @@ -534,6 +556,16 @@ struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx, chain->flags |= CHAIN_F_BASECHAIN; } + if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_USERDATA)) { + udata = nftnl_chain_get_data(nlc, NFTNL_CHAIN_USERDATA, &ulen); + if (nftnl_udata_parse(udata, ulen, chain_parse_udata_cb, ud) < 0) { + netlink_io_error(ctx, NULL, "Cannot parse userdata"); + return NULL; + } + if (ud[NFTNL_UDATA_CHAIN_COMMENT]) + chain->comment = xstrdup(nftnl_udata_get(ud[NFTNL_UDATA_CHAIN_COMMENT])); + } + return chain; } diff --git a/src/parser_bison.y b/src/parser_bison.y index c7ea520c..4c71cd61 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -1724,6 +1724,14 @@ chain_block : /* empty */ { $$ = $<chain>-1; } list_add_tail(&$2->list, &$1->rules); $$ = $1; } + | chain_block comment_spec stmt_separator + { + if (already_set($1->comment, &@2, state)) { + xfree($2); + YYERROR; + } + $1->comment = $2; + } ; subchain_block : /* empty */ { $$ = $<chain>-1; } diff --git a/src/rule.c b/src/rule.c index dabb3579..d75b36c4 100644 --- a/src/rule.c +++ b/src/rule.c @@ -929,6 +929,7 @@ void chain_free(struct chain *chain) xfree(chain->dev_array); expr_free(chain->priority.expr); expr_free(chain->policy); + xfree(chain->comment); xfree(chain); } @@ -1220,6 +1221,8 @@ static void chain_print_declaration(const struct chain *chain, nft_print(octx, "\tchain %s {", chain->handle.chain.name); if (nft_output_handle(octx)) nft_print(octx, " # handle %" PRIu64, chain->handle.handle.id); + if (chain->comment) + nft_print(octx, "\n\t\tcomment \"%s\"", chain->comment); nft_print(octx, "\n"); if (chain->flags & CHAIN_F_BASECHAIN) { nft_print(octx, "\t\ttype %s hook %s", chain->type, diff --git a/tests/shell/testcases/optionals/comments_chain_0 b/tests/shell/testcases/optionals/comments_chain_0 new file mode 100755 index 00000000..fba961c7 --- /dev/null +++ b/tests/shell/testcases/optionals/comments_chain_0 @@ -0,0 +1,12 @@ +#!/bin/bash + +EXPECTED='table ip test_table { + chain test_chain { + comment "test" + } +} +' + +set -e + +$NFT -f - <<< "$EXPECTED" diff --git a/tests/shell/testcases/optionals/dumps/comments_chain_0.nft b/tests/shell/testcases/optionals/dumps/comments_chain_0.nft new file mode 100644 index 00000000..be3d8f33 --- /dev/null +++ b/tests/shell/testcases/optionals/dumps/comments_chain_0.nft @@ -0,0 +1,5 @@ +table ip test_table { + chain test_chain { + comment "test" + } +} -- 2.27.0