netfilter-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH nft 0/9] concat support
@ 2015-06-05 13:42 Patrick McHardy
  2015-06-05 13:42 ` [PATCH nft 1/9] eval: prohibit variable sized types in concat expressions Patrick McHardy
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Patrick McHardy @ 2015-06-05 13:42 UTC (permalink / raw)
  To: pablo; +Cc: netfilter-devel

The following patches add support for concatenations to nft. 

The series begins by changing register allocation to take the real size
of an expression into account and allocate an approriate number of 32
bit registers. This is however only done when concatenations are actually
used, so in all other cases we'll continue to use 128 bit registers
for compatibility.

The next part is delinearization, which maps the new registers numbers
appropriately and changes individual expression reconstruction to build
concat expression when indicated by the LHS and RHS sizes.

The final patch changes set element delinearization to reconstruct the
concat expression in set elements when indicated by the key type of the
set.


Patrick McHardy (9):
  eval: prohibit variable sized types in concat expressions
  headers: sync headers for new register values
  netlink: pass expression to register allocation/release functions
  netlink_linearize: use NFT_REG32 values internally
  netlink_linearize: generate concat expressions
  netlink: pad constant concat sub-expressions
  netlink_delinearize: introduce register translation helper
  netlink_delinearize: handle relational and lookup concat expressions
  netlink: handle concat expressions in set data

 include/linux/netfilter/nf_tables.h |  34 +++++++++-
 include/netlink.h                   |  15 +++++
 src/datatype.c                      |   5 +-
 src/evaluate.c                      |   7 ++
 src/netlink.c                       |  46 ++++++++++---
 src/netlink_delinearize.c           | 130 ++++++++++++++++++++++++++++++++----
 src/netlink_linearize.c             | 105 ++++++++++++++++++++---------
 7 files changed, 288 insertions(+), 54 deletions(-)

-- 
2.1.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH nft 1/9] eval: prohibit variable sized types in concat expressions
  2015-06-05 13:42 [PATCH nft 0/9] concat support Patrick McHardy
@ 2015-06-05 13:42 ` Patrick McHardy
  2015-06-05 13:42 ` [PATCH nft 2/9] headers: sync headers for new register values Patrick McHardy
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Patrick McHardy @ 2015-06-05 13:42 UTC (permalink / raw)
  To: pablo; +Cc: netfilter-devel

Since we need to calculate the length of the entire concat type, we can
not support variable sized types where the length can't be determined
by the type.

This only affects base types since all higher types include a length.

Signed-off-by: Patrick McHardy <kaber@trash.net>
---
 src/evaluate.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/evaluate.c b/src/evaluate.c
index e260a80..d99b38f 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -620,6 +620,13 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
 						 "expecting %s",
 						 dtype->desc);
 
+		if (dtype == NULL && i->dtype->size == 0)
+			return expr_binary_error(ctx->msgs, i, *expr,
+						 "can not use variable sized "
+						 "data types (%s) in concat "
+						 "expressions",
+						 i->dtype->name);
+
 		tmp = concat_subtype_lookup(type, --off);
 		expr_set_context(&ctx->ectx, tmp, tmp->size);
 
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH nft 2/9] headers: sync headers for new register values
  2015-06-05 13:42 [PATCH nft 0/9] concat support Patrick McHardy
  2015-06-05 13:42 ` [PATCH nft 1/9] eval: prohibit variable sized types in concat expressions Patrick McHardy
@ 2015-06-05 13:42 ` Patrick McHardy
  2015-06-05 13:42 ` [PATCH nft 3/9] netlink: pass expression to register allocation/release functions Patrick McHardy
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Patrick McHardy @ 2015-06-05 13:42 UTC (permalink / raw)
  To: pablo; +Cc: netfilter-devel

Signed-off-by: Patrick McHardy <kaber@trash.net>
---
 include/linux/netfilter/nf_tables.h | 34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 0e96443..33056dc 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -4,16 +4,45 @@
 #define NFT_CHAIN_MAXNAMELEN	32
 #define NFT_USERDATA_MAXLEN	256
 
+/**
+ * enum nft_registers - nf_tables registers
+ *
+ * nf_tables used to have five registers: a verdict register and four data
+ * registers of size 16. The data registers have been changed to 16 registers
+ * of size 4. For compatibility reasons, the NFT_REG_[1-4] registers still
+ * map to areas of size 16, the 4 byte registers are addressed using
+ * NFT_REG32_00 - NFT_REG32_15.
+ */
 enum nft_registers {
 	NFT_REG_VERDICT,
 	NFT_REG_1,
 	NFT_REG_2,
 	NFT_REG_3,
 	NFT_REG_4,
-	__NFT_REG_MAX
+	__NFT_REG_MAX,
+
+	NFT_REG32_00	= 8,
+	MFT_REG32_01,
+	NFT_REG32_02,
+	NFT_REG32_03,
+	NFT_REG32_04,
+	NFT_REG32_05,
+	NFT_REG32_06,
+	NFT_REG32_07,
+	NFT_REG32_08,
+	NFT_REG32_09,
+	NFT_REG32_10,
+	NFT_REG32_11,
+	NFT_REG32_12,
+	NFT_REG32_13,
+	NFT_REG32_14,
+	NFT_REG32_15,
 };
 #define NFT_REG_MAX	(__NFT_REG_MAX - 1)
 
