[nft,3/8] json: Add ct timeout support

Message ID 20181011154901.20082-4-phil@nwl.cc
State Accepted
Delegated to: Pablo Neira
Headers show
Series
  • monitor: Use libnftables for JSON output
Related show

Commit Message

Phil Sutter Oct. 11, 2018, 3:48 p.m.
Add support for printing and parsing ct timeout objects to JSON API.

Signed-off-by: Phil Sutter <phil@nwl.cc>
---
 src/json.c                 | 29 ++++++++++++++
 src/parser_json.c          | 82 +++++++++++++++++++++++++++++++++++++-
 tests/py/ip/objects.t.json |  7 ++++
 3 files changed, 117 insertions(+), 1 deletion(-)

Patch

diff --git a/src/json.c b/src/json.c
index 0191a2ea7df0d..b8d9333e877a8 100644
--- a/src/json.c
+++ b/src/json.c
@@ -235,6 +235,23 @@  static json_t *proto_name_json(uint8_t proto)
 	return json_integer(proto);
 }
 
+static json_t *timeout_policy_json(uint8_t l4, const uint32_t *timeout)
+{
+	json_t *root = NULL;
+	unsigned int i;
+
+	for (i = 0; i < timeout_protocol[l4].array_size; i++) {
+		if (timeout[i] == timeout_protocol[l4].dflt_timeout[i])
+			continue;
+
+		if (!root)
+			root = json_object();
+		json_object_set(root, timeout_protocol[l4].state_to_name[i],
+				json_integer(timeout[i]));
+	}
+	return root ? : json_null();
+}
+
 static json_t *obj_print_json(struct output_ctx *octx, const struct obj *obj)
 {
 	const char *rate_unit = NULL, *burst_unit = NULL;
@@ -273,6 +290,18 @@  static json_t *obj_print_json(struct output_ctx *octx, const struct obj *obj)
 		json_object_update(root, tmp);
 		json_decref(tmp);
 		break;
+	case NFT_OBJECT_CT_TIMEOUT:
+		type = "ct timeout";
+		tmp = timeout_policy_json(obj->ct_timeout.l4proto,
+					  obj->ct_timeout.timeout);
+		tmp = json_pack("{s:o, s:s, s:o}",
+				"protocol",
+				proto_name_json(obj->ct_timeout.l4proto),
+				"l3proto", family2str(obj->ct_timeout.l3proto),
+				"policy", tmp);
+		json_object_update(root, tmp);
+		json_decref(tmp);
+		break;
 	case NFT_OBJECT_LIMIT:
 		rate = obj->limit.rate;
 		burst = obj->limit.burst;
diff --git a/src/parser_json.c b/src/parser_json.c
index 9aadc33ed93a0..35464c9a83c83 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -2106,7 +2106,22 @@  static struct stmt *json_parse_cthelper_stmt(struct json_ctx *ctx,
 	stmt->objref.type = NFT_OBJECT_CT_HELPER;
 	stmt->objref.expr = json_parse_stmt_expr(ctx, value);
 	if (!stmt->objref.expr) {
-		json_error(ctx, "Invalid cthelper reference.");
+		json_error(ctx, "Invalid ct helper reference.");
+		stmt_free(stmt);
+		return NULL;
+	}
+	return stmt;
+}
+
+static struct stmt *json_parse_cttimeout_stmt(struct json_ctx *ctx,
+					     const char *key, json_t *value)
+{
+	struct stmt *stmt = objref_stmt_alloc(int_loc);
+
+	stmt->objref.type = NFT_OBJECT_CT_TIMEOUT;
+	stmt->objref.expr = json_parse_stmt_expr(ctx, value);
+	if (!stmt->objref.expr) {
+		json_error(ctx, "Invalid ct timeout reference.");
 		stmt_free(stmt);
 		return NULL;
 	}
@@ -2257,6 +2272,7 @@  static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root)
 		{ "set", json_parse_set_stmt },
 		{ "log", json_parse_log_stmt },
 		{ "ct helper", json_parse_cthelper_stmt },
+		{ "ct timeout", json_parse_cttimeout_stmt },
 		{ "meter", json_parse_meter_stmt },
 		{ "queue", json_parse_queue_stmt },
 		{ "ct count", json_parse_connlimit_stmt },
@@ -2737,6 +2753,39 @@  static struct cmd *json_parse_cmd_add_flowtable(struct json_ctx *ctx,
 	return cmd_alloc(op, cmd_obj, &h, int_loc, flowtable);
 }
 
+static int json_parse_ct_timeout_policy(struct json_ctx *ctx,
+					json_t *root, struct obj *obj)
+{
+	json_t *tmp, *val;
+	const char *key;
+
+	if (!json_unpack(root, "{s:o}", "policy", &tmp))
+		return 0;
+
+	if (json_is_object(tmp)) {
+		json_error(ctx, "Invalid ct timeout policy.");
+		return 1;
+	}
+
+	init_list_head(&obj->ct_timeout.timeout_list);
+	json_object_foreach(tmp, key, val) {
+		struct timeout_state *ts;
+
+		if (!json_is_integer(val)) {
+			json_error(ctx, "Invalid ct timeout policy value for '%s'.", key);
+			return 1;
+		}
+
+		ts = xzalloc(sizeof(*ts));
+		ts->timeout_str = xstrdup(key);
+		ts->timeout_value = json_integer_value(val);
+		ts->location = *int_loc;
+		init_list_head(&ts->head);
+		list_add_tail(&ts->head, &obj->ct_timeout.timeout_list);
+	}
+	return 0;
+}
+
 static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
 					     json_t *root, enum cmd_ops op,
 					     enum cmd_obj cmd_obj)
