[nft,v3,1/3] src: Add support for NFTNL_SET_DESC_CONCAT
diff mbox series

Message ID 99924cfb6e472ee5da9d29e6ee23949cd361c729.1579434179.git.sbrivio@redhat.com
State Changes Requested
Delegated to: Pablo Neira
Headers show
Series
  • Introduce support for concatenated ranges
Related show

Commit Message

Stefano Brivio Jan. 19, 2020, 1:34 p.m. UTC
To support arbitrary range concatenations, the kernel needs to know
how long each field in the concatenation is. The new libnftnl
NFTNL_SET_DESC_CONCAT set attribute describes this as an array of
lengths, in bytes, of concatenated fields.

While evaluating concatenated expressions, export the datatype size
into the new field_len array, and hand the data over via libnftnl.

Similarly, when data is passed back from libnftnl, parse it into
the set description.

When set data is cloned, we now need to copy the additional fields
in set_clone(), too.

This change depends on the libnftnl patch with title:
  set: Add support for NFTA_SET_DESC_CONCAT attributes

v3: Rework to use set description data instead of a stand-alone
    attribute
v2: No changes

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
---
 include/expression.h |  2 ++
 include/rule.h       |  6 +++++-
 src/evaluate.c       | 14 +++++++++++---
 src/mnl.c            |  7 +++++++
 src/netlink.c        | 11 +++++++++++
 src/rule.c           |  2 +-
 6 files changed, 37 insertions(+), 5 deletions(-)

Patch
diff mbox series

diff --git a/include/expression.h b/include/expression.h
index b3e79c490b1a..6196be58c2a6 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -261,6 +261,8 @@  struct expr {
 			struct list_head	expressions;
 			unsigned int		size;
 			uint32_t		set_flags;
+			uint8_t			field_len[NFT_REG32_COUNT];
+			uint8_t			field_count;
 		};
 		struct {
 			/* EXPR_SET_REF */
diff --git a/include/rule.h b/include/rule.h
index d5b31765612e..a7f106f715cf 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -289,7 +289,9 @@  extern struct rule *rule_lookup_by_index(const struct chain *chain,
  * @rg_cache:	cached range element (left)
  * @policy:	set mechanism policy
  * @automerge:	merge adjacents and overlapping elements, if possible
- * @desc:	set mechanism desc
+ * @desc.size:		count of set elements
+ * @desc.field_len:	length of single concatenated fields, bytes
+ * @desc.field_count:	count of concatenated fields
  */
 struct set {
 	struct list_head	list;
@@ -310,6 +312,8 @@  struct set {
 	bool			key_typeof_valid;
 	struct {
 		uint32_t	size;
+		uint8_t		field_len[NFT_REG32_COUNT];
+		uint8_t		field_count;
 	} desc;
 };
 
diff --git a/src/evaluate.c b/src/evaluate.c
index e7881543d2de..52b8a154d24d 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1217,6 +1217,8 @@  static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr,
 	struct expr *i, *next;
 
 	list_for_each_entry_safe(i, next, &(*expr)->expressions, list) {
+		unsigned dsize_bytes;
+
 		if (expr_is_constant(*expr) && dtype && off == 0)
 			return expr_binary_error(ctx->msgs, i, *expr,
 						 "unexpected concat component, "
@@ -1241,6 +1243,9 @@  static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr,
 						 i->dtype->name);
 
 		ntype = concat_subtype_add(ntype, i->dtype->type);
+
+		dsize_bytes = div_round_up(i->dtype->size, BITS_PER_BYTE);
+		(*expr)->field_len[(*expr)->field_count++] = dsize_bytes;
 	}
 
 	(*expr)->flags |= flags;
@@ -3346,9 +3351,12 @@  static int set_evaluate(struct eval_ctx *ctx, struct set *set)
 			return set_key_data_error(ctx, set,
 						  set->key->dtype, type);
 	}
-	if (set->flags & NFT_SET_INTERVAL &&
-	    set->key->etype == EXPR_CONCAT)
-		return set_error(ctx, set, "concatenated types not supported in interval sets");
+
+	if (set->flags & NFT_SET_INTERVAL && set->key->etype == EXPR_CONCAT) {
+		memcpy(&set->desc.field_len, &set->key->field_len,
+		       sizeof(set->desc.field_len));
+		set->desc.field_count = set->key->field_count;
+	}
 
 	if (set_is_datamap(set->flags)) {
 		if (set->data == NULL)
diff --git a/src/mnl.c b/src/mnl.c
index d5bdff293c61..340380ba6fef 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -905,6 +905,13 @@  int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
 	if (set->data)
 		set_key_expression(ctx, set->data, set->flags, udbuf, NFTNL_UDATA_SET_DATA_TYPEOF);
 
+	if (set->desc.field_len[0]) {
+		nftnl_set_set_data(nls, NFTNL_SET_DESC_CONCAT,
+				   set->desc.field_len,
+				   set->desc.field_count *
+				   sizeof(set->desc.field_len[0]));
+	}
+
 	nftnl_set_set_data(nls, NFTNL_SET_USERDATA, nftnl_udata_buf_data(udbuf),
 			   nftnl_udata_buf_len(udbuf));
 	nftnl_udata_buf_free(udbuf);
diff --git a/src/netlink.c b/src/netlink.c
index a9ccebaf8efd..791943b4d926 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -773,6 +773,17 @@  struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
 	if (nftnl_set_is_set(nls, NFTNL_SET_DESC_SIZE))
 		set->desc.size = nftnl_set_get_u32(nls, NFTNL_SET_DESC_SIZE);
 
+	if (nftnl_set_is_set(nls, NFTNL_SET_DESC_CONCAT)) {
+		uint32_t len = NFT_REG32_COUNT;
+		const uint8_t *data;
+
+		data = nftnl_set_get_data(nls, NFTNL_SET_DESC_CONCAT, &len);
+		if (data) {
+			memcpy(set->desc.field_len, data, len);
+			set->desc.field_count = len;
+		}
+	}
+
 	return set;
 }
 
diff --git a/src/rule.c b/src/rule.c
index 883b07072025..4853c4f302ee 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -337,7 +337,7 @@  struct set *set_clone(const struct set *set)
 	new_set->objtype	= set->objtype;
 	new_set->policy		= set->policy;
 	new_set->automerge	= set->automerge;
-	new_set->desc.size	= set->desc.size;
+	new_set->desc		= set->desc;
 
 	return new_set;
 }