Add support for printing and parsing ct timeout objects to JSON API. Signed-off-by: Phil Sutter <phil@xxxxxx> --- src/json.c | 29 ++++++++++++++ src/parser_json.c | 82 +++++++++++++++++++++++++++++++++++++- tests/py/ip/objects.t.json | 7 ++++ 3 files changed, 117 insertions(+), 1 deletion(-) 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" + } +] + -- 2.19.0