From: Alexandre Knecht Date: Tue, 20 Jan 2026 19:53:01 +0000 (+0100) Subject: parser_json: support handle for rule positioning in explicit JSON format X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=26d84debe2f21a9df409b9376f4a2624743ab6ea;p=thirdparty%2Fnftables.git parser_json: support handle for rule positioning in explicit JSON format This patch enables handle-based rule positioning for JSON add/insert commands by using a context flag to distinguish between explicit and implicit command formats. When processing JSON: - Explicit commands like {"add": {"rule": ...}} set no flag, allowing handle fields to be converted to position for rule placement - Implicit format (bare objects like {"rule": ...}, used in export/import) sets CTX_F_IMPLICIT flag, causing handles to be ignored for portability This approach ensures that: - Explicit rule adds with handles work for positioning - Non-rule objects (tables, chains, sets, etc.) are unaffected - Export/import remains compatible (handles ignored) The semantics for explicit rule commands are: ADD with handle: inserts rule AFTER the specified handle INSERT with handle: inserts rule BEFORE the specified handle Implementation details: - CTX_F_IMPLICIT flag (bit 10) marks implicit add commands - CTX_F_EXPR_MASK uses inverse mask for future-proof expression flag filtering - Handle-to-position conversion in json_parse_cmd_add_rule() - Variables declared at function start per project style Link: https://patchwork.ozlabs.org/project/netfilter-devel/patch/20251029224530.1962783-2-knecht.alexandre@gmail.com/ Suggested-by: Phil Sutter Suggested-by: Florian Westphal Signed-off-by: Alexandre Knecht Signed-off-by: Phil Sutter --- diff --git a/src/parser_json.c b/src/parser_json.c index 7b4f3384..67e4f2c0 100644 --- a/src/parser_json.c +++ b/src/parser_json.c @@ -51,6 +51,10 @@ #define CTX_F_MAP (1 << 7) /* LHS of map_expr */ #define CTX_F_CONCAT (1 << 8) /* inside concat_expr */ #define CTX_F_COLLAPSED (1 << 9) +#define CTX_F_IMPLICIT (1 << 10) /* implicit add (export/import format) */ + +/* Mask for flags that affect expression parsing context (all except command-level flags) */ +#define CTX_F_EXPR_MASK (UINT32_MAX & ~(CTX_F_COLLAPSED | CTX_F_IMPLICIT)) struct json_ctx { struct nft_ctx *nft; @@ -1725,10 +1729,14 @@ static struct expr *json_parse_expr(struct json_ctx *ctx, json_t *root) return NULL; for (i = 0; i < array_size(cb_tbl); i++) { + uint32_t expr_flags; + if (strcmp(type, cb_tbl[i].name)) continue; - if ((cb_tbl[i].flags & ctx->flags) != ctx->flags) { + /* Only check expression context flags, not command-level flags */ + expr_flags = ctx->flags & CTX_F_EXPR_MASK; + if ((cb_tbl[i].flags & expr_flags) != expr_flags) { json_error(ctx, "Expression type %s not allowed in context (%s).", type, ctx_flags_to_string(ctx)); return NULL; @@ -3201,6 +3209,17 @@ static struct cmd *json_parse_cmd_add_rule(struct json_ctx *ctx, json_t *root, h.index.id++; } + /* For explicit add/insert/create commands, handle is used for positioning. + * Convert handle to position for proper rule placement. + * Skip this for implicit adds (export/import format). + */ + if (!(ctx->flags & CTX_F_IMPLICIT) && + (op == CMD_INSERT || op == CMD_ADD || op == CMD_CREATE) && + !json_unpack(root, "{s:I}", "handle", &h.handle.id)) { + h.position.id = h.handle.id; + h.handle.id = 0; + } + rule = rule_alloc(int_loc, NULL); json_unpack(root, "{s:s}", "comment", &comment); @@ -4342,6 +4361,8 @@ static struct cmd *json_parse_cmd(struct json_ctx *ctx, json_t *root) //{ "monitor", CMD_MONITOR, json_parse_cmd_monitor }, //{ "describe", CMD_DESCRIBE, json_parse_cmd_describe } }; + uint32_t old_flags; + struct cmd *cmd; unsigned int i; json_t *tmp; @@ -4352,8 +4373,17 @@ static struct cmd *json_parse_cmd(struct json_ctx *ctx, json_t *root) return parse_cb_table[i].cb(ctx, tmp, parse_cb_table[i].op); } - /* to accept 'list ruleset' output 1:1, try add command */ - return json_parse_cmd_add(ctx, root, CMD_ADD); + /* to accept 'list ruleset' output 1:1, try add command + * Mark as implicit to distinguish from explicit add commands. + * This allows explicit {"add": {"rule": ...}} to use handle for positioning + * while implicit {"rule": ...} (export format) ignores handles. + */ + old_flags = ctx->flags; + ctx->flags |= CTX_F_IMPLICIT; + cmd = json_parse_cmd_add(ctx, root, CMD_ADD); + ctx->flags = old_flags; + + return cmd; } static int json_verify_metainfo(struct json_ctx *ctx, json_t *root)