[nft PATCH 13/15] mnl: Provide libnftnl with set element meta info when dumping

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



To consistently print set elements' data regs irrespective of host byte
order, libnftnl needs to be provided with data reg sizes and byteorder.

To collect sizes, generalize the population of 'field_len' and
'field_count' fields to non-interval concat keys, too. Perform the same
data collection for target data in maps as well, making use of
'data_len' and 'data_count' fields in set desc.

Collect individual data reg fields' byteorder info on demand by
inspecting the constructed data types of concatenated keys/values.

To pass above data along to nftnl_set_elem_snprintf_desc() when dumping
set elements, pass a pointer to the relevant struct set when calling
mnl_nft_setelem_batch().

Signed-off-by: Phil Sutter <phil@xxxxxx>
---
 src/evaluate.c | 16 ++++++----
 src/mnl.c      | 84 ++++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 81 insertions(+), 19 deletions(-)

diff --git a/src/evaluate.c b/src/evaluate.c
index 983808d65714b..5a875eaf8b17c 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1582,13 +1582,13 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
 		map = *expr;
 		map->mappings->set->flags |= map->mappings->set->init->set_flags;
 
-		if (map->mappings->set->flags & NFT_SET_INTERVAL &&
-		    map->map->etype == EXPR_CONCAT) {
+		if (map->map->etype == EXPR_CONCAT) {
 			memcpy(&map->mappings->set->desc.field_len, &map->map->field_len,
 			       sizeof(map->mappings->set->desc.field_len));
 			map->mappings->set->desc.field_count = map->map->field_count;
 			map->mappings->flags |= NFT_SET_CONCAT;
 		}
+
 		break;
 	case EXPR_SYMBOL:
 		if (expr_evaluate(ctx, &map->mappings) < 0)
@@ -3974,7 +3974,7 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
 						  set->key->dtype, type);
 	}
 
