From: Phil Sutter Date: Fri, 27 Sep 2024 22:55:34 +0000 (+0200) Subject: json: Support typeof in set and map types X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=5ba01aecc101d55bbe1e93b3d29614fb84052f54;p=thirdparty%2Fnftables.git json: Support typeof in set and map types commit bb6312484af93a83a9ec8716f3887a43566a775a upstream. Implement this as a special "type" property value which is an object with sole property "typeof". The latter's value is the JSON representation of the expression in set->key, so for concatenated typeofs it is a concat expression. All this is a bit clumsy right now but it works and it should be possible to tear it down a bit for more user-friendliness in a compatible way by either replacing the concat expression by the array it contains or even the whole "typeof" object - the parser would just assume any object (or objects in an array) in the "type" property value are expressions to extract a type from. Signed-off-by: Phil Sutter --- diff --git a/doc/libnftables-json.adoc b/doc/libnftables-json.adoc index 1cce0e69..10c17fa1 100644 --- a/doc/libnftables-json.adoc +++ b/doc/libnftables-json.adoc @@ -332,7 +332,7 @@ ____ "auto-merge":* 'BOOLEAN' *}}* -'SET_TYPE' := 'STRING' | *[* 'SET_TYPE_LIST' *]* +'SET_TYPE' := 'STRING' | *[* 'SET_TYPE_LIST' *]* | *{ "typeof":* 'EXPRESSION' *}* 'SET_TYPE_LIST' := 'STRING' [*,* 'SET_TYPE_LIST' ] 'SET_POLICY' := *"performance"* | *"memory"* 'SET_FLAG_LIST' := 'SET_FLAG' [*,* 'SET_FLAG_LIST' ] @@ -372,8 +372,9 @@ that they translate a unique key to a value. Automatic merging of adjacent/overlapping set elements in interval sets. ==== TYPE -The set type might be a string, such as *"ipv4_addr"* or an array -consisting of strings (for concatenated types). +The set type might be a string, such as *"ipv4_addr"*, an array +consisting of strings (for concatenated types) or a *typeof* object containing +an expression to extract the type from. ==== ELEM A single set element might be given as string, integer or boolean value for diff --git a/src/json.c b/src/json.c index e950157f..9e4e1c1f 100644 --- a/src/json.c +++ b/src/json.c @@ -86,6 +86,17 @@ static json_t *set_dtype_json(const struct expr *key) return root; } +static json_t *set_key_dtype_json(const struct set *set, + struct output_ctx *octx) +{ + bool use_typeof = set->key_typeof_valid; + + if (!use_typeof) + return set_dtype_json(set->key); + + return json_pack("{s:o}", "typeof", expr_print_json(set->key, octx)); +} + static json_t *stmt_print_json(const struct stmt *stmt, struct output_ctx *octx) { char buf[1024]; @@ -148,7 +159,7 @@ static json_t *set_print_json(struct output_ctx *octx, const struct set *set) "family", family2str(set->handle.family), "name", set->handle.set.name, "table", set->handle.table.name, - "type", set_dtype_json(set->key), + "type", set_key_dtype_json(set, octx), "handle", set->handle.handle.id); if (set->comment) diff --git a/src/parser_json.c b/src/parser_json.c index 5f66a38b..f37304ad 100644 --- a/src/parser_json.c +++ b/src/parser_json.c @@ -1657,7 +1657,16 @@ static struct expr *json_parse_dtype_expr(struct json_ctx *ctx, json_t *root) compound_expr_add(expr, i); } return expr; + } else if (json_is_object(root)) { + const char *key; + json_t *val; + + if (!json_unpack_stmt(ctx, root, &key, &val) && + !strcmp(key, "typeof")) { + return json_parse_expr(ctx, val); + } } + json_error(ctx, "Invalid set datatype."); return NULL; }