Blame SOURCES/0032-src-store-expr-not-dtype-to-track-data-in-sets.patch

19e5f4
From 19da892698f1dce2125a796ad86239711896978f Mon Sep 17 00:00:00 2001
19e5f4
From: Phil Sutter <psutter@redhat.com>
19e5f4
Date: Mon, 7 Dec 2020 18:25:20 +0100
19e5f4
Subject: [PATCH] src: store expr, not dtype to track data in sets
19e5f4
19e5f4
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1877022
19e5f4
Upstream Status: nftables commit 343a51702656a
19e5f4
19e5f4
commit 343a51702656a6476e37cfb84609a82155c7fc5e
19e5f4
Author: Florian Westphal <fw@strlen.de>
19e5f4
Date:   Tue Jul 16 19:03:55 2019 +0200
19e5f4
19e5f4
    src: store expr, not dtype to track data in sets
19e5f4
19e5f4
    This will be needed once we add support for the 'typeof' keyword to
19e5f4
    handle maps that could e.g. store 'ct helper' "type" values.
19e5f4
19e5f4
    Instead of:
19e5f4
19e5f4
    set foo {
19e5f4
            type ipv4_addr . mark;
19e5f4
19e5f4
    this would allow
19e5f4
19e5f4
    set foo {
19e5f4
            typeof(ip saddr) . typeof(ct mark);
19e5f4
19e5f4
    (exact syntax TBD).
19e5f4
19e5f4
    This would be needed to allow sets that store variable-sized data types
19e5f4
    (string, integer and the like) that can't be used at at the moment.
19e5f4
19e5f4
    Adding special data types for everything is problematic due to the
19e5f4
    large amount of different types needed.
19e5f4
19e5f4
    For anonymous sets, e.g. "string" can be used because the needed size can
19e5f4
    be inferred from the statement, e.g.  'osf name { "Windows", "Linux }',
19e5f4
    but in case of named sets that won't work because 'type string' lacks the
19e5f4
    context needed to derive the size information.
19e5f4
19e5f4
    With 'typeof(osf name)' the context is there, but at the moment it won't
19e5f4
    help because the expression is discarded instantly and only the data
19e5f4
    type is retained.
19e5f4
19e5f4
    Signed-off-by: Florian Westphal <fw@strlen.de>
19e5f4
---
19e5f4
 include/datatype.h |  1 -
19e5f4
 include/netlink.h  |  1 -
bfbb76
 include/rule.h     |  6 ++---
bfbb76
 src/datatype.c     |  5 ----
bfbb76
 src/evaluate.c     | 58 ++++++++++++++++++++++++++++++++--------------
19e5f4
 src/expression.c   |  2 +-
19e5f4
 src/json.c         |  4 ++--
bfbb76
 src/mnl.c          |  6 ++---
19e5f4
 src/monitor.c      |  2 +-
bfbb76
 src/netlink.c      | 32 ++++++++++++-------------
19e5f4
 src/parser_bison.y |  3 +--
bfbb76
 src/parser_json.c  |  8 +++++--
bfbb76
 src/rule.c         |  8 +++----
bfbb76
 src/segtree.c      |  8 +++++--
19e5f4
 14 files changed, 81 insertions(+), 63 deletions(-)
19e5f4
19e5f4
diff --git a/include/datatype.h b/include/datatype.h
19e5f4
index 49b8f60..04b4892 100644
19e5f4
--- a/include/datatype.h
19e5f4
+++ b/include/datatype.h
19e5f4
@@ -293,7 +293,6 @@ concat_subtype_lookup(uint32_t type, unsigned int n)
19e5f4
 
19e5f4
 extern const struct datatype *
19e5f4
 set_datatype_alloc(const struct datatype *orig_dtype, unsigned int byteorder);
19e5f4
-extern void set_datatype_destroy(const struct datatype *dtype);
19e5f4
 
19e5f4
 extern void time_print(uint64_t msec, struct output_ctx *octx);
19e5f4
 extern struct error_record *time_parse(const struct location *loc,
19e5f4
diff --git a/include/netlink.h b/include/netlink.h
19e5f4
index e694171..88d12ba 100644
19e5f4
--- a/include/netlink.h
19e5f4
+++ b/include/netlink.h
19e5f4
@@ -189,6 +189,5 @@ int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type,
19e5f4
 			    struct netlink_mon_handler *monh);
19e5f4
 
19e5f4
 enum nft_data_types dtype_map_to_kernel(const struct datatype *dtype);
19e5f4
-const struct datatype *dtype_map_from_kernel(enum nft_data_types type);
19e5f4
 
19e5f4
 #endif /* NFTABLES_NETLINK_H */
19e5f4
diff --git a/include/rule.h b/include/rule.h
19e5f4
index 626973e..3637462 100644
19e5f4
--- a/include/rule.h
19e5f4
+++ b/include/rule.h
19e5f4
@@ -283,8 +283,7 @@ extern struct rule *rule_lookup_by_index(const struct chain *chain,
19e5f4
  * @gc_int:	garbage collection interval
19e5f4
  * @timeout:	default timeout value
19e5f4
  * @key:	key expression (data type, length))
19e5f4
- * @datatype:	mapping data type
19e5f4
- * @datalen:	mapping data len
19e5f4
+ * @data:	mapping data expression
19e5f4
  * @objtype:	mapping object type
19e5f4
  * @init:	initializer
19e5f4
  * @rg_cache:	cached range element (left)
19e5f4
@@ -303,8 +302,7 @@ struct set {
19e5f4
 	uint32_t		gc_int;
19e5f4
 	uint64_t		timeout;
19e5f4
 	struct expr		*key;
19e5f4
-	const struct datatype	*datatype;
19e5f4
-	unsigned int		datalen;
19e5f4
+	struct expr		*data;
19e5f4
 	uint32_t		objtype;
19e5f4
 	struct expr		*init;
19e5f4
 	struct expr		*rg_cache;
19e5f4
diff --git a/src/datatype.c b/src/datatype.c
19e5f4
index b9e167e..189e1b4 100644
19e5f4
--- a/src/datatype.c
19e5f4
+++ b/src/datatype.c
19e5f4
@@ -1190,11 +1190,6 @@ const struct datatype *set_datatype_alloc(const struct datatype *orig_dtype,
19e5f4
 	return dtype;
19e5f4
 }
19e5f4
 
19e5f4
-void set_datatype_destroy(const struct datatype *dtype)
19e5f4
-{
19e5f4
-	datatype_free(dtype);
19e5f4
-}
19e5f4
-
19e5f4
 static struct error_record *time_unit_parse(const struct location *loc,
19e5f4
 					    const char *str, uint64_t *unit)
19e5f4
 {
19e5f4
diff --git a/src/evaluate.c b/src/evaluate.c
19e5f4
index f66251b..578dcae 100644
19e5f4
--- a/src/evaluate.c
19e5f4
+++ b/src/evaluate.c
19e5f4
@@ -1383,6 +1383,7 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
19e5f4
 {
19e5f4
 	struct expr_ctx ectx = ctx->ectx;
19e5f4
 	struct expr *map = *expr, *mappings;
19e5f4
+	const struct datatype *dtype;
19e5f4
 	struct expr *key;
19e5f4
 
19e5f4
 	expr_set_context(&ctx->ectx, NULL, 0);
19e5f4
@@ -1405,10 +1406,14 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
19e5f4
 		mappings = implicit_set_declaration(ctx, "__map%d",
19e5f4
 						    key,
19e5f4
 						    mappings);
19e5f4
-		mappings->set->datatype =
19e5f4
-			datatype_get(set_datatype_alloc(ectx.dtype,
19e5f4
-							ectx.byteorder));
19e5f4
-		mappings->set->datalen  = ectx.len;
19e5f4
+
19e5f4
+		dtype = set_datatype_alloc(ectx.dtype, ectx.byteorder);
19e5f4
+
19e5f4
+		mappings->set->data = constant_expr_alloc(&netlink_location,
19e5f4
+							  dtype, dtype->byteorder,
19e5f4
+							  ectx.len, NULL);
19e5f4
+		if (ectx.len && mappings->set->data->len != ectx.len)
19e5f4
+			BUG("%d vs %d\n", mappings->set->data->len, ectx.len);
19e5f4
 
19e5f4
 		map->mappings = mappings;
19e5f4
 
19e5f4
@@ -1444,7 +1449,7 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
19e5f4
 					 map->mappings->set->key->dtype->desc,
19e5f4
 					 map->map->dtype->desc);
19e5f4
 
19e5f4
-	datatype_set(map, map->mappings->set->datatype);
19e5f4
+	datatype_set(map, map->mappings->set->data->dtype);
19e5f4
 	map->flags |= EXPR_F_CONSTANT;
19e5f4
 
19e5f4
 	/* Data for range lookups needs to be in big endian order */
19e5f4
@@ -1474,7 +1479,12 @@ static int expr_evaluate_mapping(struct eval_ctx *ctx, struct expr **expr)
19e5f4
 				  "Key must be a constant");
19e5f4
 	mapping->flags |= mapping->left->flags & EXPR_F_SINGLETON;
19e5f4
 
19e5f4
-	expr_set_context(&ctx->ectx, set->datatype, set->datalen);
19e5f4
+	if (set->data) {
19e5f4
+		expr_set_context(&ctx->ectx, set->data->dtype, set->data->len);
19e5f4
+	} else {
19e5f4
+		assert((set->flags & NFT_SET_MAP) == 0);
19e5f4
+	}
19e5f4
+
19e5f4
 	if (expr_evaluate(ctx, &mapping->right) < 0)
19e5f4
 		return -1;
19e5f4
 	if (!expr_is_constant(mapping->right))
19e5f4
@@ -2119,7 +2129,7 @@ static int stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
19e5f4
 					 (*expr)->len);
19e5f4
 	else if ((*expr)->dtype->type != TYPE_INTEGER &&
19e5f4
 		 !datatype_equal((*expr)->dtype, dtype))
19e5f4
-		return stmt_binary_error(ctx, *expr, stmt,
19e5f4
+		return stmt_binary_error(ctx, *expr, stmt,		/* verdict vs invalid? */
19e5f4
 					 "datatype mismatch: expected %s, "
19e5f4
 					 "expression has type %s",
19e5f4
 					 dtype->desc, (*expr)->dtype->desc);
19e5f4
@@ -3113,9 +3123,9 @@ static int stmt_evaluate_map(struct eval_ctx *ctx, struct stmt *stmt)
19e5f4
 				  "Key expression comments are not supported");
19e5f4
 
19e5f4
 	if (stmt_evaluate_arg(ctx, stmt,
19e5f4
-			      stmt->map.set->set->datatype,
19e5f4
-			      stmt->map.set->set->datalen,
19e5f4
-			      stmt->map.set->set->datatype->byteorder,
19e5f4
+			      stmt->map.set->set->data->dtype,
19e5f4
+			      stmt->map.set->set->data->len,
19e5f4
+			      stmt->map.set->set->data->byteorder,
19e5f4
 			      &stmt->map.data->key) < 0)
19e5f4
 		return -1;
19e5f4
 	if (expr_is_constant(stmt->map.data))
19e5f4
@@ -3161,8 +3171,12 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt)
19e5f4
 
19e5f4
 		mappings = implicit_set_declaration(ctx, "__objmap%d",
19e5f4
 						    key, mappings);
19e5f4
-		mappings->set->datatype = &string_type;
19e5f4
-		mappings->set->datalen  = NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE;
19e5f4
+
19e5f4
+		mappings->set->data = constant_expr_alloc(&netlink_location,
19e5f4
+							  &string_type,
19e5f4
+							  BYTEORDER_HOST_ENDIAN,
19e5f4
+							  NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE,
19e5f4
+							  NULL);
19e5f4
 		mappings->set->objtype  = stmt->objref.type;
19e5f4
 
19e5f4
 		map->mappings = mappings;
19e5f4
@@ -3197,7 +3211,7 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt)
19e5f4
 					 map->mappings->set->key->dtype->desc,
19e5f4
 					 map->map->dtype->desc);
19e5f4
 
19e5f4
-	datatype_set(map, map->mappings->set->datatype);
19e5f4
+	datatype_set(map, map->mappings->set->data->dtype);
19e5f4
 	map->flags |= EXPR_F_CONSTANT;
19e5f4
 
19e5f4
 	/* Data for range lookups needs to be in big endian order */
19e5f4
@@ -3346,17 +3360,25 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
19e5f4
 	}
19e5f4
 
19e5f4
 	if (set_is_datamap(set->flags)) {
19e5f4
-		if (set->datatype == NULL)
19e5f4
+		if (set->data == NULL)
19e5f4
 			return set_error(ctx, set, "map definition does not "
19e5f4
 					 "specify mapping data type");
19e5f4
 
19e5f4
-		set->datalen = set->datatype->size;
19e5f4
-		if (set->datalen == 0 && set->datatype->type != TYPE_VERDICT)
19e5f4
+		if (set->data->len == 0 && set->data->dtype->type != TYPE_VERDICT)
19e5f4
 			return set_error(ctx, set, "unqualified mapping data "
19e5f4
 					 "type specified in map definition");
19e5f4
 	} else if (set_is_objmap(set->flags)) {
19e5f4
-		set->datatype = &string_type;
19e5f4
-		set->datalen  = NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE;
19e5f4
+		if (set->data) {
19e5f4
+			assert(set->data->etype == EXPR_VALUE);
19e5f4
+			assert(set->data->dtype == &string_type);
19e5f4
+		}
19e5f4
+
19e5f4
+		assert(set->data == NULL);
19e5f4
+		set->data = constant_expr_alloc(&netlink_location, &string_type,
19e5f4
+						BYTEORDER_HOST_ENDIAN,
19e5f4
+						NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE,
19e5f4
+						NULL);
19e5f4
+
19e5f4
 	}
