nftables/0039-parser_json-Introduce-parse_flags_array.patch
Phil Sutter 63fbb66589 nftables-1.0.9-8.el9
* Tue Jun 30 2026 Phil Sutter <psutter@redhat.com> [1.0.9-8.el9]
- parser_json: fix map/set type confusion crash in map statement parser (Phil Sutter) [RHEL-190549]
- parser_json: bail out on malformed statement in set (Phil Sutter) [RHEL-190549]
- parser_json: allow statement stateful statement only in set elements (Phil Sutter) [RHEL-190549]
- parser_json: fix crash in json_parse_set_stmt_list (Phil Sutter) [RHEL-190549]
- cache: honor -c/--check for reset commands (Phil Sutter) [RHEL-190549]
- mnl: Fix ordering of hooks in 'list hooks' output (Phil Sutter) [RHEL-190549]
- segtree: Fix for variable-sized object may not be initialized (Phil Sutter) [RHEL-190549]
- cache: Filter for table when listing flowtables (Phil Sutter) [RHEL-190549]
- cache: Filter for table when listing sets or maps (Phil Sutter) [RHEL-190549]
- cache: Relax chain_cache_dump filter application (Phil Sutter) [RHEL-190549]
- cache: Respect family in all list commands (Phil Sutter) [RHEL-190549]
- json: complete multi-statement set element support (Phil Sutter) [RHEL-190549]
- mergesort: Align concatenation sort order with Big Endian (Phil Sutter) [RHEL-190549]
- optimize: expand expression list when merging into concatenation (Phil Sutter) [RHEL-190549]
- mergesort: Fix sorting of string values (Phil Sutter) [RHEL-190549]
- segtree: Fix range aggregation on Big Endian (Phil Sutter) [RHEL-190549]
- monitor: fix memleak in setelem cb (Phil Sutter) [RHEL-190549]
- tests: json_echo: Drop rule handle before multi-add (Phil Sutter) [RHEL-190549]
- rule: skip CMD_OBJ_SETELEMS with no elements after set flush (Phil Sutter) [RHEL-190549]
- doc: libnftables-json: Describe RULESET object (Phil Sutter) [RHEL-190549]
- doc: don't suggest to disable GSO (Phil Sutter) [RHEL-190549]
- tests: py: inet/osf.t: Fix element ordering in JSON equivalents (Phil Sutter) [RHEL-190549]
- tests: py: any/ct.t.json.output: Drop leftover entry (Phil Sutter) [RHEL-190549]
- optimize: Fix verdict expression comparison (Phil Sutter) [RHEL-190549]
- datatype: Fix boolean type on Big Endian (Phil Sutter) [RHEL-190549]
- datatype: clamp boolean value to 0 and 1 (Phil Sutter) [RHEL-190549]
- src: parser_json: fix format string bugs (Phil Sutter) [RHEL-190549]
- doc: fix tcpdump example (Phil Sutter) [RHEL-190549]
- fib: Fix for existence check on Big Endian (Phil Sutter) [RHEL-190549]
- monitor: Inform JSON printer when reporting an object delete event (Phil Sutter) [RHEL-190549]
- tests: monitor: Fix regex collecting expected echo output (Phil Sutter) [RHEL-190549]
- monitor: Quote device names in chain declarations, too (Phil Sutter) [RHEL-190549]
- mnl: continue on ENOBUFS errors when processing batch (Phil Sutter) [RHEL-190549]
- mnl: silence compiler warning (Phil Sutter) [RHEL-190549]
- fib: restore JSON output for relational expressions (Phil Sutter) [RHEL-190549]
- json: Do not reduce single-item arrays on output (Phil Sutter) [RHEL-190549]
- src: ensure chain policy evaluation when specified (Phil Sutter) [RHEL-190549]
- segtree: incorrect type when aggregating concatenated set ranges (Phil Sutter) [RHEL-190549]
- tests: py: Fix tests added for 'icmpv6 taddr' support (Phil Sutter) [RHEL-190549]
- tests: py: Drop stale entry from ip/snat.t.payload (Phil Sutter) [RHEL-190549]
- tests: py: Drop stale entries from ip6/{ct,meta}.t.json (Phil Sutter) [RHEL-190549]
- tests: py: Drop stale entry from ip/snat.t.json (Phil Sutter) [RHEL-190549]
- tests: py: Drop duplicate test from inet/vxlan.t (Phil Sutter) [RHEL-190549]
- tests: py: Drop stale entry from inet/tcp.t.json (Phil Sutter) [RHEL-190549]
- tests: py: Drop duplicate test from inet/gretap.t (Phil Sutter) [RHEL-190549]
- tests: py: Drop duplicate test from inet/gre.t (Phil Sutter) [RHEL-190549]
- tests: py: Drop duplicate test from inet/geneve.t (Phil Sutter) [RHEL-190549]
- tests: py: Drop stale entries since redundant test case removal (Phil Sutter) [RHEL-190549]
- src: netlink: netlink_delinearize_table() may return NULL (Phil Sutter) [RHEL-190549]
- doc: nft.8: Minor NAT STATEMENTS section review (Phil Sutter) [RHEL-190549]
- mnl: Call mnl_attr_nest_end() just once (Phil Sutter) [RHEL-190549]
- evaluate: validate set expression type before accessing flags (Phil Sutter) [RHEL-190549]
- rule: print chain and flowtable devices in quotes (Phil Sutter) [RHEL-190549]
- tests: shell: skip if kernel does not support flowtable counter (Phil Sutter) [RHEL-190549]
- tests: shell: adjust add-after-delete flowtable for older kernels (Phil Sutter) [RHEL-190549]
- tests/shell: cover long interface name in "0042chain_variable_0" test (Phil Sutter) [RHEL-190549]
- tests: py: re-enables nft-test.py to load the local nftables.py (Phil Sutter) [RHEL-190549]
- fib: allow to use it in set statements (Phil Sutter) [RHEL-190549]
- fib: allow to check if route exists in maps (Phil Sutter) [RHEL-190549]
- tests: py: fix json single-flag output for fib & synproxy (Phil Sutter) [RHEL-190549]
- parser_json: Introduce parse_flags_array() (Phil Sutter) [RHEL-190549]
- json: work around fuzzer-induced assert crashes (Phil Sutter) [RHEL-190549]
- json: Introduce json_add_array_new() (Phil Sutter) [RHEL-190549]
- json: Print single synproxy flags as non-array (Phil Sutter) [RHEL-190549]
- json: Print single fib flag as non-array (Phil Sutter) [RHEL-190549]
- json: fix use after free in table_flags_json() (Phil Sutter) [RHEL-190549]
- doc: extend description of fib expression (Phil Sutter) [RHEL-190549]
- json: reject too long interface names (Phil Sutter) [RHEL-190549]
- parser_bison: allow delete command with map via handle (Phil Sutter) [RHEL-190549]
- parser_bison: only reset by name is supported by now (Phil Sutter) [RHEL-190549]
- cache: assert name is non-nul when looking up (Phil Sutter) [RHEL-190549]
- rule: skip fuzzy lookup if object name is not available (Phil Sutter) [RHEL-190549]
- src: BASECHAIN flag no longer implies presence of priority expression (Phil Sutter) [RHEL-190549]
- netlink: Avoid crash upon missing NFTNL_OBJ_CT_TIMEOUT_ARRAY attribute (Phil Sutter) [RHEL-190549]
- tests: py: Properly fix JSON equivalents for netdev/reject.t (Phil Sutter) [RHEL-190549]
- tests: monitor: Fix for single flag array avoidance (Phil Sutter) [RHEL-190549]
- json: Support typeof in set and map types (Phil Sutter) [RHEL-190549]
- netlink: Do not allocate a bogus flowtable priority expr (Phil Sutter) [RHEL-190549]
- netlink: Fix for potential crash parsing a flowtable (Phil Sutter) [RHEL-190549]
- json: prevent null deref if chain->policy is not set (Phil Sutter) [RHEL-190549]
- netlink: Catch unknown types when deserializing objects (Phil Sutter) [RHEL-190549]
- netlink: Avoid potential NULL-ptr deref parsing set elem expressions (Phil Sutter) [RHEL-190549]
- json: Print single set flag as non-array (Phil Sutter) [RHEL-190549]
- doc: Fix typo in nat statement 'prefix' description (Phil Sutter) [RHEL-190549]
Resolves: RHEL-190549
2026-06-30 19:42:31 +02:00