@@ -2834,6 +2883,37 @@  static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
 			obj->ct_helper.l3proto = NFPROTO_IPV4;
 		}
 		break;
+	case NFT_OBJECT_CT_TIMEOUT:
+		cmd_obj = CMD_OBJ_CT_TIMEOUT;
+		obj->type = NFT_OBJECT_CT_TIMEOUT;
+		if (!json_unpack(root, "{s:s}", "protocol", &tmp)) {
+			if (!strcmp(tmp, "tcp")) {
+				obj->ct_timeout.l4proto = IPPROTO_TCP;
+			} else if (!strcmp(tmp, "udp")) {
+				obj->ct_timeout.l4proto = IPPROTO_UDP;
+			} else {
+				json_error(ctx, "Invalid ct timeout protocol '%s'.", tmp);
+				obj_free(obj);
+				return NULL;
+			}
+		}
+		if (!json_unpack(root, "{s:s}", "l3proto", &tmp)) {
+			int family = parse_family(tmp);
+
+			if (family < 0) {
+				json_error(ctx, "Invalid ct timeout l3proto '%s'.", tmp);
+				obj_free(obj);
+				return NULL;
+			}
+			obj->ct_timeout.l3proto = family;
+		} else {
+			obj->ct_timeout.l3proto = NFPROTO_IPV4;
+		}
+		if (json_parse_ct_timeout_policy(ctx, root, obj)) {
+			obj_free(obj);
+			return NULL;
+		}
+		break;
 	case CMD_OBJ_LIMIT:
 		obj->type = NFT_OBJECT_LIMIT;
 		if (json_unpack_err(ctx, root, "{s:I, s:s}",
diff --git a/tests/py/ip/objects.t.json b/tests/py/ip/objects.t.json
index 8e838cf414397..a98d73c5f3157 100644
--- a/tests/py/ip/objects.t.json
+++ b/tests/py/ip/objects.t.json
@@ -186,3 +186,10 @@ 
     }
 ]
 
+# ct timeout set "cttime1"
+[
+    {
+        "ct timeout": "cttime1"
+    }
+]
+