19e5f4
 
19e5f4
 	ctx->set = set;
19e5f4
diff --git a/src/expression.c b/src/expression.c
19e5f4
index 5070b10..6fa2f1d 100644
19e5f4
--- a/src/expression.c
19e5f4
+++ b/src/expression.c
19e5f4
@@ -1010,7 +1010,7 @@ static void map_expr_print(const struct expr *expr, struct output_ctx *octx)
19e5f4
 {
19e5f4
 	expr_print(expr->map, octx);
19e5f4
 	if (expr->mappings->etype == EXPR_SET_REF &&
19e5f4
-	    expr->mappings->set->datatype->type == TYPE_VERDICT)
19e5f4
+	    expr->mappings->set->data->dtype->type == TYPE_VERDICT)
19e5f4
 		nft_print(octx, " vmap ");
19e5f4
 	else
19e5f4
 		nft_print(octx, " map ");
19e5f4
diff --git a/src/json.c b/src/json.c
19e5f4
index 3498e24..1906e7d 100644
19e5f4
--- a/src/json.c
19e5f4
+++ b/src/json.c
19e5f4
@@ -82,7 +82,7 @@ static json_t *set_print_json(struct output_ctx *octx, const struct set *set)
19e5f4
 
19e5f4
 	if (set_is_datamap(set->flags)) {
19e5f4
 		type = "map";
19e5f4
-		datatype_ext = set->datatype->name;
19e5f4
+		datatype_ext = set->data->dtype->name;
19e5f4
 	} else if (set_is_objmap(set->flags)) {
19e5f4
 		type = "map";
19e5f4
 		datatype_ext = obj_type_name(set->objtype);
19e5f4
@@ -645,7 +645,7 @@ json_t *map_expr_json(const struct expr *expr, struct output_ctx *octx)
19e5f4
 	const char *type = "map";
19e5f4
 
19e5f4
 	if (expr->mappings->etype == EXPR_SET_REF &&
19e5f4
-	    expr->mappings->set->datatype->type == TYPE_VERDICT)
19e5f4
+	    expr->mappings->set->data->dtype->type == TYPE_VERDICT)
19e5f4
 		type = "vmap";
