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

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