Blame SOURCES/0050-tcpopts-clean-up-parser-tcpopt.c-plumbing.patch

0341a5
From 0aa694acf7c233f9426e48d0644b29ddec4fb16d Mon Sep 17 00:00:00 2001
0341a5
From: Phil Sutter <psutter@redhat.com>
0341a5
Date: Mon, 12 Jul 2021 17:44:08 +0200
0341a5
Subject: [PATCH] tcpopts: clean up parser -> tcpopt.c plumbing
0341a5
0341a5
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334
0341a5
Upstream Status: nftables commit 41158e0388ac5
0341a5
0341a5
commit 41158e0388ac56380fc0ee301f0d43f95ec43fab
0341a5
Author: Florian Westphal <fw@strlen.de>
0341a5
Date:   Mon Nov 2 14:53:26 2020 +0100
0341a5
0341a5
    tcpopts: clean up parser -> tcpopt.c plumbing
0341a5
0341a5
    tcpopt template mapping is asymmetric:
0341a5
    one mapping is to match dumped netlink exthdr expression to the original
0341a5
    tcp option template.
0341a5
0341a5
    This struct is indexed by the raw, on-write kind/type number.
0341a5
0341a5
    The other mapping maps parsed options to the tcp option template.
0341a5
    Remove the latter.  The parser is changed to translate the textual
0341a5
    option name, e.g. "maxseg" to the on-wire number.
0341a5
0341a5
    This avoids the second mapping, it will also allow to more easily
0341a5
    support raw option matching in a followup patch.
0341a5
0341a5
    Signed-off-by: Florian Westphal <fw@strlen.de>
0341a5
---
0341a5
 doc/payload-expression.txt |  4 +-
0341a5
 include/tcpopt.h           | 35 ++++++++-------
0341a5
 src/parser_bison.y         | 26 +++++------
0341a5
 src/parser_json.c          | 10 ++---
0341a5
 src/scanner.l              |  3 +-
0341a5
 src/tcpopt.c               | 92 +++++++++++++++-----------------------
0341a5
 6 files changed, 75 insertions(+), 95 deletions(-)
0341a5
0341a5
diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt
0341a5
index 3d7057c..27145c3 100644
0341a5
--- a/doc/payload-expression.txt
0341a5
+++ b/doc/payload-expression.txt
0341a5
@@ -525,13 +525,13 @@ nftables currently supports matching (finding) a given ipv6 extension header, TC
0341a5
 *dst* {*nexthdr* | *hdrlength*}
0341a5
 *mh* {*nexthdr* | *hdrlength* | *checksum* | *type*}
0341a5
 *srh* {*flags* | *tag* | *sid* | *seg-left*}
0341a5
-*tcp option* {*eol* | *noop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} 'tcp_option_field'
0341a5
+*tcp option* {*eol* | *nop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} 'tcp_option_field'
0341a5
 *ip option* { lsrr | ra | rr | ssrr } 'ip_option_field'
0341a5
 
0341a5
 The following syntaxes are valid only in a relational expression with boolean type on right-hand side for checking header existence only:
0341a5
 [verse]
0341a5
 *exthdr* {*hbh* | *frag* | *rt* | *dst* | *mh*}
0341a5
-*tcp option* {*eol* | *noop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*}
0341a5
+*tcp option* {*eol* | *nop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*}
0341a5
 *ip option* { lsrr | ra | rr | ssrr }
0341a5
 
0341a5
 .IPv6 extension headers
0341a5
diff --git a/include/tcpopt.h b/include/tcpopt.h
0341a5
index ffdbcb0..7f3fbb8 100644
0341a5
--- a/include/tcpopt.h
0341a5
+++ b/include/tcpopt.h
0341a5
@@ -6,7 +6,7 @@
0341a5
 #include <statement.h>
0341a5
 
0341a5
 extern struct expr *tcpopt_expr_alloc(const struct location *loc,
0341a5
-				      uint8_t type, uint8_t field);
0341a5
+				      unsigned int kind, unsigned int field);
0341a5
 
