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

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