Blob Blame History Raw
From 3ce7e132a4828b707c94efb0cb5058067828353d Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Fri, 12 May 2017 17:56:59 +0200
Subject: [PATCH] src: meta priority support using tc classid

Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1380326
Upstream Status: nftables commit 6f2eb8548e0d1
Conflicts: Context change in tests due to missing meta random keyword.

commit 6f2eb8548e0d18078989adec069b438b2f154767
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date:   Tue Aug 16 23:30:18 2016 +0200

    src: meta priority support using tc classid

    This patch adds the missing bits to scan and parse the meta priority
    handle as expressed by tc classid major:minor syntax.

    The :minor syntax is not support for two reason: major is always >= 1
    and this clashes with port syntax in nat.

    Here below, several example on how to match the packet priority field:

       nft add rule filter forward meta priority abcd:0
       nft add rule filter forward meta priority abcd:1234

    and to set it, you have to:

       nft add rule filter forward meta priority set abcd:1234

    The priority expression in flex looks ahead to restrict the pattern to
    avoid problems with mappings:

    {classid}/[ \t\n:\-},]

    So the following doesn't break:

       ... vmap { 25:accept }
                  ^^^^^

    The lookahead expression requires a slight change to extend the input
    string in one byte.

    This patch is conservative as you always have to explicity indicate
    major and minor numbers even if zero.

    We could consider supporting this shortcut in the future:

            abcd:

    However, with regards to this:

            :abcd

    We don't need to support it since major number is assumed to be >= 1.
    However, if we ever decide to support this, we'll have problems since
    this clashes with our port representation in redirect and mangle.

    So let's keep this simple and start with this approach.

    Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/cli.c                   |  8 +++++
 src/erec.c                  |  1 +
 src/main.c                  |  3 +-
 src/meta.c                  | 39 +++++++++++++++++-------
 src/scanner.l               |  6 ++++
 src/statement.c             |  2 +-
 tests/py/any/meta.t         | 22 ++++++++------
 tests/py/any/meta.t.payload | 72 +++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 131 insertions(+), 22 deletions(-)

diff --git a/src/cli.c b/src/cli.c
index adffd6b..a74411a 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -92,6 +92,8 @@ static void cli_complete(char *line)
 	const HIST_ENTRY *hist;
 	const char *c;
 	LIST_HEAD(msgs);