0341a5
 extern void tcpopt_init_raw(struct expr *expr, uint8_t type,
0341a5
 			    unsigned int offset, unsigned int len,
0341a5
@@ -15,21 +15,22 @@ extern void tcpopt_init_raw(struct expr *expr, uint8_t type,
0341a5
 extern bool tcpopt_find_template(struct expr *expr, const struct expr *mask,
0341a5
 				 unsigned int *shift);
0341a5
 
0341a5
-enum tcpopt_hdr_types {
0341a5
-	TCPOPTHDR_INVALID,
0341a5
-	TCPOPTHDR_EOL,
0341a5
-	TCPOPTHDR_NOOP,
0341a5
-	TCPOPTHDR_MAXSEG,
0341a5
-	TCPOPTHDR_WINDOW,
0341a5
-	TCPOPTHDR_SACK_PERMITTED,
0341a5
-	TCPOPTHDR_SACK0,
0341a5
-	TCPOPTHDR_SACK1,
0341a5
-	TCPOPTHDR_SACK2,
0341a5
-	TCPOPTHDR_SACK3,
0341a5
-	TCPOPTHDR_TIMESTAMP,
0341a5
-	TCPOPTHDR_ECHO,
0341a5
-	TCPOPTHDR_ECHO_REPLY,
0341a5
-	__TCPOPTHDR_MAX
0341a5
+/* TCP option numbers used on wire */
0341a5
+enum tcpopt_kind {
0341a5
+	TCPOPT_KIND_EOL = 0,
0341a5
+	TCPOPT_KIND_NOP = 1,
0341a5
+	TCPOPT_KIND_MAXSEG = 2,
0341a5
+	TCPOPT_KIND_WINDOW = 3,
0341a5
+	TCPOPT_KIND_SACK_PERMITTED = 4,
0341a5
+	TCPOPT_KIND_SACK = 5,
0341a5
+	TCPOPT_KIND_TIMESTAMP = 8,
0341a5
+	TCPOPT_KIND_ECHO = 8,
0341a5
+	__TCPOPT_KIND_MAX,
0341a5
+
0341a5
+	/* extra oob info, internal to nft */
0341a5
+	TCPOPT_KIND_SACK1 = 256,
0341a5
+	TCPOPT_KIND_SACK2 = 257,
0341a5
+	TCPOPT_KIND_SACK3 = 258,
0341a5
 };
0341a5
 
0341a5
 enum tcpopt_hdr_fields {
0341a5
@@ -44,6 +45,6 @@ enum tcpopt_hdr_fields {
0341a5
 	TCPOPTHDR_FIELD_TSECR,
0341a5
 };
0341a5
 
0341a5
-extern const struct exthdr_desc *tcpopthdr_protocols[__TCPOPTHDR_MAX];
0341a5
+extern const struct exthdr_desc *tcpopt_protocols[__TCPOPT_KIND_MAX];
0341a5
 
0341a5
 #endif /* NFTABLES_TCPOPT_H */
0341a5
diff --git a/src/parser_bison.y b/src/parser_bison.y
0341a5
index 56d26e3..8f77766 100644
0341a5
--- a/src/parser_bison.y
0341a5
+++ b/src/parser_bison.y
0341a5
@@ -384,7 +384,7 @@ int nft_lex(void *, void *, void *);
0341a5
 %token OPTION			"option"
0341a5
 %token ECHO			"echo"
0341a5
 %token EOL			"eol"
0341a5
-%token NOOP			"noop"
0341a5
+%token NOP			"nop"
0341a5
 %token SACK			"sack"
0341a5
 %token SACK0			"sack0"
0341a5
 %token SACK1			"sack1"
0341a5
@@ -4732,18 +4732,18 @@ tcp_hdr_field		:	SPORT		{ $$ = TCPHDR_SPORT; }
0341a5
 			|	URGPTR		{ $$ = TCPHDR_URGPTR; }
0341a5
 			;
0341a5
 
0341a5
-tcp_hdr_option_type	:	EOL		{ $$ = TCPOPTHDR_EOL; }
0341a5
-			|	NOOP		{ $$ = TCPOPTHDR_NOOP; }
0341a5
-			|	MSS  	  	{ $$ = TCPOPTHDR_MAXSEG; }
0341a5
-			|	WINDOW		{ $$ = TCPOPTHDR_WINDOW; }
0341a5
-			|	SACK_PERM	{ $$ = TCPOPTHDR_SACK_PERMITTED; }
0341a5
-			|	SACK		{ $$ = TCPOPTHDR_SACK0; }
0341a5
-			|	SACK0		{ $$ = TCPOPTHDR_SACK0; }
0341a5
-			|	SACK1		{ $$ = TCPOPTHDR_SACK1; }
0341a5
-			|	SACK2		{ $$ = TCPOPTHDR_SACK2; }
0341a5
-			|	SACK3		{ $$ = TCPOPTHDR_SACK3; }
0341a5
-			|	ECHO		{ $$ = TCPOPTHDR_ECHO; }
0341a5
-			|	TIMESTAMP	{ $$ = TCPOPTHDR_TIMESTAMP; }
0341a5
+tcp_hdr_option_type	:	EOL		{ $$ = TCPOPT_KIND_EOL; }
0341a5
+			|	NOP		{ $$ = TCPOPT_KIND_NOP; }
0341a5
+			|	MSS  	  	{ $$ = TCPOPT_KIND_MAXSEG; }
0341a5
+			|	WINDOW		{ $$ = TCPOPT_KIND_WINDOW; }
0341a5
+			|	SACK_PERM	{ $$ = TCPOPT_KIND_SACK_PERMITTED; }
0341a5
+			|	SACK		{ $$ = TCPOPT_KIND_SACK; }
0341a5
+			|	SACK0		{ $$ = TCPOPT_KIND_SACK; }
0341a5
+			|	SACK1		{ $$ = TCPOPT_KIND_SACK1; }
0341a5
+			|	SACK2		{ $$ = TCPOPT_KIND_SACK2; }
0341a5
+			|	SACK3		{ $$ = TCPOPT_KIND_SACK3; }
0341a5
+			|	ECHO		{ $$ = TCPOPT_KIND_ECHO; }
0341a5
+			|	TIMESTAMP	{ $$ = TCPOPT_KIND_TIMESTAMP; }
0341a5
 			;
0341a5
 
0341a5
 tcp_hdr_option_field	:	KIND		{ $$ = TCPOPTHDR_FIELD_KIND; }
0341a5
diff --git a/src/parser_json.c b/src/parser_json.c
0341a5
index 662bb4b..44b58a0 100644
0341a5
--- a/src/parser_json.c
0341a5
+++ b/src/parser_json.c
0341a5
@@ -456,9 +456,9 @@ static int json_parse_tcp_option_type(const char *name, int *val)
0341a5
 {
0341a5
 	unsigned int i;
0341a5
 
0341a5
-	for (i = 0; i < array_size(tcpopthdr_protocols); i++) {
0341a5
-		if (tcpopthdr_protocols[i] &&
0341a5
-		    !strcmp(tcpopthdr_protocols[i]->name, name)) {
0341a5
+	for (i = 0; i < array_size(tcpopt_protocols); i++) {
0341a5
+		if (tcpopt_protocols[i] &&
0341a5
+		    !strcmp(tcpopt_protocols[i]->name, name)) {
0341a5
 			if (val)
0341a5
 				*val = i;
0341a5
 			return 0;
0341a5
@@ -467,7 +467,7 @@ static int json_parse_tcp_option_type(const char *name, int *val)
0341a5
 	/* special case for sack0 - sack3 */
0341a5
 	if (sscanf(name, "sack%u", &i) == 1 && i < 4) {
0341a5
 		if (val)
0341a5
-			*val = TCPOPTHDR_SACK0 + i;
0341a5
+			*val = TCPOPT_KIND_SACK + i;
0341a5
 		return 0;
0341a5
 	}
0341a5
 	return 1;
0341a5
@@ -476,7 +476,7 @@ static int json_parse_tcp_option_type(const char *name, int *val)
0341a5
 static int json_parse_tcp_option_field(int type, const char *name, int *val)
0341a5
 {
0341a5
 	unsigned int i;
0341a5
-	const struct exthdr_desc *desc = tcpopthdr_protocols[type];
0341a5
+	const struct exthdr_desc *desc = tcpopt_protocols[type];
0341a5
 
0341a5
 	for (i = 0; i < array_size(desc->templates); i++) {
0341a5
 		if (desc->templates[i].token &&
0341a5
diff --git a/src/scanner.l b/src/scanner.l
0341a5
index a369802..20b1b2d 100644
0341a5
--- a/src/scanner.l
0341a5
+++ b/src/scanner.l
0341a5
@@ -421,7 +421,8 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
0341a5
 "eol"			{ return EOL; }
0341a5
 "maxseg"		{ return MSS; }
0341a5
 "mss"			{ return MSS; }
0341a5
-"noop"			{ return NOOP; }
0341a5
+"nop"			{ return NOP; }
0341a5
+"noop"			{ return NOP; }
0341a5
 "sack"			{ return SACK; }
0341a5
 "sack0"			{ return SACK0; }
0341a5
 "sack1"			{ return SACK1; }
0341a5
diff --git a/src/tcpopt.c b/src/tcpopt.c
0341a5
index 6dbaa9e..8d5bdec 100644
0341a5
--- a/src/tcpopt.c
0341a5
+++ b/src/tcpopt.c
0341a5
@@ -20,7 +20,7 @@ static const struct proto_hdr_template tcpopt_unknown_template =
0341a5
 			   __offset, __len)
0341a5
 static const struct exthdr_desc tcpopt_eol = {
0341a5
 	.name		= "eol",
0341a5
-	.type		= TCPOPT_EOL,
0341a5
+	.type		= TCPOPT_KIND_EOL,
0341a5
 	.templates	= {
0341a5
 		[TCPOPTHDR_FIELD_KIND]		= PHT("kind",  0,    8),
0341a5
 	},
0341a5
@@ -28,7 +28,7 @@ static const struct exthdr_desc tcpopt_eol = {
0341a5
 
0341a5
 static const struct exthdr_desc tcpopt_nop = {
0341a5
 	.name		= "noop",
0341a5
-	.type		= TCPOPT_NOP,
0341a5
+	.type		= TCPOPT_KIND_NOP,
0341a5
 	.templates	= {
0341a5
 		[TCPOPTHDR_FIELD_KIND]		= PHT("kind",   0,   8),
0341a5
 	},
0341a5
@@ -36,7 +36,7 @@ static const struct exthdr_desc tcpopt_nop = {
0341a5
 
0341a5
 static const struct exthdr_desc tcptopt_maxseg = {
0341a5
 	.name		= "maxseg",
0341a5
-	.type		= TCPOPT_MAXSEG,
0341a5
+	.type		= TCPOPT_KIND_MAXSEG,
0341a5
 	.templates	= {
0341a5
 		[TCPOPTHDR_FIELD_KIND]		= PHT("kind",   0,  8),
0341a5
 		[TCPOPTHDR_FIELD_LENGTH]	= PHT("length", 8,  8),
0341a5
@@ -46,7 +46,7 @@ static const struct exthdr_desc tcptopt_maxseg = {
0341a5
 
0341a5
 static const struct exthdr_desc tcpopt_window = {
0341a5
 	.name		= "window",
0341a5
-	.type		= TCPOPT_WINDOW,
0341a5
+	.type		= TCPOPT_KIND_WINDOW,
0341a5
 	.templates	= {
0341a5
 		[TCPOPTHDR_FIELD_KIND]		= PHT("kind",   0,  8),
0341a5
 		[TCPOPTHDR_FIELD_LENGTH]	= PHT("length", 8,  8),
0341a5
@@ -56,7 +56,7 @@ static const struct exthdr_desc tcpopt_window = {
0341a5
 
0341a5
 static const struct exthdr_desc tcpopt_sack_permitted = {
0341a5
 	.name		= "sack-perm",
0341a5
-	.type		= TCPOPT_SACK_PERMITTED,
0341a5
+	.type		= TCPOPT_KIND_SACK_PERMITTED,
0341a5
 	.templates	= {
0341a5
 		[TCPOPTHDR_FIELD_KIND]		= PHT("kind",   0, 8),
0341a5
 		[TCPOPTHDR_FIELD_LENGTH]	= PHT("length", 8, 8),
0341a5
@@ -65,7 +65,7 @@ static const struct exthdr_desc tcpopt_sack_permitted = {
0341a5
 
0341a5
 static const struct exthdr_desc tcpopt_sack = {
0341a5
 	.name		= "sack",
0341a5
-	.type		= TCPOPT_SACK,
0341a5
+	.type		= TCPOPT_KIND_SACK,
0341a5
 	.templates	= {
0341a5
 		[TCPOPTHDR_FIELD_KIND]		= PHT("kind",   0,   8),
0341a5
 		[TCPOPTHDR_FIELD_LENGTH]		= PHT("length", 8,   8),
0341a5
@@ -76,7 +76,7 @@ static const struct exthdr_desc tcpopt_sack = {
0341a5
 
0341a5
 static const struct exthdr_desc tcpopt_timestamp = {
0341a5
 	.name		= "timestamp",
0341a5
-	.type		= TCPOPT_TIMESTAMP,
0341a5
+	.type		= TCPOPT_KIND_TIMESTAMP,
0341a5
 	.templates	= {
0341a5
 		[TCPOPTHDR_FIELD_KIND]		= PHT("kind",   0,  8),
0341a5
 		[TCPOPTHDR_FIELD_LENGTH]	= PHT("length", 8,  8),
0341a5
@@ -86,19 +86,14 @@ static const struct exthdr_desc tcpopt_timestamp = {
0341a5
 };
0341a5
 #undef PHT
0341a5
 
0341a5
-#define TCPOPT_OBSOLETE ((struct exthdr_desc *)NULL)
0341a5
-#define TCPOPT_ECHO 6
0341a5
-#define TCPOPT_ECHO_REPLY 7
0341a5
-static const struct exthdr_desc *tcpopt_protocols[] = {
0341a5
-	[TCPOPT_EOL]		= &tcpopt_eol,
0341a5
-	[TCPOPT_NOP]		= &tcpopt_nop,
0341a5
-	[TCPOPT_MAXSEG]		= &tcptopt_maxseg,
0341a5
-	[TCPOPT_WINDOW]		= &tcpopt_window,
0341a5
-	[TCPOPT_SACK_PERMITTED]	= &tcpopt_sack_permitted,
0341a5
-	[TCPOPT_SACK]		= &tcpopt_sack,
0341a5
-	[TCPOPT_ECHO]		= TCPOPT_OBSOLETE,
0341a5
-	[TCPOPT_ECHO_REPLY]	= TCPOPT_OBSOLETE,
0341a5
-	[TCPOPT_TIMESTAMP]	= &tcpopt_timestamp,
0341a5
+const struct exthdr_desc *tcpopt_protocols[] = {
0341a5
+	[TCPOPT_KIND_EOL]		= &tcpopt_eol,
0341a5
+	[TCPOPT_KIND_NOP]		= &tcpopt_nop,
0341a5
+	[TCPOPT_KIND_MAXSEG]		= &tcptopt_maxseg,
0341a5
+	[TCPOPT_KIND_WINDOW]		= &tcpopt_window,
0341a5
+	[TCPOPT_KIND_SACK_PERMITTED]	= &tcpopt_sack_permitted,
0341a5
+	[TCPOPT_KIND_SACK]		= &tcpopt_sack,
0341a5
+	[TCPOPT_KIND_TIMESTAMP]		= &tcpopt_timestamp,
0341a5
 };
0341a5
 
0341a5
 static unsigned int calc_offset(const struct exthdr_desc *desc,
0341a5
@@ -136,51 +131,34 @@ static unsigned int calc_offset_reverse(const struct exthdr_desc *desc,
0341a5
 	}
0341a5
 }
0341a5
 
0341a5
-const struct exthdr_desc *tcpopthdr_protocols[__TCPOPTHDR_MAX] = {
0341a5
-	[TCPOPTHDR_EOL]			= &tcpopt_eol,
0341a5
-	[TCPOPTHDR_NOOP]		= &tcpopt_nop,
0341a5
-	[TCPOPTHDR_MAXSEG]		= &tcptopt_maxseg,
0341a5
-	[TCPOPTHDR_WINDOW]		= &tcpopt_window,
0341a5
-	[TCPOPTHDR_SACK_PERMITTED]	= &tcpopt_sack_permitted,
0341a5
-	[TCPOPTHDR_SACK0]		= &tcpopt_sack,
0341a5
-	[TCPOPTHDR_SACK1]		= &tcpopt_sack,
0341a5
-	[TCPOPTHDR_SACK2]		= &tcpopt_sack,
0341a5
-	[TCPOPTHDR_SACK3]		= &tcpopt_sack,
0341a5
-	[TCPOPTHDR_ECHO]		= TCPOPT_OBSOLETE,
0341a5
-	[TCPOPTHDR_ECHO_REPLY]		= TCPOPT_OBSOLETE,
0341a5
-	[TCPOPTHDR_TIMESTAMP]		= &tcpopt_timestamp,
0341a5
-};
0341a5
-
0341a5
-static uint8_t tcpopt_optnum[] = {
0341a5
-	[TCPOPTHDR_SACK0]	= 0,
0341a5
-	[TCPOPTHDR_SACK1]	= 1,
0341a5
-	[TCPOPTHDR_SACK2]	= 2,
0341a5
-	[TCPOPTHDR_SACK3]	= 3,
0341a5
-};
0341a5
-
0341a5
-static uint8_t tcpopt_find_optnum(uint8_t optnum)
0341a5
-{
0341a5
-	if (optnum > TCPOPTHDR_SACK3)
0341a5
-		return 0;
0341a5
-
0341a5
-	return tcpopt_optnum[optnum];
0341a5
-}
0341a5
-
0341a5
-struct expr *tcpopt_expr_alloc(const struct location *loc, uint8_t type,
0341a5
-			       uint8_t field)
0341a5
+struct expr *tcpopt_expr_alloc(const struct location *loc,
0341a5
+			       unsigned int kind,
0341a5
+			       unsigned int field)
0341a5
 {
0341a5
 	const struct proto_hdr_template *tmpl;
0341a5
 	const struct exthdr_desc *desc;
0341a5
+	uint8_t optnum = 0;
0341a5
 	struct expr *expr;
0341a5
-	uint8_t optnum;
0341a5
 
0341a5
-	desc = tcpopthdr_protocols[type];
0341a5
+	switch (kind) {
0341a5
+	case TCPOPT_KIND_SACK1:
0341a5
+		kind = TCPOPT_KIND_SACK;
0341a5
+		optnum = 1;
0341a5
+		break;
0341a5
+	case TCPOPT_KIND_SACK2:
0341a5
+		kind = TCPOPT_KIND_SACK;
0341a5
+		optnum = 2;
0341a5
+		break;
0341a5
+	case TCPOPT_KIND_SACK3:
0341a5
+		kind = TCPOPT_KIND_SACK;
0341a5
+		optnum = 3;
0341a5
+	}
0341a5
+
0341a5
+	desc = tcpopt_protocols[kind];
0341a5
 	tmpl = &desc->templates[field];
0341a5
 	if (!tmpl)
0341a5
 		return NULL;
0341a5
 
0341a5
-	optnum = tcpopt_find_optnum(type);
0341a5
-
0341a5
 	expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype,
0341a5
 			  BYTEORDER_BIG_ENDIAN, tmpl->len);
0341a5
 	expr->exthdr.desc   = desc;
0341a5
@@ -206,7 +184,7 @@ void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int offset,
0341a5
 	assert(type < array_size(tcpopt_protocols));
0341a5
 	expr->exthdr.desc = tcpopt_protocols[type];
0341a5
 	expr->exthdr.flags = flags;
0341a5
-	assert(expr->exthdr.desc != TCPOPT_OBSOLETE);
0341a5
+	assert(expr->exthdr.desc != NULL);
0341a5
 
0341a5
 	for (i = 0; i < array_size(expr->exthdr.desc->templates); ++i) {
0341a5
 		tmpl = &expr->exthdr.desc->templates[i];
0341a5
-- 
0341a5
2.31.1
0341a5