All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH nft 01/12] evaluate: transfer right shifts to constant side
@ 2016-05-11 21:05 Pablo Neira Ayuso
  2016-05-11 21:05 ` [PATCH nft 02/12] evaluate: transfer right shifts to range side Pablo Neira Ayuso
                   ` (10 more replies)
  0 siblings, 11 replies; 12+ messages in thread
From: Pablo Neira Ayuso @ 2016-05-11 21:05 UTC (permalink / raw)
  To: netfilter-devel

From: Patrick McHardy <kaber@trash.net>

This provides a generic way to transfer shifts from the left hand side
to the right hand constant side of a relational expression when
performing transformations from the evaluation step.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/evaluate.c | 30 ++++++++++++++++++++++++++----
 1 file changed, 26 insertions(+), 4 deletions(-)

diff --git a/src/evaluate.c b/src/evaluate.c
index 7444d09..f862cd0 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -698,6 +698,7 @@ static int constant_binop_simplify(struct eval_ctx *ctx, struct expr **expr)
 		break;
 	case OP_LSHIFT:
 		assert(left->byteorder == BYTEORDER_HOST_ENDIAN);
+		mpz_set(val, left->value);
 		mpz_lshift_ui(val, mpz_get_uint32(right->value));
 		mpz_and(val, val, mask);
 		break;
