* [nft PATCH] parser_json: Introduce parse_flags_array()
@ 2025-05-07 22:28 Phil Sutter
2025-05-08 21:47 ` [nft PATCH 0/6] Add test for parse_flags_array() Phil Sutter
0 siblings, 1 reply; 10+ messages in thread
From: Phil Sutter @ 2025-05-07 22:28 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
Various objects support a 'flags' property with value usually being an
array of strings. There is a special case, when merely a single flag is
set: The value may be a string representing this flag.
Introduce a function assisting in parsing this polymorphic value. Have
callers pass a parser callback translating a single flag name into a
corresponding value. Luckily, these single flag parsers are very common
already.
As a side-effect, enable the single flag spec for set flags as well and
update the documentation accordingly.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
doc/libnftables-json.adoc | 5 +-
src/parser_json.c | 466 +++++++++++---------------------------
2 files changed, 136 insertions(+), 335 deletions(-)
diff --git a/doc/libnftables-json.adoc b/doc/libnftables-json.adoc
index 244eb412fbdc7..643884d5c1063 100644
--- a/doc/libnftables-json.adoc
+++ b/doc/libnftables-json.adoc
@@ -317,7 +317,7 @@ ____
"handle":* 'NUMBER'*,
"type":* 'SET_TYPE'*,
"policy":* 'SET_POLICY'*,
- "flags": [* 'SET_FLAG_LIST' *],
+ "flags":* 'SET_FLAGS'*,
"elem":* 'SET_ELEMENTS'*,
"timeout":* 'NUMBER'*,
"gc-interval":* 'NUMBER'*,
@@ -333,7 +333,7 @@ ____
"type":* 'SET_TYPE'*,
"map":* 'STRING'*,
"policy":* 'SET_POLICY'*,
- "flags": [* 'SET_FLAG_LIST' *],
+ "flags":* 'SET_FLAGS'*,
"elem":* 'SET_ELEMENTS'*,
"timeout":* 'NUMBER'*,
"gc-interval":* 'NUMBER'*,
@@ -344,6 +344,7 @@ ____
'SET_TYPE' := 'STRING' | *[* 'SET_TYPE_LIST' *]* | *{ "typeof":* 'EXPRESSION' *}*
'SET_TYPE_LIST' := 'STRING' [*,* 'SET_TYPE_LIST' ]
'SET_POLICY' := *"performance"* | *"memory"*
+'SET_FLAGS' := 'SET_FLAG' | *[* 'SET_FLAG_LIST' *]*
'SET_FLAG_LIST' := 'SET_FLAG' [*,* 'SET_FLAG_LIST' ]
'SET_FLAG' := *"constant"* | *"interval"* | *"timeout"*
'SET_ELEMENTS' := 'EXPRESSION' | *[* 'EXPRESSION_LIST' *]*
diff --git a/src/parser_json.c b/src/parser_json.c
index 724cba8816235..e3dd14cda3504 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -197,6 +197,60 @@ static int json_unpack_stmt(struct json_ctx *ctx, json_t *root,
return 1;
}
+/**
+ * parse_flags_array - parse JSON property as an array of flags
+ *
+ * @ctx: JSON parser context
+ * @obj: JSON object to extract property from
+ * @key: name of property containing the flags array
+ * @flag_parser: Callback parsing a single flag, returns 0 on error
+ *
+ * The property value may be a string representing a single flag or an array of
+ * strings representing a number of flags whose values are ORed together.
+ *
+ * @return: Combined flag value, 0 if no such property found or -1 if data is
+ * malformed or flag parsing failed.
+ */
+static int parse_flags_array(struct json_ctx *ctx, json_t *obj, const char *key,
+ unsigned int (*flag_parser)(const char *flag))
+{
+ json_t *value = json_object_get(obj, key), *tmp;
+ size_t index;
+ int ret = 0;
+
+ if (!value)
+ return 0;
+
+ if (json_is_string(value)) {
+ ret = flag_parser(json_string_value(value));
+ return ret ?: -1;
+ }
+
+ if (!json_is_array(value)) {
+ json_error(ctx,
+ "Expecting string or array in '%s' property.", key);
+ return -1;
+ }
+
+ json_array_foreach(value, index, tmp) {
+ int flag = 0;
+
+ if (json_is_string(tmp))
+ flag = flag_parser(json_string_value(tmp));
+
+ if (!flag) {
+ json_error(ctx,
+ "Invalid flag in '%s' property array at index %zu.",
+ key, index);
+ return -1;
+ }
+
+ ret |= flag;
+ }
+
+ return ret;
+}
+
static int parse_family(const char *name, uint32_t *family)
{
unsigned int i;
@@ -1077,7 +1131,7 @@ static struct expr *json_parse_hash_expr(struct json_ctx *ctx,
return hash_expr;
}
-static int fib_flag_parse(const char *name, int *flags)
+static unsigned int fib_flag_parse(const char *name)
{
const char *fib_flags[] = {
"saddr",
@@ -1089,12 +1143,10 @@ static int fib_flag_parse(const char *name, int *flags)
unsigned int i;
for (i = 0; i < array_size(fib_flags); i++) {
- if (!strcmp(name, fib_flags[i])) {
- *flags |= (1 << i);
- return 0;
- }
+ if (!strcmp(name, fib_flags[i]))
+ return 1 << i;
}
- return 1;
+ return 0;
}
static struct expr *json_parse_fib_expr(struct json_ctx *ctx,
@@ -1107,11 +1159,9 @@ static struct expr *json_parse_fib_expr(struct json_ctx *ctx,
[NFT_FIB_RESULT_ADDRTYPE] = "type",
};
enum nft_fib_result resultval = NFT_FIB_RESULT_UNSPEC;
- json_t *flags, *value;
const char *result;
- unsigned int i;
- size_t index;
int flagval = 0;
+ unsigned int i;
if (json_unpack_err(ctx, root, "{s:s}", "result", &result))
return NULL;
@@ -1127,34 +1177,9 @@ static struct expr *json_parse_fib_expr(struct json_ctx *ctx,
return NULL;
}
- if (!json_unpack(root, "{s:o}", "flags", &flags)) {
- const char *flag;
-
- if (json_is_string(flags)) {
- flag = json_string_value(flags);
-
- if (fib_flag_parse(flag, &flagval)) {
- json_error(ctx, "Invalid fib flag '%s'.", flag);
- return NULL;
- }
- } else if (!json_is_array(flags)) {
- json_error(ctx, "Unexpected object type in fib tuple.");
- return NULL;
- }
-
- json_array_foreach(flags, index, value) {
- if (!json_is_string(value)) {
- json_error(ctx, "Unexpected object type in fib flags array at index %zd.", index);
- return NULL;
- }
- flag = json_string_value(value);
-
- if (fib_flag_parse(flag, &flagval)) {
- json_error(ctx, "Invalid fib flag '%s'.", flag);
- return NULL;
- }
- }
- }
+ flagval = parse_flags_array(ctx, root, "flags", fib_flag_parse);
+ if (flagval < 0)
+ return NULL;
/* sanity checks from fib_expr in parser_bison.y */
@@ -2151,8 +2176,7 @@ static struct stmt *json_parse_secmark_stmt(struct json_ctx *ctx,
return stmt;
}
-static int json_parse_nat_flag(struct json_ctx *ctx,
- json_t *root, int *flags)
+static unsigned int json_parse_nat_flag(const char *flag)
{
const struct {
const char *flag;
@@ -2163,51 +2187,16 @@ static int json_parse_nat_flag(struct json_ctx *ctx,
{ "persistent", NF_NAT_RANGE_PERSISTENT },
{ "netmap", NF_NAT_RANGE_NETMAP },
};
- const char *flag;
unsigned int i;
- assert(flags);
-
- if (!json_is_string(root)) {
- json_error(ctx, "Invalid nat flag type %s, expected string.",
- json_typename(root));
- return 1;
- }
- flag = json_string_value(root);
for (i = 0; i < array_size(flag_tbl); i++) {
- if (!strcmp(flag, flag_tbl[i].flag)) {
- *flags |= flag_tbl[i].val;
- return 0;
- }
- }
- json_error(ctx, "Unknown nat flag '%s'.", flag);
- return 1;
-}
-
-static int json_parse_nat_flags(struct json_ctx *ctx, json_t *root)
-{
- int flags = 0;
- json_t *value;
- size_t index;
-
- if (json_is_string(root)) {
- json_parse_nat_flag(ctx, root, &flags);
- return flags;
- } else if (!json_is_array(root)) {
- json_error(ctx, "Invalid nat flags type %s.",
- json_typename(root));
- return -1;
- }
- json_array_foreach(root, index, value) {
- if (json_parse_nat_flag(ctx, value, &flags))
- json_error(ctx, "Parsing nat flag at index %zu failed.",
- index);
+ if (!strcmp(flag, flag_tbl[i].flag))
+ return flag_tbl[i].val;
}
- return flags;
+ return 0;
}
-static int json_parse_nat_type_flag(struct json_ctx *ctx,
- json_t *root, int *flags)
+static unsigned int json_parse_nat_type_flag(const char *flag)
{
const struct {
const char *flag;
@@ -2217,47 +2206,13 @@ static int json_parse_nat_type_flag(struct json_ctx *ctx,
{ "prefix", STMT_NAT_F_PREFIX },
{ "concat", STMT_NAT_F_CONCAT },
};
- const char *flag;
unsigned int i;
- assert(flags);
-
- if (!json_is_string(root)) {
- json_error(ctx, "Invalid nat type flag type %s, expected string.",
- json_typename(root));
- return 1;
- }
- flag = json_string_value(root);
for (i = 0; i < array_size(flag_tbl); i++) {
- if (!strcmp(flag, flag_tbl[i].flag)) {
- *flags |= flag_tbl[i].val;
- return 0;
- }
- }
- json_error(ctx, "Unknown nat type flag '%s'.", flag);
- return 1;
-}
-
-static int json_parse_nat_type_flags(struct json_ctx *ctx, json_t *root)
-{
- int flags = 0;
- json_t *value;
- size_t index;
-
- if (json_is_string(root)) {
- json_parse_nat_type_flag(ctx, root, &flags);
- return flags;
- } else if (!json_is_array(root)) {
- json_error(ctx, "Invalid nat flags type %s.",
- json_typename(root));
- return -1;
- }
- json_array_foreach(root, index, value) {
- if (json_parse_nat_type_flag(ctx, value, &flags))
- json_error(ctx, "Parsing nat type flag at index %zu failed.",
- index);
+ if (!strcmp(flag, flag_tbl[i].flag))
+ return flag_tbl[i].val;
}
- return flags;
+ return 0;
}
static int nat_type_parse(const char *type)
@@ -2280,7 +2235,7 @@ static int nat_type_parse(const char *type)
static struct stmt *json_parse_nat_stmt(struct json_ctx *ctx,
const char *key, json_t *value)
{
- int type, familyval;
+ int type, familyval, flags;
struct stmt *stmt;
json_t *tmp;
@@ -2313,24 +2268,20 @@ static struct stmt *json_parse_nat_stmt(struct json_ctx *ctx,
return NULL;
}
}
- if (!json_unpack(value, "{s:o}", "flags", &tmp)) {
- int flags = json_parse_nat_flags(ctx, tmp);
-
- if (flags < 0) {
- stmt_free(stmt);
- return NULL;
- }
- stmt->nat.flags = flags;
+ flags = parse_flags_array(ctx, value, "flags", json_parse_nat_flag);
+ if (flags < 0) {
+ stmt_free(stmt);
+ return NULL;
}
- if (!json_unpack(value, "{s:o}", "type_flags", &tmp)) {
- int flags = json_parse_nat_type_flags(ctx, tmp);
+ stmt->nat.flags = flags;
- if (flags < 0) {
- stmt_free(stmt);
- return NULL;
- }
- stmt->nat.type_flags = flags;
+ flags = parse_flags_array(ctx, value, "type_flags",
+ json_parse_nat_type_flag);
+ if (flags < 0) {
+ stmt_free(stmt);
+ return NULL;
}
+ stmt->nat.type_flags = flags;
return stmt;
}
@@ -2563,8 +2514,7 @@ static struct stmt *json_parse_map_stmt(struct json_ctx *ctx,
return stmt;
}
-static int json_parse_log_flag(struct json_ctx *ctx,
- json_t *root, int *flags)
+static unsigned int json_parse_log_flag(const char *flag)
{
const struct {
const char *flag;
@@ -2577,47 +2527,13 @@ static int json_parse_log_flag(struct json_ctx *ctx,
{ "ether", NF_LOG_MACDECODE },
{ "all", NF_LOG_MASK },
};
- const char *flag;
unsigned int i;
- assert(flags);
-
- if (!json_is_string(root)) {
- json_error(ctx, "Invalid log flag type %s, expected string.",
- json_typename(root));
- return 1;
- }
- flag = json_string_value(root);
for (i = 0; i < array_size(flag_tbl); i++) {
- if (!strcmp(flag, flag_tbl[i].flag)) {
- *flags |= flag_tbl[i].val;
- return 0;
- }
- }
- json_error(ctx, "Unknown log flag '%s'.", flag);
- return 1;
-}
-
-static int json_parse_log_flags(struct json_ctx *ctx, json_t *root)
-{
- int flags = 0;
- json_t *value;
- size_t index;
-
- if (json_is_string(root)) {
- json_parse_log_flag(ctx, root, &flags);
- return flags;
- } else if (!json_is_array(root)) {
- json_error(ctx, "Invalid log flags type %s.",
- json_typename(root));
- return -1;
- }
- json_array_foreach(root, index, value) {
- if (json_parse_log_flag(ctx, value, &flags))
- json_error(ctx, "Parsing log flag at index %zu failed.",
- index);
+ if (!strcmp(flag, flag_tbl[i].flag))
+ return flag_tbl[i].val;
}
- return flags;
+ return 0;
}
static struct stmt *json_parse_log_stmt(struct json_ctx *ctx,
@@ -2625,8 +2541,7 @@ static struct stmt *json_parse_log_stmt(struct json_ctx *ctx,
{
const char *tmpstr;
struct stmt *stmt;
- json_t *jflags;
- int tmp;
+ int tmp, flags;
stmt = log_stmt_alloc(int_loc);
@@ -2657,20 +2572,17 @@ static struct stmt *json_parse_log_stmt(struct json_ctx *ctx,
stmt->log.level = level;
stmt->log.flags |= STMT_LOG_LEVEL;
}
- if (!json_unpack(value, "{s:o}", "flags", &jflags)) {
- int flags = json_parse_log_flags(ctx, jflags);
-
- if (flags < 0) {
- stmt_free(stmt);
- return NULL;
- }
- stmt->log.logflags = flags;
+ flags = parse_flags_array(ctx, value, "flags", json_parse_log_flag);
+ if (flags < 0) {
+ stmt_free(stmt);
+ return NULL;
}
+ stmt->log.logflags = flags;
+
return stmt;
}
-static int json_parse_synproxy_flag(struct json_ctx *ctx,
- json_t *root, int *flags)
+static unsigned int json_parse_synproxy_flag(const char *flag)
{
const struct {
const char *flag;
@@ -2679,54 +2591,19 @@ static int json_parse_synproxy_flag(struct json_ctx *ctx,
{ "timestamp", NF_SYNPROXY_OPT_TIMESTAMP },
{ "sack-perm", NF_SYNPROXY_OPT_SACK_PERM },
};
- const char *flag;
unsigned int i;
- assert(flags);
-
- if (!json_is_string(root)) {
- json_error(ctx, "Invalid synproxy flag type %s, expected string.",
- json_typename(root));
- return 1;
- }
- flag = json_string_value(root);
for (i = 0; i < array_size(flag_tbl); i++) {
- if (!strcmp(flag, flag_tbl[i].flag)) {
- *flags |= flag_tbl[i].val;
- return 0;
- }
- }
- json_error(ctx, "Unknown synproxy flag '%s'.", flag);
- return 1;
-}
-
-static int json_parse_synproxy_flags(struct json_ctx *ctx, json_t *root)
-{
- int flags = 0;
- json_t *value;
- size_t index;
-
- if (json_is_string(root)) {
- json_parse_synproxy_flag(ctx, root, &flags);
- return flags;
- } else if (!json_is_array(root)) {
- json_error(ctx, "Invalid synproxy flags type %s.",
- json_typename(root));
- return -1;
- }
- json_array_foreach(root, index, value) {
- if (json_parse_synproxy_flag(ctx, value, &flags))
- json_error(ctx, "Parsing synproxy flag at index %zu failed.",
- index);
+ if (!strcmp(flag, flag_tbl[i].flag))
+ return flag_tbl[i].val;
}
- return flags;
+ return 0;
}
static struct stmt *json_parse_synproxy_stmt(struct json_ctx *ctx,
const char *key, json_t *value)
{
struct stmt *stmt = NULL;
- json_t *jflags;
int tmp, flags;
if (json_typeof(value) == JSON_NULL) {
@@ -2756,15 +2633,16 @@ static struct stmt *json_parse_synproxy_stmt(struct json_ctx *ctx,
stmt->synproxy.wscale = tmp;
stmt->synproxy.flags |= NF_SYNPROXY_OPT_WSCALE;
}
- if (!json_unpack(value, "{s:o}", "flags", &jflags)) {
+
+ flags = parse_flags_array(ctx, value, "flags",
+ json_parse_synproxy_flag);
+ if (flags < 0) {
+ stmt_free(stmt);
+ return NULL;
+ }
+ if (flags) {
if (!stmt)
stmt = synproxy_stmt_alloc(int_loc);
- flags = json_parse_synproxy_flags(ctx, jflags);
-
- if (flags < 0) {
- stmt_free(stmt);
- return NULL;
- }
stmt->synproxy.flags |= flags;
}
@@ -2859,14 +2737,12 @@ static struct stmt *json_parse_meter_stmt(struct json_ctx *ctx,
return stmt;
}
-static int queue_flag_parse(const char *name, uint16_t *flags)
+static unsigned int queue_flag_parse(const char *name)
{
if (!strcmp(name, "bypass"))
- *flags |= NFT_QUEUE_FLAG_BYPASS;
+ return NFT_QUEUE_FLAG_BYPASS;
else if (!strcmp(name, "fanout"))
- *flags |= NFT_QUEUE_FLAG_CPU_FANOUT;
- else
- return 1;
+ return NFT_QUEUE_FLAG_CPU_FANOUT;
return 0;
}
@@ -2874,8 +2750,8 @@ static struct stmt *json_parse_queue_stmt(struct json_ctx *ctx,
const char *key, json_t *value)
{
struct expr *qexpr = NULL;
- uint16_t flags = 0;
json_t *tmp;
+ int flags;
if (!json_unpack(value, "{s:o}", "num", &tmp)) {
qexpr = json_parse_stmt_expr(ctx, tmp);
@@ -2884,43 +2760,13 @@ static struct stmt *json_parse_queue_stmt(struct json_ctx *ctx,
return NULL;
}
}
- if (!json_unpack(value, "{s:o}", "flags", &tmp)) {
- const char *flag;
- size_t index;
- json_t *val;
-
- if (json_is_string(tmp)) {
- flag = json_string_value(tmp);
-
- if (queue_flag_parse(flag, &flags)) {
- json_error(ctx, "Invalid queue flag '%s'.",
- flag);
- expr_free(qexpr);
- return NULL;
- }
- } else if (!json_is_array(tmp)) {
- json_error(ctx, "Unexpected object type in queue flags.");
- expr_free(qexpr);
- return NULL;
- }
-
- json_array_foreach(tmp, index, val) {
- if (!json_is_string(val)) {
- json_error(ctx, "Invalid object in queue flag array at index %zu.",
- index);
- expr_free(qexpr);
- return NULL;
- }
- flag = json_string_value(val);
- if (queue_flag_parse(flag, &flags)) {
- json_error(ctx, "Invalid queue flag '%s'.",
- flag);
- expr_free(qexpr);
- return NULL;
- }
- }
+ flags = parse_flags_array(ctx, value, "flags", queue_flag_parse);
+ if (flags < 0) {
+ expr_free(qexpr);
+ return NULL;
}
+
return queue_stmt_alloc(int_loc, qexpr, flags);
}
@@ -3031,45 +2877,6 @@ static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root)
return NULL;
}
-static int json_parse_table_flags(struct json_ctx *ctx, json_t *root,
- enum table_flags *flags)
-{
- json_t *tmp, *tmp2;
- size_t index;
- int flag;
-
- if (json_unpack(root, "{s:o}", "flags", &tmp))
- return 0;
-
- if (json_is_string(tmp)) {
- flag = parse_table_flag(json_string_value(tmp));
- if (flag) {
- *flags = flag;
- return 0;
- }
- json_error(ctx, "Invalid table flag '%s'.",
- json_string_value(tmp));
- return 1;
- }
- if (!json_is_array(tmp)) {
- json_error(ctx, "Unexpected table flags value.");
- return 1;
- }
- json_array_foreach(tmp, index, tmp2) {
- if (json_is_string(tmp2)) {
- flag = parse_table_flag(json_string_value(tmp2));
-
- if (flag) {
- *flags |= flag;
- continue;
- }
- }
- json_error(ctx, "Invalid table flag at index %zu.", index);
- return 1;
- }
- return 0;
-}
-
static struct cmd *json_parse_cmd_add_table(struct json_ctx *ctx, json_t *root,
enum cmd_ops op, enum cmd_obj obj)
{
@@ -3078,7 +2885,7 @@ static struct cmd *json_parse_cmd_add_table(struct json_ctx *ctx, json_t *root,
.table.location = *int_loc,
};
struct table *table = NULL;
- enum table_flags flags = 0;
+ int flags = 0;
if (json_unpack_err(ctx, root, "{s:s}",
"family", &family))
@@ -3089,9 +2896,10 @@ static struct cmd *json_parse_cmd_add_table(struct json_ctx *ctx, json_t *root,
return NULL;
json_unpack(root, "{s:s}", "comment", &comment);
- if (json_parse_table_flags(ctx, root, &flags))
- return NULL;
+ flags = parse_flags_array(ctx, root, "flags", parse_table_flag);
+ if (flags < 0)
+ return NULL;
} else if (op == CMD_DELETE &&
json_unpack(root, "{s:s}", "name", &h.table.name) &&
json_unpack(root, "{s:I}", "handle", &h.handle.id)) {
@@ -3363,7 +3171,7 @@ static int string_to_nft_object(const char *str)
return 0;
}
-static int string_to_set_flag(const char *str)
+static unsigned int string_to_set_flag(const char *str)
{
const struct {
enum nft_set_flags val;
@@ -3390,6 +3198,7 @@ static struct cmd *json_parse_cmd_add_set(struct json_ctx *ctx, json_t *root,
const char *family = "", *policy;
json_t *tmp, *stmt_json;
struct set *set;
+ int flags;
if (json_unpack_err(ctx, root, "{s:s, s:s}",
"family", &family,
@@ -3472,23 +3281,16 @@ static struct cmd *json_parse_cmd_add_set(struct json_ctx *ctx, json_t *root,
return NULL;
}
}
- if (!json_unpack(root, "{s:o}", "flags", &tmp)) {
- json_t *value;
- size_t index;
-
- json_array_foreach(tmp, index, value) {
- int flag;
- if (!json_is_string(value) ||
- !(flag = string_to_set_flag(json_string_value(value)))) {
- json_error(ctx, "Invalid set flag at index %zu.", index);
- set_free(set);
- handle_free(&h);
- return NULL;
- }
- set->flags |= flag;
- }
+ flags = parse_flags_array(ctx, root, "flags", string_to_set_flag);
+ if (flags < 0) {
+ json_error(ctx, "Invalid set flags in set '%s'.", h.set.name);
+ set_free(set);
+ handle_free(&h);
+ return NULL;
}
+ set->flags |= flags;
+
if (!json_unpack(root, "{s:o}", "elem", &tmp)) {
set->init = json_parse_set_expr(ctx, "elem", tmp);
if (!set->init) {
@@ -3673,7 +3475,6 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
int inv = 0, flags = 0, i, j;
struct handle h = { 0 };
struct obj *obj;
- json_t *jflags;
if (json_unpack_err(ctx, root, "{s:s, s:s}",
"family", &family,
@@ -3853,13 +3654,12 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
obj->synproxy.wscale = j;
obj->synproxy.flags |= NF_SYNPROXY_OPT_MSS;
obj->synproxy.flags |= NF_SYNPROXY_OPT_WSCALE;
- if (!json_unpack(root, "{s:o}", "flags", &jflags)) {
- flags = json_parse_synproxy_flags(ctx, jflags);
- if (flags < 0)
- goto err_free_obj;
+ flags = parse_flags_array(ctx, root, "flags",
+ json_parse_synproxy_flag);
+ if (flags < 0)
+ goto err_free_obj;
- obj->synproxy.flags |= flags;
- }
+ obj->synproxy.flags |= flags;
break;
default:
BUG("Invalid CMD '%d'", cmd_obj);
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [nft PATCH 0/6] Add test for parse_flags_array()
2025-05-07 22:28 [nft PATCH] parser_json: Introduce parse_flags_array() Phil Sutter
@ 2025-05-08 21:47 ` Phil Sutter
2025-05-08 21:47 ` [nft PATCH 1/6] doc: Fix typo in nat statement 'prefix' description Phil Sutter
` (6 more replies)
0 siblings, 7 replies; 10+ messages in thread
From: Phil Sutter @ 2025-05-08 21:47 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
The function introduced in previous patch relaxes JSON syntax in parsing
selected properties which usually contain an array as value to also
accept a string representing the only array element.
The test asserting correct parsing of such properties exposed JSON
printer's limitation in some properties to not reduce the array value
when possible.
To make things consistent, This series enhances the JSON printer by
support for array reduction where missing (patches 2-4), then introduces
a shared routine to combine the common idiom in patch 5. Patch 6 finally
adds the actual shell test case. Patch 1 is merely fallout, a trivial
fix identified when working on the test implementation.
Phil Sutter (6):
doc: Fix typo in nat statement 'prefix' description
json: Print single set flag as non-array
json: Print single fib flag as non-array
json: Print single synproxy flags as non-array
json: Introduce json_add_array_new()
tests: shell: Add test case for JSON 'flags' arrays
doc/statements.txt | 2 +-
src/json.c | 89 +++------
.../cache/dumps/0002_interval_0.json-nft | 4 +-
.../json/dumps/0001set_statements_0.json-nft | 4 +-
tests/shell/testcases/json/single_flag | 189 ++++++++++++++++++
.../listing/dumps/0010sets_0.json-nft | 8 +-
.../listing/dumps/0012sets_0.json-nft | 8 +-
.../listing/dumps/0022terse_0.json-nft | 4 +-
...5interval_map_add_many_elements_0.json-nft | 4 +-
.../dumps/0006interval_map_overlap_0.json-nft | 4 +-
.../dumps/0008interval_map_delete_0.json-nft | 4 +-
.../maps/dumps/0012map_concat_0.json-nft | 4 +-
.../testcases/maps/dumps/0013map_0.json-nft | 4 +-
.../maps/dumps/map_with_flags_0.json-nft | 4 +-
.../maps/dumps/named_limits.json-nft | 8 +-
.../maps/dumps/pipapo_double_flush.json-nft | 4 +-
.../dumps/typeof_maps_add_delete.json-nft | 4 +-
.../maps/dumps/typeof_maps_update_0.json-nft | 8 +-
.../maps/dumps/vmap_timeout.json-nft | 8 +-
.../nft-f/dumps/0025empty_dynset_0.json-nft | 12 +-
.../optimizations/dumps/merge_vmaps.json-nft | 4 +-
.../dumps/skip_unsupported.json-nft | 4 +-
.../packetpath/dumps/set_lookups.json-nft | 8 +-
.../dumps/0004replace_0.json-nft | 4 +-
.../dumps/0011reset_0.json-nft | 4 +-
.../sets/dumps/0001named_interval_0.json-nft | 16 +-
.../0002named_interval_automerging_0.json-nft | 4 +-
.../0004named_interval_shadow_0.json-nft | 4 +-
.../0005named_interval_shadow_0.json-nft | 4 +-
.../dumps/0008comments_interval_0.json-nft | 4 +-
.../dumps/0009comments_timeout_0.json-nft | 4 +-
.../sets/dumps/0015rulesetflush_0.json-nft | 4 +-
.../dumps/0022type_selective_flush_0.json-nft | 4 +-
.../sets/dumps/0024synproxy_0.json-nft | 4 +-
.../sets/dumps/0027ipv6_maps_ipv4_0.json-nft | 4 +-
.../sets/dumps/0028autoselect_0.json-nft | 12 +-
.../sets/dumps/0028delete_handle_0.json-nft | 4 +-
.../dumps/0032restore_set_simple_0.json-nft | 8 +-
.../dumps/0033add_set_simple_flat_0.json-nft | 8 +-
.../sets/dumps/0034get_element_0.json-nft | 12 +-
.../0035add_set_elements_flat_0.json-nft | 4 +-
.../sets/dumps/0038meter_list_0.json-nft | 4 +-
.../sets/dumps/0039delete_interval_0.json-nft | 4 +-
.../0040get_host_endian_elements_0.json-nft | 4 +-
.../sets/dumps/0041interval_0.json-nft | 4 +-
.../sets/dumps/0042update_set_0.json-nft | 4 +-
.../dumps/0043concatenated_ranges_1.json-nft | 8 +-
.../dumps/0044interval_overlap_1.json-nft | 4 +-
.../sets/dumps/0049set_define_0.json-nft | 4 +-
.../dumps/0051set_interval_counter_0.json-nft | 4 +-
.../sets/dumps/0052overlap_0.json-nft | 4 +-
.../sets/dumps/0054comments_set_0.json-nft | 8 +-
.../sets/dumps/0055tcpflags_0.json-nft | 4 +-
.../sets/dumps/0060set_multistmt_1.json-nft | 4 +-
.../sets/dumps/0062set_connlimit_0.json-nft | 8 +-
.../sets/dumps/0063set_catchall_0.json-nft | 4 +-
.../sets/dumps/0064map_catchall_0.json-nft | 4 +-
.../sets/dumps/0069interval_merge_0.json-nft | 4 +-
.../0071unclosed_prefix_interval_0.json-nft | 8 +-
.../sets/dumps/0073flat_interval_set.json-nft | 4 +-
.../dumps/0074nested_interval_set.json-nft | 4 +-
.../sets/dumps/concat_interval_0.json-nft | 8 +-
.../sets/dumps/dynset_missing.json-nft | 4 +-
.../sets/dumps/exact_overlap_0.json-nft | 4 +-
.../testcases/sets/dumps/inner_0.json-nft | 4 +-
.../sets/dumps/meter_set_reuse.json-nft | 4 +-
.../dumps/range_with_same_start_end.json-nft | 4 +-
.../set_element_timeout_updates.json-nft | 4 +-
.../testcases/sets/dumps/set_eval_0.json-nft | 4 +-
.../sets/dumps/sets_with_ifnames.json-nft | 12 +-
.../transactions/dumps/0037set_0.json-nft | 4 +-
.../transactions/dumps/0038set_0.json-nft | 4 +-
.../transactions/dumps/0039set_0.json-nft | 4 +-
.../transactions/dumps/0047set_0.json-nft | 4 +-
.../transactions/dumps/doubled-set.json-nft | 4 +-
75 files changed, 311 insertions(+), 353 deletions(-)
create mode 100755 tests/shell/testcases/json/single_flag
--
2.49.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [nft PATCH 1/6] doc: Fix typo in nat statement 'prefix' description
2025-05-08 21:47 ` [nft PATCH 0/6] Add test for parse_flags_array() Phil Sutter
@ 2025-05-08 21:47 ` Phil Sutter
2025-05-08 21:47 ` [nft PATCH 2/6] json: Print single set flag as non-array Phil Sutter
` (5 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Phil Sutter @ 2025-05-08 21:47 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
No point in repeating 'to map' here.
Fixes: 19d73ccdd39fa ("doc: add nat examples")
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
doc/statements.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/statements.txt b/doc/statements.txt
index 74af1d1a54e9a..79a01384660f6 100644
--- a/doc/statements.txt
+++ b/doc/statements.txt
@@ -438,7 +438,7 @@ Before kernel 4.18 nat statements require both prerouting and postrouting base c
to be present since otherwise packets on the return path won't be seen by
netfilter and therefore no reverse translation will take place.
-The optional *prefix* keyword allows to map to map *n* source addresses to *n*
+The optional *prefix* keyword allows to map *n* source addresses to *n*
destination addresses. See 'Advanced NAT examples' below.
.NAT statement values
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [nft PATCH 2/6] json: Print single set flag as non-array
2025-05-08 21:47 ` [nft PATCH 0/6] Add test for parse_flags_array() Phil Sutter
2025-05-08 21:47 ` [nft PATCH 1/6] doc: Fix typo in nat statement 'prefix' description Phil Sutter
@ 2025-05-08 21:47 ` Phil Sutter
2025-05-08 21:47 ` [nft PATCH 3/6] json: Print single fib " Phil Sutter
` (4 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Phil Sutter @ 2025-05-08 21:47 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
The code obviously intended to do this already but got the array length
check wrong.
Fixes: e70354f53e9f6 ("libnftables: Implement JSON output support")
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
src/json.c | 2 +-
.../cache/dumps/0002_interval_0.json-nft | 4 +---
.../json/dumps/0001set_statements_0.json-nft | 4 +---
.../testcases/listing/dumps/0010sets_0.json-nft | 8 ++------
.../testcases/listing/dumps/0012sets_0.json-nft | 8 ++------
.../testcases/listing/dumps/0022terse_0.json-nft | 4 +---
...0005interval_map_add_many_elements_0.json-nft | 4 +---
.../dumps/0006interval_map_overlap_0.json-nft | 4 +---
.../dumps/0008interval_map_delete_0.json-nft | 4 +---
.../maps/dumps/0012map_concat_0.json-nft | 4 +---
.../testcases/maps/dumps/0013map_0.json-nft | 4 +---
.../maps/dumps/map_with_flags_0.json-nft | 4 +---
.../testcases/maps/dumps/named_limits.json-nft | 8 ++------
.../maps/dumps/pipapo_double_flush.json-nft | 4 +---
.../maps/dumps/typeof_maps_add_delete.json-nft | 4 +---
.../maps/dumps/typeof_maps_update_0.json-nft | 8 ++------
.../testcases/maps/dumps/vmap_timeout.json-nft | 8 ++------
.../nft-f/dumps/0025empty_dynset_0.json-nft | 12 +++---------
.../optimizations/dumps/merge_vmaps.json-nft | 4 +---
.../dumps/skip_unsupported.json-nft | 4 +---
.../packetpath/dumps/set_lookups.json-nft | 8 ++------
.../rule_management/dumps/0004replace_0.json-nft | 4 +---
.../rule_management/dumps/0011reset_0.json-nft | 4 +---
.../sets/dumps/0001named_interval_0.json-nft | 16 ++++------------
.../0002named_interval_automerging_0.json-nft | 4 +---
.../dumps/0004named_interval_shadow_0.json-nft | 4 +---
.../dumps/0005named_interval_shadow_0.json-nft | 4 +---
| 4 +---
| 4 +---
.../sets/dumps/0015rulesetflush_0.json-nft | 4 +---
.../dumps/0022type_selective_flush_0.json-nft | 4 +---
.../testcases/sets/dumps/0024synproxy_0.json-nft | 4 +---
.../sets/dumps/0027ipv6_maps_ipv4_0.json-nft | 4 +---
.../sets/dumps/0028autoselect_0.json-nft | 12 +++---------
.../sets/dumps/0028delete_handle_0.json-nft | 4 +---
.../sets/dumps/0032restore_set_simple_0.json-nft | 8 ++------
.../dumps/0033add_set_simple_flat_0.json-nft | 8 ++------
.../sets/dumps/0034get_element_0.json-nft | 12 +++---------
.../dumps/0035add_set_elements_flat_0.json-nft | 4 +---
.../sets/dumps/0038meter_list_0.json-nft | 4 +---
.../sets/dumps/0039delete_interval_0.json-nft | 4 +---
.../0040get_host_endian_elements_0.json-nft | 4 +---
.../testcases/sets/dumps/0041interval_0.json-nft | 4 +---
.../sets/dumps/0042update_set_0.json-nft | 4 +---
.../dumps/0043concatenated_ranges_1.json-nft | 8 ++------
.../sets/dumps/0044interval_overlap_1.json-nft | 4 +---
.../sets/dumps/0049set_define_0.json-nft | 4 +---
.../dumps/0051set_interval_counter_0.json-nft | 4 +---
.../testcases/sets/dumps/0052overlap_0.json-nft | 4 +---
| 8 ++------
.../testcases/sets/dumps/0055tcpflags_0.json-nft | 4 +---
.../sets/dumps/0060set_multistmt_1.json-nft | 4 +---
.../sets/dumps/0062set_connlimit_0.json-nft | 8 ++------
.../sets/dumps/0063set_catchall_0.json-nft | 4 +---
.../sets/dumps/0064map_catchall_0.json-nft | 4 +---
.../sets/dumps/0069interval_merge_0.json-nft | 4 +---
.../0071unclosed_prefix_interval_0.json-nft | 8 ++------
.../sets/dumps/0073flat_interval_set.json-nft | 4 +---
.../sets/dumps/0074nested_interval_set.json-nft | 4 +---
.../sets/dumps/concat_interval_0.json-nft | 8 ++------
.../testcases/sets/dumps/dynset_missing.json-nft | 4 +---
.../sets/dumps/exact_overlap_0.json-nft | 4 +---
.../shell/testcases/sets/dumps/inner_0.json-nft | 4 +---
.../sets/dumps/meter_set_reuse.json-nft | 4 +---
.../dumps/range_with_same_start_end.json-nft | 4 +---
.../dumps/set_element_timeout_updates.json-nft | 4 +---
.../testcases/sets/dumps/set_eval_0.json-nft | 4 +---
.../sets/dumps/sets_with_ifnames.json-nft | 12 +++---------
.../transactions/dumps/0037set_0.json-nft | 4 +---
.../transactions/dumps/0038set_0.json-nft | 4 +---
.../transactions/dumps/0039set_0.json-nft | 4 +---
.../transactions/dumps/0047set_0.json-nft | 4 +---
.../transactions/dumps/doubled-set.json-nft | 4 +---
73 files changed, 97 insertions(+), 289 deletions(-)
diff --git a/src/json.c b/src/json.c
index 41a5720188419..6b27ccb927017 100644
--- a/src/json.c
+++ b/src/json.c
@@ -199,7 +199,7 @@ static json_t *set_print_json(struct output_ctx *octx, const struct set *set)
if (set->flags & NFT_SET_EVAL)
json_array_append_new(tmp, json_pack("s", "dynamic"));
- if (json_array_size(tmp) > 0) {
+ if (json_array_size(tmp) > 1) {
json_object_set_new(root, "flags", tmp);
} else {
if (json_array_size(tmp))
diff --git a/tests/shell/testcases/cache/dumps/0002_interval_0.json-nft b/tests/shell/testcases/cache/dumps/0002_interval_0.json-nft
index fa15d658dcd5c..5e2b9b420b6db 100644
--- a/tests/shell/testcases/cache/dumps/0002_interval_0.json-nft
+++ b/tests/shell/testcases/cache/dumps/0002_interval_0.json-nft
@@ -21,9 +21,7 @@
"table": "t",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"prefix": {
diff --git a/tests/shell/testcases/json/dumps/0001set_statements_0.json-nft b/tests/shell/testcases/json/dumps/0001set_statements_0.json-nft
index 91db43e29ea9f..ecc7eade91a60 100644
--- a/tests/shell/testcases/json/dumps/0001set_statements_0.json-nft
+++ b/tests/shell/testcases/json/dumps/0001set_statements_0.json-nft
@@ -34,9 +34,7 @@
"type": "ipv4_addr",
"handle": 0,
"size": 65535,
- "flags": [
- "dynamic"
- ]
+ "flags": "dynamic"
}
},
{
diff --git a/tests/shell/testcases/listing/dumps/0010sets_0.json-nft b/tests/shell/testcases/listing/dumps/0010sets_0.json-nft
index efca892e3667b..6aa99b4e16d24 100644
--- a/tests/shell/testcases/listing/dumps/0010sets_0.json-nft
+++ b/tests/shell/testcases/listing/dumps/0010sets_0.json-nft
@@ -62,9 +62,7 @@
"table": "test_arp",
"type": "inet_service",
"handle": 0,
- "flags": [
- "constant"
- ]
+ "flags": "constant"
}
},
{
@@ -106,9 +104,7 @@
"table": "filter",
"type": "inet_service",
"handle": 0,
- "flags": [
- "constant"
- ]
+ "flags": "constant"
}
},
{
diff --git a/tests/shell/testcases/listing/dumps/0012sets_0.json-nft b/tests/shell/testcases/listing/dumps/0012sets_0.json-nft
index efca892e3667b..6aa99b4e16d24 100644
--- a/tests/shell/testcases/listing/dumps/0012sets_0.json-nft
+++ b/tests/shell/testcases/listing/dumps/0012sets_0.json-nft
@@ -62,9 +62,7 @@
"table": "test_arp",
"type": "inet_service",
"handle": 0,
- "flags": [
- "constant"
- ]
+ "flags": "constant"
}
},
{
@@ -106,9 +104,7 @@
"table": "filter",
"type": "inet_service",
"handle": 0,
- "flags": [
- "constant"
- ]
+ "flags": "constant"
}
},
{
diff --git a/tests/shell/testcases/listing/dumps/0022terse_0.json-nft b/tests/shell/testcases/listing/dumps/0022terse_0.json-nft
index bd6383dac5e37..1a33d6888033b 100644
--- a/tests/shell/testcases/listing/dumps/0022terse_0.json-nft
+++ b/tests/shell/testcases/listing/dumps/0022terse_0.json-nft
@@ -33,9 +33,7 @@
"table": "filter",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
"10.10.10.10",
"10.10.11.11"
diff --git a/tests/shell/testcases/maps/dumps/0005interval_map_add_many_elements_0.json-nft b/tests/shell/testcases/maps/dumps/0005interval_map_add_many_elements_0.json-nft
index d1a4629500533..f9ac5bce9315b 100644
--- a/tests/shell/testcases/maps/dumps/0005interval_map_add_many_elements_0.json-nft
+++ b/tests/shell/testcases/maps/dumps/0005interval_map_add_many_elements_0.json-nft
@@ -22,9 +22,7 @@
"type": "ipv4_addr",
"handle": 0,
"map": "ipv4_addr",
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
[
{
diff --git a/tests/shell/testcases/maps/dumps/0006interval_map_overlap_0.json-nft b/tests/shell/testcases/maps/dumps/0006interval_map_overlap_0.json-nft
index 1e983219ae0d4..d6b32d0f8204c 100644
--- a/tests/shell/testcases/maps/dumps/0006interval_map_overlap_0.json-nft
+++ b/tests/shell/testcases/maps/dumps/0006interval_map_overlap_0.json-nft
@@ -22,9 +22,7 @@
"type": "ipv4_addr",
"handle": 0,
"map": "ipv4_addr",
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
[
{
diff --git a/tests/shell/testcases/maps/dumps/0008interval_map_delete_0.json-nft b/tests/shell/testcases/maps/dumps/0008interval_map_delete_0.json-nft
index bd3c6cc7ebf55..09cb6c8578ffb 100644
--- a/tests/shell/testcases/maps/dumps/0008interval_map_delete_0.json-nft
+++ b/tests/shell/testcases/maps/dumps/0008interval_map_delete_0.json-nft
@@ -34,9 +34,7 @@
"type": "ipv4_addr",
"handle": 0,
"map": "mark",
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
[
"127.0.0.2",
diff --git a/tests/shell/testcases/maps/dumps/0012map_concat_0.json-nft b/tests/shell/testcases/maps/dumps/0012map_concat_0.json-nft
index 88bf4984dbde7..85384c5329614 100644
--- a/tests/shell/testcases/maps/dumps/0012map_concat_0.json-nft
+++ b/tests/shell/testcases/maps/dumps/0012map_concat_0.json-nft
@@ -50,9 +50,7 @@
},
"handle": 0,
"map": "verdict",
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
[
{
diff --git a/tests/shell/testcases/maps/dumps/0013map_0.json-nft b/tests/shell/testcases/maps/dumps/0013map_0.json-nft
index e91a269d8e6e6..2c8d21b43f20e 100644
--- a/tests/shell/testcases/maps/dumps/0013map_0.json-nft
+++ b/tests/shell/testcases/maps/dumps/0013map_0.json-nft
@@ -38,9 +38,7 @@
],
"handle": 0,
"map": "verdict",
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
[
{
diff --git a/tests/shell/testcases/maps/dumps/map_with_flags_0.json-nft b/tests/shell/testcases/maps/dumps/map_with_flags_0.json-nft
index 97b7e94e59fa4..94ec5f751ba57 100644
--- a/tests/shell/testcases/maps/dumps/map_with_flags_0.json-nft
+++ b/tests/shell/testcases/maps/dumps/map_with_flags_0.json-nft
@@ -22,9 +22,7 @@
"type": "ipv4_addr",
"handle": 0,
"map": "ipv4_addr",
- "flags": [
- "timeout"
- ]
+ "flags": "timeout"
}
}
]
diff --git a/tests/shell/testcases/maps/dumps/named_limits.json-nft b/tests/shell/testcases/maps/dumps/named_limits.json-nft
index 3c6845ac43b42..07e2892915392 100644
--- a/tests/shell/testcases/maps/dumps/named_limits.json-nft
+++ b/tests/shell/testcases/maps/dumps/named_limits.json-nft
@@ -144,9 +144,7 @@
},
"handle": 0,
"map": "limit",
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
[
{
@@ -286,9 +284,7 @@
},
"handle": 0,
"map": "limit",
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
[
{
diff --git a/tests/shell/testcases/maps/dumps/pipapo_double_flush.json-nft b/tests/shell/testcases/maps/dumps/pipapo_double_flush.json-nft
index ef8c3930f8153..dc793a65f16dd 100644
--- a/tests/shell/testcases/maps/dumps/pipapo_double_flush.json-nft
+++ b/tests/shell/testcases/maps/dumps/pipapo_double_flush.json-nft
@@ -33,9 +33,7 @@
],
"handle": 0,
"map": "verdict",
- "flags": [
- "interval"
- ]
+ "flags": "interval"
}
}
]
diff --git a/tests/shell/testcases/maps/dumps/typeof_maps_add_delete.json-nft b/tests/shell/testcases/maps/dumps/typeof_maps_add_delete.json-nft
index effe02dcf8364..8b18a78d6982f 100644
--- a/tests/shell/testcases/maps/dumps/typeof_maps_add_delete.json-nft
+++ b/tests/shell/testcases/maps/dumps/typeof_maps_add_delete.json-nft
@@ -50,9 +50,7 @@
"handle": 0,
"map": "mark",
"size": 64,
- "flags": [
- "timeout"
- ],
+ "flags": "timeout",
"timeout": 300,
"stmt": [
{
diff --git a/tests/shell/testcases/maps/dumps/typeof_maps_update_0.json-nft b/tests/shell/testcases/maps/dumps/typeof_maps_update_0.json-nft
index 731514663b1aa..b79237d0838db 100644
--- a/tests/shell/testcases/maps/dumps/typeof_maps_update_0.json-nft
+++ b/tests/shell/testcases/maps/dumps/typeof_maps_update_0.json-nft
@@ -39,9 +39,7 @@
"handle": 0,
"map": "mark",
"size": 65535,
- "flags": [
- "timeout"
- ],
+ "flags": "timeout",
"timeout": 360
}
},
@@ -61,9 +59,7 @@
"handle": 0,
"map": "mark",
"size": 65535,
- "flags": [
- "timeout"
- ],
+ "flags": "timeout",
"timeout": 60
}
},
diff --git a/tests/shell/testcases/maps/dumps/vmap_timeout.json-nft b/tests/shell/testcases/maps/dumps/vmap_timeout.json-nft
index 71e9a9ee9f21b..2d7d8cc2306cd 100644
--- a/tests/shell/testcases/maps/dumps/vmap_timeout.json-nft
+++ b/tests/shell/testcases/maps/dumps/vmap_timeout.json-nft
@@ -66,9 +66,7 @@
"type": "inet_service",
"handle": 0,
"map": "verdict",
- "flags": [
- "timeout"
- ],
+ "flags": "timeout",
"gc-interval": 10,
"elem": [
[
@@ -107,9 +105,7 @@
},
"handle": 0,
"map": "verdict",
- "flags": [
- "timeout"
- ],
+ "flags": "timeout",
"gc-interval": 10,
"elem": [
[
diff --git a/tests/shell/testcases/nft-f/dumps/0025empty_dynset_0.json-nft b/tests/shell/testcases/nft-f/dumps/0025empty_dynset_0.json-nft
index 0cde23b00000a..63d6764172ff6 100644
--- a/tests/shell/testcases/nft-f/dumps/0025empty_dynset_0.json-nft
+++ b/tests/shell/testcases/nft-f/dumps/0025empty_dynset_0.json-nft
@@ -27,9 +27,7 @@
"inet_service"
],
"handle": 0,
- "flags": [
- "dynamic"
- ],
+ "flags": "dynamic",
"elem": [
{
"elem": {
@@ -64,9 +62,7 @@
"inet_service"
],
"handle": 0,
- "flags": [
- "dynamic"
- ]
+ "flags": "dynamic"
}
},
{
@@ -82,9 +78,7 @@
"inet_service"
],
"handle": 0,
- "flags": [
- "dynamic"
- ],
+ "flags": "dynamic",
"elem": [
{
"elem": {
diff --git a/tests/shell/testcases/optimizations/dumps/merge_vmaps.json-nft b/tests/shell/testcases/optimizations/dumps/merge_vmaps.json-nft
index e87f1c4c082eb..f058d6f1db069 100644
--- a/tests/shell/testcases/optimizations/dumps/merge_vmaps.json-nft
+++ b/tests/shell/testcases/optimizations/dumps/merge_vmaps.json-nft
@@ -46,9 +46,7 @@
"type": "ipv4_addr",
"handle": 0,
"size": 65535,
- "flags": [
- "dynamic"
- ]
+ "flags": "dynamic"
}
},
{
diff --git a/tests/shell/testcases/optimizations/dumps/skip_unsupported.json-nft b/tests/shell/testcases/optimizations/dumps/skip_unsupported.json-nft
index d6347b1eeed6e..bf5a8cec53630 100644
--- a/tests/shell/testcases/optimizations/dumps/skip_unsupported.json-nft
+++ b/tests/shell/testcases/optimizations/dumps/skip_unsupported.json-nft
@@ -29,9 +29,7 @@
"table": "x",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"prefix": {
diff --git a/tests/shell/testcases/packetpath/dumps/set_lookups.json-nft b/tests/shell/testcases/packetpath/dumps/set_lookups.json-nft
index bcf6914e95cb9..23f4b17fc53c3 100644
--- a/tests/shell/testcases/packetpath/dumps/set_lookups.json-nft
+++ b/tests/shell/testcases/packetpath/dumps/set_lookups.json-nft
@@ -36,9 +36,7 @@
"iface_index"
],
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"concat": [
@@ -113,9 +111,7 @@
"table": "t",
"type": "iface_index",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
"lo"
]
diff --git a/tests/shell/testcases/rule_management/dumps/0004replace_0.json-nft b/tests/shell/testcases/rule_management/dumps/0004replace_0.json-nft
index 767e80f14ff26..811cb73804f5d 100644
--- a/tests/shell/testcases/rule_management/dumps/0004replace_0.json-nft
+++ b/tests/shell/testcases/rule_management/dumps/0004replace_0.json-nft
@@ -38,9 +38,7 @@
"table": "t",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ]
+ "flags": "interval"
}
},
{
diff --git a/tests/shell/testcases/rule_management/dumps/0011reset_0.json-nft b/tests/shell/testcases/rule_management/dumps/0011reset_0.json-nft
index bc242467e22a7..e57dee799b4f3 100644
--- a/tests/shell/testcases/rule_management/dumps/0011reset_0.json-nft
+++ b/tests/shell/testcases/rule_management/dumps/0011reset_0.json-nft
@@ -38,9 +38,7 @@
"type": "ipv4_addr",
"handle": 0,
"size": 65535,
- "flags": [
- "dynamic"
- ],
+ "flags": "dynamic",
"elem": [
{
"elem": {
diff --git a/tests/shell/testcases/sets/dumps/0001named_interval_0.json-nft b/tests/shell/testcases/sets/dumps/0001named_interval_0.json-nft
index b9c66a21aa084..9200154a6ed85 100644
--- a/tests/shell/testcases/sets/dumps/0001named_interval_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0001named_interval_0.json-nft
@@ -29,9 +29,7 @@
"table": "t",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"range": [
@@ -55,9 +53,7 @@
"table": "t",
"type": "ipv6_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"prefix": {
@@ -81,9 +77,7 @@
"table": "t",
"type": "inet_proto",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"range": [
@@ -107,9 +101,7 @@
"table": "t",
"type": "inet_service",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"range": [
diff --git a/tests/shell/testcases/sets/dumps/0002named_interval_automerging_0.json-nft b/tests/shell/testcases/sets/dumps/0002named_interval_automerging_0.json-nft
index 4c0be67000a02..b083ecb52bb52 100644
--- a/tests/shell/testcases/sets/dumps/0002named_interval_automerging_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0002named_interval_automerging_0.json-nft
@@ -21,9 +21,7 @@
"table": "t",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"prefix": {
diff --git a/tests/shell/testcases/sets/dumps/0004named_interval_shadow_0.json-nft b/tests/shell/testcases/sets/dumps/0004named_interval_shadow_0.json-nft
index c55858fa9c9b9..c79d9ba8518af 100644
--- a/tests/shell/testcases/sets/dumps/0004named_interval_shadow_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0004named_interval_shadow_0.json-nft
@@ -21,9 +21,7 @@
"table": "t",
"type": "ipv6_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"prefix": {
diff --git a/tests/shell/testcases/sets/dumps/0005named_interval_shadow_0.json-nft b/tests/shell/testcases/sets/dumps/0005named_interval_shadow_0.json-nft
index a75681f36cb8e..464661e62ae14 100644
--- a/tests/shell/testcases/sets/dumps/0005named_interval_shadow_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0005named_interval_shadow_0.json-nft
@@ -21,9 +21,7 @@
"table": "t",
"type": "ipv6_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"prefix": {
--git a/tests/shell/testcases/sets/dumps/0008comments_interval_0.json-nft b/tests/shell/testcases/sets/dumps/0008comments_interval_0.json-nft
index c6f5aa68837ce..e7152413d4bb9 100644
--- a/tests/shell/testcases/sets/dumps/0008comments_interval_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0008comments_interval_0.json-nft
@@ -21,9 +21,7 @@
"table": "t",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"elem": {
--git a/tests/shell/testcases/sets/dumps/0009comments_timeout_0.json-nft b/tests/shell/testcases/sets/dumps/0009comments_timeout_0.json-nft
index 2418b39a76a06..a67a06707106d 100644
--- a/tests/shell/testcases/sets/dumps/0009comments_timeout_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0009comments_timeout_0.json-nft
@@ -21,9 +21,7 @@
"table": "t",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "timeout"
- ],
+ "flags": "timeout",
"elem": [
{
"elem": {
diff --git a/tests/shell/testcases/sets/dumps/0015rulesetflush_0.json-nft b/tests/shell/testcases/sets/dumps/0015rulesetflush_0.json-nft
index 6268e216aa03c..86d7eb6a4b6b1 100644
--- a/tests/shell/testcases/sets/dumps/0015rulesetflush_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0015rulesetflush_0.json-nft
@@ -36,9 +36,7 @@
"table": "filter",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"prefix": {
diff --git a/tests/shell/testcases/sets/dumps/0022type_selective_flush_0.json-nft b/tests/shell/testcases/sets/dumps/0022type_selective_flush_0.json-nft
index c617139235c23..dcb62eb739d56 100644
--- a/tests/shell/testcases/sets/dumps/0022type_selective_flush_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0022type_selective_flush_0.json-nft
@@ -49,9 +49,7 @@
"type": "ipv4_addr",
"handle": 0,
"size": 1024,
- "flags": [
- "dynamic"
- ]
+ "flags": "dynamic"
}
},
{
diff --git a/tests/shell/testcases/sets/dumps/0024synproxy_0.json-nft b/tests/shell/testcases/sets/dumps/0024synproxy_0.json-nft
index 0af613333592d..dd71bb394442d 100644
--- a/tests/shell/testcases/sets/dumps/0024synproxy_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0024synproxy_0.json-nft
@@ -58,9 +58,7 @@
"type": "ipv4_addr",
"handle": 0,
"map": "synproxy",
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
[
{
diff --git a/tests/shell/testcases/sets/dumps/0027ipv6_maps_ipv4_0.json-nft b/tests/shell/testcases/sets/dumps/0027ipv6_maps_ipv4_0.json-nft
index b9251ffa58900..75d8b46d86a10 100644
--- a/tests/shell/testcases/sets/dumps/0027ipv6_maps_ipv4_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0027ipv6_maps_ipv4_0.json-nft
@@ -21,9 +21,7 @@
"table": "t",
"type": "ipv6_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"prefix": {
diff --git a/tests/shell/testcases/sets/dumps/0028autoselect_0.json-nft b/tests/shell/testcases/sets/dumps/0028autoselect_0.json-nft
index 5968b2e0c11f0..05fc072c3ca7f 100644
--- a/tests/shell/testcases/sets/dumps/0028autoselect_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0028autoselect_0.json-nft
@@ -34,9 +34,7 @@
"type": "inet_proto",
"handle": 0,
"size": 65535,
- "flags": [
- "dynamic"
- ]
+ "flags": "dynamic"
}
},
{
@@ -47,9 +45,7 @@
"type": "ipv4_addr",
"handle": 0,
"size": 65535,
- "flags": [
- "dynamic"
- ]
+ "flags": "dynamic"
}
},
{
@@ -60,9 +56,7 @@
"type": "ipv4_addr",
"handle": 0,
"size": 1024,
- "flags": [
- "dynamic"
- ]
+ "flags": "dynamic"
}
},
{
diff --git a/tests/shell/testcases/sets/dumps/0028delete_handle_0.json-nft b/tests/shell/testcases/sets/dumps/0028delete_handle_0.json-nft
index 96314141bc084..9e5f708df3a74 100644
--- a/tests/shell/testcases/sets/dumps/0028delete_handle_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0028delete_handle_0.json-nft
@@ -30,9 +30,7 @@
"table": "test-ip",
"type": "inet_service",
"handle": 0,
- "flags": [
- "timeout"
- ],
+ "flags": "timeout",
"timeout": 10845
}
},
diff --git a/tests/shell/testcases/sets/dumps/0032restore_set_simple_0.json-nft b/tests/shell/testcases/sets/dumps/0032restore_set_simple_0.json-nft
index 4d194bff1b164..7a723150c1a35 100644
--- a/tests/shell/testcases/sets/dumps/0032restore_set_simple_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0032restore_set_simple_0.json-nft
@@ -25,9 +25,7 @@
"ipv4_addr"
],
"handle": 0,
- "flags": [
- "timeout"
- ]
+ "flags": "timeout"
}
},
{
@@ -40,9 +38,7 @@
"inet_service"
],
"handle": 0,
- "flags": [
- "timeout"
- ]
+ "flags": "timeout"
}
}
]
diff --git a/tests/shell/testcases/sets/dumps/0033add_set_simple_flat_0.json-nft b/tests/shell/testcases/sets/dumps/0033add_set_simple_flat_0.json-nft
index 16684438c37f2..5697652859078 100644
--- a/tests/shell/testcases/sets/dumps/0033add_set_simple_flat_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0033add_set_simple_flat_0.json-nft
@@ -25,9 +25,7 @@
"ipv4_addr"
],
"handle": 0,
- "flags": [
- "timeout"
- ]
+ "flags": "timeout"
}
},
{
@@ -40,9 +38,7 @@
"inet_service"
],
"handle": 0,
- "flags": [
- "timeout"
- ]
+ "flags": "timeout"
}
}
]
diff --git a/tests/shell/testcases/sets/dumps/0034get_element_0.json-nft b/tests/shell/testcases/sets/dumps/0034get_element_0.json-nft
index bfc0e4a0f5886..4f5ba0aaac578 100644
--- a/tests/shell/testcases/sets/dumps/0034get_element_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0034get_element_0.json-nft
@@ -21,9 +21,7 @@
"table": "t",
"type": "inet_service",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
10,
{
@@ -49,9 +47,7 @@
"table": "t",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
"10.0.0.1",
{
@@ -91,9 +87,7 @@
"inet_service"
],
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"concat": [
diff --git a/tests/shell/testcases/sets/dumps/0035add_set_elements_flat_0.json-nft b/tests/shell/testcases/sets/dumps/0035add_set_elements_flat_0.json-nft
index e4c77147b88f6..f9fe4e6f113ea 100644
--- a/tests/shell/testcases/sets/dumps/0035add_set_elements_flat_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0035add_set_elements_flat_0.json-nft
@@ -21,9 +21,7 @@
"table": "x",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ]
+ "flags": "interval"
}
}
]
diff --git a/tests/shell/testcases/sets/dumps/0038meter_list_0.json-nft b/tests/shell/testcases/sets/dumps/0038meter_list_0.json-nft
index 5b13f59a72615..6f6555d224371 100644
--- a/tests/shell/testcases/sets/dumps/0038meter_list_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0038meter_list_0.json-nft
@@ -44,9 +44,7 @@
"type": "ipv4_addr",
"handle": 0,
"size": 128,
- "flags": [
- "dynamic"
- ]
+ "flags": "dynamic"
}
},
{
diff --git a/tests/shell/testcases/sets/dumps/0039delete_interval_0.json-nft b/tests/shell/testcases/sets/dumps/0039delete_interval_0.json-nft
index d6e46aad20a50..afa819584e5b3 100644
--- a/tests/shell/testcases/sets/dumps/0039delete_interval_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0039delete_interval_0.json-nft
@@ -21,9 +21,7 @@
"table": "t",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"range": [
diff --git a/tests/shell/testcases/sets/dumps/0040get_host_endian_elements_0.json-nft b/tests/shell/testcases/sets/dumps/0040get_host_endian_elements_0.json-nft
index 4b6cf03c45961..486ca453281e4 100644
--- a/tests/shell/testcases/sets/dumps/0040get_host_endian_elements_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0040get_host_endian_elements_0.json-nft
@@ -21,9 +21,7 @@
"table": "t",
"type": "mark",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"range": [
diff --git a/tests/shell/testcases/sets/dumps/0041interval_0.json-nft b/tests/shell/testcases/sets/dumps/0041interval_0.json-nft
index 14a393305a3f3..c59a65ae29fd8 100644
--- a/tests/shell/testcases/sets/dumps/0041interval_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0041interval_0.json-nft
@@ -21,9 +21,7 @@
"table": "t",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
"192.168.2.196"
]
diff --git a/tests/shell/testcases/sets/dumps/0042update_set_0.json-nft b/tests/shell/testcases/sets/dumps/0042update_set_0.json-nft
index bc1d4cc2284d8..3f98e120d19bd 100644
--- a/tests/shell/testcases/sets/dumps/0042update_set_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0042update_set_0.json-nft
@@ -39,9 +39,7 @@
"type": "ether_addr",
"handle": 0,
"size": 65535,
- "flags": [
- "dynamic"
- ]
+ "flags": "dynamic"
}
},
{
diff --git a/tests/shell/testcases/sets/dumps/0043concatenated_ranges_1.json-nft b/tests/shell/testcases/sets/dumps/0043concatenated_ranges_1.json-nft
index 92b59c861de10..5ce063d7e4304 100644
--- a/tests/shell/testcases/sets/dumps/0043concatenated_ranges_1.json-nft
+++ b/tests/shell/testcases/sets/dumps/0043concatenated_ranges_1.json-nft
@@ -24,9 +24,7 @@
"ipv6_addr"
],
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"concat": [
@@ -1584,9 +1582,7 @@
"ipv4_addr"
],
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"concat": [
diff --git a/tests/shell/testcases/sets/dumps/0044interval_overlap_1.json-nft b/tests/shell/testcases/sets/dumps/0044interval_overlap_1.json-nft
index f4aae383524ff..8f82990af70d6 100644
--- a/tests/shell/testcases/sets/dumps/0044interval_overlap_1.json-nft
+++ b/tests/shell/testcases/sets/dumps/0044interval_overlap_1.json-nft
@@ -21,9 +21,7 @@
"table": "t",
"type": "inet_service",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
25,
30,
diff --git a/tests/shell/testcases/sets/dumps/0049set_define_0.json-nft b/tests/shell/testcases/sets/dumps/0049set_define_0.json-nft
index f8495bab8b0f3..98ccafd463cc4 100644
--- a/tests/shell/testcases/sets/dumps/0049set_define_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0049set_define_0.json-nft
@@ -33,9 +33,7 @@
"table": "filter",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"auto-merge": true,
"elem": [
"1.1.1.1"
diff --git a/tests/shell/testcases/sets/dumps/0051set_interval_counter_0.json-nft b/tests/shell/testcases/sets/dumps/0051set_interval_counter_0.json-nft
index b468b5f9044ca..96cb397f0c584 100644
--- a/tests/shell/testcases/sets/dumps/0051set_interval_counter_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0051set_interval_counter_0.json-nft
@@ -33,9 +33,7 @@
"table": "x",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"elem": {
diff --git a/tests/shell/testcases/sets/dumps/0052overlap_0.json-nft b/tests/shell/testcases/sets/dumps/0052overlap_0.json-nft
index 96d5fbccd7d40..1ea8ede677aa3 100644
--- a/tests/shell/testcases/sets/dumps/0052overlap_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0052overlap_0.json-nft
@@ -21,9 +21,7 @@
"table": "filter",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"auto-merge": true,
"elem": [
"10.10.10.10",
--git a/tests/shell/testcases/sets/dumps/0054comments_set_0.json-nft b/tests/shell/testcases/sets/dumps/0054comments_set_0.json-nft
index 3fd6d37e18103..a729392270c01 100644
--- a/tests/shell/testcases/sets/dumps/0054comments_set_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0054comments_set_0.json-nft
@@ -22,9 +22,7 @@
"type": "ipv4_addr",
"handle": 0,
"comment": "test",
- "flags": [
- "interval"
- ]
+ "flags": "interval"
}
},
{
@@ -36,9 +34,7 @@
"handle": 0,
"comment": "another test",
"map": "ipv4_addr",
- "flags": [
- "interval"
- ]
+ "flags": "interval"
}
}
]
diff --git a/tests/shell/testcases/sets/dumps/0055tcpflags_0.json-nft b/tests/shell/testcases/sets/dumps/0055tcpflags_0.json-nft
index e37139f334466..0232ad6f28e3b 100644
--- a/tests/shell/testcases/sets/dumps/0055tcpflags_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0055tcpflags_0.json-nft
@@ -21,9 +21,7 @@
"table": "test",
"type": "tcp_flag",
"handle": 0,
- "flags": [
- "constant"
- ],
+ "flags": "constant",
"elem": [
{
"|": [
diff --git a/tests/shell/testcases/sets/dumps/0060set_multistmt_1.json-nft b/tests/shell/testcases/sets/dumps/0060set_multistmt_1.json-nft
index 6098dc563141f..99805e553da0e 100644
--- a/tests/shell/testcases/sets/dumps/0060set_multistmt_1.json-nft
+++ b/tests/shell/testcases/sets/dumps/0060set_multistmt_1.json-nft
@@ -34,9 +34,7 @@
"type": "ipv4_addr",
"handle": 0,
"size": 65535,
- "flags": [
- "dynamic"
- ],
+ "flags": "dynamic",
"elem": [
{
"elem": {
diff --git a/tests/shell/testcases/sets/dumps/0062set_connlimit_0.json-nft b/tests/shell/testcases/sets/dumps/0062set_connlimit_0.json-nft
index c5e60e36c89ea..7a948b1da0cff 100644
--- a/tests/shell/testcases/sets/dumps/0062set_connlimit_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0062set_connlimit_0.json-nft
@@ -22,9 +22,7 @@
"type": "ipv4_addr",
"handle": 0,
"size": 65535,
- "flags": [
- "dynamic"
- ]
+ "flags": "dynamic"
}
},
{
@@ -35,9 +33,7 @@
"type": "ipv4_addr",
"handle": 0,
"size": 65535,
- "flags": [
- "dynamic"
- ],
+ "flags": "dynamic",
"stmt": [
{
"ct count": {
diff --git a/tests/shell/testcases/sets/dumps/0063set_catchall_0.json-nft b/tests/shell/testcases/sets/dumps/0063set_catchall_0.json-nft
index 3006f75a8fcc6..fcfe9830f3600 100644
--- a/tests/shell/testcases/sets/dumps/0063set_catchall_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0063set_catchall_0.json-nft
@@ -55,9 +55,7 @@
"table": "x",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"elem": {
diff --git a/tests/shell/testcases/sets/dumps/0064map_catchall_0.json-nft b/tests/shell/testcases/sets/dumps/0064map_catchall_0.json-nft
index 64dd26670528b..b7496ac853f10 100644
--- a/tests/shell/testcases/sets/dumps/0064map_catchall_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0064map_catchall_0.json-nft
@@ -50,9 +50,7 @@
"type": "ipv4_addr",
"handle": 0,
"map": "ipv4_addr",
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
[
{
diff --git a/tests/shell/testcases/sets/dumps/0069interval_merge_0.json-nft b/tests/shell/testcases/sets/dumps/0069interval_merge_0.json-nft
index d7b32f8cc0e24..7868cb3359160 100644
--- a/tests/shell/testcases/sets/dumps/0069interval_merge_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0069interval_merge_0.json-nft
@@ -21,9 +21,7 @@
"table": "x",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"auto-merge": true,
"elem": [
{
diff --git a/tests/shell/testcases/sets/dumps/0071unclosed_prefix_interval_0.json-nft b/tests/shell/testcases/sets/dumps/0071unclosed_prefix_interval_0.json-nft
index 6b579a2e09fff..588c2b1b6689c 100644
--- a/tests/shell/testcases/sets/dumps/0071unclosed_prefix_interval_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/0071unclosed_prefix_interval_0.json-nft
@@ -29,9 +29,7 @@
"table": "t",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"prefix": {
@@ -55,9 +53,7 @@
"table": "t",
"type": "ipv6_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"prefix": {
diff --git a/tests/shell/testcases/sets/dumps/0073flat_interval_set.json-nft b/tests/shell/testcases/sets/dumps/0073flat_interval_set.json-nft
index e2fb6214238fa..e4649a7d0c22e 100644
--- a/tests/shell/testcases/sets/dumps/0073flat_interval_set.json-nft
+++ b/tests/shell/testcases/sets/dumps/0073flat_interval_set.json-nft
@@ -32,9 +32,7 @@
"type": "ipv4_addr",
"handle": 0,
"map": "counter",
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
[
{
diff --git a/tests/shell/testcases/sets/dumps/0074nested_interval_set.json-nft b/tests/shell/testcases/sets/dumps/0074nested_interval_set.json-nft
index e2fb6214238fa..e4649a7d0c22e 100644
--- a/tests/shell/testcases/sets/dumps/0074nested_interval_set.json-nft
+++ b/tests/shell/testcases/sets/dumps/0074nested_interval_set.json-nft
@@ -32,9 +32,7 @@
"type": "ipv4_addr",
"handle": 0,
"map": "counter",
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
[
{
diff --git a/tests/shell/testcases/sets/dumps/concat_interval_0.json-nft b/tests/shell/testcases/sets/dumps/concat_interval_0.json-nft
index d65065e4f0947..3283f26958f71 100644
--- a/tests/shell/testcases/sets/dumps/concat_interval_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/concat_interval_0.json-nft
@@ -25,9 +25,7 @@
"inet_service"
],
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"stmt": [
{
"counter": null
@@ -45,9 +43,7 @@
"mark"
],
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"concat": [
diff --git a/tests/shell/testcases/sets/dumps/dynset_missing.json-nft b/tests/shell/testcases/sets/dumps/dynset_missing.json-nft
index ad8a7cc0564a8..9de5b821f79e7 100644
--- a/tests/shell/testcases/sets/dumps/dynset_missing.json-nft
+++ b/tests/shell/testcases/sets/dumps/dynset_missing.json-nft
@@ -34,9 +34,7 @@
"type": "ipv4_addr",
"handle": 0,
"size": 65535,
- "flags": [
- "dynamic"
- ]
+ "flags": "dynamic"
}
},
{
diff --git a/tests/shell/testcases/sets/dumps/exact_overlap_0.json-nft b/tests/shell/testcases/sets/dumps/exact_overlap_0.json-nft
index 958d1e5cf6caf..7bba69d54556a 100644
--- a/tests/shell/testcases/sets/dumps/exact_overlap_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/exact_overlap_0.json-nft
@@ -21,9 +21,7 @@
"table": "t",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"prefix": {
diff --git a/tests/shell/testcases/sets/dumps/inner_0.json-nft b/tests/shell/testcases/sets/dumps/inner_0.json-nft
index e5dc198f436be..581d534012e44 100644
--- a/tests/shell/testcases/sets/dumps/inner_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/inner_0.json-nft
@@ -74,9 +74,7 @@
},
"handle": 0,
"size": 65535,
- "flags": [
- "dynamic"
- ]
+ "flags": "dynamic"
}
},
{
diff --git a/tests/shell/testcases/sets/dumps/meter_set_reuse.json-nft b/tests/shell/testcases/sets/dumps/meter_set_reuse.json-nft
index ab4ac06184d03..9210c90b158d4 100644
--- a/tests/shell/testcases/sets/dumps/meter_set_reuse.json-nft
+++ b/tests/shell/testcases/sets/dumps/meter_set_reuse.json-nft
@@ -33,9 +33,7 @@
],
"handle": 0,
"size": 65535,
- "flags": [
- "dynamic"
- ]
+ "flags": "dynamic"
}
},
{
diff --git a/tests/shell/testcases/sets/dumps/range_with_same_start_end.json-nft b/tests/shell/testcases/sets/dumps/range_with_same_start_end.json-nft
index c4682475917e5..e1daa8f86529f 100644
--- a/tests/shell/testcases/sets/dumps/range_with_same_start_end.json-nft
+++ b/tests/shell/testcases/sets/dumps/range_with_same_start_end.json-nft
@@ -21,9 +21,7 @@
"table": "t",
"type": "inet_service",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
10,
30,
diff --git a/tests/shell/testcases/sets/dumps/set_element_timeout_updates.json-nft b/tests/shell/testcases/sets/dumps/set_element_timeout_updates.json-nft
index d92d8d7a54940..acb2f1f4944ac 100644
--- a/tests/shell/testcases/sets/dumps/set_element_timeout_updates.json-nft
+++ b/tests/shell/testcases/sets/dumps/set_element_timeout_updates.json-nft
@@ -40,9 +40,7 @@
}
},
"handle": 0,
- "flags": [
- "timeout"
- ],
+ "flags": "timeout",
"timeout": 60
}
}
diff --git a/tests/shell/testcases/sets/dumps/set_eval_0.json-nft b/tests/shell/testcases/sets/dumps/set_eval_0.json-nft
index 6f692381b6f7c..6f4f4c61600b2 100644
--- a/tests/shell/testcases/sets/dumps/set_eval_0.json-nft
+++ b/tests/shell/testcases/sets/dumps/set_eval_0.json-nft
@@ -33,9 +33,7 @@
"table": "nat",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ]
+ "flags": "interval"
}
},
{
diff --git a/tests/shell/testcases/sets/dumps/sets_with_ifnames.json-nft b/tests/shell/testcases/sets/dumps/sets_with_ifnames.json-nft
index ac4284293c32a..77ca50868f26f 100644
--- a/tests/shell/testcases/sets/dumps/sets_with_ifnames.json-nft
+++ b/tests/shell/testcases/sets/dumps/sets_with_ifnames.json-nft
@@ -71,9 +71,7 @@
"table": "testifsets",
"type": "ifname",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
"abcdef*",
"othername",
@@ -117,9 +115,7 @@
"ifname"
],
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"concat": [
@@ -166,9 +162,7 @@
"type": "ifname",
"handle": 0,
"map": "verdict",
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
[
"abcdef*",
diff --git a/tests/shell/testcases/transactions/dumps/0037set_0.json-nft b/tests/shell/testcases/transactions/dumps/0037set_0.json-nft
index e4c77147b88f6..f9fe4e6f113ea 100644
--- a/tests/shell/testcases/transactions/dumps/0037set_0.json-nft
+++ b/tests/shell/testcases/transactions/dumps/0037set_0.json-nft
@@ -21,9 +21,7 @@
"table": "x",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ]
+ "flags": "interval"
}
}
]
diff --git a/tests/shell/testcases/transactions/dumps/0038set_0.json-nft b/tests/shell/testcases/transactions/dumps/0038set_0.json-nft
index 0a36f4a809a0d..5f97d09e82c6c 100644
--- a/tests/shell/testcases/transactions/dumps/0038set_0.json-nft
+++ b/tests/shell/testcases/transactions/dumps/0038set_0.json-nft
@@ -21,9 +21,7 @@
"table": "x",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"prefix": {
diff --git a/tests/shell/testcases/transactions/dumps/0039set_0.json-nft b/tests/shell/testcases/transactions/dumps/0039set_0.json-nft
index 0a36f4a809a0d..5f97d09e82c6c 100644
--- a/tests/shell/testcases/transactions/dumps/0039set_0.json-nft
+++ b/tests/shell/testcases/transactions/dumps/0039set_0.json-nft
@@ -21,9 +21,7 @@
"table": "x",
"type": "ipv4_addr",
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"prefix": {
diff --git a/tests/shell/testcases/transactions/dumps/0047set_0.json-nft b/tests/shell/testcases/transactions/dumps/0047set_0.json-nft
index a7e677b2e702c..fb6348f229b57 100644
--- a/tests/shell/testcases/transactions/dumps/0047set_0.json-nft
+++ b/tests/shell/testcases/transactions/dumps/0047set_0.json-nft
@@ -22,9 +22,7 @@
"type": "ipv4_addr",
"handle": 0,
"map": "classid",
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
[
"10.1.26.2",
diff --git a/tests/shell/testcases/transactions/dumps/doubled-set.json-nft b/tests/shell/testcases/transactions/dumps/doubled-set.json-nft
index 2dced1240528f..1b9af211945ec 100644
--- a/tests/shell/testcases/transactions/dumps/doubled-set.json-nft
+++ b/tests/shell/testcases/transactions/dumps/doubled-set.json-nft
@@ -24,9 +24,7 @@
"ifname"
],
"handle": 0,
- "flags": [
- "interval"
- ],
+ "flags": "interval",
"elem": [
{
"concat": [
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [nft PATCH 3/6] json: Print single fib flag as non-array
2025-05-08 21:47 ` [nft PATCH 0/6] Add test for parse_flags_array() Phil Sutter
2025-05-08 21:47 ` [nft PATCH 1/6] doc: Fix typo in nat statement 'prefix' description Phil Sutter
2025-05-08 21:47 ` [nft PATCH 2/6] json: Print single set flag as non-array Phil Sutter
@ 2025-05-08 21:47 ` Phil Sutter
2025-05-08 21:47 ` [nft PATCH 4/6] json: Print single synproxy flags " Phil Sutter
` (3 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Phil Sutter @ 2025-05-08 21:47 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
Check array size and reduce the array if possible.
The zero array length check is dead code here due to the surrounding 'if
(flags)' block, but it's a common idiom one could replace by a shared
routine later.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
src/json.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/json.c b/src/json.c
index 6b27ccb927017..a8b0abeba6396 100644
--- a/src/json.c
+++ b/src/json.c
@@ -939,7 +939,15 @@ json_t *fib_expr_json(const struct expr *expr, struct output_ctx *octx)
}
if (flags)
json_array_append_new(tmp, json_integer(flags));
- json_object_set_new(root, "flags", tmp);
+
+ if (json_array_size(tmp) > 1) {
+ json_object_set_new(root, "flags", tmp);
+ } else {
+ if (json_array_size(tmp))
+ json_object_set(root, "flags",
+ json_array_get(tmp, 0));
+ json_decref(tmp);
+ }
}
return json_pack("{s:o}", "fib", root);
}
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [nft PATCH 4/6] json: Print single synproxy flags as non-array
2025-05-08 21:47 ` [nft PATCH 0/6] Add test for parse_flags_array() Phil Sutter
` (2 preceding siblings ...)
2025-05-08 21:47 ` [nft PATCH 3/6] json: Print single fib " Phil Sutter
@ 2025-05-08 21:47 ` Phil Sutter
2025-05-08 21:47 ` [nft PATCH 5/6] json: Introduce json_add_array_new() Phil Sutter
` (2 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Phil Sutter @ 2025-05-08 21:47 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
src/json.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/json.c b/src/json.c
index a8b0abeba6396..0034c02f678ff 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1686,10 +1686,14 @@ json_t *synproxy_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
if (stmt->synproxy.flags & NF_SYNPROXY_OPT_SACK_PERM)
json_array_append_new(flags, json_string("sack-perm"));
- if (json_array_size(flags) > 0)
+ if (json_array_size(flags) > 1) {
json_object_set_new(root, "flags", flags);
- else
+ } else {
+ if (json_array_size(flags))
+ json_object_set(root, "flags",
+ json_array_get(flags, 0));
json_decref(flags);
+ }
if (!json_object_size(root)) {
json_decref(root);
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [nft PATCH 5/6] json: Introduce json_add_array_new()
2025-05-08 21:47 ` [nft PATCH 0/6] Add test for parse_flags_array() Phil Sutter
` (3 preceding siblings ...)
2025-05-08 21:47 ` [nft PATCH 4/6] json: Print single synproxy flags " Phil Sutter
@ 2025-05-08 21:47 ` Phil Sutter
2025-05-08 21:47 ` [nft PATCH 6/6] tests: shell: Add test case for JSON 'flags' arrays Phil Sutter
2025-05-12 21:45 ` [nft PATCH 0/6] Add test for parse_flags_array() Pablo Neira Ayuso
6 siblings, 0 replies; 10+ messages in thread
From: Phil Sutter @ 2025-05-08 21:47 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
Propagate nat_stmt_add_array() to a generic helper for use in all spots
adding an array property which may reduce to a single item or even not
exist at all.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
src/json.c | 99 +++++++++++++-----------------------------------------
1 file changed, 24 insertions(+), 75 deletions(-)
diff --git a/src/json.c b/src/json.c
index 0034c02f678ff..cbed9ce9ccb73 100644
--- a/src/json.c
+++ b/src/json.c
@@ -51,6 +51,18 @@ static int json_array_extend_new(json_t *array, json_t *other_array)
return ret;
}
+static void json_add_array_new(json_t *obj, const char *name, json_t *array)
+{
+ if (json_array_size(array) > 1) {
+ json_object_set_new(obj, name, array);
+ } else {
+ if (json_array_size(array))
+ json_object_set(obj, name,
+ json_array_get(array, 0));
+ json_decref(array);
+ }
+}
+
static json_t *expr_print_json(const struct expr *expr, struct output_ctx *octx)
{
const struct expr_ops *ops;
@@ -198,14 +210,7 @@ static json_t *set_print_json(struct output_ctx *octx, const struct set *set)
json_array_append_new(tmp, json_pack("s", "timeout"));
if (set->flags & NFT_SET_EVAL)
json_array_append_new(tmp, json_pack("s", "dynamic"));
-
- if (json_array_size(tmp) > 1) {
- json_object_set_new(root, "flags", tmp);
- } else {
- if (json_array_size(tmp))
- json_object_set(root, "flags", json_array_get(tmp, 0));
- json_decref(tmp);
- }
+ json_add_array_new(root, "flags", tmp);
if (set->timeout) {
tmp = json_integer(set->timeout / 1000);
@@ -449,19 +454,16 @@ static json_t *obj_print_json(const struct obj *obj)
json_decref(tmp);
break;
case NFT_OBJECT_SYNPROXY:
- flags = json_array();
tmp = json_pack("{s:i, s:i}",
"mss", obj->synproxy.mss,
"wscale", obj->synproxy.wscale);
+
+ flags = json_array();
if (obj->synproxy.flags & NF_SYNPROXY_OPT_TIMESTAMP)
json_array_append_new(flags, json_string("timestamp"));
if (obj->synproxy.flags & NF_SYNPROXY_OPT_SACK_PERM)
json_array_append_new(flags, json_string("sack-perm"));
-
- if (json_array_size(flags) > 0)
- json_object_set_new(tmp, "flags", flags);
- else
- json_decref(flags);
+ json_add_array_new(tmp, "flags", flags);
json_object_update(root, tmp);
json_decref(tmp);
@@ -515,31 +517,18 @@ static json_t *table_flags_json(const struct table *table)
flags >>= 1;
i++;
}
- switch (json_array_size(root)) {
- case 0:
- json_decref(root);
- return NULL;
- case 1:
- json_unpack(root, "[O]", &tmp);
- json_decref(root);
- root = tmp;
- break;
- }
return root;
}
static json_t *table_print_json(const struct table *table)
{
- json_t *root, *tmp;
+ json_t *root;
root = json_pack("{s:s, s:s, s:I}",
"family", family2str(table->handle.family),
"name", table->handle.table.name,
"handle", table->handle.handle.id);
-
- tmp = table_flags_json(table);
- if (tmp)
- json_object_set_new(root, "flags", tmp);
+ json_add_array_new(root, "flags", table_flags_json(table));
if (table->comment)
json_object_set_new(root, "comment", json_string(table->comment));
@@ -940,14 +929,7 @@ json_t *fib_expr_json(const struct expr *expr, struct output_ctx *octx)
if (flags)
json_array_append_new(tmp, json_integer(flags));
- if (json_array_size(tmp) > 1) {
- json_object_set_new(root, "flags", tmp);
- } else {
- if (json_array_size(tmp))
- json_object_set(root, "flags",
- json_array_get(tmp, 0));
- json_decref(tmp);
- }
+ json_add_array_new(root, "flags", tmp);
}
return json_pack("{s:o}", "fib", root);
}
@@ -1384,14 +1366,7 @@ json_t *log_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
if (stmt->log.logflags & NF_LOG_MACDECODE)
json_array_append_new(flags, json_string("ether"));
}
- if (json_array_size(flags) > 1) {
- json_object_set_new(root, "flags", flags);
- } else {
- if (json_array_size(flags))
- json_object_set(root, "flags",
- json_array_get(flags, 0));
- json_decref(flags);
- }
+ json_add_array_new(root, "flags", flags);
if (!json_object_size(root)) {
json_decref(root);
@@ -1426,18 +1401,6 @@ static json_t *nat_type_flags_json(uint32_t type_flags)
return array;
}
-static void nat_stmt_add_array(json_t *root, const char *name, json_t *array)
-{
- if (json_array_size(array) > 1) {
- json_object_set_new(root, name, array);
- } else {
- if (json_array_size(array))
- json_object_set(root, name,
- json_array_get(array, 0));
- json_decref(array);
- }
-}
-
json_t *nat_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
{
json_t *root = json_object();
@@ -1459,12 +1422,12 @@ json_t *nat_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
json_object_set_new(root, "port",
expr_print_json(stmt->nat.proto, octx));
- nat_stmt_add_array(root, "flags", array);
+ json_add_array_new(root, "flags", array);
if (stmt->nat.type_flags) {
array = nat_type_flags_json(stmt->nat.type_flags);
- nat_stmt_add_array(root, "type_flags", array);
+ json_add_array_new(root, "type_flags", array);
}
if (!json_object_size(root)) {
@@ -1616,14 +1579,7 @@ json_t *queue_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
json_array_append_new(flags, json_string("bypass"));
if (stmt->queue.flags & NFT_QUEUE_FLAG_CPU_FANOUT)
json_array_append_new(flags, json_string("fanout"));
- if (json_array_size(flags) > 1) {
- json_object_set_new(root, "flags", flags);
- } else {
- if (json_array_size(flags))
- json_object_set(root, "flags",
- json_array_get(flags, 0));
- json_decref(flags);
- }
+ json_add_array_new(root, "flags", flags);
if (!json_object_size(root)) {
json_decref(root);
@@ -1686,14 +1642,7 @@ json_t *synproxy_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
if (stmt->synproxy.flags & NF_SYNPROXY_OPT_SACK_PERM)
json_array_append_new(flags, json_string("sack-perm"));
- if (json_array_size(flags) > 1) {
- json_object_set_new(root, "flags", flags);
- } else {
- if (json_array_size(flags))
- json_object_set(root, "flags",
- json_array_get(flags, 0));
- json_decref(flags);
- }
+ json_add_array_new(root, "flags", flags);
if (!json_object_size(root)) {
json_decref(root);
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [nft PATCH 6/6] tests: shell: Add test case for JSON 'flags' arrays
2025-05-08 21:47 ` [nft PATCH 0/6] Add test for parse_flags_array() Phil Sutter
` (4 preceding siblings ...)
2025-05-08 21:47 ` [nft PATCH 5/6] json: Introduce json_add_array_new() Phil Sutter
@ 2025-05-08 21:47 ` Phil Sutter
2025-05-12 21:45 ` [nft PATCH 0/6] Add test for parse_flags_array() Pablo Neira Ayuso
6 siblings, 0 replies; 10+ messages in thread
From: Phil Sutter @ 2025-05-08 21:47 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
Ensure these arrays are reduced if containing just a single item and
parser interprets them correctly in any case.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
tests/shell/testcases/json/single_flag | 189 +++++++++++++++++++++++++
1 file changed, 189 insertions(+)
create mode 100755 tests/shell/testcases/json/single_flag
diff --git a/tests/shell/testcases/json/single_flag b/tests/shell/testcases/json/single_flag
new file mode 100755
index 0000000000000..41fab63b0a23b
--- /dev/null
+++ b/tests/shell/testcases/json/single_flag
@@ -0,0 +1,189 @@
+#!/bin/bash
+#
+# Test various "flags" properties in JSON syntax:
+# - single item arrays are abbreviated as non-array in output
+# - both non-array and single item array accepted in input
+# - single and multiple item values are correctly printed in output and
+# recognized in input (checked against standard syntax input/output)
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_json)
+
+set -e
+
+json_sanitize() {
+ sed -e 's/{"metainfo": {[^}]*}}, //' \
+ -e 's/\("handle":\) [0-9]*/\1 0/g'
+}
+back_n_forth() { # (std, json)
+ $NFT flush ruleset
+ $NFT -f - <<< "$1"
+ diff --label "line ${BASH_LINENO[0]}: JSON output" \
+ --label "line ${BASH_LINENO[0]}: JSON expect" \
+ -u <($NFT -j list ruleset | json_sanitize) <(echo "$2")
+
+ $NFT flush ruleset
+ $NFT -j -f - <<< "$2"
+ diff --label "line ${BASH_LINENO[0]}: std output" \
+ --label "line ${BASH_LINENO[0]}: std expect" \
+ -u <($NFT list ruleset) <(echo "$1")
+}
+json_equiv() { # (json_in, json_out)
+ $NFT flush ruleset
+ $NFT -j -f - <<< "$1"
+ diff --label "line ${BASH_LINENO[0]}: JSON equiv output" \
+ --label "line ${BASH_LINENO[0]}: JSON equiv expect" \
+ -u <($NFT -j list ruleset | json_sanitize) <(echo "$2")
+}
+
+#
+# test table flags
+#
+
+STD_TABLE_1="table ip t {
+ flags dormant
+}"
+JSON_TABLE_1='{"nftables": [{"table": {"family": "ip", "name": "t", "handle": 0, "flags": "dormant"}}]}'
+JSON_TABLE_1_EQUIV=$(sed 's/\("flags":\) \([^}]*\)/\1 [\2]/' <<< "$JSON_TABLE_1")
+
+STD_TABLE_2=$(sed 's/\(flags dormant\)/\1,persist/' <<< "$STD_TABLE_1")
+JSON_TABLE_2=$(sed 's/\("flags":\) \("dormant"\)/\1 [\2, "persist"]/' <<< "$JSON_TABLE_1")
+
+back_n_forth "$STD_TABLE_1" "$JSON_TABLE_1"
+json_equiv "$JSON_TABLE_1_EQUIV" "$JSON_TABLE_1"
+back_n_forth "$STD_TABLE_2" "$JSON_TABLE_2"
+
+#
+# test set flags
+#
+
+STD_SET_1="table ip t {
+ set s {
+ type inet_proto
+ flags interval
+ }
+}"
+JSON_SET_1='{"nftables": [{"table": {"family": "ip", "name": "t", "handle": 0}}, {"set": {"family": "ip", "name": "s", "table": "t", "type": "inet_proto", "handle": 0, "flags": "interval"}}]}'
+JSON_SET_1_EQUIV=$(sed 's/\("flags":\) \([^}]*\)/\1 [\2]/' <<< "$JSON_SET_1")
+
+STD_SET_2=$(sed 's/\(flags interval\)/\1,timeout/' <<< "$STD_SET_1")
+JSON_SET_2=$(sed 's/\("flags":\) \("interval"\)/\1 [\2, "timeout"]/' <<< "$JSON_SET_1")
+
+back_n_forth "$STD_SET_1" "$JSON_SET_1"
+json_equiv "$JSON_SET_1_EQUIV" "$JSON_SET_1"
+back_n_forth "$STD_SET_2" "$JSON_SET_2"
+
+#
+# test fib expression flags
+#
+
+STD_FIB_1="table ip t {
+ chain c {
+ fib saddr oif exists
+ }
+}"
+JSON_FIB_1='{"nftables": [{"table": {"family": "ip", "name": "t", "handle": 0}}, {"chain": {"family": "ip", "table": "t", "name": "c", "handle": 0}}, {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"match": {"op": "==", "left": {"fib": {"result": "oif", "flags": "saddr"}}, "right": true}}]}}]}'
+JSON_FIB_1_EQUIV=$(sed 's/\("flags":\) \([^}]*\)/\1 [\2]/' <<< "$JSON_FIB_1")
+
+STD_FIB_2=$(sed 's/\(fib saddr\)/\1 . iif/' <<< "$STD_FIB_1")
+JSON_FIB_2=$(sed 's/\("flags":\) \("saddr"\)/\1 [\2, "iif"]/' <<< "$JSON_FIB_1")
+
+back_n_forth "$STD_FIB_1" "$JSON_FIB_1"
+json_equiv "$JSON_FIB_1_EQUIV" "$JSON_FIB_1"
+back_n_forth "$STD_FIB_2" "$JSON_FIB_2"
+
+#
+# test nat statement flags
+#
+
+STD_NAT_1="table ip t {
+ chain c {
+ dnat to 192.168.0.0/24 persistent
+ }
+}"
+JSON_NAT_1='{"nftables": [{"table": {"family": "ip", "name": "t", "handle": 0}}, {"chain": {"family": "ip", "table": "t", "name": "c", "handle": 0}}, {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"dnat": {"addr": {"prefix": {"addr": "192.168.0.0", "len": 24}}, "flags": "persistent"}}]}}]}'
+JSON_NAT_1_EQUIV=$(sed 's/\("flags":\) \([^}]*\)/\1 [\2]/' <<< "$JSON_NAT_1")
+
+STD_NAT_2=$(sed 's/\(persistent\)/random,\1/' <<< "$STD_NAT_1")
+JSON_NAT_2=$(sed 's/\("flags":\) \("persistent"\)/\1 ["random", \2]/' <<< "$JSON_NAT_1")
+
+back_n_forth "$STD_NAT_1" "$JSON_NAT_1"
+json_equiv "$JSON_NAT_1_EQUIV" "$JSON_NAT_1"
+back_n_forth "$STD_NAT_2" "$JSON_NAT_2"
+
+#
+# test log statement flags
+#
+
+STD_LOG_1="table ip t {
+ chain c {
+ log flags tcp sequence
+ }
+}"
+JSON_LOG_1='{"nftables": [{"table": {"family": "ip", "name": "t", "handle": 0}}, {"chain": {"family": "ip", "table": "t", "name": "c", "handle": 0}}, {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"log": {"flags": "tcp sequence"}}]}}]}'
+JSON_LOG_1_EQUIV=$(sed 's/\("flags":\) \([^}]*\)/\1 [\2]/' <<< "$JSON_LOG_1")
+
+STD_LOG_2=$(sed 's/\(tcp sequence\)/\1,options/' <<< "$STD_LOG_1")
+JSON_LOG_2=$(sed 's/\("flags":\) \("tcp sequence"\)/\1 [\2, "tcp options"]/' <<< "$JSON_LOG_1")
+
+back_n_forth "$STD_LOG_1" "$JSON_LOG_1"
+json_equiv "$JSON_LOG_1_EQUIV" "$JSON_LOG_1"
+back_n_forth "$STD_LOG_2" "$JSON_LOG_2"
+
+#
+# test synproxy statement flags
+#
+
+STD_SYNPROXY_1="table ip t {
+ chain c {
+ synproxy sack-perm
+ }
+}"
+JSON_SYNPROXY_1='{"nftables": [{"table": {"family": "ip", "name": "t", "handle": 0}}, {"chain": {"family": "ip", "table": "t", "name": "c", "handle": 0}}, {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"synproxy": {"flags": "sack-perm"}}]}}]}'
+JSON_SYNPROXY_1_EQUIV=$(sed 's/\("flags":\) \([^}]*\)/\1 [\2]/' <<< "$JSON_SYNPROXY_1")
+
+STD_SYNPROXY_2=$(sed 's/\(sack-perm\)/timestamp \1/' <<< "$STD_SYNPROXY_1")
+JSON_SYNPROXY_2=$(sed 's/\("flags":\) \("sack-perm"\)/\1 ["timestamp", \2]/' <<< "$JSON_SYNPROXY_1")
+
+back_n_forth "$STD_SYNPROXY_1" "$JSON_SYNPROXY_1"
+json_equiv "$JSON_SYNPROXY_1_EQUIV" "$JSON_SYNPROXY_1"
+back_n_forth "$STD_SYNPROXY_2" "$JSON_SYNPROXY_2"
+
+#
+# test synproxy object flags
+#
+
+STD_SYNPROXY_OBJ_1="table ip t {
+ synproxy s {
+ mss 1280
+ wscale 64
+ sack-perm
+ }
+}"
+JSON_SYNPROXY_OBJ_1='{"nftables": [{"table": {"family": "ip", "name": "t", "handle": 0}}, {"synproxy": {"family": "ip", "name": "s", "table": "t", "handle": 0, "mss": 1280, "wscale": 64, "flags": "sack-perm"}}]}'
+JSON_SYNPROXY_OBJ_1_EQUIV=$(sed 's/\("flags":\) \([^}]*\)/\1 [\2]/' <<< "$JSON_SYNPROXY_OBJ_1")
+
+STD_SYNPROXY_OBJ_2=$(sed 's/ \(sack-perm\)/timestamp \1/' <<< "$STD_SYNPROXY_OBJ_1")
+JSON_SYNPROXY_OBJ_2=$(sed 's/\("flags":\) \("sack-perm"\)/\1 ["timestamp", \2]/' <<< "$JSON_SYNPROXY_OBJ_1")
+
+back_n_forth "$STD_SYNPROXY_OBJ_1" "$JSON_SYNPROXY_OBJ_1"
+json_equiv "$JSON_SYNPROXY_OBJ_1_EQUIV" "$JSON_SYNPROXY_OBJ_1"
+back_n_forth "$STD_SYNPROXY_OBJ_2" "$JSON_SYNPROXY_OBJ_2"
+
+#
+# test queue statement flags
+#
+
+STD_QUEUE_1="table ip t {
+ chain c {
+ queue flags bypass to 1-10
+ }
+}"
+JSON_QUEUE_1='{"nftables": [{"table": {"family": "ip", "name": "t", "handle": 0}}, {"chain": {"family": "ip", "table": "t", "name": "c", "handle": 0}}, {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"queue": {"num": {"range": [1, 10]}, "flags": "bypass"}}]}}]}'
+JSON_QUEUE_1_EQUIV=$(sed 's/\("flags":\) \([^}]*\)/\1 [\2]/' <<< "$JSON_QUEUE_1")
+
+STD_QUEUE_2=$(sed 's/\(bypass\)/\1,fanout/' <<< "$STD_QUEUE_1")
+JSON_QUEUE_2=$(sed 's/\("flags":\) \("bypass"\)/\1 [\2, "fanout"]/' <<< "$JSON_QUEUE_1")
+
+back_n_forth "$STD_QUEUE_1" "$JSON_QUEUE_1"
+json_equiv "$JSON_QUEUE_1_EQUIV" "$JSON_QUEUE_1"
+back_n_forth "$STD_QUEUE_2" "$JSON_QUEUE_2"
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [nft PATCH 0/6] Add test for parse_flags_array()
2025-05-08 21:47 ` [nft PATCH 0/6] Add test for parse_flags_array() Phil Sutter
` (5 preceding siblings ...)
2025-05-08 21:47 ` [nft PATCH 6/6] tests: shell: Add test case for JSON 'flags' arrays Phil Sutter
@ 2025-05-12 21:45 ` Pablo Neira Ayuso
2025-05-13 8:49 ` Phil Sutter
6 siblings, 1 reply; 10+ messages in thread
From: Pablo Neira Ayuso @ 2025-05-12 21:45 UTC (permalink / raw)
To: Phil Sutter; +Cc: netfilter-devel
On Thu, May 08, 2025 at 11:47:16PM +0200, Phil Sutter wrote:
> The function introduced in previous patch relaxes JSON syntax in parsing
> selected properties which usually contain an array as value to also
> accept a string representing the only array element.
>
> The test asserting correct parsing of such properties exposed JSON
> printer's limitation in some properties to not reduce the array value
> when possible.
>
> To make things consistent, This series enhances the JSON printer by
> support for array reduction where missing (patches 2-4), then introduces
> a shared routine to combine the common idiom in patch 5. Patch 6 finally
> adds the actual shell test case. Patch 1 is merely fallout, a trivial
> fix identified when working on the test implementation.
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [nft PATCH 0/6] Add test for parse_flags_array()
2025-05-12 21:45 ` [nft PATCH 0/6] Add test for parse_flags_array() Pablo Neira Ayuso
@ 2025-05-13 8:49 ` Phil Sutter
0 siblings, 0 replies; 10+ messages in thread
From: Phil Sutter @ 2025-05-13 8:49 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
On Mon, May 12, 2025 at 11:45:34PM +0200, Pablo Neira Ayuso wrote:
> On Thu, May 08, 2025 at 11:47:16PM +0200, Phil Sutter wrote:
> > The function introduced in previous patch relaxes JSON syntax in parsing
> > selected properties which usually contain an array as value to also
> > accept a string representing the only array element.
> >
> > The test asserting correct parsing of such properties exposed JSON
> > printer's limitation in some properties to not reduce the array value
> > when possible.
> >
> > To make things consistent, This series enhances the JSON printer by
> > support for array reduction where missing (patches 2-4), then introduces
> > a shared routine to combine the common idiom in patch 5. Patch 6 finally
> > adds the actual shell test case. Patch 1 is merely fallout, a trivial
> > fix identified when working on the test implementation.
>
> Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
Series applied.
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2025-05-13 8:49 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-07 22:28 [nft PATCH] parser_json: Introduce parse_flags_array() Phil Sutter
2025-05-08 21:47 ` [nft PATCH 0/6] Add test for parse_flags_array() Phil Sutter
2025-05-08 21:47 ` [nft PATCH 1/6] doc: Fix typo in nat statement 'prefix' description Phil Sutter
2025-05-08 21:47 ` [nft PATCH 2/6] json: Print single set flag as non-array Phil Sutter
2025-05-08 21:47 ` [nft PATCH 3/6] json: Print single fib " Phil Sutter
2025-05-08 21:47 ` [nft PATCH 4/6] json: Print single synproxy flags " Phil Sutter
2025-05-08 21:47 ` [nft PATCH 5/6] json: Introduce json_add_array_new() Phil Sutter
2025-05-08 21:47 ` [nft PATCH 6/6] tests: shell: Add test case for JSON 'flags' arrays Phil Sutter
2025-05-12 21:45 ` [nft PATCH 0/6] Add test for parse_flags_array() Pablo Neira Ayuso
2025-05-13 8:49 ` Phil Sutter
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.