-	if (set->flags & NFT_SET_INTERVAL && set->key->etype == EXPR_CONCAT) {
+	if (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;
@@ -3986,9 +3986,13 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
 			return set_error(ctx, set, "map definition does not "
 					 "specify mapping data type");
 
-		if (set->data->etype == EXPR_CONCAT &&
-		    set_expr_evaluate_concat(ctx, &set->data) < 0)
-			return -1;
+		if (set->data->etype == EXPR_CONCAT) {
+			if (expr_evaluate_concat(ctx, &set->data) < 0)
+				return -1;
+			memcpy(&set->desc.data_len, &set->data->field_len,
+			       sizeof(set->desc.data_len));
+			set->desc.data_count = set->data->field_count;
+		}
 
 		if (set->data->flags & EXPR_F_INTERVAL)
 			set->data->len *= 2;
diff --git a/src/mnl.c b/src/mnl.c
index a3ee32680a77a..5bb6dcad81a09 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -1063,6 +1063,44 @@ static void set_key_expression(struct netlink_ctx *ctx,
 /*
  * Set
  */
+
+static uint16_t dtype_byteorder_bits(const struct datatype *dtype,
+				     enum byteorder byteorder)
+{
+	const struct datatype *subtype;
+	uint16_t bits = 0;
+	int n, dsz, i = 0;
+
+	if (dtype->type == TYPE_VERDICT)
+		return 0;
+
+	if (!(dtype->type & ~TYPE_MASK)) {
+		/* XXX: is this right? does set->key->byteorder take
+		 *      precedence over set->key->dtype->byteorder?
+		 *      if not, respect byteorder only if
+		 *      dtype->byteorder == BYTEORDER_INVALID
+		 */
+		if (dtype->byteorder == BYTEORDER_BIG_ENDIAN ||
+		    byteorder == BYTEORDER_BIG_ENDIAN)
+			return -1;
+		return 0;
+	}
+	n = div_round_up(fls(dtype->type), TYPE_BITS);
+	while (n > 0 && concat_subtype_id(dtype->type, --n)) {
+		subtype = concat_subtype_lookup(dtype->type, n);
+		if (!subtype)
+			break;
+
+		for (dsz = subtype->size;
+		     dsz > 0;
+		     dsz -= sizeof(uint32_t) * BITS_PER_BYTE) {
+			bits |= (subtype->byteorder ==
+				 BYTEORDER_BIG_ENDIAN) << i++;
+		}
+	}
+	return bits;
+}
+
 int mnl_nft_set_add(struct netlink_ctx *ctx, struct cmd *cmd,
 		    unsigned int flags)
 {
@@ -1535,16 +1573,36 @@ static bool mnl_nft_attr_nest_overflow(struct nlmsghdr *nlh,
 	return false;
 }
 
-static void netlink_dump_setelem(const struct nftnl_set_elem *nlse,
-				 struct netlink_ctx *ctx)
+static void set_to_desc(struct nftnl_set_desc *desc, const struct set *set)
+{
+	if (!set)
+		return;
+
+	memcpy(desc, &set->desc, sizeof(*desc));
+
+	desc->byteorder = dtype_byteorder_bits(set->key->dtype,
+					       set->key->byteorder);
+
+	if (!set_is_datamap(set->flags))
+		return;
+
+	desc->byteorder |= dtype_byteorder_bits(set->data->dtype,
+						set->data->byteorder) << 16;
+}
+
+static void netlink_dump_setelem(struct nftnl_set_elem *nlse,
+				 struct netlink_ctx *ctx, const struct set *set)
 {
 	FILE *fp = ctx->nft->output.output_fp;
+	struct nftnl_set_desc desc;
 	char buf[4096];
 
 	if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp)
 		return;
 
-	nftnl_set_elem_snprintf(buf, sizeof(buf), nlse, NFTNL_OUTPUT_DEFAULT, 0);
+	set_to_desc(&desc, set);
+	nftnl_set_elem_snprintf_desc(buf, sizeof(buf), nlse, &desc,
+				     NFTNL_OUTPUT_DEFAULT, 0);
 	fprintf(fp, "\t%s", buf);
 }
 
@@ -1562,8 +1620,8 @@ static int mnl_nft_setelem_batch(const struct nftnl_set *nls,
 				 struct nftnl_batch *batch,
 				 enum nf_tables_msg_types cmd,
 				 unsigned int flags, uint32_t seqnum,
-				 const struct expr *set,
-				 struct netlink_ctx *ctx)
+				 const struct expr *init,
+				 struct netlink_ctx *ctx, const struct set *set)
 {
 	struct nlattr *nest1, *nest2;
 	struct nftnl_set_elem *nlse;
@@ -1574,8 +1632,8 @@ static int mnl_nft_setelem_batch(const struct nftnl_set *nls,
 	if (cmd == NFT_MSG_NEWSETELEM)
 		flags |= NLM_F_CREATE;
 
-	if (set)
-		expr = list_first_entry(&set->expressions, struct expr, list);
+	if (init)
+		expr = list_first_entry(&init->expressions, struct expr, list);
 
 next:
 	nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(batch), cmd,
@@ -1595,15 +1653,15 @@ next:
 				 htonl(nftnl_set_get_u32(nls, NFTNL_SET_ID)));
 	}
 
-	if (!set || list_empty(&set->expressions))
+	if (!init || list_empty(&init->expressions))
 		return 0;
 
 	assert(expr);
 	nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_LIST_ELEMENTS);
-	list_for_each_entry_from(expr, &set->expressions, list) {
-		nlse = alloc_nftnl_setelem(set, expr);
+	list_for_each_entry_from(expr, &init->expressions, list) {
+		nlse = alloc_nftnl_setelem(init, expr);
 		nest2 = nftnl_set_elem_nlmsg_build(nlh, nlse, ++i);
-		netlink_dump_setelem(nlse, ctx);
+		netlink_dump_setelem(nlse, ctx, set);
 		nftnl_set_elem_free(nlse);
 		if (mnl_nft_attr_nest_overflow(nlh, nest1, nest2)) {
 			mnl_attr_nest_end(nlh, nest1);
@@ -1641,7 +1699,7 @@ int mnl_nft_setelem_add(struct netlink_ctx *ctx, const struct set *set,
 	netlink_dump_set(nls, ctx);
 
 	err = mnl_nft_setelem_batch(nls, ctx->batch, NFT_MSG_NEWSETELEM,
-				    flags, ctx->seqnum, expr, ctx);
+				    flags, ctx->seqnum, expr, ctx, set);
 	nftnl_set_free(nls);
 
 	return err;
@@ -1697,7 +1755,7 @@ int mnl_nft_setelem_del(struct netlink_ctx *ctx, const struct cmd *cmd)
 	netlink_dump_set(nls, ctx);
 
 	err = mnl_nft_setelem_batch(nls, ctx->batch, NFT_MSG_DELSETELEM, 0,
-				    ctx->seqnum, cmd->expr, ctx);
+				    ctx->seqnum, cmd->expr, ctx, cmd->elem.set);
 	nftnl_set_free(nls);
 
 	return err;
-- 
2.33.0




[Index of Archives]     [Netfitler Users]     [Berkeley Packet Filter]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux