diff options
| author | Fernando Fernandez Mancera <fmancera@suse.de> | 2025-08-21 11:13:01 +0200 |
|---|---|---|
| committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2025-08-27 23:51:12 +0200 |
| commit | 3a957f8f1ff1e111c4d7121749a400dfcac685b7 (patch) | |
| tree | 7c712b3274b1608b75edaf9bbf7045e9fa4a113f /src/parser_json.c | |
| parent | 59f03bf14835fe5764b016491ce50715df5711c2 (diff) | |
tunnel: add tunnel object and statement json support
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src/parser_json.c')
| -rw-r--r-- | src/parser_json.c | 236 |
1 files changed, 233 insertions, 3 deletions
diff --git a/src/parser_json.c b/src/parser_json.c index ebb96d79..8bca6a59 100644 --- a/src/parser_json.c +++ b/src/parser_json.c @@ -439,6 +439,23 @@ static struct expr *json_parse_meta_expr(struct json_ctx *ctx, return meta_expr_alloc(int_loc, key); } +static struct expr *json_parse_tunnel_expr(struct json_ctx *ctx, + const char *type, json_t *root) +{ + struct error_record *erec; + unsigned int key; + const char *name; + + if (json_unpack_err(ctx, root, "{s:s}", "key", &name)) + return NULL; + erec = tunnel_key_parse(int_loc, name, &key); + if (erec) { + erec_queue(erec, ctx->msgs); + return NULL; + } + return tunnel_expr_alloc(int_loc, key); +} + static struct expr *json_parse_osf_expr(struct json_ctx *ctx, const char *type, json_t *root) { @@ -1642,6 +1659,7 @@ static struct expr *json_parse_expr(struct json_ctx *ctx, json_t *root) { "rt", json_parse_rt_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT }, { "ct", json_parse_ct_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT }, { "numgen", json_parse_numgen_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT }, + { "tunnel", json_parse_tunnel_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SES | CTX_F_MAP }, /* below two are hash expr */ { "jhash", json_parse_hash_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT }, { "symhash", json_parse_hash_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT }, @@ -2202,6 +2220,23 @@ static struct stmt *json_parse_secmark_stmt(struct json_ctx *ctx, return stmt; } +static struct stmt *json_parse_tunnel_stmt(struct json_ctx *ctx, + const char *key, json_t *value) +{ + struct stmt *stmt; + + stmt = objref_stmt_alloc(int_loc); + stmt->objref.type = NFT_OBJECT_TUNNEL; + stmt->objref.expr = json_parse_stmt_expr(ctx, value); + if (!stmt->objref.expr) { + json_error(ctx, "Invalid tunnel reference."); + stmt_free(stmt); + return NULL; + } + + return stmt; +} + static unsigned int json_parse_nat_flag(const char *flag) { const struct { @@ -2870,6 +2905,7 @@ static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root) { "synproxy", json_parse_synproxy_stmt }, { "reset", json_parse_optstrip_stmt }, { "secmark", json_parse_secmark_stmt }, + { "tunnel", json_parse_tunnel_stmt }, }; const char *type; unsigned int i; @@ -3518,14 +3554,139 @@ static int json_parse_ct_timeout_policy(struct json_ctx *ctx, return 0; } +static int json_parse_tunnel_erspan(struct json_ctx *ctx, + json_t *root, struct obj *obj) +{ + const char *dir; + json_t *tmp; + int i; + + if (json_unpack_err(ctx, root, "{s:o}", "tunnel", &tmp)) + return 1; + + if (json_unpack_err(ctx, tmp, "{s:i}", "version", &obj->tunnel.erspan.version)) + return 1; + + switch (obj->tunnel.erspan.version) { + case 1: + if (json_unpack_err(ctx, tmp, "{s:i}", + "index", &obj->tunnel.erspan.v1.index)) + return 1; + break; + case 2: + if (json_unpack_err(ctx, tmp, "{s:s, s:i}", + "dir", &dir, + "hwid", &i)) + return 1; + obj->tunnel.erspan.v2.hwid = i; + + if (!strcmp(dir, "ingress")) { + obj->tunnel.erspan.v2.direction = 0; + } else if (!strcmp(dir, "egress")) { + obj->tunnel.erspan.v2.direction = 1; + } else { + json_error(ctx, "Invalid direction '%s'.", dir); + return 1; + } + break; + default: + json_error(ctx, "Invalid erspan version %u" , obj->tunnel.erspan.version); + return 1; + } + + return 0; +} + +static enum tunnel_type json_parse_tunnel_type(struct json_ctx *ctx, + const char *type) +{ + const struct { + const char *type; + int val; + } type_tbl[] = { + { "erspan", TUNNEL_ERSPAN }, + { "vxlan", TUNNEL_VXLAN }, + { "geneve", TUNNEL_GENEVE }, + }; + unsigned int i; + + if (!type) + return TUNNEL_UNSPEC; + + for (i = 0; i < array_size(type_tbl); i++) { + if (!strcmp(type, type_tbl[i].type)) + return type_tbl[i].val; + } + + return TUNNEL_UNSPEC; +} + +static int json_parse_tunnel_src_and_dst(struct json_ctx *ctx, + json_t *root, + struct obj *obj) +{ + bool is_ipv4 = false, src_set = false, dst_set = false; + struct expr *expr; + json_t *tmp; + + if (!json_unpack(root, "{s:o}", "src-ipv4", &tmp)) { + is_ipv4 = true; + src_set = true; + expr = json_parse_expr(ctx, tmp); + if (!expr) + return -1; + datatype_set(expr, &ipaddr_type); + obj->tunnel.src = expr; + } + + if (!json_unpack(root, "{s:o}", "src-ipv6", &tmp)) { + if (is_ipv4 || src_set) + return -1; + src_set = true; + expr = json_parse_expr(ctx, tmp); + if (!expr) + return -1; + datatype_set(expr, &ip6addr_type); + obj->tunnel.src = expr; + } + + if (!json_unpack(root, "{s:o}", "dst-ipv4", &tmp)) { + dst_set = true; + if (!is_ipv4) + return -1; + expr = json_parse_expr(ctx, tmp); + if (!expr) + return -1; + datatype_set(expr, &ipaddr_type); + obj->tunnel.dst = expr; + } + + if (!json_unpack(root, "{s:o}", "dst-ipv6", &tmp)) { + if (is_ipv4 || dst_set) + return -1; + dst_set = true; + expr = json_parse_expr(ctx, tmp); + if (!expr) + return -1; + datatype_set(expr, &ip6addr_type); + obj->tunnel.dst = expr; + } + + if (!dst_set || !src_set) + return -1; + + 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) { - const char *family, *tmp, *rate_unit = "packets", *burst_unit = "bytes"; + const char *family, *tmp = NULL, *rate_unit = "packets", *burst_unit = "bytes"; uint32_t l3proto = NFPROTO_UNSPEC; int inv = 0, flags = 0, i, j; struct handle h = { 0 }; + json_t *tmp_json; struct obj *obj; if (json_unpack_err(ctx, root, "{s:s, s:s}", @@ -3713,8 +3874,77 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx, obj->synproxy.flags |= flags; break; - case CMD_OBJ_TUNNEL: - /* TODO */ + case NFT_OBJECT_TUNNEL: + cmd_obj = CMD_OBJ_TUNNEL; + obj->type = NFT_OBJECT_TUNNEL; + + if (json_parse_tunnel_src_and_dst(ctx, root, obj)) + goto err_free_obj; + + json_unpack(root, "{s:i}", "id", &obj->tunnel.id); + json_unpack(root, "{s:i}", "sport", &i); + obj->tunnel.sport = i; + json_unpack(root, "{s:i}", "dport", &i); + obj->tunnel.sport = i; + json_unpack(root, "{s:i}", "ttl", &i); + obj->tunnel.ttl = i; + json_unpack(root, "{s:i}", "tos", &i); + obj->tunnel.tos = i; + json_unpack(root, "{s:s}", "type", &tmp); + + obj->tunnel.type = json_parse_tunnel_type(ctx, tmp); + switch (obj->tunnel.type) { + case TUNNEL_UNSPEC: + break; + case TUNNEL_ERSPAN: + if (json_parse_tunnel_erspan(ctx, root, obj)) + goto err_free_obj; + break; + case TUNNEL_VXLAN: + if (json_unpack_err(ctx, root, + "{s:o}", "tunnel", &tmp_json)) + goto err_free_obj; + + json_unpack(tmp_json, "{s:i}", + "gbp", &obj->tunnel.vxlan.gbp); + break; + case TUNNEL_GENEVE: + json_t *value; + size_t index; + + if (json_unpack_err(ctx, root, + "{s:o}", "tunnel", &tmp_json)) + goto err_free_obj; + + json_array_foreach(tmp_json, index, value) { + struct tunnel_geneve *geneve = xmalloc(sizeof(struct tunnel_geneve)); + if (!geneve) + memory_allocation_error(); + + if (json_unpack_err(ctx, value, "{s:i, s:i, s:s}", + "class", &i, + "opt-type", &j, + "data", &tmp)) { + free(geneve); + goto err_free_obj; + } + geneve->geneve_class = i; + geneve->type = j; + + if (tunnel_geneve_data_str2array(tmp, + geneve->data, + &geneve->data_len)) { + free(geneve); + goto err_free_obj; + } + + if (index == 0) + init_list_head(&obj->tunnel.geneve_opts); + + list_add_tail(&geneve->list, &obj->tunnel.geneve_opts); + } + break; + } break; default: BUG("Invalid CMD '%d'", cmd_obj); |