+#define NFT_REG_SIZE	16
+#define NFT_REG32_SIZE	4
+
 /**
  * enum nft_verdicts - nf_tables internal verdicts
  *
@@ -358,6 +387,9 @@ enum nft_data_attributes {
 };
 #define NFTA_DATA_MAX		(__NFTA_DATA_MAX - 1)
 
+/* Maximum length of a value */
+#define NFT_DATA_VALUE_MAXLEN	64
+
 /**
  * enum nft_verdict_attributes - nf_tables verdict netlink attributes
  *
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH nft 3/9] netlink: pass expression to register allocation/release functions
  2015-06-05 13:42 [PATCH nft 0/9] concat support Patrick McHardy
  2015-06-05 13:42 ` [PATCH nft 1/9] eval: prohibit variable sized types in concat expressions Patrick McHardy
  2015-06-05 13:42 ` [PATCH nft 2/9] headers: sync headers for new register values Patrick McHardy
@ 2015-06-05 13:42 ` Patrick McHardy
  2015-06-05 13:42 ` [PATCH nft 4/9] netlink_linearize: use NFT_REG32 values internally Patrick McHardy
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Patrick McHardy @ 2015-06-05 13:42 UTC (permalink / raw)
  To: pablo; +Cc: netfilter-devel

Prepare for taking the expression size into account.

Signed-off-by: Patrick McHardy <kaber@trash.net>
---
 src/netlink_linearize.c | 54 +++++++++++++++++++++++++------------------------
 1 file changed, 28 insertions(+), 26 deletions(-)

diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index fbc6ae1..beeb0c2 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -30,14 +30,16 @@ static void netlink_put_register(struct nft_rule_expr *nle,
 	nft_rule_expr_set_u32(nle, attr, reg);
 }
 
-static enum nft_registers get_register(struct netlink_linearize_ctx *ctx)
+static enum nft_registers get_register(struct netlink_linearize_ctx *ctx,
+				       const struct expr *expr)
 {
 	if (ctx->reg_low > NFT_REG_MAX)
 		BUG("register reg_low %u invalid\n", ctx->reg_low);
 	return ctx->reg_low++;
 }
 
-static void release_register(struct netlink_linearize_ctx *ctx)
+static void release_register(struct netlink_linearize_ctx *ctx,
+			     const struct expr *expr)
 {
 	ctx->reg_low--;
 }
@@ -124,7 +126,7 @@ static void netlink_gen_map(struct netlink_linearize_ctx *ctx,
 	assert(expr->mappings->ops->type == EXPR_SET_REF);
 
 	if (dreg == NFT_REG_VERDICT)
-		sreg = get_register(ctx);
+		sreg = get_register(ctx, expr->map);
 	else
 		sreg = dreg;
 
@@ -139,7 +141,7 @@ static void netlink_gen_map(struct netlink_linearize_ctx *ctx,
 			      expr->mappings->set->handle.set_id);
 
 	if (dreg == NFT_REG_VERDICT)
-		release_register(ctx);
+		release_register(ctx, expr->map);
 
 	nft_rule_add_expr(ctx->nlr, nle);
 }
@@ -154,7 +156,7 @@ static void netlink_gen_lookup(struct netlink_linearize_ctx *ctx,
 	assert(expr->right->ops->type == EXPR_SET_REF);
 	assert(dreg == NFT_REG_VERDICT);
 
-	sreg = get_register(ctx);
+	sreg = get_register(ctx, expr->left);
 	netlink_gen_expr(ctx, expr->left, sreg);
 
 	nle = alloc_nft_expr("lookup");
@@ -164,7 +166,7 @@ static void netlink_gen_lookup(struct netlink_linearize_ctx *ctx,
 	nft_rule_expr_set_u32(nle, NFT_EXPR_LOOKUP_SET_ID,
 			      expr->right->set->handle.set_id);
 
-	release_register(ctx);
+	release_register(ctx, expr->left);
 	nft_rule_add_expr(ctx->nlr, nle);
 }
 
@@ -206,7 +208,7 @@ static void netlink_gen_cmp(struct netlink_linearize_ctx *ctx,
 	if (expr->right->ops->type == EXPR_RANGE)
 		return netlink_gen_range(ctx, expr, dreg);
 
-	sreg = get_register(ctx);
+	sreg = get_register(ctx, expr->left);
 	netlink_gen_expr(ctx, expr->left, sreg);
 
 	switch (expr->right->ops->type) {
@@ -242,7 +244,7 @@ static void netlink_gen_cmp(struct netlink_linearize_ctx *ctx,
 			      netlink_gen_cmp_op(expr->op));
 	netlink_gen_data(right, &nld);
 	nft_rule_expr_set(nle, NFT_EXPR_CMP_DATA, nld.value, nld.len);
-	release_register(ctx);
+	release_register(ctx, expr->left);
 
 	nft_rule_add_expr(ctx->nlr, nle);
 }
@@ -258,7 +260,7 @@ static void netlink_gen_range(struct netlink_linearize_ctx *ctx,
 
 	assert(dreg == NFT_REG_VERDICT);
 
-	sreg = get_register(ctx);
+	sreg = get_register(ctx, expr->left);
 	netlink_gen_expr(ctx, expr->left, sreg);
 
 	nle = alloc_nft_expr("cmp");
@@ -301,7 +303,7 @@ static void netlink_gen_range(struct netlink_linearize_ctx *ctx,
 	nft_rule_expr_set(nle, NFT_EXPR_CMP_DATA, nld.value, nld.len);
 	nft_rule_add_expr(ctx->nlr, nle);
 
-	release_register(ctx);
+	release_register(ctx, expr->left);
 }
 
 static void netlink_gen_flagcmp(struct netlink_linearize_ctx *ctx,
@@ -316,7 +318,7 @@ static void netlink_gen_flagcmp(struct netlink_linearize_ctx *ctx,
 
 	assert(dreg == NFT_REG_VERDICT);
 
-	sreg = get_register(ctx);
+	sreg = get_register(ctx, expr->left);
 	netlink_gen_expr(ctx, expr->left, sreg);
 	len = div_round_up(expr->left->len, BITS_PER_BYTE);
 
@@ -340,7 +342,7 @@ static void netlink_gen_flagcmp(struct netlink_linearize_ctx *ctx,
 	nft_rule_add_expr(ctx->nlr, nle);
 
 	mpz_clear(zero);
-	release_register(ctx);
+	release_register(ctx, expr->left);
 }
 
 static void netlink_gen_relational(struct netlink_linearize_ctx *ctx,
@@ -565,9 +567,9 @@ static void netlink_gen_meta_stmt(struct netlink_linearize_ctx *ctx,
 	struct nft_rule_expr *nle;
 	enum nft_registers sreg;
 
-	sreg = get_register(ctx);
+	sreg = get_register(ctx, stmt->meta.expr);
 	netlink_gen_expr(ctx, stmt->meta.expr, sreg);
-	release_register(ctx);
+	release_register(ctx, stmt->meta.expr);
 
 	nle = alloc_nft_expr("meta");
 	netlink_put_register(nle, NFT_EXPR_META_SREG, sreg);
@@ -647,11 +649,11 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
 		nft_rule_expr_set_u32(nle, NFT_EXPR_NAT_FLAGS, stmt->nat.flags);
 
 	if (stmt->nat.addr) {
-		amin_reg = get_register(ctx);
+		amin_reg = get_register(ctx, NULL);
 		registers++;
 
 		if (stmt->nat.addr->ops->type == EXPR_RANGE) {
-			amax_reg = get_register(ctx);
+			amax_reg = get_register(ctx, NULL);
 			registers++;
 
 			netlink_gen_expr(ctx, stmt->nat.addr->left, amin_reg);
@@ -669,11 +671,11 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
 	}
 
 	if (stmt->nat.proto) {
-		pmin_reg = get_register(ctx);
+		pmin_reg = get_register(ctx, NULL);
 		registers++;
 
 		if (stmt->nat.proto->ops->type == EXPR_RANGE) {
-			pmax_reg = get_register(ctx);
+			pmax_reg = get_register(ctx, NULL);
 			registers++;
 
 			netlink_gen_expr(ctx, stmt->nat.proto->left, pmin_reg);
@@ -690,7 +692,7 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
 	}
 
 	while (registers > 0) {
-		release_register(ctx);
+		release_register(ctx, NULL);
 		registers--;
 	}
 
@@ -724,11 +726,11 @@ static void netlink_gen_redir_stmt(struct netlink_linearize_ctx *ctx,
 				      stmt->redir.flags);
 
 	if (stmt->redir.proto) {
-		pmin_reg = get_register(ctx);
+		pmin_reg = get_register(ctx, NULL);
 		registers++;
 
 		if (stmt->redir.proto->ops->type == EXPR_RANGE) {
-			pmax_reg = get_register(ctx);
+			pmax_reg = get_register(ctx, NULL);
 			registers++;
 
 			netlink_gen_expr(ctx, stmt->redir.proto->left,
@@ -750,7 +752,7 @@ static void netlink_gen_redir_stmt(struct netlink_linearize_ctx *ctx,
 	}
 
 	while (registers > 0) {
-		release_register(ctx);
+		release_register(ctx, NULL);
 		registers--;
 	}
 
@@ -791,9 +793,9 @@ static void netlink_gen_ct_stmt(struct netlink_linearize_ctx *ctx,
 	struct nft_rule_expr *nle;
 	enum nft_registers sreg;
 
-	sreg = get_register(ctx);
+	sreg = get_register(ctx, stmt->ct.expr);
 	netlink_gen_expr(ctx, stmt->ct.expr, sreg);
-	release_register(ctx);
+	release_register(ctx, stmt->ct.expr);
 
 	nle = alloc_nft_expr("ct");
 	netlink_put_register(nle, NFT_EXPR_CT_SREG, sreg);
@@ -807,9 +809,9 @@ static void netlink_gen_set_stmt(struct netlink_linearize_ctx *ctx,
 	struct nft_rule_expr *nle;
 	enum nft_registers sreg_key;
 
-	sreg_key = get_register(ctx);
+	sreg_key = get_register(ctx, stmt->set.key);
 	netlink_gen_expr(ctx, stmt->set.key, sreg_key);
-	release_register(ctx);
+	release_register(ctx, stmt->set.key);
 
 	nle = alloc_nft_expr("dynset");
 	netlink_put_register(nle, NFT_EXPR_DYNSET_SREG_KEY, sreg_key);
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH nft 4/9] netlink_linearize: use NFT_REG32 values internally
  2015-06-05 13:42 [PATCH nft 0/9] concat support Patrick McHardy
                   ` (2 preceding siblings ...)
  2015-06-05 13:42 ` [PATCH nft 3/9] netlink: pass expression to register allocation/release functions Patrick McHardy
@ 2015-06-05 13:42 ` Patrick McHardy
  2015-06-05 13:42 ` [PATCH nft 5/9] netlink_linearize: generate concat expressions Patrick McHardy
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Patrick McHardy @ 2015-06-05 13:42 UTC (permalink / raw)
  To: pablo; +Cc: netfilter-devel

Prepare netlink_linearize for 32 bit register usage:

Switch to use 16 data registers of 32 bit each. A helper function takes
care of mapping the registers to the NFT_REG32 values and, if the
register refers to the beginning of an 128 bit area, the old NFT_REG_1-4
values for compatibility.

New register reservation and release helper function take the size into
account and reserve the required amount of registers.

The reservation and release functions will so far still always allocate
128 bit. If no other expression in a rule uses a 32 bit register directly,
these will be mapped to the old register values, meaning everything
continues to work with old kernel versions.

Signed-off-by: Patrick McHardy <kaber@trash.net>
---
 include/netlink.h       |  5 +++++
 src/netlink_linearize.c | 43 +++++++++++++++++++++++++++++++++++++++----
 2 files changed, 44 insertions(+), 4 deletions(-)

diff --git a/include/netlink.h b/include/netlink.h
index 9f24ea5..9b42fdb 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -53,6 +53,11 @@ struct nft_data_delinearize {
 	int		verdict;
 };
 
+static inline unsigned int netlink_register_space(unsigned int size)
+{
+	return div_round_up(size, NFT_REG32_SIZE * BITS_PER_BYTE);
+}
+
 extern void netlink_gen_data(const struct expr *expr,
 			     struct nft_data_linearize *data);
 extern void netlink_gen_raw_data(const mpz_t value, enum byteorder byteorder,
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index beeb0c2..6930b39 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -27,21 +27,54 @@ struct netlink_linearize_ctx {
 static void netlink_put_register(struct nft_rule_expr *nle,
 				 uint32_t attr, uint32_t reg)
 {
+	/* Convert to 128 bit register numbers if possible for compatibility */
+	if (reg != NFT_REG_VERDICT) {
+		reg -= NFT_REG_1;
+		if (reg % (NFT_REG_SIZE / NFT_REG32_SIZE) == 0)
+			reg = NFT_REG_1 + reg / (NFT_REG_SIZE / NFT_REG32_SIZE);
+		else
+			reg += NFT_REG32_00;
+	}
+
 	nft_rule_expr_set_u32(nle, attr, reg);
 }
 
