[nft PATCH 9/9] JSON: Add metainfo object to all output

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Right now this object merely contains the nftables version and release
name as well as a JSON schema version, but it could be extended
arbitrarily. In the future, this will also allow for non-compatible
schema changes should the need for this arise.

Adjust the parser to accept metainfo objects and make it verify
json_schema_version to be less than or equal to the one hard-coded in
the library.

Signed-off-by: Phil Sutter <phil@xxxxxx>
---
 doc/libnftables-json.adoc | 25 +++++++++++++++++++++++--
 include/json.h            |  2 ++
 src/json.c                | 19 ++++++++++++++++---
 src/parser_json.c         | 27 +++++++++++++++++++++++++++
 4 files changed, 68 insertions(+), 5 deletions(-)

diff --git a/doc/libnftables-json.adoc b/doc/libnftables-json.adoc
index c174a35487d46..59bac17fd0051 100644
--- a/doc/libnftables-json.adoc
+++ b/doc/libnftables-json.adoc
@@ -16,13 +16,14 @@ libnftables-json - Supported JSON schema by libnftables
 
 'CMD_OBJECTS' := 'CMD_OBJECT' [ *,* 'CMD_OBJECTS' ]
 
-'CMD_OBJECT' := *{* 'CMD'*:* 'LIST_OBJECT' *}*
+'CMD_OBJECT' := *{* 'CMD'*:* 'LIST_OBJECT' *}* | 'METAINFO_OBJECT'
 
 'CMD' := *"add"* | *"replace"* | *"create"* | *"insert"* | *"delete"* |
          *"list"* | *"reset"* | *"flush"* | *"rename"*
 
 'LIST_OBJECT' := 'TABLE' | 'CHAIN' | 'RULE' | 'SET' | 'MAP' | 'ELEMENT' |
-		 'FLOWTABLE' | 'COUNTER' | 'QUOTA' | 'CT_HELPER' | 'LIMIT'
+		 'FLOWTABLE' | 'COUNTER' | 'QUOTA' | 'CT_HELPER' | 'LIMIT' |
+		 'METAINFO_OBJECT'
 
 == DESCRIPTION
 libnftables supports JSON formatted input and output. This is implemented as an
@@ -47,6 +48,26 @@ It's value is a ruleset element - basically identical to output elements apart
 from certain properties which may be interpreted differently or are required
 when output generally omits them.
 
+== METAINFO OBJECT
+In output, the first object in *nftables* array is a special one containing
+library information. Its content is as follows:
+
+[verse]
+*{ "metainfo": {
+	"version":* 'STRING'*,
+	"release_name":* 'STRING'*,
+	"json_schema_version":* 'NUMBER'
+*}}*
+
+The values of *version* and *release_name* properties are equal to the package
+version and release name as printed by *nft -v*. The value of
+*json_schema_version* property is an integer indicating the schema version.
+
+If supplied in library input, the parser will verify *json_schema_version* value
+to not exceed the internally hardcoded one (to make sure the given schema is
+fully understood). In future, a lower number than the internal one may activate
+compatibility mode to parse outdated and incompatible JSON input.
+
 == COMMAND OBJECTS
 The structure accepts an arbitrary amount of commands which are interpreted in
 order of appearance. For instance, the following standard syntax input:
diff --git a/include/json.h b/include/json.h
index b75512b8475fb..7967dd20fc83e 100644
--- a/include/json.h
+++ b/include/json.h
@@ -15,6 +15,8 @@ struct table;
 
 #ifdef HAVE_LIBJANSSON
 
+#define JSON_SCHEMA_VERSION 1
+
 #include <jansson.h>
 
 json_t *binop_expr_json(const struct expr *expr, struct output_ctx *octx);
diff --git a/src/json.c b/src/json.c
index 199ca0a308bcd..8d55885fa3916 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1499,6 +1499,14 @@ static json_t *do_list_flowtables_json(struct netlink_ctx *ctx, struct cmd *cmd)
 	return root;
 }
 
+static json_t *generate_json_metainfo(void)
+{
+	return json_pack("{s: {s:s, s:s, s:i}}", "metainfo",
+			 "version", PACKAGE_VERSION,
+			 "release_name", RELEASE_NAME,
+			 "json_schema_version", JSON_SCHEMA_VERSION);
+}
+
 int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd)
 {
 	struct table *table = NULL;
@@ -1565,10 +1573,15 @@ int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd)
 		BUG("invalid command object type %u\n", cmd->obj);
 	}
 
-	if (json_is_array(root) && !json_array_size(root)) {
-		json_decref(root);
-		root = json_null();
+	if (!json_is_array(root)) {
+		json_t *tmp = json_array();
+
+		json_array_append_new(tmp, root);
+		root = tmp;
 	}
+
+	json_array_insert_new(root, 0, generate_json_metainfo());
+
 	root = json_pack("{s:o}", "nftables", root);
 	json_dumpf(root, ctx->octx->output_fp, 0);
 	json_decref(root);
diff --git a/src/parser_json.c b/src/parser_json.c
index 404dbe9fa82a6..ce85b798e908e 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -3060,6 +3060,22 @@ static struct cmd *json_parse_cmd(struct json_ctx *ctx, json_t *root)
 	return NULL;
 }
 
+static int json_verify_metainfo(struct json_ctx *ctx, json_t *root)
+{
+	int schema_version;
+
+	if (!json_unpack(root, "{s:i}", "json_schema_version", &schema_version))
+			return 0;
+
+	if (schema_version > JSON_SCHEMA_VERSION) {
+		json_error(ctx, "Schema version %d not supported, maximum supported version is %d\n",
+			   schema_version, JSON_SCHEMA_VERSION);
+		return 1;
+	}
+
+	return 0;
+}
+
 static int __json_parse(struct json_ctx *ctx, json_t *root)
 {
 	struct eval_ctx ectx = {
@@ -3084,11 +3100,22 @@ static int __json_parse(struct json_ctx *ctx, json_t *root)
 		/* this is more or less from parser_bison.y:716 */
 		LIST_HEAD(list);
 		struct cmd *cmd;
+		json_t *tmp2;
 
 		if (!json_is_object(value)) {
 			json_error(ctx, "Unexpected command array element of type %s, expected object.", json_typename(value));
 			return -1;
 		}
+
+		tmp2 = json_object_get(value, "metainfo");
+		if (tmp2) {
+			if (json_verify_metainfo(ctx, tmp2)) {
+				json_error(ctx, "Metainfo verification failed.");
+				return -1;
+			}
+			continue;
+		}
+
 		cmd = json_parse_cmd(ctx, value);
 
 		if (!cmd) {
-- 
2.18.0





[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux