From 2fa54d8a49352bda44d3e25d1d7ba3531faf3303 Mon Sep 17 00:00:00 2001 From: Shyam Saini Date: Tue, 5 Dec 2017 19:37:34 +0530 Subject: src: Add import command for low level json This new operation allows to import low level virtual machine ruleset in json to make incremental changes using the parse functions of libnftnl. A basic way to test this new functionality is: $ cat file.json | nft import vm json where the file.json is a ruleset exported in low level json format. To export json rules in low level virtual machine format we need to specify "vm" token before json. See below $ nft export vm json and $ nft export/import json will do no operations. Same goes with "$nft monitor" Highly based on work from Alvaro Neira and Arturo Borrero Acked-by: Arturo Borrero Gonzalez Signed-off-by: Shyam Saini Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 285 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 285 insertions(+) (limited to 'src/netlink.c') diff --git a/src/netlink.c b/src/netlink.c index 9677ffc0..23f92443 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -3035,6 +3036,290 @@ int netlink_monitor(struct netlink_mon_handler *monhandler, monhandler); } +static int netlink_markup_setelems(const struct nftnl_parse_ctx *ctx) +{ + const struct ruleset_parse *rp; + struct nftnl_set *set; + uint32_t cmd; + int ret = -1; + + set = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_SET); + rp = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_DATA); + + cmd = nftnl_ruleset_ctx_get_u32(ctx, NFTNL_RULESET_CTX_CMD); + switch (cmd) { + case NFTNL_CMD_ADD: + ret = mnl_nft_setelem_batch_add(set, rp->nl_ctx->batch, + 0, rp->nl_ctx->seqnum); + break; + case NFTNL_CMD_DELETE: + ret = mnl_nft_setelem_batch_del(set, rp->nl_ctx->batch, + 0, rp->nl_ctx->seqnum); + break; + default: + errno = EOPNOTSUPP; + break; + } + + return ret; +} + +static int netlink_markup_set(const struct nftnl_parse_ctx *ctx) +{ + const struct ruleset_parse *rp; + struct nftnl_set *set; + uint32_t cmd; + int ret = -1; + + set = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_SET); + rp = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_DATA); + + cmd = nftnl_ruleset_ctx_get_u32(ctx, NFTNL_RULESET_CTX_CMD); + switch (cmd) { + case NFTNL_CMD_ADD: + ret = mnl_nft_set_batch_add(set, rp->nl_ctx->batch, NLM_F_EXCL, + rp->nl_ctx->seqnum); + break; + case NFTNL_CMD_DELETE: + ret = mnl_nft_set_batch_del(set, rp->nl_ctx->batch, + 0, rp->nl_ctx->seqnum); + break; + default: + errno = EOPNOTSUPP; + break; + } + + if (ret < 0) + return ret; + + return netlink_markup_setelems(ctx); +} + +static int netlink_markup_build_rule(const struct nftnl_parse_ctx *ctx, + uint32_t cmd, struct nftnl_rule *rule) +{ + const struct ruleset_parse *rp; + uint32_t nl_flags; + int ret = -1; + + rp = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_DATA); + + switch (cmd) { + case NFTNL_CMD_ADD: + nl_flags = NLM_F_APPEND | NLM_F_CREATE; + nftnl_rule_unset(rule, NFTNL_RULE_HANDLE); + ret = mnl_nft_rule_batch_add(rule, rp->nl_ctx->batch, nl_flags, + rp->nl_ctx->seqnum); + break; + case NFTNL_CMD_DELETE: + ret = mnl_nft_rule_batch_del(rule, rp->nl_ctx->batch, + 0, rp->nl_ctx->seqnum); + break; + case NFTNL_CMD_REPLACE: + nl_flags = NLM_F_REPLACE; + ret = mnl_nft_rule_batch_add(rule, rp->nl_ctx->batch, nl_flags, + rp->nl_ctx->seqnum); + break; + case NFTNL_CMD_INSERT: + nl_flags = NLM_F_CREATE; + nftnl_rule_unset(rule, NFTNL_RULE_HANDLE); + ret = mnl_nft_rule_batch_add(rule, rp->nl_ctx->batch, nl_flags, + rp->nl_ctx->seqnum); + break; + default: + errno = EOPNOTSUPP; + break; + } + + return ret; + +} + +static int netlink_markup_rule(const struct nftnl_parse_ctx *ctx) +{ + struct nftnl_rule *rule; + uint32_t cmd; + + cmd = nftnl_ruleset_ctx_get_u32(ctx, NFTNL_RULESET_CTX_CMD); + rule = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_RULE); + + return netlink_markup_build_rule(ctx, cmd, rule); +} + +static int netlink_markup_build_flush(const struct nftnl_parse_ctx *ctx) +{ + struct nftnl_rule *rule; + struct nftnl_table *table; + struct nftnl_chain *chain; + const char *table_get_name, *table_get_family; + const char *chain_get_table, *chain_get_name, *chain_get_family; + uint32_t type; + int ret = -1; + + rule = nftnl_rule_alloc(); + if (rule == NULL) + return -1; + + type = nftnl_ruleset_ctx_get_u32(ctx, NFTNL_RULESET_CTX_TYPE); + switch (type) { + case NFTNL_RULESET_TABLE: + table = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_TABLE); + table_get_name = nftnl_table_get(table, NFTNL_TABLE_NAME); + table_get_family = nftnl_table_get(table, NFTNL_TABLE_FAMILY); + + nftnl_rule_set(rule, NFTNL_RULE_TABLE, table_get_name); + nftnl_rule_set(rule, NFTNL_RULE_FAMILY, table_get_family); + break; + case NFTNL_RULESET_CHAIN: + chain = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_CHAIN); + chain_get_table = nftnl_chain_get(chain, NFTNL_CHAIN_TABLE); + chain_get_name = nftnl_chain_get(chain, NFTNL_CHAIN_NAME); + chain_get_family = nftnl_chain_get(chain, NFTNL_TABLE_FAMILY); + + nftnl_rule_set(rule, NFTNL_RULE_TABLE, chain_get_table); + nftnl_rule_set(rule, NFTNL_RULE_CHAIN, chain_get_name); + nftnl_rule_set(rule, NFTNL_RULE_FAMILY, chain_get_family); + break; + default: + errno = EOPNOTSUPP; + goto err; + } + + ret = netlink_markup_build_rule(ctx, NFTNL_CMD_DELETE, rule); +err: + nftnl_rule_free(rule); + return ret; +} + +static int netlink_markup_chain(const struct nftnl_parse_ctx *ctx) +{ + const struct ruleset_parse *rp; + struct nftnl_chain *chain; + uint32_t cmd; + int ret = -1; + + chain = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_CHAIN); + rp = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_DATA); + + nftnl_chain_unset(chain, NFTNL_CHAIN_HANDLE); + + cmd = nftnl_ruleset_ctx_get_u32(ctx, NFTNL_RULESET_CTX_CMD); + switch (cmd) { + case NFTNL_CMD_ADD: + ret = mnl_nft_chain_batch_add(chain, rp->nl_ctx->batch, + 0, rp->nl_ctx->seqnum); + break; + case NFTNL_CMD_DELETE: + ret = mnl_nft_chain_batch_del(chain, rp->nl_ctx->batch, + 0, rp->nl_ctx->seqnum); + break; + case NFTNL_CMD_FLUSH: + ret = netlink_markup_build_flush(ctx); + break; + default: + errno = EOPNOTSUPP; + break; + } + + return ret; +} + + +static int netlink_markup_build_table(const struct nftnl_parse_ctx *ctx, + uint32_t cmd, struct nftnl_table *table) +{ + struct ruleset_parse *rp; + int ret = -1; + + rp = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_DATA); + + switch (cmd) { + case NFTNL_CMD_ADD: + ret = mnl_nft_table_batch_add(table, rp->nl_ctx->batch, + 0, rp->nl_ctx->seqnum); + break; + case NFTNL_CMD_DELETE: + ret = mnl_nft_table_batch_del(table, rp->nl_ctx->batch, + 0, rp->nl_ctx->seqnum); + break; + case NFTNL_CMD_FLUSH: + ret = netlink_markup_build_flush(ctx); + break; + default: + errno = EOPNOTSUPP; + break; + } + + return ret; +} + +static int netlink_markup_table(const struct nftnl_parse_ctx *ctx) +{ + struct nftnl_table *table; + uint32_t cmd; + + cmd = nftnl_ruleset_ctx_get_u32(ctx, NFTNL_RULESET_CTX_CMD); + table = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_TABLE); + + return netlink_markup_build_table(ctx, cmd, table); +} + +static int netlink_markup_flush(const struct nftnl_parse_ctx *ctx) +{ + struct nftnl_table *table; + int ret; + + table = nftnl_table_alloc(); + if (table == NULL) + return -1; + + ret = netlink_markup_build_table(ctx, NFTNL_CMD_DELETE, table); + nftnl_table_free(table); + + return ret; +} + +int netlink_markup_parse_cb(const struct nftnl_parse_ctx *ctx) +{ + struct ruleset_parse *rp; + uint32_t type; + int ret = -1; + + rp = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_DATA); + + type = nftnl_ruleset_ctx_get_u32(ctx, NFTNL_RULESET_CTX_TYPE); + switch (type) { + case NFTNL_RULESET_TABLE: + ret = netlink_markup_table(ctx); + break; + case NFTNL_RULESET_CHAIN: + ret = netlink_markup_chain(ctx); + break; + case NFTNL_RULESET_RULE: + ret = netlink_markup_rule(ctx); + break; + case NFTNL_RULESET_SET: + ret = netlink_markup_set(ctx); + break; + case NFTNL_RULESET_SET_ELEMS: + ret = netlink_markup_setelems(ctx); + break; + case NFTNL_RULESET_RULESET: + ret = netlink_markup_flush(ctx); + break; + default: + errno = EOPNOTSUPP; + break; + } + + nftnl_ruleset_ctx_free(ctx); + if (ret < 0) + netlink_io_error(rp->nl_ctx, &rp->cmd->location, + "Could not import: %s", strerror(errno)); + + return 0; +} + bool netlink_batch_supported(struct mnl_socket *nf_sock, uint32_t *seqnum) { return mnl_batch_supported(nf_sock, seqnum); -- cgit v1.2.3