[nft PATCH] meta: introduce datatype ifname_type

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

 



This new datatype is a string subtype.
It will allow us to build named maps/sets using meta keys like 'iifname',
'oifname', 'ibriport' or 'obriport'.

Example:

table inet t {
	set s {
		type ifname
		elements = { "eth0",
			     "eth1" }
	}

	chain c {
		iifname @s accept
		oifname @s accept
	}
}

Signed-off-by: Arturo Borrero Gonzalez <arturo@xxxxxxxxxxxxx>
---
 doc/nft.xml                                        |    8 ++---
 include/datatype.h                                 |    2 +
 include/meta.h                                     |    1 +
 src/datatype.c                                     |    1 +
 src/evaluate.c                                     |   19 +++++++++--
 src/meta.c                                         |   17 +++++++---
 src/netlink_delinearize.c                          |   27 +++++++++++----
 src/netlink_linearize.c                            |   14 +++++---
 .../shell/testcases/maps/0007named_ifname_dtype_0  |   35 ++++++++++++++++++++
 .../shell/testcases/sets/0029named_ifname_dtype_0  |   35 ++++++++++++++++++++
 10 files changed, 134 insertions(+), 25 deletions(-)
 create mode 100755 tests/shell/testcases/maps/0007named_ifname_dtype_0
 create mode 100755 tests/shell/testcases/sets/0029named_ifname_dtype_0

diff --git a/doc/nft.xml b/doc/nft.xml
index 9d21e9a..6748265 100644
--- a/doc/nft.xml
+++ b/doc/nft.xml
@@ -2572,7 +2572,7 @@ filter output icmpv6 type { echo-request, echo-reply }
 							<row>
 								<entry>iifname</entry>
 								<entry>Input interface name</entry>
-								<entry>string</entry>
+								<entry>ifname</entry>
 							</row>
 							<row>
 								<entry>iiftype</entry>
@@ -2587,7 +2587,7 @@ filter output icmpv6 type { echo-request, echo-reply }
 							<row>
 								<entry>oifname</entry>
 								<entry>Output interface name</entry>
-								<entry>string</entry>
+								<entry>ifname</entry>
 							</row>
 							<row>
 								<entry>oiftype</entry>
@@ -2612,12 +2612,12 @@ filter output icmpv6 type { echo-request, echo-reply }
 							<row>
 								<entry>ibriport</entry>
 								<entry>Input bridge interface name</entry>
-								<entry>string</entry>
+								<entry>ifname</entry>
 							</row>
 							<row>
 								<entry>obriport</entry>
 								<entry>Output bridge interface name</entry>
-								<entry>string</entry>
+								<entry>ifname</entry>
 							</row>
 							<row>
 								<entry>pkttype</entry>
diff --git a/include/datatype.h b/include/datatype.h
index cc4cb07..dd94e80 100644
--- a/include/datatype.h
+++ b/include/datatype.h
@@ -41,6 +41,7 @@
  * @TYPE_ICMPX_CODE:	icmpx code (integer subtype)
  * @TYPE_DEVGROUP:	devgroup code (integer subtype)
  * @TYPE_DSCP:		Differentiated Services Code Point (integer subtype)