+	int len;
+	char *s;
 
 	if (line == NULL) {
 		printf("\n");
@@ -119,6 +121,12 @@ static void cli_complete(char *line)
 	if (hist == NULL || strcmp(hist->line, line))
 		add_history(line);
 
+	len = strlen(line);
+	s = xmalloc(len + 2);
+	snprintf(s, len + 2, "%s\n", line);
+	xfree(line);
+	line = s;
+
 	parser_init(state, &msgs);
 	scanner_push_buffer(scanner, &indesc_cli, line);
 	nft_run(scanner, state, &msgs);
diff --git a/src/erec.c b/src/erec.c
index d514230..adbc096 100644
--- a/src/erec.c
+++ b/src/erec.c
@@ -92,6 +92,7 @@ void erec_print(FILE *f, const struct error_record *erec)
 	case INDESC_BUFFER:
 	case INDESC_CLI:
 		line = indesc->data;
+		*strchrnul(line, '\n') = '\0';
 		break;
 	case INDESC_FILE:
 		memset(buf, 0, sizeof(buf));
diff --git a/src/main.c b/src/main.c
index ad73d80..39a47bb 100644
--- a/src/main.c
+++ b/src/main.c
@@ -328,12 +328,13 @@ int main(int argc, char * const *argv)
 		for (len = 0, i = optind; i < argc; i++)
 			len += strlen(argv[i]) + strlen(" ");
 
-		buf = xzalloc(len + 1);
+		buf = xzalloc(len + 2);
 		for (i = optind; i < argc; i++) {
 			strcat(buf, argv[i]);
 			if (i + 1 < argc)
 				strcat(buf, " ");
 		}
+		strcat(buf, "\n");
 		parser_init(&state, &msgs);
 		scanner = scanner_init(&state);
 		scanner_push_buffer(scanner, &indesc_cmdline, buf);
diff --git a/src/meta.c b/src/meta.c
index 3a72d10..652b1cf 100644
--- a/src/meta.c
+++ b/src/meta.c
@@ -10,6 +10,7 @@
  * Development of this code funded by Astaro AG (http://www.astaro.com/)
  */
 
+#include <errno.h>
 #include <stddef.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -89,34 +90,50 @@ static struct error_record *tchandle_type_parse(const struct expr *sym,
 						struct expr **res)
 {
 	uint32_t handle;
+	char *str;
 
 	if (strcmp(sym->identifier, "root") == 0)
 		handle = TC_H_ROOT;
 	else if (strcmp(sym->identifier, "none") == 0)
 		handle = TC_H_UNSPEC;
-	else if (sym->identifier[0] == ':') {
-		if (sscanf(sym->identifier, ":%04x", &handle) != 1)
+	else if (strchr(sym->identifier, ':')) {
+		uint16_t tmp;
+		char *colon;
+
+		str = xstrdup(sym->identifier);
+
+		colon = strchr(str, ':');
+		if (!colon)
 			goto err;
-	} else if (sym->identifier[strlen(sym->identifier)-1] == ':') {
-		if (sscanf(sym->identifier, "%04x:", &handle) != 1)
+
+		*colon = '\0';
+
+		errno = 0;
+		tmp = strtoull(str, NULL, 16);
+		if (errno != 0)
 			goto err;
 
-		handle <<= 16;
-	} else {
-		uint32_t min, max;
+		handle = (tmp << 16);
+		if (str[strlen(str) - 1] == ':')
+			goto out;
 
-		if (sscanf(sym->identifier, "%04x:%04x", &max, &min) != 2)
+		errno = 0;
+		tmp = strtoull(colon + 1, NULL, 16);
+		if (errno != 0)
 			goto err;
 
-		handle = max << 16 | min;
+		handle |= tmp;
+	} else {
+		handle = strtoull(sym->identifier, NULL, 0);
 	}
+out:
 	*res = constant_expr_alloc(&sym->location, sym->dtype,
 				   BYTEORDER_HOST_ENDIAN,
 				   sizeof(handle) * BITS_PER_BYTE, &handle);
 	return NULL;
 err:
-	return error(&sym->location, "Could not parse %s",
-		     sym->dtype->desc);
+	xfree(str);
+	return error(&sym->location, "Could not parse %s", sym->dtype->desc);
 }
 
 static const struct datatype tchandle_type = {
diff --git a/src/scanner.l b/src/scanner.l
index 88669d0..5855041 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -170,6 +170,7 @@ macaddr		(([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2})
 ip4addr		(([[:digit:]]{1,3}"."){3}([[:digit:]]{1,3}))
 ip6addr		({v680}|{v67}|{v66}|{v65}|{v64}|{v63}|{v62}|{v61}|{v60})
 
+classid		({hexdigit}{1,4}:{hexdigit}{1,4})
 addrstring	({macaddr}|{ip4addr}|{ip6addr})
 
 %option prefix="nft_"
@@ -500,6 +501,11 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 				return NUM;
 			}
 
+{classid}/[ \t\n:\-},]	{
+				yylval->string = xstrdup(yytext);
+				return STRING;
+			}
+
 {quotedstring}		{
 				yytext[yyleng - 1] = '\0';
 				yylval->string = xstrdup(yytext + 1);
diff --git a/src/statement.c b/src/statement.c
index 76f528b..0960f44 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -458,7 +458,7 @@ static void redir_stmt_print(const struct stmt *stmt)
 	printf("redirect");
 
 	if (stmt->redir.proto) {
-		printf(" to ");
+		printf(" to :");
 		expr_print(stmt->redir.proto);
 	}
 
diff --git a/tests/py/any/meta.t b/tests/py/any/meta.t
index 424cb18..6ea06d9 100644
--- a/tests/py/any/meta.t
+++ b/tests/py/any/meta.t
@@ -38,15 +38,19 @@ meta l4proto { 33, 55, 67, 88};ok;meta l4proto { 33, 55, 67, 88}
 meta l4proto { 33-55};ok
 - meta l4proto != { 33-55};ok
 
-- meta priority :aabb;ok
-- meta priority bcad:dadc;ok
-- meta priority aabb:;ok
-- meta priority != :aabb;ok
-- meta priority != bcad:dadc;ok
-- meta priority != aabb:;ok
-- meta priority bcad:dada-bcad:dadc;ok
-- meta priority != bcad:dada-bcad:dadc;ok
-- meta priority {bcad:dada, bcad:dadc, aaaa:bbbb};ok
+meta priority root;ok
+meta priority none;ok
+meta priority 0x87654321;ok;meta priority 8765:4321
+meta priority 2271560481;ok;meta priority 8765:4321
+meta priority 1:1234;ok
+meta priority bcad:dadc;ok
+meta priority aabb:0;ok
+meta priority != bcad:dadc;ok
+meta priority != aabb:0;ok
+meta priority bcad:dada-bcad:dadc;ok
+meta priority != bcad:dada-bcad:dadc;ok
+meta priority {bcad:dada, bcad:dadc, aaaa:bbbb};ok
+meta priority set cafe:beef;ok
 - meta priority != {bcad:dada, bcad:dadc, aaaa:bbbb};ok
 
 meta mark 0x4;ok;mark 0x00000004
diff --git a/tests/py/any/meta.t.payload b/tests/py/any/meta.t.payload
index 00a2f20..8065178 100644
--- a/tests/py/any/meta.t.payload
+++ b/tests/py/any/meta.t.payload
@@ -775,3 +775,75 @@ ip test-ip4 output
   [ meta load oif => reg 9 ]
   [ lookup reg 1 set __map%d dreg 0 ]
 
+# meta priority root
+ip test-ip4 input 
+  [ meta load priority => reg 1 ]
+  [ cmp eq reg 1 0xffffffff ]
+
+# meta priority none
+netdev test-netdev ingress 
+  [ meta load priority => reg 1 ]
+  [ cmp eq reg 1 0x00000000 ]
+
+# meta priority 1:1234
+ip test-ip4 input
+  [ meta load priority => reg 1 ]
+  [ cmp eq reg 1 0x00011234 ]
+
+# meta priority bcad:dadc
+ip test-ip4 input 
+  [ meta load priority => reg 1 ]
+  [ cmp eq reg 1 0xbcaddadc ]
+
+# meta priority aabb:0
+ip test-ip4 input 
+  [ meta load priority => reg 1 ]
+  [ cmp eq reg 1 0xaabb0000 ]
+
+# meta priority != bcad:dadc
+ip test-ip4 input 
+  [ meta load priority => reg 1 ]
+  [ cmp neq reg 1 0xbcaddadc ]
+
+# meta priority != aabb:0
+ip test-ip4 input 
+  [ meta load priority => reg 1 ]
+  [ cmp neq reg 1 0xaabb0000 ]
+
+# meta priority bcad:dada-bcad:dadc
+ip test-ip4 input 
+  [ meta load priority => reg 1 ]
+  [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+  [ cmp gte reg 1 0xdadaadbc ]
+  [ cmp lte reg 1 0xdcdaadbc ]
+
+# meta priority != bcad:dada-bcad:dadc
+ip test-ip4 input 
+  [ meta load priority => reg 1 ]
+  [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+  [ cmp lt reg 1 0xdadaadbc ]
+  [ cmp gt reg 1 0xdcdaadbc ]
+
+# meta priority {bcad:dada, bcad:dadc, aaaa:bbbb}
+__set%d test-ip4 3
+__set%d test-ip4 0
+	element bcaddada  : 0 [end]	element bcaddadc  : 0 [end]	element aaaabbbb  : 0 [end]
+ip test-ip4 input 
+  [ meta load priority => reg 1 ]
+  [ lookup reg 1 set __set%d ]
+
+# meta priority set cafe:beef
+ip test-ip4 input 
+  [ immediate reg 1 0xcafebeef ]
+  [ meta set priority with reg 1 ]
+
+# meta priority 0x87654321
+ip test-ip4 input
+  [ meta load priority => reg 1 ]
+  [ cmp eq reg 1 0x87654321 ]
+
+# meta priority 2271560481
+ip test-ip4 input
+  [ meta load priority => reg 1 ]
+  [ cmp eq reg 1 0x87654321 ]
+
-- 
1.8.3.1