19e5f4
 
19e5f4
 	return json_pack("{s:{s:o, s:o}}", type,
19e5f4
diff --git a/src/mnl.c b/src/mnl.c
19e5f4
index 221ee05..23341e6 100644
19e5f4
--- a/src/mnl.c
19e5f4
+++ b/src/mnl.c
19e5f4
@@ -839,9 +839,9 @@ int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
19e5f4
 			  div_round_up(set->key->len, BITS_PER_BYTE));
19e5f4
 	if (set_is_datamap(set->flags)) {
19e5f4
 		nftnl_set_set_u32(nls, NFTNL_SET_DATA_TYPE,
19e5f4
-				  dtype_map_to_kernel(set->datatype));
19e5f4
+				  dtype_map_to_kernel(set->data->dtype));
19e5f4
 		nftnl_set_set_u32(nls, NFTNL_SET_DATA_LEN,
19e5f4
-				  set->datalen / BITS_PER_BYTE);
19e5f4
+				  set->data->len / BITS_PER_BYTE);
19e5f4
 	}
19e5f4
 	if (set_is_objmap(set->flags))
19e5f4
 		nftnl_set_set_u32(nls, NFTNL_SET_OBJ_TYPE, set->objtype);
19e5f4
@@ -873,7 +873,7 @@ int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
19e5f4
 