+static enum nft_registers __get_register(struct netlink_linearize_ctx *ctx,
+					 unsigned int size)
+{
+	unsigned int reg, n;
+
+	n = netlink_register_space(size);
+	if (ctx->reg_low + n > NFT_REG_1 + NFT_REG32_15 - NFT_REG32_00 + 1)
+		BUG("register reg_low %u invalid\n", ctx->reg_low);
+
+	reg = ctx->reg_low;
+	ctx->reg_low += n;
+	return reg;
+}
+
+static void __release_register(struct netlink_linearize_ctx *ctx,
+			       unsigned int size)
+{
+	unsigned int n;
+
+	n = netlink_register_space(size);
+	if (ctx->reg_low < NFT_REG_1 + n)
+		BUG("register reg_low %u invalid\n", ctx->reg_low);
+
+	ctx->reg_low -= n;
+}
+
 static enum nft_registers get_register(struct netlink_linearize_ctx *ctx,
 				       const struct expr *expr)
 {
-	if (ctx->reg_low > NFT_REG_MAX)
-		BUG("register reg_low %u invalid\n", ctx->reg_low);
-	return ctx->reg_low++;
+	return __get_register(ctx, NFT_REG_SIZE * BITS_PER_BYTE);
 }
 
 static void release_register(struct netlink_linearize_ctx *ctx,
 			     const struct expr *expr)
 {
-	ctx->reg_low--;
+	__release_register(ctx, NFT_REG_SIZE * BITS_PER_BYTE);
 }
 
 static void netlink_gen_expr(struct netlink_linearize_ctx *ctx,
@@ -509,6 +542,8 @@ static void netlink_gen_expr(struct netlink_linearize_ctx *ctx,
 			     const struct expr *expr,
 			     enum nft_registers dreg)
 {
+	assert(dreg < ctx->reg_low);
+
 	switch (expr->ops->type) {
 	case EXPR_VERDICT:
 	case EXPR_VALUE:
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH nft 5/9] netlink_linearize: generate concat expressions
  2015-06-05 13:42 [PATCH nft 0/9] concat support Patrick McHardy
                   ` (3 preceding siblings ...)
  2015-06-05 13:42 ` [PATCH nft 4/9] netlink_linearize: use NFT_REG32 values internally Patrick McHardy
@ 2015-06-05 13:42 ` Patrick McHardy
  2015-06-05 13:42 ` [PATCH nft 6/9] netlink: pad constant concat sub-expressions Patrick McHardy
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Patrick McHardy @ 2015-06-05 13:42 UTC (permalink / raw)
  To: pablo; +Cc: netfilter-devel

Use the real length for reserving/releasing registers when generating
concat expressions.

Signed-off-by: Patrick McHardy <kaber@trash.net>
---
 src/netlink_linearize.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 6930b39..bf1e56b 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -68,13 +68,19 @@ static void __release_register(struct netlink_linearize_ctx *ctx,
 static enum nft_registers get_register(struct netlink_linearize_ctx *ctx,
 				       const struct expr *expr)
 {
-	return __get_register(ctx, NFT_REG_SIZE * BITS_PER_BYTE);
+	if (expr && expr->ops->type == EXPR_CONCAT)
+		return __get_register(ctx, expr->len);
+	else
+		return __get_register(ctx, NFT_REG_SIZE * BITS_PER_BYTE);
 }
 
 static void release_register(struct netlink_linearize_ctx *ctx,
 			     const struct expr *expr)
 {
-	__release_register(ctx, NFT_REG_SIZE * BITS_PER_BYTE);
+	if (expr && expr->ops->type == EXPR_CONCAT)
+		__release_register(ctx, expr->len);
+	else
+		__release_register(ctx, NFT_REG_SIZE * BITS_PER_BYTE);
 }
 
 static void netlink_gen_expr(struct netlink_linearize_ctx *ctx,
@@ -87,8 +93,10 @@ static void netlink_gen_concat(struct netlink_linearize_ctx *ctx,
 {
 	const struct expr *i;
 
-	list_for_each_entry(i, &expr->expressions, list)
+	list_for_each_entry(i, &expr->expressions, list) {
 		netlink_gen_expr(ctx, i, dreg);
+		dreg += netlink_register_space(i->len);
+	}
 }
 
 static void netlink_gen_payload(struct netlink_linearize_ctx *ctx,
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH nft 6/9] netlink: pad constant concat sub-expressions
  2015-06-05 13:42 [PATCH nft 0/9] concat support Patrick McHardy
                   ` (4 preceding siblings ...)
  2015-06-05 13:42 ` [PATCH nft 5/9] netlink_linearize: generate concat expressions Patrick McHardy
@ 2015-06-05 13:42 ` Patrick McHardy
  2015-06-05 13:42 ` [PATCH nft 7/9] netlink_delinearize: introduce register translation helper Patrick McHardy
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Patrick McHardy @ 2015-06-05 13:42 UTC (permalink / raw)
  To: pablo; +Cc: netfilter-devel

Pad all but the last sub-expressions of a concat expressions.

Signed-off-by: Patrick McHardy <kaber@trash.net>
---
 include/netlink.h | 10 ++++++++++
 src/datatype.c    |  3 ++-
 src/netlink.c     | 14 ++++++--------
 3 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/include/netlink.h b/include/netlink.h
index 9b42fdb..185c435 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -58,6 +58,16 @@ static inline unsigned int netlink_register_space(unsigned int size)
 	return div_round_up(size, NFT_REG32_SIZE * BITS_PER_BYTE);
 }
 
+static inline unsigned int netlink_padded_len(unsigned int size)
+{
+	return netlink_register_space(size) * NFT_REG32_SIZE * BITS_PER_BYTE;
+}
+
+static inline unsigned int netlink_padding_len(unsigned int size)
+{
+	return netlink_padded_len(size) - size;
+}
+
 extern void netlink_gen_data(const struct expr *expr,
 			     struct nft_data_linearize *data);
 extern void netlink_gen_raw_data(const mpz_t value, enum byteorder byteorder,
diff --git a/src/datatype.c b/src/datatype.c
index f93337b..a06a58e 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -23,6 +23,7 @@
 #include <expression.h>
 #include <gmputil.h>
 #include <erec.h>
+#include <netlink.h>
 
 #include <netinet/ip_icmp.h>
 #include <netinet/icmp6.h>
@@ -943,7 +944,7 @@ const struct datatype *concat_type_alloc(uint32_t type)
 		strncat(desc, i->desc, sizeof(desc) - strlen(desc) - 1);
 		strncat(name, i->name, sizeof(name) - strlen(name) - 1);
 
-		size += i->size;
+		size += netlink_padded_len(i->size);
 		subtypes++;
 	}
 	strncat(desc, ")", sizeof(desc) - strlen(desc) - 1);
diff --git a/src/netlink.c b/src/netlink.c
index d31387f..3369d22 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -273,23 +273,21 @@ static void netlink_gen_concat_data(const struct expr *expr,
 	const struct expr *i;
 	unsigned int len, offset;
 
-	len = 0;
-	list_for_each_entry(i, &expr->expressions, list)
-		len += i->len;
-
+	len = expr->len / BITS_PER_BYTE;
 	if (1) {
-		unsigned char data[len / BITS_PER_BYTE];
+		unsigned char data[len];
 
+		memset(data, 0, sizeof(data));
 		offset = 0;
 		list_for_each_entry(i, &expr->expressions, list) {
 			assert(i->ops->type == EXPR_VALUE);
 			mpz_export_data(data + offset, i->value, i->byteorder,
 					i->len / BITS_PER_BYTE);
-			offset += i->len / BITS_PER_BYTE;
+			offset += netlink_padded_len(i->len) / BITS_PER_BYTE;
 		}
 
-		memcpy(nld->value, data, len / BITS_PER_BYTE);
-		nld->len = len / BITS_PER_BYTE;
+		memcpy(nld->value, data, len);
+		nld->len = len;
 	}
 }
 
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH nft 7/9] netlink_delinearize: introduce register translation helper
  2015-06-05 13:42 [PATCH nft 0/9] concat support Patrick McHardy
                   ` (5 preceding siblings ...)
  2015-06-05 13:42 ` [PATCH nft 6/9] netlink: pad constant concat sub-expressions Patrick McHardy
@ 2015-06-05 13:42 ` Patrick McHardy
  2015-06-05 13:42 ` [PATCH nft 8/9] netlink_delinearize: handle relational and lookup concat expressions Patrick McHardy
  2015-06-05 13:42 ` [PATCH nft 9/9] netlink: handle concat expressions in set data Patrick McHardy
  8 siblings, 0 replies; 10+ messages in thread
From: Patrick McHardy @ 2015-06-05 13:42 UTC (permalink / raw)
  To: pablo; +Cc: netfilter-devel

Introduce a helper function to translate register numbers from the kernel
from the compat values to the NFT_REG32 values.

Internally we use the register numbers 0-16:

* 0 is the verdict register in both old and new addressing modes.
* 1-16 are the 32 bit data registers

The NFT_REG32_00 values are mapped to 1-16, the NFT_REG_1-NFT_REG_4
values are each use up 4 registers starting at 1 (1, 5, 9, 13).

Signed-off-by: Patrick McHardy <kaber@trash.net>
---
 src/netlink_delinearize.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index e9ce76e..91da859 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -30,7 +30,7 @@ struct netlink_parse_ctx {
 	struct list_head	*msgs;
 	struct table		*table;
 	struct rule		*rule;
-	struct expr		*registers[NFT_REG_MAX + 1];
+	struct expr		*registers[1 + NFT_REG32_15 - NFT_REG32_00 + 1];
 };
 
 static void __fmtstring(3, 4) netlink_error(struct netlink_parse_ctx *ctx,
@@ -49,14 +49,23 @@ static void __fmtstring(3, 4) netlink_error(struct netlink_parse_ctx *ctx,
 static unsigned int netlink_parse_register(const struct nft_rule_expr *nle,
 					   unsigned int attr)
 {
-	return nft_rule_expr_get_u32(nle, attr);
+	unsigned int reg;
+
+	reg = nft_rule_expr_get_u32(nle, attr);
+	/* Translate 128bit registers to corresponding 32bit registers */
+	if (reg >= NFT_REG_1 && reg <= NFT_REG_4)
+		reg = 1 + (reg - NFT_REG_1) * (NFT_REG_SIZE / NFT_REG32_SIZE);
+	else if (reg >= NFT_REG32_00)
+		reg = 1 + reg - NFT_REG32_00;
+
+	return reg;
 }
 
 static void netlink_set_register(struct netlink_parse_ctx *ctx,
 				 enum nft_registers reg,
 				 struct expr *expr)
 {
-	if (reg > NFT_REG_MAX) {
+	if (reg == NFT_REG_VERDICT || reg > 1 + NFT_REG32_15 - NFT_REG32_00) {
 		netlink_error(ctx, &expr->location,
 			      "Invalid destination register %u", reg);
 		expr_free(expr);
@@ -75,7 +84,7 @@ static struct expr *netlink_get_register(struct netlink_parse_ctx *ctx,
 {
 	struct expr *expr;
 
-	if (reg == NFT_REG_VERDICT || reg > NFT_REG_MAX) {
+	if (reg == NFT_REG_VERDICT || reg > 1 + NFT_REG32_15 - NFT_REG32_00) {
 		netlink_error(ctx, loc, "Invalid source register %u", reg);
 		return NULL;
 	}
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH nft 8/9] netlink_delinearize: handle relational and lookup concat expressions
  2015-06-05 13:42 [PATCH nft 0/9] concat support Patrick McHardy
                   ` (6 preceding siblings ...)
  2015-06-05 13:42 ` [PATCH nft 7/9] netlink_delinearize: introduce register translation helper Patrick McHardy
@ 2015-06-05 13:42 ` Patrick McHardy
  2015-06-05 13:42 ` [PATCH nft 9/9] netlink: handle concat expressions in set data Patrick McHardy
  8 siblings, 0 replies; 10+ messages in thread
From: Patrick McHardy @ 2015-06-05 13:42 UTC (permalink / raw)
  To: pablo; +Cc: netfilter-devel

When the RHS length differs from the LHS length (which is only the
first expression), both expressions are assumed to be concat expressions.

The LHS concat expression is reconstructed from the available register
values, advancing by the number of registers required by the subexpressions'
register space, until the RHS length has been reached.

The RHS concat expression is reconstructed by splitting the data value
into multiple subexpressions based on the LHS concat expressions types.

Signed-off-by: Patrick McHardy <kaber@trash.net>
---
 src/netlink_delinearize.c | 113 ++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 104 insertions(+), 9 deletions(-)

diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 91da859..08fd580 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -104,6 +104,63 @@ static void netlink_release_registers(struct netlink_parse_ctx *ctx)
 		expr_free(ctx->registers[i]);
 }
 
+static struct expr *netlink_parse_concat_expr(struct netlink_parse_ctx *ctx,
+					      const struct location *loc,
+					      unsigned int reg,
+					      unsigned int len)
+{
+	struct expr *concat, *expr;
+
+	concat = concat_expr_alloc(loc);
+	while (len > 0) {
+		expr = netlink_get_register(ctx, loc, reg);
+		if (expr == NULL) {
+			netlink_error(ctx, loc,
+				      "Relational expression size mismatch");
+			goto err;
+		}
+		compound_expr_add(concat, expr);
+
+		len -= netlink_padded_len(expr->len);
+		reg += netlink_register_space(expr->len);
+	}
+	return concat;
+
+err:
+	expr_free(concat);
+	return NULL;
+}
+
+static struct expr *netlink_parse_concat_data(struct netlink_parse_ctx *ctx,
+					      const struct location *loc,
+					      unsigned int reg,
+					      unsigned int len,
+					      struct expr *data)
+{
+	struct expr *concat, *expr, *i;
+
+	concat = concat_expr_alloc(loc);
+	while (len > 0) {
+		expr = netlink_get_register(ctx, loc, reg);
+		if (expr == NULL) {
+			netlink_error(ctx, loc,
+				      "Relational expression size mismatch");
+			goto err;
+		}
+		i = constant_expr_splice(data, expr->len);
+		data->len -= netlink_padding_len(expr->len);
+		compound_expr_add(concat, i);
+
+		len -= netlink_padded_len(expr->len);
+		reg += netlink_register_space(expr->len);
+	}
+	return concat;
+
+err:
+	expr_free(concat);
+	return NULL;
+}
+
 static void netlink_parse_immediate(struct netlink_parse_ctx *ctx,
 				    const struct location *loc,
 				    const struct nft_rule_expr *nle)
@@ -175,9 +232,18 @@ static void netlink_parse_cmp(struct netlink_parse_ctx *ctx,
 	nld.value = nft_rule_expr_get(nle, NFT_EXPR_CMP_DATA, &nld.len);
 	right = netlink_alloc_value(loc, &nld);
 
-	if (left->len != right->len)
-		return netlink_error(ctx, loc,
-				     "Relational expression size mismatch");
+	if (left->len != right->len) {
+		if (left->len > right->len)
+			return netlink_error(ctx, loc,
+					     "Relational expression size "
+					     "mismatch");
+		left = netlink_parse_concat_expr(ctx, loc, sreg, right->len);
+		if (left == NULL)
+			return;
+		right = netlink_parse_concat_data(ctx, loc, sreg, right->len, right);
+		if (right == NULL)
+			return;
+	}
 
 	expr = relational_expr_alloc(loc, op, left, right);
 	stmt = expr_stmt_alloc(loc, expr);
@@ -194,12 +260,6 @@ static void netlink_parse_lookup(struct netlink_parse_ctx *ctx,
 	struct expr *expr, *left, *right;
 	struct set *set;
 
-	sreg = netlink_parse_register(nle, NFT_EXPR_LOOKUP_SREG);
-	left = netlink_get_register(ctx, loc, sreg);
-	if (left == NULL)
-		return netlink_error(ctx, loc,
-				     "Lookup expression has no left hand side");
-
 	name = nft_rule_expr_get_str(nle, NFT_EXPR_LOOKUP_SET);
 	set  = set_lookup(ctx->table, name);
 	if (set == NULL)
@@ -207,6 +267,18 @@ static void netlink_parse_lookup(struct netlink_parse_ctx *ctx,
 				     "Unknown set '%s' in lookup expression",
 				     name);
 
+	sreg = netlink_parse_register(nle, NFT_EXPR_LOOKUP_SREG);
+	left = netlink_get_register(ctx, loc, sreg);
+	if (left == NULL)
+		return netlink_error(ctx, loc,
+				     "Lookup expression has no left hand side");
+
+	if (left->len < set->keylen) {
+		left = netlink_parse_concat_expr(ctx, loc, sreg, set->keylen);
+		if (left == NULL)
+			return;
+	}
+
 	right = set_ref_expr_alloc(loc, set);
 
 	if (nft_rule_expr_is_set(nle, NFT_EXPR_LOOKUP_DREG)) {
@@ -724,6 +796,12 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
 		return netlink_error(ctx, loc,
 				     "Dynset statement has no key expression");
 
+	if (expr->len < set->keylen) {
+		expr = netlink_parse_concat_expr(ctx, loc, sreg, set->keylen);
+		if (expr == NULL)
+			return;
+	}
+
 	expr = set_elem_expr_alloc(&expr->location, expr);
 	expr->timeout = nft_rule_expr_get_u64(nle, NFT_EXPR_DYNSET_TIMEOUT);
 
@@ -1000,6 +1078,23 @@ static void expr_postprocess(struct rule_pp_ctx *ctx,
 		list_for_each_entry(i, &expr->expressions, list)
 			expr_postprocess(ctx, stmt, &i);
 		break;
+	case EXPR_CONCAT: {
+		unsigned int type = expr->dtype->type, ntype = 0;
+		int off = expr->dtype->subtypes;
+		const struct datatype *dtype;
+
+		list_for_each_entry(i, &expr->expressions, list) {
+			if (type) {
+				dtype = concat_subtype_lookup(type, --off);
+				expr_set_type(i, dtype, dtype->byteorder);
+			}
+			expr_postprocess(ctx, stmt, &i);
+
+			ntype = concat_subtype_add(ntype, i->dtype->type);
+		}
+		expr->dtype = concat_type_alloc(ntype);
+		break;
+	}
 	case EXPR_UNARY:
 		expr_postprocess(ctx, stmt, &expr->arg);
 		expr_set_type(expr->arg, expr->arg->dtype, !expr->arg->byteorder);
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH nft 9/9] netlink: handle concat expressions in set data
  2015-06-05 13:42 [PATCH nft 0/9] concat support Patrick McHardy
                   ` (7 preceding siblings ...)
  2015-06-05 13:42 ` [PATCH nft 8/9] netlink_delinearize: handle relational and lookup concat expressions Patrick McHardy
@ 2015-06-05 13:42 ` Patrick McHardy
  8 siblings, 0 replies; 10+ messages in thread
From: Patrick McHardy @ 2015-06-05 13:42 UTC (permalink / raw)
  To: pablo; +Cc: netfilter-devel

Reconstruct the concat expressions in set data by splicing off the
subtype values based on the keytype of the set.

Signed-off-by: Patrick McHardy
---
 src/datatype.c |  2 +-
 src/netlink.c  | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/src/datatype.c b/src/datatype.c
index a06a58e..ca83426 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -932,7 +932,7 @@ const struct datatype *concat_type_alloc(uint32_t type)
 	unsigned int size = 0, subtypes = 0, n;
 
 	n = div_round_up(fls(type), TYPE_BITS);
-	while (concat_subtype_id(type, --n)) {
+	while (n > 0 && concat_subtype_id(type, --n)) {
 		i = concat_subtype_lookup(type, n);
 		if (i == NULL)
 			return NULL;
diff --git a/src/netlink.c b/src/netlink.c
index 3369d22..1167c95 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1383,6 +1383,36 @@ static int netlink_del_setelems_compat(struct netlink_ctx *ctx,
 	return err;
 }
 
+static struct expr *netlink_parse_concat_elem(const struct datatype *dtype,
+					      struct expr *data)
+{
+	const struct datatype *subtype;
+	struct expr *concat, *expr;
+	int off = dtype->subtypes;
+
+	concat = concat_expr_alloc(&data->location);
+	while (off > 0) {
+		subtype = concat_subtype_lookup(dtype->type, --off);
+
+		expr		= constant_expr_splice(data, subtype->size);
+		expr->dtype     = subtype;
+		expr->byteorder = subtype->byteorder;
+
+		if (expr->byteorder == BYTEORDER_HOST_ENDIAN)
+			mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
+
+		if (expr->dtype->basetype != NULL &&
+		    expr->dtype->basetype->type == TYPE_BITMASK)
+			expr = bitmask_expr_to_binops(expr);
+
+		compound_expr_add(concat, expr);
+		data->len -= netlink_padding_len(expr->len);
+	}
+	expr_free(data);
+
+	return concat;
+}
+
 static int netlink_delinearize_setelem(struct nft_set_elem *nlse,
 				       struct set *set)
 {
@@ -1398,6 +1428,8 @@ static int netlink_delinearize_setelem(struct nft_set_elem *nlse,
 	key = netlink_alloc_value(&netlink_location, &nld);
 	key->dtype	= set->keytype;
 	key->byteorder	= set->keytype->byteorder;
+	if (set->keytype->subtypes)
+		key = netlink_parse_concat_elem(set->keytype, key);
 
 	if (!(set->flags & SET_F_INTERVAL) &&
 	    key->byteorder == BYTEORDER_HOST_ENDIAN)
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2015-06-05 13:42 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-06-05 13:42 [PATCH nft 0/9] concat support Patrick McHardy
2015-06-05 13:42 ` [PATCH nft 1/9] eval: prohibit variable sized types in concat expressions Patrick McHardy
2015-06-05 13:42 ` [PATCH nft 2/9] headers: sync headers for new register values Patrick McHardy
2015-06-05 13:42 ` [PATCH nft 3/9] netlink: pass expression to register allocation/release functions Patrick McHardy
2015-06-05 13:42 ` [PATCH nft 4/9] netlink_linearize: use NFT_REG32 values internally Patrick McHardy
2015-06-05 13:42 ` [PATCH nft 5/9] netlink_linearize: generate concat expressions Patrick McHardy
2015-06-05 13:42 ` [PATCH nft 6/9] netlink: pad constant concat sub-expressions Patrick McHardy
2015-06-05 13:42 ` [PATCH nft 7/9] netlink_delinearize: introduce register translation helper Patrick McHardy
2015-06-05 13:42 ` [PATCH nft 8/9] netlink_delinearize: handle relational and lookup concat expressions Patrick McHardy
2015-06-05 13:42 ` [PATCH nft 9/9] netlink: handle concat expressions in set data Patrick McHardy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).