This is a first exclusive start condition, i.e. one which rejects unscoped tokens. When tokenizing, flex all too easily falls back into treating something as STRING when it could be split into tokens instead. Via an exclusive start condition, the string-fallback can be disabled as needed. With rates in typical formatting /, tokenizer result depended on whitespace placement. SCANSTATE_RATE forces flex to split the string into tokens and fall back to JUNK upon failure. For this to work, tokens which shall still be recognized must be enabled in SCANSTATE_RATE (or all scopes denoted by '*'). This includes any tokens possibly following SCANSTATE_RATE to please the parser's lookahead behaviour. Signed-off-by: Phil Sutter --- include/datatype.h | 4 --- include/parser.h | 1 + src/datatype.c | 61 ------------------------------- src/parser_bison.y | 23 +++--------- src/scanner.l | 55 ++++++++++++++-------------- tests/py/any/limit.t | 6 ++++ tests/py/any/limit.t.json | 70 ++++++++++++++++++++++++++++++++++++ tests/py/any/limit.t.payload | 20 +++++++++++ 8 files changed, 130 insertions(+), 110 deletions(-) diff --git a/include/datatype.h b/include/datatype.h index 63dba330137a0..4c5d6ff8d9002 100644 --- a/include/datatype.h +++ b/include/datatype.h @@ -309,10 +309,6 @@ extern void time_print(uint64_t msec, struct output_ctx *octx); extern struct error_record *time_parse(const struct location *loc, const char *c, uint64_t *res); -extern struct error_record *rate_parse(const struct location *loc, - const char *str, uint64_t *rate, - uint64_t *unit); - struct limit_rate { uint64_t rate, unit; }; diff --git a/include/parser.h b/include/parser.h index 8cfd22e9e6c42..889302baf5950 100644 --- a/include/parser.h +++ b/include/parser.h @@ -47,6 +47,7 @@ enum startcond_type { PARSER_SC_META, PARSER_SC_POLICY, PARSER_SC_QUOTA, + PARSER_SC_RATE, PARSER_SC_SCTP, PARSER_SC_SECMARK, PARSER_SC_TCP, diff --git a/src/datatype.c b/src/datatype.c index 1950a2f3757b8..189738513bf8c 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -1488,67 +1488,6 @@ const struct datatype *set_datatype_alloc(const struct datatype *orig_dtype, return dtype; } -static struct error_record *time_unit_parse(const struct location *loc, - const char *str, uint64_t *unit) -{ - if (strcmp(str, "second") == 0) - *unit = 1ULL; - else if (strcmp(str, "minute") == 0) - *unit = 1ULL * 60; - else if (strcmp(str, "hour") == 0) - *unit = 1ULL * 60 * 60; - else if (strcmp(str, "day") == 0) - *unit = 1ULL * 60 * 60 * 24; - else if (strcmp(str, "week") == 0) - *unit = 1ULL * 60 * 60 * 24 * 7; - else - return error(loc, "Wrong time format, expecting second, minute, hour, day or week"); - - return NULL; -} - -static struct error_record *data_unit_parse(const struct location *loc, - const char *str, uint64_t *rate) -{ - if (strcmp(str, "bytes") == 0) - *rate = 1ULL; - else if (strcmp(str, "kbytes") == 0) - *rate = 1024; - else if (strcmp(str, "mbytes") == 0) - *rate = 1024 * 1024; - else - return error(loc, "Wrong unit format, expecting bytes, kbytes or mbytes"); - - return NULL; -} - -struct error_record *rate_parse(const struct location *loc, const char *str, - uint64_t *rate, uint64_t *unit) -{ - const char *slash, *rate_str; - struct error_record *erec; - - slash = strchr(str, '/'); - if (!slash) - return error(loc, "wrong rate format, expecting {bytes,kbytes,mbytes}/{second,minute,hour,day,week}"); - - rate_str = strndup(str, slash - str); - if (!rate_str) - memory_allocation_error(); - - erec = data_unit_parse(loc, rate_str, rate); - free_const(rate_str); - - if (erec != NULL) - return erec; - - erec = time_unit_parse(loc, slash + 1, unit); - if (erec != NULL) - return erec; - - return NULL; -} - static const struct symbol_table boolean_tbl = { .base = BASE_DECIMAL, .symbols = { diff --git a/src/parser_bison.y b/src/parser_bison.y index a7e5ace067bf5..c2964799f7e97 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -1113,6 +1113,7 @@ close_scope_osf : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_OSF); } close_scope_policy : { scanner_pop_start_cond(nft->scanner, PARSER_SC_POLICY); }; close_scope_quota : { scanner_pop_start_cond(nft->scanner, PARSER_SC_QUOTA); }; close_scope_queue : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_QUEUE); }; +close_scope_rate : { scanner_pop_start_cond(nft->scanner, PARSER_SC_RATE); }; close_scope_reject : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_REJECT); }; close_scope_reset : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_RESET); }; close_scope_rt : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_RT); }; @@ -3557,7 +3558,7 @@ limit_stmt_alloc : LIMIT RATE } ; -limit_stmt : limit_stmt_alloc limit_args +limit_stmt : limit_stmt_alloc limit_args close_scope_rate ; limit_args : limit_mode limit_rate_pkts limit_burst_pkts @@ -3652,21 +3653,7 @@ limit_burst_bytes : /* empty */ { $$ = 0; } | BURST NUM bytes_unit { $$ = $2 * $3; } ; -limit_rate_bytes : NUM STRING - { - struct error_record *erec; - uint64_t rate, unit; - - erec = rate_parse(&@$, $2, &rate, &unit); - free_const($2); - if (erec != NULL) { - erec_queue(erec, state->msgs); - YYERROR; - } - $$.rate = rate * $1; - $$.unit = unit; - } - | NUM bytes_unit SLASH time_unit +limit_rate_bytes : NUM bytes_unit SLASH time_unit { $$.rate = $1 * $2; $$.unit = $4; @@ -4897,7 +4884,7 @@ ct_obj_alloc : /* empty */ } ; -limit_config : RATE limit_mode limit_rate_pkts limit_burst_pkts +limit_config : RATE limit_mode limit_rate_pkts limit_burst_pkts close_scope_rate { struct limit *limit; @@ -4908,7 +4895,7 @@ limit_config : RATE limit_mode limit_rate_pkts limit_burst_pkts limit->type = NFT_LIMIT_PKTS; limit->flags = $2; } - | RATE limit_mode limit_rate_bytes limit_burst_bytes + | RATE limit_mode limit_rate_bytes limit_burst_bytes close_scope_rate { struct limit *limit; diff --git a/src/scanner.l b/src/scanner.l index 4cbc8a44c89c8..9d8fade8308d3 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -219,6 +219,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) %s SCANSTATE_META %s SCANSTATE_POLICY %s SCANSTATE_QUOTA +%x SCANSTATE_RATE %s SCANSTATE_SCTP %s SCANSTATE_SECMARK %s SCANSTATE_TCP @@ -275,12 +276,12 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "ge" { return GTE; } ">" { return GT; } "gt" { return GT; } -"," { return COMMA; } +<*>"," { return COMMA; } "." { return DOT; } ":" { return COLON; } -";" { return SEMICOLON; } +<*>";" { return SEMICOLON; } "{" { return '{'; } -"}" { return '}'; } +<*>"}" { return '}'; } "[" { return '['; } "]" { return ']'; } "(" { return '('; } @@ -297,7 +298,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "or" { return '|'; } "!" { return NOT; } "not" { return NOT; } -"/" { return SLASH; } +<*>"/" { return SLASH; } "-" { return DASH; } "*" { return ASTERISK; } "@" { scanner_push_start_cond(yyscanner, SCANSTATE_AT); return AT; } @@ -410,12 +411,12 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "hooks" { return HOOKS; } } -"counter" { scanner_push_start_cond(yyscanner, SCANSTATE_COUNTER); return COUNTER; } +<*>"counter" { scanner_push_start_cond(yyscanner, SCANSTATE_COUNTER); return COUNTER; } "name" { return NAME; } -"packets" { return PACKETS; } -"bytes" { return BYTES; } -"kbytes" { return KBYTES; } -"mbytes" { return MBYTES; } +"packets" { return PACKETS; } +"bytes" { return BYTES; } +"kbytes" { return KBYTES; } +"mbytes" { return MBYTES; } "last" { scanner_push_start_cond(yyscanner, SCANSTATE_LAST); return LAST; } { @@ -428,7 +429,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "rules" { return RULES; } } -"log" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_LOG); return LOG; } +<*>"log" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_LOG); return LOG; } "prefix" { return PREFIX; } { "snaplen" { return SNAPLEN; } @@ -453,8 +454,8 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "fanout" { return FANOUT;} } "limit" { scanner_push_start_cond(yyscanner, SCANSTATE_LIMIT); return LIMIT; } -{ - "rate" { return RATE; } +{ + "rate" { scanner_push_start_cond(yyscanner, SCANSTATE_RATE); return RATE; } "burst" { return BURST; } /* time_unit */ @@ -462,17 +463,17 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "minute" { return MINUTE; } "week" { return WEEK; } } -"over" { return OVER; } +"over" { return OVER; } "quota" { scanner_push_start_cond(yyscanner, SCANSTATE_QUOTA); return QUOTA; } -{ +{ "until" { return UNTIL; } } "used" { return USED; } -"hour" { return HOUR; } -"day" { return DAY; } +<*>"hour" { return HOUR; } +<*>"day" { return DAY; } "reject" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_REJECT); return _REJECT; } { @@ -901,7 +902,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) return STRING; } -{hexstring} { +<*>{hexstring} { errno = 0; yylval->val = strtoull(yytext, NULL, 16); if (errno != 0) { @@ -911,7 +912,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) return NUM; } -{decstring} { +<*>{decstring} { int base = yytext[0] == '0' ? 8 : 10; char *end; @@ -945,32 +946,32 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) return STRING; } -{newline_crlf} { return CRLF; } +<*>{newline_crlf} { return CRLF; } -\\{newline} { +<*>\\{newline} { reset_pos(yyget_extra(yyscanner), yylloc); } -{newline} { +<*>{newline} { reset_pos(yyget_extra(yyscanner), yylloc); return NEWLINE; } -{tab}+ -{space}+ -{comment_line} { +<*>{tab}+ +<*>{space}+ +<*>{comment_line} { reset_pos(yyget_extra(yyscanner), yylloc); } -{comment} +<*>{comment} -<> { +<*><> { update_pos(yyget_extra(yyscanner), yylloc, 1); scanner_pop_buffer(yyscanner); if (YY_CURRENT_BUFFER == NULL) return TOKEN_EOF; } -. { return JUNK; } +<*>. { return JUNK; } %% diff --git a/tests/py/any/limit.t b/tests/py/any/limit.t index 2a84e3f56e4ef..5c95ffa52ee8a 100644 --- a/tests/py/any/limit.t +++ b/tests/py/any/limit.t @@ -49,3 +49,9 @@ limit rate over 10230 mbytes/second;ok limit rate over 1025 bytes/second burst 512 bytes;ok limit rate over 1025 kbytes/second burst 1023 kbytes;ok limit rate over 1025 mbytes/second burst 1025 kbytes;ok + +limit rate over 1025bytes/second burst 512bytes;ok;limit rate over 1025 bytes/second burst 512 bytes +limit rate over 1025bytes /second burst 512bytes;ok;limit rate over 1025 bytes/second burst 512 bytes +limit rate over 1025bytes/ second burst 512bytes;ok;limit rate over 1025 bytes/second burst 512 bytes +limit rate over 1025bytes / second burst 512bytes;ok;limit rate over 1025 bytes/second burst 512 bytes +limit rate over 1025 bytes / second burst 512bytes;ok;limit rate over 1025 bytes/second burst 512 bytes diff --git a/tests/py/any/limit.t.json b/tests/py/any/limit.t.json index 73160b27fad81..49a48960ecf86 100644 --- a/tests/py/any/limit.t.json +++ b/tests/py/any/limit.t.json @@ -360,3 +360,73 @@ } } ] + +# limit rate over 1025bytes/second burst 512bytes +[ + { + "limit": { + "burst": 512, + "burst_unit": "bytes", + "inv": true, + "per": "second", + "rate": 1025, + "rate_unit": "bytes" + } + } +] + +# limit rate over 1025bytes /second burst 512bytes +[ + { + "limit": { + "burst": 512, + "burst_unit": "bytes", + "inv": true, + "per": "second", + "rate": 1025, + "rate_unit": "bytes" + } + } +] + +# limit rate over 1025bytes/ second burst 512bytes +[ + { + "limit": { + "burst": 512, + "burst_unit": "bytes", + "inv": true, + "per": "second", + "rate": 1025, + "rate_unit": "bytes" + } + } +] + +# limit rate over 1025bytes / second burst 512bytes +[ + { + "limit": { + "burst": 512, + "burst_unit": "bytes", + "inv": true, + "per": "second", + "rate": 1025, + "rate_unit": "bytes" + } + } +] + +# limit rate over 1025 bytes / second burst 512bytes +[ + { + "limit": { + "burst": 512, + "burst_unit": "bytes", + "inv": true, + "per": "second", + "rate": 1025, + "rate_unit": "bytes" + } + } +] diff --git a/tests/py/any/limit.t.payload b/tests/py/any/limit.t.payload index dc6701b3521c9..901275dafcaa0 100644 --- a/tests/py/any/limit.t.payload +++ b/tests/py/any/limit.t.payload @@ -122,3 +122,23 @@ ip test-ip4 output # limit rate over 1025 mbytes/second burst 1025 kbytes ip test-ip4 output [ limit rate 1074790400/second burst 1049600 type bytes flags 0x1 ] + +# limit rate over 1025bytes/second burst 512bytes +ip test-ip4 output + [ limit rate 1025/second burst 512 type bytes flags 0x1 ] + +# limit rate over 1025bytes /second burst 512bytes +ip test-ip4 output + [ limit rate 1025/second burst 512 type bytes flags 0x1 ] + +# limit rate over 1025bytes/ second burst 512bytes +ip test-ip4 output + [ limit rate 1025/second burst 512 type bytes flags 0x1 ] + +# limit rate over 1025bytes / second burst 512bytes +ip test-ip4 output + [ limit rate 1025/second burst 512 type bytes flags 0x1 ] + +# limit rate over 1025 bytes / second burst 512bytes +ip test-ip4 output + [ limit rate 1025/second burst 512 type bytes flags 0x1 ] -- 2.51.0