Place new chains, flowtables, and sets and objects in struct table and let nft_cmd_expand() allocate the commands instead. Likewise new rules get appended to chain->rules. This makes sure chains are created before set elements that reference them, and rules get created after sets that are referenced by rules. Instead of allocating a new command, search for the table/chain in the existing transaction queue and append the object there. Signed-off-by: Florian Westphal <fw@xxxxxxxxx> --- src/parser_json.c | 129 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 123 insertions(+), 6 deletions(-) diff --git a/src/parser_json.c b/src/parser_json.c index 91c1e01cee52..a557e3ee81a3 100644 --- a/src/parser_json.c +++ b/src/parser_json.c @@ -55,6 +55,7 @@ struct json_ctx { struct list_head *msgs; struct list_head *cmds; uint32_t flags; + bool in_ruleset; }; #define is_RHS(ctx) (ctx->flags & CTX_F_RHS) @@ -2977,6 +2978,55 @@ static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root) return NULL; } +static bool table_eq(const struct handle *th, const struct handle *handle) +{ + return th->family == handle->family && + strcmp(th->table.name, handle->table.name) == 0; +} + +static struct table *json_cmd_get_table(struct json_ctx *ctx, + const struct handle *handle) +{ + struct cmd *cmd; + + if (!ctx->in_ruleset) + return NULL; + + list_for_each_entry(cmd, ctx->cmds, list) { + if (cmd->op != CMD_ADD) + continue; + if (cmd->obj != CMD_OBJ_TABLE) + continue; + if (table_eq(&cmd->handle, handle)) { + if (cmd->table) + return cmd->table; + + cmd->table = table_alloc(); + handle_merge(&cmd->table->handle, &cmd->handle); + return cmd->table; + } + } + + return NULL; +} + +static struct chain *json_cmd_get_chain(struct json_ctx *ctx, + const struct handle *handle) +{ + struct table *table =json_cmd_get_table(ctx, handle); + struct chain *chain; + + if (!table) + return NULL; + + list_for_each_entry(chain, &table->chains, list) { + if (strcmp(chain->handle.chain.name, handle->chain.name) == 0) + return chain; + } + + return NULL; +} + static struct cmd *json_parse_cmd_add_table(struct json_ctx *ctx, json_t *root, enum cmd_ops op, enum cmd_obj obj) { @@ -3114,8 +3164,23 @@ static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root, op == CMD_LIST || op == CMD_FLUSH || json_unpack(root, "{s:s, s:s, s:i}", - "type", &type, "hook", &hookstr, "prio", &prio)) + "type", &type, "hook", &hookstr, "prio", &prio)) { + struct table *table = json_cmd_get_table(ctx, &h); + + if (table) { + assert(op == CMD_ADD); + + if (!chain) + chain = chain_alloc(); + + handle_merge(&chain->handle, &h); + list_add_tail(&chain->list, &table->chains); + handle_free(&h); + return NULL; + } + return cmd_alloc(op, obj, &h, int_loc, chain); + } if (!chain) chain = chain_alloc(); @@ -3153,10 +3218,20 @@ static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root, } } - if (op == CMD_ADD) + handle_merge(&chain->handle, &h); + + if (op == CMD_ADD) { + struct table *table = json_cmd_get_table(ctx, &h); + json_object_del(root, "handle"); - handle_merge(&chain->handle, &h); + if (table) { + list_add_tail(&chain->list, &table->chains); + handle_free(&h); + return NULL; + } + } + return cmd_alloc(op, obj, &h, int_loc, chain); } @@ -3231,9 +3306,17 @@ static struct cmd *json_parse_cmd_add_rule(struct json_ctx *ctx, json_t *root, rule_stmt_append(rule, stmt); } - if (op == CMD_ADD) + if (op == CMD_ADD) { + struct chain *chain = json_cmd_get_chain(ctx, &h); + json_object_del(root, "handle"); + if (chain) { + list_add_tail(&rule->list, &chain->rules); + handle_free(&h); + return NULL; + } + } return cmd_alloc(op, obj, &h, int_loc, rule); } @@ -3399,9 +3482,18 @@ static struct cmd *json_parse_cmd_add_set(struct json_ctx *ctx, json_t *root, handle_merge(&set->handle, &h); - if (op == CMD_ADD) + if (op == CMD_ADD) { + struct table *table = json_cmd_get_table(ctx, &h); + json_object_del(root, "handle"); + if (table) { + list_add_tail(&set->list, &table->sets); + handle_free(&h); + return NULL; + } + } + return cmd_alloc(op, obj, &h, int_loc, set); } @@ -3505,6 +3597,18 @@ static struct cmd *json_parse_cmd_add_flowtable(struct json_ctx *ctx, return CMD_ERR_PTR(-1); } } + + if (op == CMD_ADD) { + struct table *table = json_cmd_get_table(ctx, &h); + + if (table) { + handle_merge(&flowtable->handle, &h); + list_add_tail(&flowtable->list, &table->flowtables); + handle_free(&h); + return NULL; + } + } + return cmd_alloc(op, cmd_obj, &h, int_loc, flowtable); } @@ -3754,9 +3858,19 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx, BUG("Invalid CMD '%d'", cmd_obj); } - if (op == CMD_ADD) + if (op == CMD_ADD) { + struct table *table = json_cmd_get_table(ctx, &h); + json_object_del(root, "handle"); + if (table) { + handle_merge(&obj->handle, &h); + list_add_tail(&obj->list, &table->objs); + handle_free(&h); + return NULL; + } + } + return cmd_alloc(op, cmd_obj, &h, int_loc, obj); } @@ -4160,10 +4274,13 @@ static int json_parse_cmd(struct json_ctx *ctx, json_t *root) return -1; } + assert(!ctx->in_ruleset); + ctx->in_ruleset = true; /* to accept 'list ruleset' output 1:1, try add command */ cmd = json_parse_cmd_add(ctx, root, CMD_ADD); if (CMD_IS_ERR(cmd)) return -1; + ctx->in_ruleset = false; out: if (cmd) { -- 2.43.0