19e5f4
 	if (set_is_datamap(set->flags) &&
19e5f4
 	    !nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_DATABYTEORDER,
19e5f4
-				 set->datatype->byteorder))
19e5f4
+				 set->data->byteorder))
19e5f4
 		memory_allocation_error();
19e5f4
 
19e5f4
 	if (set->automerge &&
19e5f4
diff --git a/src/monitor.c b/src/monitor.c
19e5f4
index fb803cf..7927b6f 100644
19e5f4
--- a/src/monitor.c
19e5f4
+++ b/src/monitor.c
19e5f4
@@ -401,7 +401,7 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type,
19e5f4
 	 */
19e5f4
 	dummyset = set_alloc(monh->loc);
19e5f4
 	dummyset->key = expr_clone(set->key);
19e5f4
-	dummyset->datatype = set->datatype;
19e5f4
+	dummyset->data = set->data;
19e5f4
 	dummyset->flags = set->flags;
19e5f4
 	dummyset->init = set_expr_alloc(monh->loc, set);
19e5f4
 
19e5f4
diff --git a/src/netlink.c b/src/netlink.c
19e5f4
index e0ba903..64e51e5 100644
19e5f4
--- a/src/netlink.c
19e5f4
+++ b/src/netlink.c
19e5f4
@@ -575,7 +575,7 @@ enum nft_data_types dtype_map_to_kernel(const struct datatype *dtype)
19e5f4
 	}
19e5f4
 }
19e5f4
 
19e5f4
-const struct datatype *dtype_map_from_kernel(enum nft_data_types type)
19e5f4
+static const struct datatype *dtype_map_from_kernel(enum nft_data_types type)
19e5f4
 {
19e5f4
 	switch (type) {
19e5f4
 	case NFT_DATA_VERDICT:
19e5f4
@@ -622,10 +622,10 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
19e5f4
 				    const struct nftnl_set *nls)
19e5f4
 {
19e5f4
 	const struct nftnl_udata *ud[NFTNL_UDATA_SET_MAX + 1] = {};
19e5f4
-	uint32_t flags, key, data, data_len, objtype = 0;
19e5f4
 	enum byteorder keybyteorder = BYTEORDER_INVALID;
19e5f4
 	enum byteorder databyteorder = BYTEORDER_INVALID;
19e5f4
-	const struct datatype *keytype, *datatype;
19e5f4
+	const struct datatype *keytype, *datatype = NULL;
19e5f4
+	uint32_t flags, key, objtype = 0;
19e5f4
 	bool automerge = false;
19e5f4
 	const char *udata;
19e5f4
 	struct set *set;
19e5f4
@@ -659,6 +659,8 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
19e5f4
 
19e5f4
 	flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
19e5f4
 	if (set_is_datamap(flags)) {
19e5f4
+		uint32_t data;
19e5f4
+
19e5f4
 		data = nftnl_set_get_u32(nls, NFTNL_SET_DATA_TYPE);
19e5f4
 		datatype = dtype_map_from_kernel(data);
19e5f4
 		if (datatype == NULL) {
19e5f4
@@ -667,8 +669,7 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
19e5f4
 					 data);
19e5f4
 			return NULL;
19e5f4
 		}
19e5f4
-	} else
19e5f4
-		datatype = NULL;
19e5f4
+	}
19e5f4
 