@@ -1094,6 +1095,8 @@ static int binop_can_transfer(struct eval_ctx *ctx,
 			return expr_binary_error(ctx->msgs, right, left,
 						 "Comparison is always false");
 		return 1;
+	case OP_RSHIFT:
+		return 1;
 	case OP_XOR:
 		return 1;
 	default:
@@ -1111,6 +1114,10 @@ static int binop_transfer_one(struct eval_ctx *ctx,
 		(*right) = binop_expr_alloc(&(*right)->location, OP_RSHIFT,
 					    *right, expr_get(left->right));
 		break;
+	case OP_RSHIFT:
+		(*right) = binop_expr_alloc(&(*right)->location, OP_LSHIFT,
+					    *right, expr_get(left->right));
+		break;
 	case OP_XOR:
 		(*right) = binop_expr_alloc(&(*right)->location, OP_XOR,
 					    *right, expr_get(left->right));
@@ -1125,6 +1132,7 @@ static int binop_transfer_one(struct eval_ctx *ctx,
 static int binop_transfer(struct eval_ctx *ctx, struct expr **expr)
 {
 	struct expr *left = (*expr)->left, *i, *next;
+	unsigned int shift;
 	int err;
 
 	if (left->ops->type != EXPR_BINOP)
@@ -1156,10 +1164,24 @@ static int binop_transfer(struct eval_ctx *ctx, struct expr **expr)
 		return 0;
 	}
 
-	left = expr_get((*expr)->left->left);
-	left->dtype = (*expr)->left->dtype;
-	expr_free((*expr)->left);
-	(*expr)->left = left;
+	switch (left->op) {
+	case OP_RSHIFT:
+		/* Mask out the bits the shift would have masked out */
+		shift = mpz_get_uint8(left->right->value);
+		mpz_bitmask(left->right->value, left->left->len);
+		mpz_lshift_ui(left->right->value, shift);
+		left->op = OP_AND;
+		break;
+	case OP_LSHIFT:
+	case OP_XOR:
+		left = expr_get((*expr)->left->left);
+		left->dtype = (*expr)->left->dtype;
+		expr_free((*expr)->left);
+		(*expr)->left = left;
+		break;
+	default:
+		BUG("invalid binop operation %u", left->op);
+	}
 	return 0;
 }
 
-- 
2.1.4


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

* [PATCH nft 02/12] evaluate: transfer right shifts to range side
  2016-05-11 21:05 [PATCH nft 01/12] evaluate: transfer right shifts to constant side Pablo Neira Ayuso
@ 2016-05-11 21:05 ` Pablo Neira Ayuso
  2016-05-11 21:05 ` [PATCH nft 03/12] evaluate: transfer right shifts to set reference side Pablo Neira Ayuso
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Pablo Neira Ayuso @ 2016-05-11 21:05 UTC (permalink / raw)
  To: netfilter-devel

This provides a generic way to transfer shifts from the left hand side
to the right hand range side of a relational expression when performing
transformations from the evaluation step.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/evaluate.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/evaluate.c b/src/evaluate.c
index f862cd0..60bbce1 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1146,6 +1146,18 @@ static int binop_transfer(struct eval_ctx *ctx, struct expr **expr)
 		if (binop_transfer_one(ctx, left, &(*expr)->right) < 0)
 			return -1;
 		break;
+	case EXPR_RANGE:
+		err = binop_can_transfer(ctx, left, (*expr)->right->left);
+		if (err <= 0)
+			return err;
+		err = binop_can_transfer(ctx, left, (*expr)->right->right);
+		if (err <= 0)
+			return err;
+		if (binop_transfer_one(ctx, left, &(*expr)->right->left) < 0)
+			return -1;
+		if (binop_transfer_one(ctx, left, &(*expr)->right->right) < 0)
+			return -1;
+		break;
 	case EXPR_SET:
 		list_for_each_entry(i, &(*expr)->right->expressions, list) {
 			err = binop_can_transfer(ctx, left, i);
-- 
2.1.4


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

* [PATCH nft 03/12] evaluate: transfer right shifts to set reference side
  2016-05-11 21:05 [PATCH nft 01/12] evaluate: transfer right shifts to constant side Pablo Neira Ayuso
  2016-05-11 21:05 ` [PATCH nft 02/12] evaluate: transfer right shifts to range side Pablo Neira Ayuso
@ 2016-05-11 21:05 ` Pablo Neira Ayuso
  2016-05-11 21:05 ` [PATCH nft 04/12] src: move payload sub-byte matching to the evaluation step Pablo Neira Ayuso
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Pablo Neira Ayuso @ 2016-05-11 21:05 UTC (permalink / raw)
  To: netfilter-devel

This provides a generic way to transfer shifts from the left hand side
to the right hand range side of a relational expression when performing
transformations from the evaluation step.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/evaluate.c            | 40 +++++++++++++++++++++++++++++++
 src/netlink_delinearize.c | 60 ++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 94 insertions(+), 6 deletions(-)

diff --git a/src/evaluate.c b/src/evaluate.c
index 60bbce1..72a0e43 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1172,6 +1172,46 @@ static int binop_transfer(struct eval_ctx *ctx, struct expr **expr)
 			list_add_tail(&i->list, &next->list);
 		}
 		break;
+	case EXPR_SET_REF:
+		list_for_each_entry(i, &(*expr)->right->set->init->expressions, list) {
+			switch (i->key->ops->type) {
+			case EXPR_VALUE:
+				err = binop_can_transfer(ctx, left, i->key);
+				if (err <= 0)
+					return err;
+				break;
+			case EXPR_RANGE:
+				err = binop_can_transfer(ctx, left, i->key->left);
+				if (err <= 0)
+					return err;
+				err = binop_can_transfer(ctx, left, i->key->right);
+				if (err <= 0)
+					return err;
+				break;
+			default:
+				break;
+			}
+		}
+		list_for_each_entry_safe(i, next, &(*expr)->right->set->init->expressions,
+					 list) {
+			list_del(&i->list);
+			switch (i->key->ops->type) {
+			case EXPR_VALUE:
+				if (binop_transfer_one(ctx, left, &i->key) < 0)
+					return -1;
+				break;
+			case EXPR_RANGE:
+				if (binop_transfer_one(ctx, left, &i->key->left) < 0)
+					return -1;
+				if (binop_transfer_one(ctx, left, &i->key->right) < 0)
+					return -1;
+				break;
+			default:
+				break;
+			}
+			list_add_tail(&i->list, &next->list);
+		}
+		break;
 	default:
 		return 0;
 	}
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 84f94fc..eb07ffb 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -1185,9 +1185,61 @@ static struct expr *binop_tree_to_list(struct expr *list, struct expr *expr)
 	return list;
 }
 
+static void binop_adjust_one(const struct expr *binop, struct expr *value,
+			     unsigned int shift)
+{
+	struct expr *left = binop->left;
+
+	assert(value->len >= binop->right->len);
+
+	mpz_rshift_ui(value->value, shift);
+	switch (left->ops->type) {
+	case EXPR_PAYLOAD:
+	case EXPR_EXTHDR:
+		value->len = left->len;
+		break;
+	default:
+		BUG("unknown expression type %s\n", left->ops->name);
+		break;
+	}
+}
+
+static void binop_adjust(struct expr *expr, unsigned int shift)
+{
+	const struct expr *binop = expr->left;
+	struct expr *right = expr->right, *i;
+
+	switch (right->ops->type) {
+	case EXPR_VALUE:
+		binop_adjust_one(binop, right, shift);
+		break;
+	case EXPR_SET_REF:
+		list_for_each_entry(i, &right->set->init->expressions, list) {
+			switch (i->key->ops->type) {
+			case EXPR_VALUE:
+				binop_adjust_one(binop, i->key, shift);
+				break;
+			case EXPR_RANGE:
+				binop_adjust_one(binop, i->key->left, shift);
+				binop_adjust_one(binop, i->key->right, shift);
+				break;
+			case EXPR_SET_ELEM:
+				binop_adjust_one(binop, i->key->key, shift);
+				break;
+			default:
+				BUG("unknown expression type %s\n", i->key->ops->name);
+			}
+		}
+		break;
+	default:
+		BUG("unknown expression type %s\n", expr->ops->name);
+		break;
+	}
+}
+
 static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr)
 {
-	struct expr *binop = expr->left, *value = expr->right;
+	struct expr *binop = expr->left;
 	struct expr *left = binop->left;
 	struct expr *mask = binop->right;
 	unsigned int shift;
@@ -1205,11 +1257,7 @@ static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr)
 		 * Finally, convert the expression to 1) by replacing
 		 * the binop with the binop payload/exthdr expression.
 		 */
-		if (value->ops->type == EXPR_VALUE) {
-			assert(value->len >= expr->left->right->len);
-			mpz_rshift_ui(value->value, shift);
-			value->len = left->len;
-		}
+		binop_adjust(expr, shift);
 
 		assert(expr->left->ops->type == EXPR_BINOP);
 		assert(binop->left == left);
-- 
2.1.4


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

* [PATCH nft 04/12] src: move payload sub-byte matching to the evaluation step
  2016-05-11 21:05 [PATCH nft 01/12] evaluate: transfer right shifts to constant side Pablo Neira Ayuso
  2016-05-11 21:05 ` [PATCH nft 02/12] evaluate: transfer right shifts to range side Pablo Neira Ayuso
  2016-05-11 21:05 ` [PATCH nft 03/12] evaluate: transfer right shifts to set reference side Pablo Neira Ayuso
@ 2016-05-11 21:05 ` Pablo Neira Ayuso
  2016-05-11 21:05 ` [PATCH nft 05/12] evaluate: handle payload matching split in two bytes Pablo Neira Ayuso
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Pablo Neira Ayuso @ 2016-05-11 21:05 UTC (permalink / raw)
  To: netfilter-devel

Generating the bitwise logic to match sub-byte payload fields from the
linearize step has several problems:

1) When the bits are split between two bytes and the payload field is
   smaller than one byte, we need to extend the expression length on
   both sides (payload and constant) of the relational expression.

2) Explicit bitmask operations on sub-byte payload fields need to be
   merge to the implicit bitmask operation, otherwise we generate two
   bitwise instructions. This is not resolved by this patch, but we
   should have a look at some point to this.

With this approach, we can benefit from the binary operation transfer
for shifts to provide a generic way to adjust the constant side of the
expression.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/evaluate.c          | 105 ++++++++++++++++++++++++++++++++++++++++++++----
 src/netlink_linearize.c |  99 ---------------------------------------------
 2 files changed, 97 insertions(+), 107 deletions(-)

diff --git a/src/evaluate.c b/src/evaluate.c
index 72a0e43..ab73261 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -362,30 +362,108 @@ conflict_resolution_gen_dependency(struct eval_ctx *ctx, int protocol,
 	return 0;
 }
 
+static uint8_t expr_offset_shift(const struct expr *expr, unsigned int offset)
+{
+	unsigned int new_offset, len;
+	int shift;
+
+	new_offset = offset % BITS_PER_BYTE;
+	len = round_up(expr->len, BITS_PER_BYTE);
+	shift = len - (new_offset + expr->len);
+	assert(shift >= 0);
+
+	return shift;
+}
+
+static void expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp)
+{
+	struct expr *expr = *exprp, *and, *mask, *lshift, *off;
+	unsigned masklen;
+	uint8_t shift;
+	mpz_t bitmask;
+
+	switch (expr->ops->type) {
+	case EXPR_PAYLOAD:
+		shift = expr_offset_shift(expr, expr->payload.offset);
+		break;
+	case EXPR_EXTHDR:
+		shift = expr_offset_shift(expr, expr->exthdr.tmpl->offset);
+		break;
+	default:
+		BUG("Unknown expression %s\n", expr->ops->name);
+	}
+
+	masklen = expr->len + shift;
+	assert(masklen <= NFT_REG_SIZE * BITS_PER_BYTE);
+
+	mpz_init2(bitmask, masklen);
+	mpz_bitmask(bitmask, expr->len);
+	mpz_lshift_ui(bitmask, shift);
+
+	mask = constant_expr_alloc(&expr->location, expr_basetype(expr),
+				   BYTEORDER_HOST_ENDIAN, masklen, NULL);
+	mpz_set(mask->value, bitmask);
+
+	and = binop_expr_alloc(&expr->location, OP_AND, expr, mask);
+	and->dtype	= expr->dtype;
+	and->byteorder	= expr->byteorder;
+	and->len	= masklen;
+
+	if (shift) {
+		off = constant_expr_alloc(&expr->location,
+					  expr_basetype(expr),
+					  BYTEORDER_BIG_ENDIAN,
+					  sizeof(shift), &shift);
+
+		lshift = binop_expr_alloc(&expr->location, OP_RSHIFT, and, off);
+		lshift->dtype		= expr->dtype;
+		lshift->byteorder	= expr->byteorder;
+		lshift->len		= masklen;
+
+		*exprp = lshift;
+	} else
+		*exprp = and;
+}
+
+static int __expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)
+{
+	struct expr *expr = *exprp;
+
+	if (expr_evaluate_primary(ctx, exprp) < 0)
+		return -1;
+
+	if (expr->exthdr.tmpl->offset % BITS_PER_BYTE != 0 ||
+	    expr->len % BITS_PER_BYTE != 0)
+		expr_evaluate_bits(ctx, exprp);
+
+	return 0;
+}
+
 /*
  * Exthdr expression: check whether dependencies are fulfilled, otherwise
  * generate the necessary relational expression and prepend it to the current
  * statement.
  */
-static int expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **expr)
+static int expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)
 {
 	const struct proto_desc *base;
+	struct expr *expr = *exprp;
 	struct stmt *nstmt;
 
 	base = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
 	if (base == &proto_ip6)
-		return expr_evaluate_primary(ctx, expr);
+		return __expr_evaluate_exthdr(ctx, exprp);
 
 	if (base)
-		return expr_error(ctx->msgs, *expr,
+		return expr_error(ctx->msgs, expr,
 				  "cannot use exthdr with %s", base->name);
 
-	if (exthdr_gen_dependency(ctx, *expr, &nstmt) < 0)
+	if (exthdr_gen_dependency(ctx, expr, &nstmt) < 0)
 		return -1;
 
 	list_add(&nstmt->list, &ctx->rule->stmts);
 
-	return expr_evaluate_primary(ctx, expr);
+	return __expr_evaluate_exthdr(ctx, exprp);
 }
 
 /* dependency supersede.
@@ -509,12 +587,21 @@ static int __expr_evaluate_payload(struct eval_ctx *ctx, struct expr *expr)
 	return 0;
 }
 
-static int expr_evaluate_payload(struct eval_ctx *ctx, struct expr **expr)
+static int expr_evaluate_payload(struct eval_ctx *ctx, struct expr **exprp)
 {
-	if (__expr_evaluate_payload(ctx, *expr) < 0)
+	struct expr *expr = *exprp;
+
+	if (__expr_evaluate_payload(ctx, expr) < 0)
 		return -1;
 
-	return expr_evaluate_primary(ctx, expr);
+	if (expr_evaluate_primary(ctx, exprp) < 0)
+		return -1;
+
+	if (expr->payload.offset % BITS_PER_BYTE != 0 ||
+	    expr->len % BITS_PER_BYTE != 0)
+		expr_evaluate_bits(ctx, exprp);
+
+	return 0;
 }
 
 /*
@@ -1096,6 +1183,8 @@ static int binop_can_transfer(struct eval_ctx *ctx,
 						 "Comparison is always false");
 		return 1;
 	case OP_RSHIFT:
+		if (ctx->ectx.len < right->len + mpz_get_uint32(left->right->value))
+			ctx->ectx.len += mpz_get_uint32(left->right->value);
 		return 1;
 	case OP_XOR:
 		return 1;
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 3263043..e0c73c0 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -104,64 +104,6 @@ static void netlink_gen_concat(struct netlink_linearize_ctx *ctx,
 	}
 }
 
-static unsigned int payload_shift_calc(const struct expr *expr,
-				       unsigned int offset)
-{
-	unsigned int len;
-	int shift;
-
-	offset %= BITS_PER_BYTE;
-	len = round_up(expr->len, BITS_PER_BYTE);
-	shift = len - (offset + expr->len);
-	assert(shift >= 0);
-
-	return shift;
-}
-
-static void netlink_gen_mask(struct netlink_linearize_ctx *ctx,
-			     const struct expr *expr,
-			     unsigned int shift,
-			     enum nft_registers dreg)
-{
-	struct nft_data_linearize nld, zero = {};
-	unsigned int len, masklen;
-	struct nftnl_expr *nle;
-	mpz_t mask;
-
-	masklen = expr->len + shift;
-	assert(masklen <= NFT_REG_SIZE * BITS_PER_BYTE);
-	mpz_init2(mask, masklen);
-	mpz_bitmask(mask, expr->len);
-	mpz_lshift_ui(mask, shift);
-
-	nle = alloc_nft_expr("bitwise");
-
-	len = div_round_up(expr->len, BITS_PER_BYTE);
-
-	nftnl_expr_set_u32(nle, NFT_EXPR_BITWISE_SREG, dreg);
-	nftnl_expr_set_u32(nle, NFT_EXPR_BITWISE_DREG, dreg);
-	nftnl_expr_set_u32(nle, NFT_EXPR_BITWISE_LEN, len);
-
-	netlink_gen_raw_data(mask, expr->byteorder, len, &nld);
-	nftnl_expr_set(nle, NFT_EXPR_BITWISE_MASK, nld.value, nld.len);
-	nftnl_expr_set(nle, NFT_EXPR_BITWISE_XOR, &zero.value, nld.len);
-
-	mpz_clear(mask);
-	nftnl_rule_add_expr(ctx->nlr, nle);
-}
-
-static void netlink_gen_payload_mask(struct netlink_linearize_ctx *ctx,
-				     const struct expr *expr,
-				     enum nft_registers dreg)
-{
-	unsigned int shift, offset;
-
-	offset = expr->payload.offset % BITS_PER_BYTE;
-	shift = payload_shift_calc(expr, offset);
-	if (shift || offset)
-		netlink_gen_mask(ctx, expr, shift, dreg);
-}
-
 static void netlink_gen_payload(struct netlink_linearize_ctx *ctx,
 				const struct expr *expr,
 				enum nft_registers dreg)
@@ -178,20 +120,6 @@ static void netlink_gen_payload(struct netlink_linearize_ctx *ctx,
 			   div_round_up(expr->len, BITS_PER_BYTE));
 
 	nftnl_rule_add_expr(ctx->nlr, nle);
-
-	netlink_gen_payload_mask(ctx, expr, dreg);
-}
-
-static void netlink_gen_exthdr_mask(struct netlink_linearize_ctx *ctx,
-				    const struct expr *expr,
-				    enum nft_registers dreg)
-{
-	unsigned int shift, offset;
-
-	offset = expr->exthdr.tmpl->offset % BITS_PER_BYTE;
-	shift = payload_shift_calc(expr, offset);
-	if (shift || offset)
-		netlink_gen_mask(ctx, expr, shift, dreg);
 }
 
 static void netlink_gen_exthdr(struct netlink_linearize_ctx *ctx,
@@ -209,8 +137,6 @@ static void netlink_gen_exthdr(struct netlink_linearize_ctx *ctx,
 	nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_LEN,
 			   div_round_up(expr->len, BITS_PER_BYTE));
 	nftnl_rule_add_expr(ctx->nlr, nle);
-
-	netlink_gen_exthdr_mask(ctx, expr, dreg);
 }
 
 static void netlink_gen_meta(struct netlink_linearize_ctx *ctx,
@@ -319,28 +245,6 @@ static void netlink_gen_range(struct netlink_linearize_ctx *ctx,
 			      const struct expr *expr,
 			      enum nft_registers dreg);
 
-static void payload_shift_value(const struct expr *left, struct expr *right)
-{
-	unsigned int offset;
-
-	if (right->ops->type != EXPR_VALUE)
-		return;
-
-	switch (left->ops->type) {
-	case EXPR_PAYLOAD:
-		offset = left->payload.offset;
-		break;
-	case EXPR_EXTHDR:
-		offset = left->exthdr.tmpl->offset;
-		break;
-	default:
-		return;
-	}
-
-	mpz_lshift_ui(right->value,
-			payload_shift_calc(left, offset));
-}
-
 static struct expr *netlink_gen_prefix(struct netlink_linearize_ctx *ctx,
 				       const struct expr *expr,
 				       enum nft_registers sreg)
@@ -409,7 +313,6 @@ static void netlink_gen_cmp(struct netlink_linearize_ctx *ctx,
 	netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
 	nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP,
 			   netlink_gen_cmp_op(expr->op));
-	payload_shift_value(expr->left, right);
 	netlink_gen_data(right, &nld);
 	nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, len);
 	release_register(ctx, expr->left);
@@ -447,7 +350,6 @@ static void netlink_gen_range(struct netlink_linearize_ctx *ctx,
 		BUG("invalid range operation %u\n", expr->op);
 	}
 
-	payload_shift_value(expr->left, range->left);
 	netlink_gen_data(range->left, &nld);
 	nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, nld.len);
 	nftnl_rule_add_expr(ctx->nlr, nle);
@@ -468,7 +370,6 @@ static void netlink_gen_range(struct netlink_linearize_ctx *ctx,
 		BUG("invalid range operation %u\n", expr->op);
 	}
 
-	payload_shift_value(expr->left, range->right);
 	netlink_gen_data(range->right, &nld);
 	nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, nld.len);
 	nftnl_rule_add_expr(ctx->nlr, nle);
-- 
2.1.4


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

* [PATCH nft 05/12] evaluate: handle payload matching split in two bytes
  2016-05-11 21:05 [PATCH nft 01/12] evaluate: transfer right shifts to constant side Pablo Neira Ayuso
                   ` (2 preceding siblings ...)
  2016-05-11 21:05 ` [PATCH nft 04/12] src: move payload sub-byte matching to the evaluation step Pablo Neira Ayuso
@ 2016-05-11 21:05 ` Pablo Neira Ayuso
  2016-05-11 21:05 ` [PATCH nft 06/12] proto: update IPv6 flowlabel offset and length according to RFC2460 Pablo Neira Ayuso
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Pablo Neira Ayuso @ 2016-05-11 21:05 UTC (permalink / raw)
  To: netfilter-devel

When the bits are split between two bytes and the payload field is
smaller than one byte, we need to extend the expression length on both
sides (payload and constant) of the relational expression.

The existing trimming from the delinerization step handles the listing
for us, so no changes on that front.

This patch allows us to match the IPv6 DSCP field which falls into the
case that is described above.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/evaluate.c | 24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/src/evaluate.c b/src/evaluate.c
index ab73261..fcd4ecd 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -362,7 +362,8 @@ conflict_resolution_gen_dependency(struct eval_ctx *ctx, int protocol,
 	return 0;
 }
 
-static uint8_t expr_offset_shift(const struct expr *expr, unsigned int offset)
+static uint8_t expr_offset_shift(const struct expr *expr, unsigned int offset,
+				 unsigned int *extra_len)
 {
 	unsigned int new_offset, len;
 	int shift;
@@ -370,34 +371,38 @@ static uint8_t expr_offset_shift(const struct expr *expr, unsigned int offset)
 	new_offset = offset % BITS_PER_BYTE;
 	len = round_up(expr->len, BITS_PER_BYTE);
 	shift = len - (new_offset + expr->len);
-	assert(shift >= 0);
-
+	while (shift < 0) {
+		shift += BITS_PER_BYTE;
+		*extra_len += BITS_PER_BYTE;
+	}
 	return shift;
 }
 
 static void expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp)
 {
 	struct expr *expr = *exprp, *and, *mask, *lshift, *off;
-	unsigned masklen;
+	unsigned masklen, len = expr->len, extra_len = 0;
 	uint8_t shift;
 	mpz_t bitmask;
 
 	switch (expr->ops->type) {
 	case EXPR_PAYLOAD:
-		shift = expr_offset_shift(expr, expr->payload.offset);
+		shift = expr_offset_shift(expr, expr->payload.offset,
+					  &extra_len);
 		break;
 	case EXPR_EXTHDR:
-		shift = expr_offset_shift(expr, expr->exthdr.tmpl->offset);
+		shift = expr_offset_shift(expr, expr->exthdr.tmpl->offset,
+					  &extra_len);
 		break;
 	default:
 		BUG("Unknown expression %s\n", expr->ops->name);
 	}
 
-	masklen = expr->len + shift;
+	masklen = len + shift;
 	assert(masklen <= NFT_REG_SIZE * BITS_PER_BYTE);
 
 	mpz_init2(bitmask, masklen);
-	mpz_bitmask(bitmask, expr->len);
+	mpz_bitmask(bitmask, len);
 	mpz_lshift_ui(bitmask, shift);
 
 	mask = constant_expr_alloc(&expr->location, expr_basetype(expr),
@@ -423,6 +428,9 @@ static void expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp)
 		*exprp = lshift;
 	} else
 		*exprp = and;
+
+	if (extra_len)
+		expr->len += extra_len;
 }
 
 static int __expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)
-- 
2.1.4


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

* [PATCH nft 06/12] proto: update IPv6 flowlabel offset and length according to RFC2460
  2016-05-11 21:05 [PATCH nft 01/12] evaluate: transfer right shifts to constant side Pablo Neira Ayuso
                   ` (3 preceding siblings ...)
  2016-05-11 21:05 ` [PATCH nft 05/12] evaluate: handle payload matching split in two bytes Pablo Neira Ayuso
@ 2016-05-11 21:05 ` Pablo Neira Ayuso
  2016-05-11 21:05 ` [PATCH nft 07/12] proto: remove priority field definition from IPv6 header Pablo Neira Ayuso
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Pablo Neira Ayuso @ 2016-05-11 21:05 UTC (permalink / raw)
  To: netfilter-devel

This is a 20 bit field according to Section 3. IPv6 Header Format.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 doc/nft.xml                     | 2 +-
 src/proto.c                     | 2 +-
 tests/py/ip6/ip6.t.payload.inet | 4 ++++
 tests/py/ip6/ip6.t.payload.ip6  | 4 ++++
 4 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/doc/nft.xml b/doc/nft.xml
index e4d227c..19b5607 100644
--- a/doc/nft.xml
+++ b/doc/nft.xml
@@ -1479,7 +1479,7 @@ filter output oif eth0
 							<row>
 								<entry>flowlabel</entry>
 								<entry>Flow label</entry>
-								<entry></entry>
+								<entry>integer (20 bit)</entry>
 							</row>
 							<row>
 								<entry>length</entry>
diff --git a/src/proto.c b/src/proto.c
index cecde0f..9e972a3 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -643,7 +643,7 @@ const struct proto_desc proto_ip6 = {
 	.templates	= {
 		[IP6HDR_VERSION]	= HDR_BITFIELD("version", &integer_type, 0, 4),
 		[IP6HDR_PRIORITY]	= HDR_BITFIELD("priority", &integer_type, 4, 4),
-		[IP6HDR_FLOWLABEL]	= IP6HDR_FIELD("flowlabel",	flow_lbl),
+		[IP6HDR_FLOWLABEL]	= HDR_BITFIELD("flowlabel", &integer_type, 12, 20),
 		[IP6HDR_LENGTH]		= IP6HDR_FIELD("length",	payload_len),
 		[IP6HDR_NEXTHDR]	= INET_PROTOCOL("nexthdr", struct ipv6hdr, nexthdr),
 		[IP6HDR_HOPLIMIT]	= IP6HDR_FIELD("hoplimit",	hop_limit),
diff --git a/tests/py/ip6/ip6.t.payload.inet b/tests/py/ip6/ip6.t.payload.inet
index 4d2ea35..3d0ae39 100644
--- a/tests/py/ip6/ip6.t.payload.inet
+++ b/tests/py/ip6/ip6.t.payload.inet
@@ -3,6 +3,7 @@ inet test-inet input
   [ meta load nfproto => reg 1 ]
   [ cmp eq reg 1 0x0000000a ]
   [ payload load 3b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
   [ cmp eq reg 1 0x00160000 ]
 
 # ip6 flowlabel != 233
@@ -10,6 +11,7 @@ inet test-inet input
   [ meta load nfproto => reg 1 ]
   [ cmp eq reg 1 0x0000000a ]
   [ payload load 3b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
   [ cmp neq reg 1 0x00e90000 ]
 
 # ip6 flowlabel { 33, 55, 67, 88}
@@ -20,6 +22,7 @@ inet test-inet input
   [ meta load nfproto => reg 1 ]
   [ cmp eq reg 1 0x0000000a ]
   [ payload load 3b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
   [ lookup reg 1 set set%d ]
 
 # ip6 flowlabel { 33-55}
@@ -30,6 +33,7 @@ inet test-inet input
   [ meta load nfproto => reg 1 ]
   [ cmp eq reg 1 0x0000000a ]
   [ payload load 3b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
   [ lookup reg 1 set set%d ]
 
 # ip6 length 22
diff --git a/tests/py/ip6/ip6.t.payload.ip6 b/tests/py/ip6/ip6.t.payload.ip6
index db59bfb..55286ee 100644
--- a/tests/py/ip6/ip6.t.payload.ip6
+++ b/tests/py/ip6/ip6.t.payload.ip6
@@ -1,11 +1,13 @@
 # ip6 flowlabel 22
 ip6 test-ip6 input
   [ payload load 3b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
   [ cmp eq reg 1 0x00160000 ]
 
 # ip6 flowlabel != 233
 ip6 test-ip6 input
   [ payload load 3b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
   [ cmp neq reg 1 0x00e90000 ]
 
 # ip6 flowlabel { 33, 55, 67, 88}
@@ -14,6 +16,7 @@ set%d test-ip6 0
 	element 00210000  : 0 [end]	element 00370000  : 0 [end]	element 00430000  : 0 [end]	element 00580000  : 0 [end]
 ip6 test-ip6 input
   [ payload load 3b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
   [ lookup reg 1 set set%d ]
 
 # ip6 flowlabel { 33-55}
@@ -22,6 +25,7 @@ set%d test-ip6 0
 	element 00000000  : 1 [end]	element 00210000  : 0 [end]	element 00380000  : 1 [end]
 ip6 test-ip6 input
   [ payload load 3b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
   [ lookup reg 1 set set%d ]
 
 # ip6 length 22
-- 
2.1.4


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

* [PATCH nft 07/12] proto: remove priority field definition from IPv6 header
  2016-05-11 21:05 [PATCH nft 01/12] evaluate: transfer right shifts to constant side Pablo Neira Ayuso
                   ` (4 preceding siblings ...)
  2016-05-11 21:05 ` [PATCH nft 06/12] proto: update IPv6 flowlabel offset and length according to RFC2460 Pablo Neira Ayuso
@ 2016-05-11 21:05 ` Pablo Neira Ayuso
  2016-05-11 21:05 ` [PATCH nft 08/12] src: add dscp support Pablo Neira Ayuso
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Pablo Neira Ayuso @ 2016-05-11 21:05 UTC (permalink / raw)
  To: netfilter-devel

This is actually part of the traffic class field according to RFC2460.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/proto.c        | 1 -
 tests/py/ip6/ip6.t | 8 --------
 2 files changed, 9 deletions(-)

diff --git a/src/proto.c b/src/proto.c
index 9e972a3..fb774b1 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -642,7 +642,6 @@ const struct proto_desc proto_ip6 = {
 	},
 	.templates	= {
 		[IP6HDR_VERSION]	= HDR_BITFIELD("version", &integer_type, 0, 4),
-		[IP6HDR_PRIORITY]	= HDR_BITFIELD("priority", &integer_type, 4, 4),
 		[IP6HDR_FLOWLABEL]	= HDR_BITFIELD("flowlabel", &integer_type, 12, 20),
 		[IP6HDR_LENGTH]		= IP6HDR_FIELD("length",	payload_len),
 		[IP6HDR_NEXTHDR]	= INET_PROTOCOL("nexthdr", struct ipv6hdr, nexthdr),
diff --git a/tests/py/ip6/ip6.t b/tests/py/ip6/ip6.t
index 2a1eee7..8226130 100644
--- a/tests/py/ip6/ip6.t
+++ b/tests/py/ip6/ip6.t
@@ -9,14 +9,6 @@
 # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 - ip6 version 6;ok
-- ip6 priority 3;ok
-
-# $ sudo nft add rule ip6 test6 input ip6 priority 33
-# <cmdline>:1:39-40: Error: Value 33 exceeds valid range 0-15
-# $ sudo nft add rule ip6 test6 input ip6 priority 3
-# <cmdline>:1:1-39: Error: Could not process rule: Invalid argument
-# add rule ip6 test6 input ip6 priority 3
-#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ip6 flowlabel 22;ok
 ip6 flowlabel != 233;ok
-- 
2.1.4


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

* [PATCH nft 08/12] src: add dscp support
  2016-05-11 21:05 [PATCH nft 01/12] evaluate: transfer right shifts to constant side Pablo Neira Ayuso
                   ` (5 preceding siblings ...)
  2016-05-11 21:05 ` [PATCH nft 07/12] proto: remove priority field definition from IPv6 header Pablo Neira Ayuso
@ 2016-05-11 21:05 ` Pablo Neira Ayuso
  2016-05-11 21:05 ` [PATCH nft 09/12] src: add ecn support Pablo Neira Ayuso
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Pablo Neira Ayuso @ 2016-05-11 21:05 UTC (permalink / raw)
  To: netfilter-devel

This supports both IPv4:

 # nft --debug=netlink add rule filter forward ip dscp cs1 counter
 ip filter forward
  [ payload load 1b @ network header + 1 => reg 1 ]
  [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
  [ cmp neq reg 1 0x00000080 ]
  [ counter pkts 0 bytes 0 ]

And also IPv6, note that in this case we take two bytes from the payload:

 # nft --debug=netlink add rule ip6 filter input ip6 dscp cs4 counter
 ip6 filter input
  [ payload load 2b @ network header + 0 => reg 1 ]
  [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
  [ cmp eq reg 1 0x00000008 ]
  [ counter pkts 0 bytes 0 ]

Given the DSCP is split in two bytes, the less significant nibble
of the first byte and the two most significant 2 bits of the second
byte.

The 8 bit traffic class in RFC2460 after the version field are used for
DSCP (6 bit) and ECN (2 bit). Support for ECN comes in a follow up
patch.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 doc/nft.xml                     | 11 +++++++---
 include/datatype.h              |  2 ++
 include/proto.h                 |  4 ++--
 src/parser_bison.y              |  7 +++---
 src/proto.c                     | 48 ++++++++++++++++++++++++++++++++++++++---
 src/scanner.l                   |  2 +-
 tests/py/ip/ip.t                | 10 ++++-----
 tests/py/ip/ip.t.payload        | 33 ++++++++++++++++++++++++++++
 tests/py/ip/ip.t.payload.inet   | 43 ++++++++++++++++++++++++++++++++++++
 tests/py/ip6/ip6.t              |  6 ++++++
 tests/py/ip6/ip6.t.payload.inet | 43 ++++++++++++++++++++++++++++++++++++
 tests/py/ip6/ip6.t.payload.ip6  | 33 ++++++++++++++++++++++++++++
 12 files changed, 225 insertions(+), 17 deletions(-)

diff --git a/doc/nft.xml b/doc/nft.xml
index 19b5607..a2770bf 100644
--- a/doc/nft.xml
+++ b/doc/nft.xml
@@ -1393,9 +1393,9 @@ filter output oif eth0
 								<entry>integer (4 bit) FIXME scaling</entry>
 							</row>
 							<row>
-								<entry>tos</entry>
-								<entry>Type Of Service</entry>
-								<entry>FIXME</entry>
+								<entry>dscp</entry>
+								<entry>Differentiated Services Code Point</entry>
+								<entry>integer (6 bit)</entry>
 							</row>
 							<row>
 								<entry>length</entry>
@@ -1477,6 +1477,11 @@ filter output oif eth0
 								<entry></entry>
 							</row>
 							<row>
+								<entry>dscp</entry>
+								<entry>Differentiated Services Code Point</entry>
+								<entry>integer (6 bit)</entry>
+							</row>
+							<row>
 								<entry>flowlabel</entry>
 								<entry>Flow label</entry>
 								<entry>integer (20 bit)</entry>
diff --git a/include/datatype.h b/include/datatype.h
index 91ca2dd..e385bac 100644
--- a/include/datatype.h
+++ b/include/datatype.h
@@ -40,6 +40,7 @@
  * @TYPE_ICMPV6_CODE:	icmpv6 code (integer subtype)
  * @TYPE_ICMPX_CODE:	icmpx code (integer subtype)
  * @TYPE_DEVGROUP:	devgroup code (integer subtype)
+ * @TYPE_DSCP:		Differentiated Services Code Point (integer subtype)
  */
 enum datatypes {
 	TYPE_INVALID,
@@ -78,6 +79,7 @@ enum datatypes {
 	TYPE_ICMPV6_CODE,
 	TYPE_ICMPX_CODE,
 	TYPE_DEVGROUP,
+	TYPE_DSCP,
 	__TYPE_MAX
 };
 #define TYPE_MAX		(__TYPE_MAX - 1)
diff --git a/include/proto.h b/include/proto.h
index 2a662a1..14af965 100644
--- a/include/proto.h
+++ b/include/proto.h
@@ -183,7 +183,7 @@ enum ip_hdr_fields {
 	IPHDR_INVALID,
 	IPHDR_VERSION,
 	IPHDR_HDRLENGTH,
-	IPHDR_TOS,
+	IPHDR_DSCP,
 	IPHDR_LENGTH,
 	IPHDR_ID,
 	IPHDR_FRAG_OFF,
@@ -220,7 +220,7 @@ enum icmp6_hdr_fields {
 enum ip6_hdr_fields {
 	IP6HDR_INVALID,
 	IP6HDR_VERSION,
-	IP6HDR_PRIORITY,
+	IP6HDR_DSCP,
 	IP6HDR_FLOWLABEL,
 	IP6HDR_LENGTH,
 	IP6HDR_NEXTHDR,
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 444ed4c..490047b 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -248,7 +248,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %token IP			"ip"
 %token HDRVERSION		"version"
 %token HDRLENGTH		"hdrlength"
-%token TOS			"tos"
+%token DSCP			"dscp"
 %token LENGTH			"length"
 %token FRAG_OFF			"frag-off"
 %token TTL			"ttl"
@@ -1102,6 +1102,7 @@ type_identifier_list	:	type_identifier
 
 type_identifier		:	STRING	{ $$ = $1; }
 			|	MARK	{ $$ = xstrdup("mark"); }
+			|	DSCP	{ $$ = xstrdup("dscp"); }
 			;
 
 hook_spec		:	TYPE		STRING		HOOK		STRING		dev_spec	PRIORITY	prio_spec
@@ -2403,7 +2404,7 @@ ip_hdr_expr		:	IP	ip_hdr_field
 
 ip_hdr_field		:	HDRVERSION	{ $$ = IPHDR_VERSION; }
 			|	HDRLENGTH	{ $$ = IPHDR_HDRLENGTH; }
-			|	TOS		{ $$ = IPHDR_TOS; }
+			|	DSCP		{ $$ = IPHDR_DSCP; }
 			|	LENGTH		{ $$ = IPHDR_LENGTH; }
 			|	ID		{ $$ = IPHDR_ID; }
 			|	FRAG_OFF	{ $$ = IPHDR_FRAG_OFF; }
@@ -2436,7 +2437,7 @@ ip6_hdr_expr		:	IP6	ip6_hdr_field
 			;
 
 ip6_hdr_field		:	HDRVERSION	{ $$ = IP6HDR_VERSION; }
-			|	PRIORITY	{ $$ = IP6HDR_PRIORITY; }
+			|	DSCP		{ $$ = IP6HDR_DSCP; }
 			|	FLOWLABEL	{ $$ = IP6HDR_FLOWLABEL; }
 			|	LENGTH		{ $$ = IP6HDR_LENGTH; }
 			|	NEXTHDR		{ $$ = IP6HDR_NEXTHDR; }
diff --git a/src/proto.c b/src/proto.c
index fb774b1..4c65e1c 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -512,6 +512,46 @@ const struct proto_desc proto_sctp = {
  */
 
 #include <netinet/ip.h>
+
+static const struct symbol_table dscp_type_tbl = {
+	.symbols	= {
+		SYMBOL("cs0",	0x00),
+		SYMBOL("cs1",	0x08),
+		SYMBOL("cs2",	0x10),
+		SYMBOL("cs3",	0x18),
+		SYMBOL("cs4",	0x20),
+		SYMBOL("cs5",	0x28),
+		SYMBOL("cs6",	0x30),
+		SYMBOL("cs7",	0x38),
+		SYMBOL("be",	0x00),
+		SYMBOL("af11",	0x0a),
+		SYMBOL("af12",	0x0c),
+		SYMBOL("af13",	0x0e),
+		SYMBOL("af21",	0x12),
+		SYMBOL("af22",	0x14),
+		SYMBOL("af23",	0x16),
+		SYMBOL("af31",	0x1a),
+		SYMBOL("af32",	0x1c),
+		SYMBOL("af33",	0x1e),
+		SYMBOL("af41",	0x22),
+		SYMBOL("af42",	0x24),
+		SYMBOL("af43",	0x26),
+		SYMBOL("ef",	0x2e),
+		SYMBOL_LIST_END
+	},
+};
+
+static const struct datatype dscp_type = {
+	.type		= TYPE_DSCP,
+	.name		= "dscp",
+	.desc		= "Differentiated Services Code Point",
+	.byteorder	= BYTEORDER_BIG_ENDIAN,
+	.size		= 6,
+	.basetype	= &integer_type,
+	.basefmt	= "0x%.2Zx",
+	.sym_tbl	= &dscp_type_tbl,
+};
+
 #define IPHDR_FIELD(__name, __member) \
 	HDR_FIELD(__name, struct iphdr, __member)
 #define IPHDR_ADDR(__name, __member) \
@@ -536,7 +576,7 @@ const struct proto_desc proto_ip = {
 	.templates	= {
 		[IPHDR_VERSION]		= HDR_BITFIELD("version", &integer_type, 0, 4),
 		[IPHDR_HDRLENGTH]	= HDR_BITFIELD("hdrlength", &integer_type, 4, 4),
-		[IPHDR_TOS]		= IPHDR_FIELD("tos",		tos),
+		[IPHDR_DSCP]            = HDR_BITFIELD("dscp", &dscp_type, 8, 6),
 		[IPHDR_LENGTH]		= IPHDR_FIELD("length",		tot_len),
 		[IPHDR_ID]		= IPHDR_FIELD("id",		id),
 		[IPHDR_FRAG_OFF]	= IPHDR_FIELD("frag-off",	frag_off),
@@ -548,7 +588,7 @@ const struct proto_desc proto_ip = {
 	},
 	.format		= {
 		.order	= {
-			IPHDR_SADDR, IPHDR_DADDR, IPHDR_TOS, IPHDR_TTL,
+			IPHDR_SADDR, IPHDR_DADDR, IPHDR_DSCP, IPHDR_TTL,
 			IPHDR_ID, IPHDR_PROTOCOL, IPHDR_LENGTH,
 		},
 		.filter	= (1 << IPHDR_VERSION)  | (1 << IPHDR_HDRLENGTH) |
@@ -642,6 +682,7 @@ const struct proto_desc proto_ip6 = {
 	},
 	.templates	= {
 		[IP6HDR_VERSION]	= HDR_BITFIELD("version", &integer_type, 0, 4),
+		[IP6HDR_DSCP]		= HDR_BITFIELD("dscp", &dscp_type, 4, 6),
 		[IP6HDR_FLOWLABEL]	= HDR_BITFIELD("flowlabel", &integer_type, 12, 20),
 		[IP6HDR_LENGTH]		= IP6HDR_FIELD("length",	payload_len),
 		[IP6HDR_NEXTHDR]	= INET_PROTOCOL("nexthdr", struct ipv6hdr, nexthdr),
@@ -651,7 +692,7 @@ const struct proto_desc proto_ip6 = {
 	},
 	.format		= {
 		.order	= {
-			IP6HDR_SADDR, IP6HDR_DADDR, IP6HDR_PRIORITY,
+			IP6HDR_SADDR, IP6HDR_DADDR, IP6HDR_DSCP,
 			IP6HDR_HOPLIMIT, IP6HDR_FLOWLABEL, IP6HDR_NEXTHDR,
 			IP6HDR_LENGTH,
 		},
@@ -881,4 +922,5 @@ static void __init proto_init(void)
 	datatype_register(&arpop_type);
 	datatype_register(&ethertype_type);
 	datatype_register(&icmp6_type_type);
+	datatype_register(&dscp_type);
 }
diff --git a/src/scanner.l b/src/scanner.l
index 60b61a5..275beaa 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -362,7 +362,7 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 "ip"			{ return IP; }
 "version"		{ return HDRVERSION; }
 "hdrlength"		{ return HDRLENGTH; }
-"tos"			{ return TOS; }
+"dscp"			{ return DSCP; }
 "length"		{ return LENGTH; }
 "frag-off"		{ return FRAG_OFF; }
 "ttl"			{ return TTL; }
diff --git a/tests/py/ip/ip.t b/tests/py/ip/ip.t
index 6dd8fe6..594136c 100644
--- a/tests/py/ip/ip.t
+++ b/tests/py/ip/ip.t
@@ -23,11 +23,11 @@
 # <cmdline>:1:37-38: Error: Value 22 exceeds valid range 0-15
 # add rule ip test input ip hdrlength 22
 
-- ip dscp CS1;ok
-- ip dscp != CS1;ok
-- ip dscp 0x38;ok
-- ip dscp != 0x20;ok
-- ip dscp {CS1, CS2, CS3, CS4, CS5, CS6, CS7, BE, AF11, AF12, AF13, AF21, AF22, AF23, AF31, AF32, AF33, AF41, AF42, AF43, EF};ok
+ip dscp cs1;ok
+ip dscp != cs1;ok
+ip dscp 0x38;ok;ip dscp cs7
+ip dscp != 0x20;ok;ip dscp != cs4
+ip dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef};ok
 - ip dscp {0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x00, 0x0a, 0x0c, 0x0e, 0x12, 0x14, 0x16, 0x1a, 0x1c, 0x1e, 0x22, 0x24, 0x26, 0x2e};ok
 - ip dscp != {CS0, CS3};ok
 
diff --git a/tests/py/ip/ip.t.payload b/tests/py/ip/ip.t.payload
index aa3bfe9..2d4fe42 100644
--- a/tests/py/ip/ip.t.payload
+++ b/tests/py/ip/ip.t.payload
@@ -1,3 +1,36 @@
+# ip dscp cs1
+ip test-ip4 input
+  [ payload load 1b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+  [ cmp eq reg 1 0x00000020 ]
+
+# ip dscp != cs1
+ip test-ip4 input
+  [ payload load 1b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+  [ cmp neq reg 1 0x00000020 ]
+
+# ip dscp 0x38
+ip test-ip4 input
+  [ payload load 1b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+  [ cmp eq reg 1 0x000000e0 ]
+
+# ip dscp != 0x20
+ip test-ip4 input
+  [ payload load 1b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+  [ cmp neq reg 1 0x00000080 ]
+
+# ip dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
+set%d test-ip4 3
+set%d test-ip4 0
+        element 00000020  : 0 [end]     element 00000040  : 0 [end]     element 00000060  : 0 [end]     element 00000080  : 0 [end]    element 000000a0  : 0 [end]      element 000000c0  : 0 [end]     element 000000e0  : 0 [end]     element 00000000  : 0 [end]     element 00000028  : 0 [end]     element 00000030  : 0 [end]     element 00000038  : 0 [end]     element 00000048  : 0 [end]     element 00000050  : 0 [end]     element 00000058  : 0 [end]     element 00000068  : 0 [end]     element 00000070  : 0 [end]     element 00000078  : 0 [end]     element 00000088  : 0 [end]     element 00000090  : 0 [end]     element 00000098  : 0 [end]     element 000000b8  : 0 [end]
+ip test-ip4 input
+  [ payload load 1b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+  [ lookup reg 1 set set%d ]
+
 # ip length 232
 ip test-ip4 input
   [ payload load 2b @ network header + 2 => reg 1 ]
diff --git a/tests/py/ip/ip.t.payload.inet b/tests/py/ip/ip.t.payload.inet
index 4d4d485..72b5e07 100644
--- a/tests/py/ip/ip.t.payload.inet
+++ b/tests/py/ip/ip.t.payload.inet
@@ -1,3 +1,46 @@
+# ip dscp cs1
+inet test-inet input
+  [ meta load nfproto => reg 1 ]
+  [ cmp eq reg 1 0x00000002 ]
+  [ payload load 1b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+  [ cmp eq reg 1 0x00000020 ]
+
+# ip dscp != cs1
+inet test-inet input
+  [ meta load nfproto => reg 1 ]
+  [ cmp eq reg 1 0x00000002 ]
+  [ payload load 1b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+  [ cmp neq reg 1 0x00000020 ]
+
+# ip dscp 0x38
+inet test-inet input
+  [ meta load nfproto => reg 1 ]
+  [ cmp eq reg 1 0x00000002 ]
+  [ payload load 1b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+  [ cmp eq reg 1 0x000000e0 ]
+
+# ip dscp != 0x20
+inet test-inet input
+  [ meta load nfproto => reg 1 ]
+  [ cmp eq reg 1 0x00000002 ]
+  [ payload load 1b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+  [ cmp neq reg 1 0x00000080 ]
+
+# ip dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
+set%d test-inet 3
+set%d test-inet 0
+        element 00000020  : 0 [end]     element 00000040  : 0 [end]     element 00000060  : 0 [end]     element 00000080  : 0 [end]    element 000000a0  : 0 [end]      element 000000c0  : 0 [end]     element 000000e0  : 0 [end]     element 00000000  : 0 [end]     element 00000028  : 0 [end]     element 00000030  : 0 [end]     element 00000038  : 0 [end]     element 00000048  : 0 [end]     element 00000050  : 0 [end]     element 00000058  : 0 [end]     element 00000068  : 0 [end]     element 00000070  : 0 [end]     element 00000078  : 0 [end]     element 00000088  : 0 [end]     element 00000090  : 0 [end]     element 00000098  : 0 [end]     element 000000b8  : 0 [end]
+inet test-inet input
+  [ meta load nfproto => reg 1 ]
+  [ cmp eq reg 1 0x00000002 ]
+  [ payload load 1b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+  [ lookup reg 1 set set%d ]
+
 # ip length 232
 inet test-inet input
   [ meta load nfproto => reg 1 ]
diff --git a/tests/py/ip6/ip6.t b/tests/py/ip6/ip6.t
index 8226130..2278618 100644
--- a/tests/py/ip6/ip6.t
+++ b/tests/py/ip6/ip6.t
@@ -10,6 +10,12 @@
 
 - ip6 version 6;ok
 
+ip6 dscp cs1;ok
+ip6 dscp != cs1;ok
+ip6 dscp 0x38;ok;ip6 dscp cs7
+ip6 dscp != 0x20;ok;ip6 dscp != cs4
+ip6 dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef};ok
+
 ip6 flowlabel 22;ok
 ip6 flowlabel != 233;ok
 - ip6 flowlabel 33-45;ok
diff --git a/tests/py/ip6/ip6.t.payload.inet b/tests/py/ip6/ip6.t.payload.inet
index 3d0ae39..35e77c1 100644
--- a/tests/py/ip6/ip6.t.payload.inet
+++ b/tests/py/ip6/ip6.t.payload.inet
@@ -1,3 +1,46 @@
+# ip6 dscp cs1
+inet test-inet input 
+  [ meta load nfproto => reg 1 ]
+  [ cmp eq reg 1 0x0000000a ]
+  [ payload load 2b @ network header + 0 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+  [ cmp eq reg 1 0x00000002 ]
+
+# ip6 dscp != cs1
+inet test-inet input 
+  [ meta load nfproto => reg 1 ]
+  [ cmp eq reg 1 0x0000000a ]
+  [ payload load 2b @ network header + 0 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+  [ cmp neq reg 1 0x00000002 ]
+
+# ip6 dscp 0x38
+inet test-inet input 
+  [ meta load nfproto => reg 1 ]
+  [ cmp eq reg 1 0x0000000a ]
+  [ payload load 2b @ network header + 0 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+  [ cmp eq reg 1 0x0000000e ]
+
+# ip6 dscp != 0x20
+inet test-inet input 
+  [ meta load nfproto => reg 1 ]
+  [ cmp eq reg 1 0x0000000a ]
+  [ payload load 2b @ network header + 0 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+  [ cmp neq reg 1 0x00000008 ]
+
+# ip6 dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
+set%d test-inet 3
+set%d test-inet 0
+        element 00000000  : 0 [end]     element 00000002  : 0 [end]     element 00000004  : 0 [end]     element 00000006  : 0 [end]    element 00000008  : 0 [end]      element 0000000a  : 0 [end]     element 0000000c  : 0 [end]     element 0000000e  : 0 [end]     element 00008002  : 0 [end]     element 00000003  : 0 [end]     element 00008003  : 0 [end]     element 00008004  : 0 [end]     element 00000005  : 0 [end]     element 00008005  : 0 [end]     element 00008006  : 0 [end]     element 00000007  : 0 [end]     element 00008007  : 0 [end]     element 00008008  : 0 [end]     element 00000009  : 0 [end]     element 00008009  : 0 [end]     element 0000800b  : 0 [end]
+inet test-inet input 
+  [ meta load nfproto => reg 1 ]
+  [ cmp eq reg 1 0x0000000a ]
+  [ payload load 2b @ network header + 0 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+  [ lookup reg 1 set set%d ]
+
 # ip6 flowlabel 22
 inet test-inet input
   [ meta load nfproto => reg 1 ]
diff --git a/tests/py/ip6/ip6.t.payload.ip6 b/tests/py/ip6/ip6.t.payload.ip6
index 55286ee..7c9d1f5 100644
--- a/tests/py/ip6/ip6.t.payload.ip6
+++ b/tests/py/ip6/ip6.t.payload.ip6
@@ -1,3 +1,36 @@
+# ip6 dscp cs1
+ip6 test-ip6 input
+  [ payload load 2b @ network header + 0 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+  [ cmp eq reg 1 0x00000002 ]
+
+# ip6 dscp != cs1
+ip6 test-ip6 input
+  [ payload load 2b @ network header + 0 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+  [ cmp neq reg 1 0x00000002 ]
+
+# ip6 dscp 0x38
+ip6 test-ip6 input
+  [ payload load 2b @ network header + 0 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+  [ cmp eq reg 1 0x0000000e ]
+
+# ip6 dscp != 0x20
+ip6 test-ip6 input
+  [ payload load 2b @ network header + 0 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+  [ cmp neq reg 1 0x00000008 ]
+
+# ip6 dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
+set%d test-ip6 3
+set%d test-ip6 0
+        element 00000002  : 0 [end]     element 00000004  : 0 [end]     element 00000006  : 0 [end]     element 00000008  : 0 [end]    element 0000000a  : 0 [end]      element 0000000c  : 0 [end]     element 0000000e  : 0 [end]     element 00000000  : 0 [end]     element 00008002  : 0 [end]     element 00000003  : 0 [end]     element 00008003  : 0 [end]     element 00008004  : 0 [end]     element 00000005  : 0 [end]     element 00008005  : 0 [end]     element 00008006  : 0 [end]     element 00000007  : 0 [end]     element 00008007  : 0 [end]     element 00008008  : 0 [end]     element 00000009  : 0 [end]     element 00008009  : 0 [end]     element 0000800b  : 0 [end]
+ip6 test-ip6 input
+  [ payload load 2b @ network header + 0 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+  [ lookup reg 1 set set%d ]
+
 # ip6 flowlabel 22
 ip6 test-ip6 input
   [ payload load 3b @ network header + 1 => reg 1 ]
-- 
2.1.4


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

* [PATCH nft 09/12] src: add ecn support
  2016-05-11 21:05 [PATCH nft 01/12] evaluate: transfer right shifts to constant side Pablo Neira Ayuso
                   ` (6 preceding siblings ...)
  2016-05-11 21:05 ` [PATCH nft 08/12] src: add dscp support Pablo Neira Ayuso
@ 2016-05-11 21:05 ` Pablo Neira Ayuso
  2016-05-11 21:05 ` [PATCH nft 10/12] tests/py: add missing netdev ip dscp payload tests Pablo Neira Ayuso
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Pablo Neira Ayuso @ 2016-05-11 21:05 UTC (permalink / raw)
  To: netfilter-devel

This supports both IPv4:

 # nft --debug=netlink add rule ip filter forward ip ecn ce counter
 ip filter forward
  [ payload load 1b @ network header + 1 => reg 1 ]
  [ bitwise reg 1 = (reg=1 & 0x00000003 ) ^ 0x00000000 ]
  [ cmp eq reg 1 0x00000003 ]
  [ counter pkts 0 bytes 0 ]

For IPv6:

 # nft --debug=netlink add rule ip6 filter forward ip6 ecn ce counter
 ip6 filter forward
  [ payload load 1b @ network header + 1 => reg 1 ]
  [ bitwise reg 1 = (reg=1 & 0x00000030 ) ^ 0x00000000 ]
  [ cmp eq reg 1 0x00000030 ]
  [ counter pkts 0 bytes 0 ]

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 doc/nft.xml        | 10 ++++++++++
 include/datatype.h |  1 +
 include/proto.h    |  2 ++
 src/parser_bison.y | 10 ++++++++++
 src/proto.c        | 30 +++++++++++++++++++++++++++---
 src/scanner.l      |  1 +
 6 files changed, 51 insertions(+), 3 deletions(-)

diff --git a/doc/nft.xml b/doc/nft.xml
index a2770bf..22d023e 100644
--- a/doc/nft.xml
+++ b/doc/nft.xml
@@ -1398,6 +1398,11 @@ filter output oif eth0
 								<entry>integer (6 bit)</entry>
 							</row>
 							<row>
+								<entry>ecn</entry>
+								<entry>Explicit Congestion Notification</entry>
+								<entry>integer (2 bit)</entry>
+							</row>
+							<row>
 								<entry>length</entry>
 								<entry>Total packet length</entry>
 								<entry>integer (16 bit)</entry>
@@ -1482,6 +1487,11 @@ filter output oif eth0
 								<entry>integer (6 bit)</entry>
 							</row>
 							<row>
+								<entry>ecn</entry>
+								<entry>Explicit Congestion Notification</entry>
+								<entry>integer (2 bit)</entry>
+							</row>
+							<row>
 								<entry>flowlabel</entry>
 								<entry>Flow label</entry>
 								<entry>integer (20 bit)</entry>
diff --git a/include/datatype.h b/include/datatype.h
index e385bac..c7e110f 100644
--- a/include/datatype.h
+++ b/include/datatype.h
@@ -80,6 +80,7 @@ enum datatypes {
 	TYPE_ICMPX_CODE,
 	TYPE_DEVGROUP,
 	TYPE_DSCP,
+	TYPE_ECN,
 	__TYPE_MAX
 };
 #define TYPE_MAX		(__TYPE_MAX - 1)
diff --git a/include/proto.h b/include/proto.h
index 14af965..4fa54a7 100644
--- a/include/proto.h
+++ b/include/proto.h
@@ -184,6 +184,7 @@ enum ip_hdr_fields {
 	IPHDR_VERSION,
 	IPHDR_HDRLENGTH,
 	IPHDR_DSCP,
+	IPHDR_ECN,
 	IPHDR_LENGTH,
 	IPHDR_ID,
 	IPHDR_FRAG_OFF,
@@ -221,6 +222,7 @@ enum ip6_hdr_fields {
 	IP6HDR_INVALID,
 	IP6HDR_VERSION,
 	IP6HDR_DSCP,
+	IP6HDR_ECN,
 	IP6HDR_FLOWLABEL,
 	IP6HDR_LENGTH,
 	IP6HDR_NEXTHDR,
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 490047b..b8d3386 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -249,6 +249,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %token HDRVERSION		"version"
 %token HDRLENGTH		"hdrlength"
 %token DSCP			"dscp"
+%token ECN			"ecn"
 %token LENGTH			"length"
 %token FRAG_OFF			"frag-off"
 %token TTL			"ttl"
@@ -1103,6 +1104,7 @@ type_identifier_list	:	type_identifier
 type_identifier		:	STRING	{ $$ = $1; }
 			|	MARK	{ $$ = xstrdup("mark"); }
 			|	DSCP	{ $$ = xstrdup("dscp"); }
+			|	ECN	{ $$ = xstrdup("ecn"); }
 			;
 
 hook_spec		:	TYPE		STRING		HOOK		STRING		dev_spec	PRIORITY	prio_spec
@@ -2187,6 +2189,12 @@ primary_rhs_expr	:	symbol_expr		{ $$ = $1; }
 						       current_scope(state),
 						       "dnat");
 			}
+			|	ECN
+			{
+				$$ = symbol_expr_alloc(&@$, SYMBOL_VALUE,
+						       current_scope(state),
+						       "ecn");
+			}
 			;
 
 relational_op		:	EQ		{ $$ = OP_EQ; }
@@ -2405,6 +2413,7 @@ ip_hdr_expr		:	IP	ip_hdr_field
 ip_hdr_field		:	HDRVERSION	{ $$ = IPHDR_VERSION; }
 			|	HDRLENGTH	{ $$ = IPHDR_HDRLENGTH; }
 			|	DSCP		{ $$ = IPHDR_DSCP; }
+			|	ECN		{ $$ = IPHDR_ECN; }
 			|	LENGTH		{ $$ = IPHDR_LENGTH; }
 			|	ID		{ $$ = IPHDR_ID; }
 			|	FRAG_OFF	{ $$ = IPHDR_FRAG_OFF; }
@@ -2438,6 +2447,7 @@ ip6_hdr_expr		:	IP6	ip6_hdr_field
 
 ip6_hdr_field		:	HDRVERSION	{ $$ = IP6HDR_VERSION; }
 			|	DSCP		{ $$ = IP6HDR_DSCP; }
+			|	ECN		{ $$ = IP6HDR_ECN; }
 			|	FLOWLABEL	{ $$ = IP6HDR_FLOWLABEL; }
 			|	LENGTH		{ $$ = IP6HDR_LENGTH; }
 			|	NEXTHDR		{ $$ = IP6HDR_NEXTHDR; }
diff --git a/src/proto.c b/src/proto.c
index 4c65e1c..4c12977 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -552,6 +552,27 @@ static const struct datatype dscp_type = {
 	.sym_tbl	= &dscp_type_tbl,
 };
 
+static const struct symbol_table ecn_type_tbl = {
+	.symbols	= {
+		SYMBOL("not-ect",	0x00),
+		SYMBOL("ect1",		0x01),
+		SYMBOL("ect0",		0x02),
+		SYMBOL("ce",		0x03),
+		SYMBOL_LIST_END
+	},
+};
+
+static const struct datatype ecn_type = {
+	.type		= TYPE_ECN,
+	.name		= "ecn",
+	.desc		= "Explicit Congestion Notification",
+	.byteorder	= BYTEORDER_BIG_ENDIAN,
+	.size		= 2,
+	.basetype	= &integer_type,
+	.basefmt	= "0x%.1Zx",
+	.sym_tbl	= &ecn_type_tbl,
+};
+
 #define IPHDR_FIELD(__name, __member) \
 	HDR_FIELD(__name, struct iphdr, __member)
 #define IPHDR_ADDR(__name, __member) \
@@ -577,6 +598,7 @@ const struct proto_desc proto_ip = {
 		[IPHDR_VERSION]		= HDR_BITFIELD("version", &integer_type, 0, 4),
 		[IPHDR_HDRLENGTH]	= HDR_BITFIELD("hdrlength", &integer_type, 4, 4),
 		[IPHDR_DSCP]            = HDR_BITFIELD("dscp", &dscp_type, 8, 6),
+		[IPHDR_ECN]		= HDR_BITFIELD("ecn", &ecn_type, 14, 2),
 		[IPHDR_LENGTH]		= IPHDR_FIELD("length",		tot_len),
 		[IPHDR_ID]		= IPHDR_FIELD("id",		id),
 		[IPHDR_FRAG_OFF]	= IPHDR_FIELD("frag-off",	frag_off),
@@ -588,8 +610,8 @@ const struct proto_desc proto_ip = {
 	},
 	.format		= {
 		.order	= {
-			IPHDR_SADDR, IPHDR_DADDR, IPHDR_DSCP, IPHDR_TTL,
-			IPHDR_ID, IPHDR_PROTOCOL, IPHDR_LENGTH,
+			IPHDR_SADDR, IPHDR_DADDR, IPHDR_DSCP, IPHDR_ECN,
+			IPHDR_TTL, IPHDR_ID, IPHDR_PROTOCOL, IPHDR_LENGTH,
 		},
 		.filter	= (1 << IPHDR_VERSION)  | (1 << IPHDR_HDRLENGTH) |
 			  (1 << IPHDR_FRAG_OFF),
@@ -683,6 +705,7 @@ const struct proto_desc proto_ip6 = {
 	.templates	= {
 		[IP6HDR_VERSION]	= HDR_BITFIELD("version", &integer_type, 0, 4),
 		[IP6HDR_DSCP]		= HDR_BITFIELD("dscp", &dscp_type, 4, 6),
+		[IP6HDR_ECN]		= HDR_BITFIELD("ecn", &ecn_type, 10, 2),
 		[IP6HDR_FLOWLABEL]	= HDR_BITFIELD("flowlabel", &integer_type, 12, 20),
 		[IP6HDR_LENGTH]		= IP6HDR_FIELD("length",	payload_len),
 		[IP6HDR_NEXTHDR]	= INET_PROTOCOL("nexthdr", struct ipv6hdr, nexthdr),
@@ -692,7 +715,7 @@ const struct proto_desc proto_ip6 = {
 	},
 	.format		= {
 		.order	= {
-			IP6HDR_SADDR, IP6HDR_DADDR, IP6HDR_DSCP,
+			IP6HDR_SADDR, IP6HDR_DADDR, IP6HDR_DSCP, IP6HDR_ECN,
 			IP6HDR_HOPLIMIT, IP6HDR_FLOWLABEL, IP6HDR_NEXTHDR,
 			IP6HDR_LENGTH,
 		},
@@ -923,4 +946,5 @@ static void __init proto_init(void)
 	datatype_register(&ethertype_type);
 	datatype_register(&icmp6_type_type);
 	datatype_register(&dscp_type);
+	datatype_register(&ecn_type);
 }
diff --git a/src/scanner.l b/src/scanner.l
index 275beaa..e8b216e 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -363,6 +363,7 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 "version"		{ return HDRVERSION; }
 "hdrlength"		{ return HDRLENGTH; }
 "dscp"			{ return DSCP; }
+"ecn"			{ return ECN; }
 "length"		{ return LENGTH; }
 "frag-off"		{ return FRAG_OFF; }
 "ttl"			{ return TTL; }
-- 
2.1.4


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

* [PATCH nft 10/12] tests/py: add missing netdev ip dscp payload tests
  2016-05-11 21:05 [PATCH nft 01/12] evaluate: transfer right shifts to constant side Pablo Neira Ayuso
                   ` (7 preceding siblings ...)
  2016-05-11 21:05 ` [PATCH nft 09/12] src: add ecn support Pablo Neira Ayuso
@ 2016-05-11 21:05 ` Pablo Neira Ayuso
  2016-05-11 21:05 ` [PATCH nft 11/12] tests/py: fix fragment-offset field Pablo Neira Ayuso
  2016-05-11 21:05 ` [PATCH nft 12/12] tests/py: fix payload of dccp type in set elements Pablo Neira Ayuso
  10 siblings, 0 replies; 12+ messages in thread
From: Pablo Neira Ayuso @ 2016-05-11 21:05 UTC (permalink / raw)
  To: netfilter-devel

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 tests/py/ip/ip.t.payload.netdev | 43 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/tests/py/ip/ip.t.payload.netdev b/tests/py/ip/ip.t.payload.netdev
index 90d6cc8..fcc466a 100644
--- a/tests/py/ip/ip.t.payload.netdev
+++ b/tests/py/ip/ip.t.payload.netdev
@@ -598,3 +598,46 @@ netdev test-netdev ingress
   [ payload load 1b @ network header + 9 => reg 1 ]
   [ cmp neq reg 1 0x00000006 ]
 
+# ip dscp cs1
+netdev test-netdev ingress 
+  [ meta load protocol => reg 1 ]
+  [ cmp eq reg 1 0x00000008 ]
+  [ payload load 1b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+  [ cmp eq reg 1 0x00000020 ]
+
+# ip dscp != cs1
+netdev test-netdev ingress 
+  [ meta load protocol => reg 1 ]
+  [ cmp eq reg 1 0x00000008 ]
+  [ payload load 1b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+  [ cmp neq reg 1 0x00000020 ]
+
+# ip dscp 0x38
+netdev test-netdev ingress 
+  [ meta load protocol => reg 1 ]
+  [ cmp eq reg 1 0x00000008 ]
+  [ payload load 1b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+  [ cmp eq reg 1 0x000000e0 ]
+
+# ip dscp != 0x20
+netdev test-netdev ingress 
+  [ meta load protocol => reg 1 ]
+  [ cmp eq reg 1 0x00000008 ]
+  [ payload load 1b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+  [ cmp neq reg 1 0x00000080 ]
+
+# ip dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
+set%d test-netdev 3
+set%d test-netdev 0
+	element 00000000  : 0 [end]	element 00000020  : 0 [end]	element 00000040  : 0 [end]	element 00000060  : 0 [end]	element 00000080  : 0 [end]	element 000000a0  : 0 [end]	element 000000c0  : 0 [end]	element 000000e0  : 0 [end]	element 00000028  : 0 [end]	element 00000030  : 0 [end]	element 00000038  : 0 [end]	element 00000048  : 0 [end]	element 00000050  : 0 [end]	element 00000058  : 0 [end]	element 00000068  : 0 [end]	element 00000070  : 0 [end]	element 00000078  : 0 [end]	element 00000088  : 0 [end]	element 00000090  : 0 [end]	element 00000098  : 0 [end]	element 000000b8  : 0 [end]
+netdev test-netdev ingress 
+  [ meta load protocol => reg 1 ]
+  [ cmp eq reg 1 0x00000008 ]
+  [ payload load 1b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+  [ lookup reg 1 set set%d ]
+
-- 
2.1.4


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

* [PATCH nft 11/12] tests/py: fix fragment-offset field
  2016-05-11 21:05 [PATCH nft 01/12] evaluate: transfer right shifts to constant side Pablo Neira Ayuso
                   ` (8 preceding siblings ...)
  2016-05-11 21:05 ` [PATCH nft 10/12] tests/py: add missing netdev ip dscp payload tests Pablo Neira Ayuso
@ 2016-05-11 21:05 ` Pablo Neira Ayuso
  2016-05-11 21:05 ` [PATCH nft 12/12] tests/py: fix payload of dccp type in set elements Pablo Neira Ayuso
  10 siblings, 0 replies; 12+ messages in thread
From: Pablo Neira Ayuso @ 2016-05-11 21:05 UTC (permalink / raw)
  To: netfilter-devel

Set elements were miscalculated.

After this patch:

element 00000801  : 0 [end]
            ^^^^

Which looks correct according to my calculations:

>>> print hex(socket.htons(33 << 3))
0x801
^^^^^

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 tests/py/ip6/frag.t.payload.inet | 4 ++--
 tests/py/ip6/frag.t.payload.ip6  | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/tests/py/ip6/frag.t.payload.inet b/tests/py/ip6/frag.t.payload.inet
index 52eaaff..a766f15 100644
--- a/tests/py/ip6/frag.t.payload.inet
+++ b/tests/py/ip6/frag.t.payload.inet
@@ -123,7 +123,7 @@ inet test-inet output
 # frag frag-off { 33, 55, 67, 88}
 set%d test-inet 3
 set%d test-inet 0
-	element 00002100  : 0 [end]	element 00003700  : 0 [end]	element 00004300  : 0 [end]	element 00005800  : 0 [end]
+	element 00000801  : 0 [end]	element 0000b801  : 0 [end]	element 00001802  : 0 [end]	element 0000c002  : 0 [end]
 inet test-inet output
   [ meta load nfproto => reg 1 ]
   [ cmp eq reg 1 0x0000000a ]
@@ -134,7 +134,7 @@ inet test-inet output
 # frag frag-off { 33-55}
 set%d test-inet 7
 set%d test-inet 0
-	element 00000000  : 1 [end]	element 00002100  : 0 [end]	element 00003800  : 1 [end]
+	element 00000000  : 1 [end]	element 00000801  : 0 [end]	element 0000b901  : 1 [end]
 inet test-inet output
   [ meta load nfproto => reg 1 ]
   [ cmp eq reg 1 0x0000000a ]
diff --git a/tests/py/ip6/frag.t.payload.ip6 b/tests/py/ip6/frag.t.payload.ip6
index a2adaae..d7a2e9f 100644
--- a/tests/py/ip6/frag.t.payload.ip6
+++ b/tests/py/ip6/frag.t.payload.ip6
@@ -93,7 +93,7 @@ ip6 test-ip6 output
 # frag frag-off { 33, 55, 67, 88}
 set%d test-ip6 3
 set%d test-ip6 0
-	element 00002100  : 0 [end]	element 00003700  : 0 [end]	element 00004300  : 0 [end]	element 00005800  : 0 [end]
+	element 00000801  : 0 [end]	element 0000b801  : 0 [end]	element 00001802  : 0 [end]	element 0000c002  : 0 [end]
 ip6 test-ip6 output
   [ exthdr load 2b @ 44 + 2 => reg 1 ]
   [ bitwise reg 1 = (reg=1 & 0x0000f8ff ) ^ 0x00000000 ]
@@ -102,7 +102,7 @@ ip6 test-ip6 output
 # frag frag-off { 33-55}
 set%d test-ip6 7
 set%d test-ip6 0
-	element 00000000  : 1 [end]	element 00002100  : 0 [end]	element 00003800  : 1 [end]
+	element 00000000  : 1 [end]	element 00000801  : 0 [end]	element 0000b901  : 1 [end]
 ip6 test-ip6 output 
   [ exthdr load 2b @ 44 + 2 => reg 1 ]
   [ bitwise reg 1 = (reg=1 & 0x0000f8ff ) ^ 0x00000000 ]
-- 
2.1.4


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

* [PATCH nft 12/12] tests/py: fix payload of dccp type in set elements
  2016-05-11 21:05 [PATCH nft 01/12] evaluate: transfer right shifts to constant side Pablo Neira Ayuso
                   ` (9 preceding siblings ...)
  2016-05-11 21:05 ` [PATCH nft 11/12] tests/py: fix fragment-offset field Pablo Neira Ayuso
@ 2016-05-11 21:05 ` Pablo Neira Ayuso
  10 siblings, 0 replies; 12+ messages in thread
From: Pablo Neira Ayuso @ 2016-05-11 21:05 UTC (permalink / raw)
  To: netfilter-devel

This value needs to be lshift one bit to be correct.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 tests/py/inet/dccp.t.payload.inet   | 2 +-
 tests/py/inet/dccp.t.payload.ip     | 2 +-
 tests/py/inet/dccp.t.payload.ip6    | 2 +-
 tests/py/inet/dccp.t.payload.netdev | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/tests/py/inet/dccp.t.payload.inet b/tests/py/inet/dccp.t.payload.inet
index 11f5aaf..06cabaf 100644
--- a/tests/py/inet/dccp.t.payload.inet
+++ b/tests/py/inet/dccp.t.payload.inet
@@ -83,7 +83,7 @@ inet test-inet input
 # dccp type {request, response, data, ack, dataack, closereq, close, reset, sync, syncack}
 set%d test-inet 3
 set%d test-inet 0
-	element 00000000  : 0 [end]     element 00000001  : 0 [end]     element 00000002  : 0 [end]     element 00000003  : 0 [end]     element 00000004  : 0 [end]     element 00000005  : 0 [end]     element 00000006  : 0 [end]     element 00000007  : 0 [end]     element 00000008  : 0 [end]     element 00000009  : 0 [end]
+	element 00000000  : 0 [end]	element 00000002  : 0 [end]	element 00000004  : 0 [end]	element 00000006  : 0 [end]	element 00000008  : 0 [end]	element 0000000a  : 0 [end]	element 0000000c  : 0 [end]	element 0000000e  : 0 [end]	element 00000010  : 0 [end]	element 00000012  : 0 [end]
 inet test-inet input
   [ meta load l4proto => reg 1 ]
   [ cmp eq reg 1 0x00000021 ]
diff --git a/tests/py/inet/dccp.t.payload.ip b/tests/py/inet/dccp.t.payload.ip
index fbf441a..3b5def4 100644
--- a/tests/py/inet/dccp.t.payload.ip
+++ b/tests/py/inet/dccp.t.payload.ip
@@ -83,7 +83,7 @@ ip test-ip4 input
 # dccp type {request, response, data, ack, dataack, closereq, close, reset, sync, syncack}
 set%d test-ip4 3
 set%d test-ip4 0
-	element 00000000  : 0 [end]     element 00000001  : 0 [end]     element 00000002  : 0 [end]     element 00000003  : 0 [end]     element 00000004  : 0 [end]     element 00000005  : 0 [end]     element 00000006  : 0 [end]     element 00000007  : 0 [end]     element 00000008  : 0 [end]     element 00000009  : 0 [end]
+	element 00000000  : 0 [end]	element 00000002  : 0 [end]	element 00000004  : 0 [end]	element 00000006  : 0 [end]	element 00000008  : 0 [end]	element 0000000a  : 0 [end]	element 0000000c  : 0 [end]	element 0000000e  : 0 [end]	element 00000010  : 0 [end]	element 00000012  : 0 [end]
 ip test-ip4 input
   [ payload load 1b @ network header + 9 => reg 1 ]
   [ cmp eq reg 1 0x00000021 ]
diff --git a/tests/py/inet/dccp.t.payload.ip6 b/tests/py/inet/dccp.t.payload.ip6
index b323c06..fd7177c 100644
--- a/tests/py/inet/dccp.t.payload.ip6
+++ b/tests/py/inet/dccp.t.payload.ip6
@@ -83,7 +83,7 @@ ip6 test-ip6 input
 # dccp type {request, response, data, ack, dataack, closereq, close, reset, sync, syncack}
 set%d test-ip6 3
 set%d test-ip6 0
-        element 00000000  : 0 [end]     element 00000001  : 0 [end]     element 00000002  : 0 [end]     element 00000003  : 0 [end]     element 00000004  : 0 [end]     element 00000005  : 0 [end]     element 00000006  : 0 [end]     element 00000007  : 0 [end]     element 00000008  : 0 [end]     element 00000009  : 0 [end]
+	element 00000000  : 0 [end]	element 00000002  : 0 [end]	element 00000004  : 0 [end]	element 00000006  : 0 [end]	element 00000008  : 0 [end]	element 0000000a  : 0 [end]	element 0000000c  : 0 [end]	element 0000000e  : 0 [end]	element 00000010  : 0 [end]	element 00000012  : 0 [end]
 ip6 test-ip6 input
   [ payload load 1b @ network header + 6 => reg 1 ]
   [ cmp eq reg 1 0x00000021 ]
diff --git a/tests/py/inet/dccp.t.payload.netdev b/tests/py/inet/dccp.t.payload.netdev
index 5a8c873..678b986 100644
--- a/tests/py/inet/dccp.t.payload.netdev
+++ b/tests/py/inet/dccp.t.payload.netdev
@@ -83,7 +83,7 @@ inet test-inet input
 # dccp type {request, response, data, ack, dataack, closereq, close, reset, sync, syncack}
 set%d test-netdev 3
 set%d test-netdev 0
-	element 00000000  : 0 [end]     element 00000001  : 0 [end]     element 00000002  : 0 [end]     element 00000003  : 0 [end]     element 00000004  : 0 [end]     element 00000005  : 0 [end]     element 00000006  : 0 [end]     element 00000007  : 0 [end]     element 00000008  : 0 [end]     element 00000009  : 0 [end]
+	element 00000000  : 0 [end]	element 00000002  : 0 [end]	element 00000004  : 0 [end]	element 00000006  : 0 [end]	element 00000008  : 0 [end]	element 0000000a  : 0 [end]	element 0000000c  : 0 [end]	element 0000000e  : 0 [end]	element 00000010  : 0 [end]	element 00000012  : 0 [end]
 netdev test-netdev ingress
   [ meta load l4proto => reg 1 ]
   [ cmp eq reg 1 0x00000021 ]
-- 
2.1.4


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

end of thread, other threads:[~2016-05-11 21:05 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-11 21:05 [PATCH nft 01/12] evaluate: transfer right shifts to constant side Pablo Neira Ayuso
2016-05-11 21:05 ` [PATCH nft 02/12] evaluate: transfer right shifts to range side Pablo Neira Ayuso
2016-05-11 21:05 ` [PATCH nft 03/12] evaluate: transfer right shifts to set reference side Pablo Neira Ayuso
2016-05-11 21:05 ` [PATCH nft 04/12] src: move payload sub-byte matching to the evaluation step Pablo Neira Ayuso
2016-05-11 21:05 ` [PATCH nft 05/12] evaluate: handle payload matching split in two bytes Pablo Neira Ayuso
2016-05-11 21:05 ` [PATCH nft 06/12] proto: update IPv6 flowlabel offset and length according to RFC2460 Pablo Neira Ayuso
2016-05-11 21:05 ` [PATCH nft 07/12] proto: remove priority field definition from IPv6 header Pablo Neira Ayuso
2016-05-11 21:05 ` [PATCH nft 08/12] src: add dscp support Pablo Neira Ayuso
2016-05-11 21:05 ` [PATCH nft 09/12] src: add ecn support Pablo Neira Ayuso
2016-05-11 21:05 ` [PATCH nft 10/12] tests/py: add missing netdev ip dscp payload tests Pablo Neira Ayuso
2016-05-11 21:05 ` [PATCH nft 11/12] tests/py: fix fragment-offset field Pablo Neira Ayuso
2016-05-11 21:05 ` [PATCH nft 12/12] tests/py: fix payload of dccp type in set elements Pablo Neira Ayuso

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.