+ * @TYPE_IFNAME:	interface name (string subtype)
  */
 enum datatypes {
 	TYPE_INVALID,
@@ -84,6 +85,7 @@ enum datatypes {
 	TYPE_FIB_ADDR,
 	TYPE_BOOLEAN,
 	TYPE_CT_EVENTBIT,
+        TYPE_IFNAME,
 	__TYPE_MAX
 };
 #define TYPE_MAX		(__TYPE_MAX - 1)
diff --git a/include/meta.h b/include/meta.h
index 47b16c4..6086a71 100644
--- a/include/meta.h
+++ b/include/meta.h
@@ -38,5 +38,6 @@ extern const struct datatype gid_type;
 extern const struct datatype uid_type;
 extern const struct datatype devgroup_type;
 extern const struct datatype pkttype_type;
+extern const struct datatype ifname_type;
 
 #endif /* NFTABLES_META_H */
diff --git a/src/datatype.c b/src/datatype.c
index 93726ca..324ac80 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -68,6 +68,7 @@ static const struct datatype *datatypes[TYPE_MAX + 1] = {
 	[TYPE_ECN]		= &ecn_type,
 	[TYPE_FIB_ADDR]         = &fib_addr_type,
 	[TYPE_BOOLEAN]		= &boolean_type,
+	[TYPE_IFNAME]		= &ifname_type,
 };
 
 const struct datatype *datatype_lookup(enum datatypes type)
diff --git a/src/evaluate.c b/src/evaluate.c
index e5ad104..80e6370 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -224,6 +224,7 @@ static int expr_evaluate_string(struct eval_ctx *ctx, struct expr **exprp)
 	struct expr *value, *prefix;
 	int data_len = ctx->ectx.len > 0 ? ctx->ectx.len : len + 1;
 	char data[data_len];
+	const struct datatype *dtype;
 
 	if (ctx->ectx.len > 0) {
 		if (expr->len > ctx->ectx.len)
@@ -240,12 +241,21 @@ static int expr_evaluate_string(struct eval_ctx *ctx, struct expr **exprp)
 		return expr_error(ctx->msgs, expr,
 				  "Empty string is not allowed");
 
+	switch (ctx->ectx.dtype->type) {
+	case TYPE_IFNAME:
+		dtype = &ifname_type;
+		break;
+	default:
+		dtype = &string_type;
+		break;
+	}
+
 	datalen = strlen(data) - 1;
 	if (data[datalen] != '*') {
 		/* We need to reallocate the constant expression with the right
 		 * expression length to avoid problems on big endian.
 		 */
-		value = constant_expr_alloc(&expr->location, &string_type,
+		value = constant_expr_alloc(&expr->location, dtype,
 					    BYTEORDER_HOST_ENDIAN,
 					    expr->len, data);
 		expr_free(expr);
@@ -260,20 +270,20 @@ static int expr_evaluate_string(struct eval_ctx *ctx, struct expr **exprp)
 		memset(unescaped_str, 0, sizeof(unescaped_str));
 		xstrunescape(data, unescaped_str);
 
-		value = constant_expr_alloc(&expr->location, &string_type,
+		value = constant_expr_alloc(&expr->location, dtype,
 					    BYTEORDER_HOST_ENDIAN,
 					    expr->len, unescaped_str);
 		expr_free(expr);
 		*exprp = value;
 		return 0;
 	}
-	value = constant_expr_alloc(&expr->location, &string_type,
+	value = constant_expr_alloc(&expr->location, dtype,
 				    BYTEORDER_HOST_ENDIAN,
 				    datalen * BITS_PER_BYTE, data);
 
 	prefix = prefix_expr_alloc(&expr->location, value,
 				   datalen * BITS_PER_BYTE);
-	prefix->dtype = &string_type;
+	prefix->dtype = dtype;
 	prefix->flags |= EXPR_F_CONSTANT;
 	prefix->byteorder = BYTEORDER_HOST_ENDIAN;
 
@@ -1769,6 +1779,7 @@ static int expr_evaluate_meta(struct eval_ctx *ctx, struct expr **exprp)
 	    meta->meta.key == NFT_META_NFPROTO)
 		return expr_error(ctx->msgs, meta,
 					  "meta nfproto is only useful in the inet family");
+
 	return expr_evaluate_primary(ctx, exprp);
 }
 
diff --git a/src/meta.c b/src/meta.c
index 8c2eca2..11de2da 100644
--- a/src/meta.c
+++ b/src/meta.c
@@ -369,6 +369,15 @@ const struct datatype devgroup_type = {
 	.flags		= DTYPE_F_PREFIX,
 };
 
+const struct datatype ifname_type = {
+	.type		= TYPE_IFNAME,
+	.name		= "ifname",
+	.desc		= "network interface name",
+	.byteorder	= BYTEORDER_HOST_ENDIAN,
+	.size		= IFNAMSIZ * BITS_PER_BYTE,
+	.basetype	= &string_type,
+};
+
 static const struct meta_template meta_templates[] = {
 	[NFT_META_LEN]		= META_TEMPLATE("length",    &integer_type,
 						4 * 8, BYTEORDER_HOST_ENDIAN),
@@ -384,14 +393,14 @@ static const struct meta_template meta_templates[] = {
 						4 * 8, BYTEORDER_HOST_ENDIAN),
 	[NFT_META_IIF]		= META_TEMPLATE("iif",       &ifindex_type,
 						4 * 8, BYTEORDER_HOST_ENDIAN),
-	[NFT_META_IIFNAME]	= META_TEMPLATE("iifname",   &string_type,
+	[NFT_META_IIFNAME]	= META_TEMPLATE("iifname",   &ifname_type,
 						IFNAMSIZ * BITS_PER_BYTE,
 						BYTEORDER_HOST_ENDIAN),
 	[NFT_META_IIFTYPE]	= META_TEMPLATE("iiftype",   &arphrd_type,
 						2 * 8, BYTEORDER_HOST_ENDIAN),
 	[NFT_META_OIF]		= META_TEMPLATE("oif",	     &ifindex_type,
 						4 * 8, BYTEORDER_HOST_ENDIAN),
-	[NFT_META_OIFNAME]	= META_TEMPLATE("oifname",   &string_type,
+	[NFT_META_OIFNAME]	= META_TEMPLATE("oifname",   &ifname_type,
 						IFNAMSIZ * BITS_PER_BYTE,
 						BYTEORDER_HOST_ENDIAN),
 	[NFT_META_OIFTYPE]	= META_TEMPLATE("oiftype",   &arphrd_type,
@@ -404,10 +413,10 @@ static const struct meta_template meta_templates[] = {
 						1    , BYTEORDER_HOST_ENDIAN),
 	[NFT_META_RTCLASSID]	= META_TEMPLATE("rtclassid", &realm_type,
 						4 * 8, BYTEORDER_HOST_ENDIAN),
-	[NFT_META_BRI_IIFNAME]	= META_TEMPLATE("ibriport",  &string_type,
+	[NFT_META_BRI_IIFNAME]	= META_TEMPLATE("ibriport",  &ifname_type,
 						IFNAMSIZ * BITS_PER_BYTE,
 						BYTEORDER_HOST_ENDIAN),
-	[NFT_META_BRI_OIFNAME]	= META_TEMPLATE("obriport",  &string_type,
+	[NFT_META_BRI_OIFNAME]	= META_TEMPLATE("obriport",  &ifname_type,
 						IFNAMSIZ * BITS_PER_BYTE,
 						BYTEORDER_HOST_ENDIAN),
 	[NFT_META_PKTTYPE]	= META_TEMPLATE("pkttype",   &pkttype_type,
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 622425e..8f95934 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -270,10 +270,15 @@ static void netlink_parse_cmp(struct netlink_parse_ctx *ctx,
 	nld.value = nftnl_expr_get(nle, NFTNL_EXPR_CMP_DATA, &nld.len);
 	right = netlink_alloc_value(loc, &nld);
 
-	if (left->len > right->len &&
-	    left->dtype != &string_type) {
-		return netlink_error(ctx, loc,
-				     "Relational expression size mismatch");
+	if (left->len > right->len) {
+		switch (left->dtype->type) {
+		case TYPE_STRING:
+		case TYPE_IFNAME:
+			break;
+		default:
+			return netlink_error(ctx, loc, "Relational expression "
+					     "size mismatch");
+		}
 	} else if (left->len > 0 && left->len < right->len) {
 		left = netlink_parse_concat_expr(ctx, loc, sreg, right->len);
 		if (left == NULL)
@@ -1728,7 +1733,7 @@ static struct expr *string_wildcard_expr_alloc(struct location *loc,
 	data[pos] = '*';
 	data[pos + 1] = '\0';
 
-	return constant_expr_alloc(loc, &string_type, BYTEORDER_HOST_ENDIAN,
+	return constant_expr_alloc(loc, expr->dtype, BYTEORDER_HOST_ENDIAN,
 				   expr->len + BITS_PER_BYTE, data);
 }
 
@@ -1744,7 +1749,7 @@ static void escaped_string_wildcard_expr_alloc(struct expr **exprp,
 	data[pos - 1] = '\\';
 	data[pos] = '*';
 
-	tmp = constant_expr_alloc(&expr->location, &string_type,
+	tmp = constant_expr_alloc(&expr->location, expr->dtype,
 				  BYTEORDER_HOST_ENDIAN,
 				  expr->len + BITS_PER_BYTE, data);
 	expr_free(expr);
@@ -1789,7 +1794,7 @@ static struct expr *expr_postprocess_string(struct expr *expr)
 {
 	struct expr *mask;
 
-	assert(expr->dtype->type == TYPE_STRING);
+	assert(expr_basetype(expr)->type == TYPE_STRING);
 	if (__expr_postprocess_string(&expr))
 		return expr;
 
@@ -1893,8 +1898,14 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
 		if (expr->byteorder == BYTEORDER_HOST_ENDIAN)
 			mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
 
-		if (expr->dtype->type == TYPE_STRING)
+		switch (expr->dtype->type) {
+		case TYPE_STRING:
+		case TYPE_IFNAME:
 			*exprp = expr_postprocess_string(expr);
+			break;
+		default:
+			break;
+		}
 
 		if (expr->dtype->basetype != NULL &&
 		    expr->dtype->basetype->type == TYPE_BITMASK)
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 99a4dde..6ec06be 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -364,15 +364,19 @@ static void netlink_gen_cmp(struct netlink_linearize_ctx *ctx,
 		return netlink_gen_lookup(ctx, expr, dreg);
 	case EXPR_PREFIX:
 		sreg = get_register(ctx, expr->left);
-		if (expr->left->dtype->type != TYPE_STRING) {
-			len = div_round_up(expr->right->len, BITS_PER_BYTE);
-			netlink_gen_expr(ctx, expr->left, sreg);
-			right = netlink_gen_prefix(ctx, expr, sreg);
-		} else {
+		switch (expr->left->dtype->type) {
+		case TYPE_STRING:
+		case TYPE_IFNAME:
 			len = div_round_up(expr->right->prefix_len, BITS_PER_BYTE);
 			right = expr->right->prefix;
 			expr->left->len = expr->right->prefix_len;
 			netlink_gen_expr(ctx, expr->left, sreg);
+			break;
+		default:
+			len = div_round_up(expr->right->len, BITS_PER_BYTE);
+			netlink_gen_expr(ctx, expr->left, sreg);
+			right = netlink_gen_prefix(ctx, expr, sreg);
+			break;
 		}
 		break;
 	default:
diff --git a/tests/shell/testcases/maps/0007named_ifname_dtype_0 b/tests/shell/testcases/maps/0007named_ifname_dtype_0
new file mode 100755
index 0000000..dcbcf2f
--- /dev/null
+++ b/tests/shell/testcases/maps/0007named_ifname_dtype_0
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+# support for ifname in named maps
+
+tmpfile=$(mktemp)
+if [ ! -w $tmpfile ] ; then
+	echo "Failed to create tmp file" >&2
+	exit 0
+fi
+
+trap "rm -rf $tmpfile" EXIT # cleanup if aborted
+
+EXPECTED="table inet t {
+	map m1 {
+		type ifname : ipv4_addr
+		elements = { \"eth0\" : 1.1.1.1 }
+	}
+
+	chain c {
+		ip daddr set iifname map @m1
+		ip daddr set oifname map @m1
+	}
+}"
+
+set -e
+echo "$EXPECTED" > $tmpfile
+$NFT -f $tmpfile
+
+GET="$($NFT list ruleset)"
+if [ "$EXPECTED" != "$GET" ] ; then
+        DIFF="$(which diff)"
+        [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+        exit 1
+fi
+
diff --git a/tests/shell/testcases/sets/0029named_ifname_dtype_0 b/tests/shell/testcases/sets/0029named_ifname_dtype_0
new file mode 100755
index 0000000..8b7ab98
--- /dev/null
+++ b/tests/shell/testcases/sets/0029named_ifname_dtype_0
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+# support for ifname in named sets
+
+tmpfile=$(mktemp)
+if [ ! -w $tmpfile ] ; then
+	echo "Failed to create tmp file" >&2
+	exit 0
+fi
+
+trap "rm -rf $tmpfile" EXIT # cleanup if aborted
+
+EXPECTED="table inet t {
+	set s {
+		type ifname
+		elements = { \"eth0\" }
+	}
+
+	chain c {
+		iifname @s accept
+		oifname @s accept
+	}
+}"
+
+set -e
+echo "$EXPECTED" > $tmpfile
+$NFT -f $tmpfile
+
+GET="$($NFT list ruleset)"
+if [ "$EXPECTED" != "$GET" ] ; then
+        DIFF="$(which diff)"
+        [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+        exit 1
+fi
+

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux