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

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