19e5f4
 	if (set_is_objmap(flags)) {
19e5f4
 		objtype = nftnl_set_get_u32(nls, NFTNL_SET_OBJ_TYPE);
19e5f4
@@ -691,16 +692,13 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
19e5f4
 
19e5f4
 	set->objtype = objtype;
19e5f4
 
19e5f4
+	set->data = NULL;
19e5f4
 	if (datatype)
19e5f4
-		set->datatype = datatype_get(set_datatype_alloc(datatype,
19e5f4
-								databyteorder));
19e5f4
-	else
19e5f4
-		set->datatype = NULL;
19e5f4
-
19e5f4
-	if (nftnl_set_is_set(nls, NFTNL_SET_DATA_LEN)) {
19e5f4
-		data_len = nftnl_set_get_u32(nls, NFTNL_SET_DATA_LEN);
19e5f4
-		set->datalen = data_len * BITS_PER_BYTE;
19e5f4
-	}
19e5f4
+		set->data = constant_expr_alloc(&netlink_location,
19e5f4
+						set_datatype_alloc(datatype, databyteorder),
19e5f4
+						databyteorder,
19e5f4
+						nftnl_set_get_u32(nls, NFTNL_SET_DATA_LEN) * BITS_PER_BYTE,
19e5f4
+						NULL);
19e5f4
 
19e5f4
 	if (nftnl_set_is_set(nls, NFTNL_SET_TIMEOUT))
19e5f4
 		set->timeout = nftnl_set_get_u64(nls, NFTNL_SET_TIMEOUT);
19e5f4
@@ -897,10 +895,10 @@ key_end:
19e5f4
 			goto out;
19e5f4
 
19e5f4
 		data = netlink_alloc_data(&netlink_location, &nld,
19e5f4
-					  set->datatype->type == TYPE_VERDICT ?
19e5f4
+					  set->data->dtype->type == TYPE_VERDICT ?
19e5f4
 					  NFT_REG_VERDICT : NFT_REG_1);
19e5f4
-		datatype_set(data, set->datatype);
19e5f4
-		data->byteorder = set->datatype->byteorder;
19e5f4
+		datatype_set(data, set->data->dtype);
19e5f4
+		data->byteorder = set->data->byteorder;
19e5f4
 		if (data->byteorder == BYTEORDER_HOST_ENDIAN)
19e5f4
 			mpz_switch_byteorder(data->value, data->len / BITS_PER_BYTE);
19e5f4
 
19e5f4
diff --git a/src/parser_bison.y b/src/parser_bison.y
19e5f4
index ea83f52..4cca31b 100644
19e5f4
--- a/src/parser_bison.y
19e5f4
+++ b/src/parser_bison.y
19e5f4
@@ -1749,9 +1749,8 @@ map_block		:	/* empty */	{ $$ = $<set>-1; }
19e5f4
 						stmt_separator
19e5f4
 			{
19e5f4
 				$1->key = $3;
19e5f4
-				$1->datatype = $5->dtype;
19e5f4
+				$1->data = $5;
19e5f4
 
19e5f4
-				expr_free($5);
19e5f4
 				$1->flags |= NFT_SET_MAP;
19e5f4
 				$$ = $1;
19e5f4
 			}
19e5f4
diff --git a/src/parser_json.c b/src/parser_json.c
19e5f4
index ce8e566..ddc694f 100644
19e5f4
--- a/src/parser_json.c
19e5f4
+++ b/src/parser_json.c
19e5f4
@@ -2833,11 +2833,15 @@ static struct cmd *json_parse_cmd_add_set(struct json_ctx *ctx, json_t *root,
19e5f4
 	}
19e5f4
 
19e5f4
 	if (!json_unpack(root, "{s:s}", "map", &dtype_ext)) {
19e5f4
+		const struct datatype *dtype;
19e5f4
+
19e5f4
 		set->objtype = string_to_nft_object(dtype_ext);
19e5f4
 		if (set->objtype) {
19e5f4
 			set->flags |= NFT_SET_OBJECT;
19e5f4
-		} else if (datatype_lookup_byname(dtype_ext)) {
19e5f4
-			set->datatype = datatype_lookup_byname(dtype_ext);
19e5f4
+		} else if ((dtype = datatype_lookup_byname(dtype_ext))) {
19e5f4
+			set->data = constant_expr_alloc(&netlink_location,
19e5f4
+							dtype, dtype->byteorder,
19e5f4
+							dtype->size, NULL);
19e5f4
 			set->flags |= NFT_SET_MAP;
19e5f4
 		} else {
19e5f4
 			json_error(ctx, "Invalid map type '%s'.", dtype_ext);
19e5f4
diff --git a/src/rule.c b/src/rule.c
19e5f4
index e18237b..f7d888b 100644
19e5f4
--- a/src/rule.c
19e5f4
+++ b/src/rule.c
19e5f4
@@ -332,8 +332,8 @@ struct set *set_clone(const struct set *set)
19e5f4
 	new_set->gc_int		= set->gc_int;
19e5f4
 	new_set->timeout	= set->timeout;
19e5f4
 	new_set->key		= expr_clone(set->key);
19e5f4
-	new_set->datatype	= datatype_get(set->datatype);
19e5f4
-	new_set->datalen	= set->datalen;
19e5f4
+	if (set->data)
19e5f4
+		new_set->data	= expr_clone(set->data);
19e5f4
 	new_set->objtype	= set->objtype;
19e5f4
 	new_set->policy		= set->policy;
19e5f4
 	new_set->automerge	= set->automerge;
19e5f4
@@ -356,7 +356,7 @@ void set_free(struct set *set)
19e5f4
 		expr_free(set->init);
19e5f4
 	handle_free(&set->handle);
19e5f4
 	expr_free(set->key);
19e5f4
-	set_datatype_destroy(set->datatype);
19e5f4
+	expr_free(set->data);
19e5f4
 	xfree(set);
19e5f4
 }
19e5f4
 
19e5f4
@@ -469,7 +469,7 @@ static void set_print_declaration(const struct set *set,
19e5f4
 	nft_print(octx, "%s%stype %s",
19e5f4
 		  opts->tab, opts->tab, set->key->dtype->name);
19e5f4
 	if (set_is_datamap(set->flags))
19e5f4
-		nft_print(octx, " : %s", set->datatype->name);
19e5f4
+		nft_print(octx, " : %s", set->data->dtype->name);
19e5f4
 	else if (set_is_objmap(set->flags))
19e5f4
 		nft_print(octx, " : %s", obj_type_name(set->objtype));
19e5f4
 
19e5f4
diff --git a/src/segtree.c b/src/segtree.c
19e5f4
index 073c6ec..d6e3ce2 100644
19e5f4
--- a/src/segtree.c
19e5f4
+++ b/src/segtree.c
19e5f4
@@ -79,8 +79,12 @@ static void seg_tree_init(struct seg_tree *tree, const struct set *set,
19e5f4
 	tree->root	= RB_ROOT;
19e5f4
 	tree->keytype	= set->key->dtype;
19e5f4
 	tree->keylen	= set->key->len;
19e5f4
-	tree->datatype	= set->datatype;
19e5f4
-	tree->datalen	= set->datalen;
19e5f4
+	tree->datatype	= NULL;
19e5f4
+	tree->datalen	= 0;
19e5f4
+	if (set->data) {
19e5f4
+		tree->datatype	= set->data->dtype;
19e5f4
+		tree->datalen	= set->data->len;
19e5f4
+	}
19e5f4
 	tree->byteorder	= first->byteorder;
19e5f4
 	tree->debug_mask = debug_mask;
19e5f4
 }
19e5f4
-- 
bfbb76
2.31.1
19e5f4