770 lines
21 KiB
Diff

From df090a258ef0753e76112b58ba3165a452fc24be Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 30 Jun 2026 14:30:19 +0200
Subject: [PATCH] parser_json: Introduce parse_flags_array()
JIRA: https://issues.redhat.com/browse/RHEL-190549
Upstream Status: nftables commit 3550dd69632f3a883ab6593daeffb514c67dfb8c
commit 3550dd69632f3a883ab6593daeffb514c67dfb8c
Author: Phil Sutter <phil@nwl.cc>
Date: Thu Apr 10 16:42:42 2025 +0200
parser_json: Introduce parse_flags_array()
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>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
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 c3e3bcc..27c96c3 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'*,
@@ -332,7 +332,7 @@ ____
"type":* 'SET_TYPE'*,
"map":* 'STRING'*,
"policy":* 'SET_POLICY'*,
- "flags": [* 'SET_FLAG_LIST' *],
+ "flags":* 'SET_FLAGS'*,
"elem":* 'SET_ELEMENTS'*,
"timeout":* 'NUMBER'*,
"gc-interval":* 'NUMBER'*,
@@ -342,6 +342,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 eefb8af..0bf81d1 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -193,6 +193,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;
@@ -1060,7 +1114,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",
@@ -1072,12 +1126,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,
@@ -1090,11 +1142,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;
@@ -1110,34 +1160,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 */
@@ -2090,8 +2115,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;
@@ -2102,51 +2126,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;
@@ -2156,47 +2145,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)
@@ -2219,7 +2174,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;
@@ -2252,24 +2207,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;
}
@@ -2481,8 +2432,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;
@@ -2495,47 +2445,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,
@@ -2543,8 +2459,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);
@@ -2577,20 +2492,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;
@@ -2599,54 +2511,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) {
@@ -2676,15 +2553,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;
}
@@ -2779,14 +2657,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;
}
@@ -2794,8 +2670,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);
@@ -2804,43 +2680,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);
}
@@ -2950,45 +2796,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)
{
@@ -2997,7 +2804,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))
@@ -3008,9 +2815,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)) {
@@ -3291,7 +3099,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;
@@ -3318,6 +3126,7 @@ static struct cmd *json_parse_cmd_add_set(struct json_ctx *ctx, json_t *root,
const char *family = "", *policy, *dtype_ext = NULL;
json_t *tmp, *stmt_json;
struct set *set;
+ int flags;
if (json_unpack_err(ctx, root, "{s:s, s:s}",
"family", &family,
@@ -3398,23 +3207,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) {
@@ -3585,7 +3387,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,
@@ -3765,13 +3566,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);