From 80ca0ed279f2c8f396976d90f2e98ba6b923081c Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Fri, 18 Oct 2024 16:39:42 +0200 Subject: [PATCH] Filter: Add enum types to filter grammar Enum types existed on semantic level, but not on syntactic level, so they could not be used in filter code. Generate filter grammar for enum types based on CF_ENUM() declarations. Thanks to lbz for the bugreport. --- conf/cf-lex.l | 2 +- conf/confbase.Y | 2 +- conf/gen_keywords.m4 | 5 +++-- conf/gen_parser.m4 | 8 ++++++-- filter/config.Y | 8 +++++--- filter/data.c | 1 + filter/test.conf | 19 +++++++++++++++++++ nest/config.Y | 3 +-- 8 files changed, 37 insertions(+), 11 deletions(-) diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 2f95f2e1..637a5d38 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -680,7 +680,7 @@ cf_lex_symbol(const char *data) int val = sym->keyword->value; if (val > 0) return val; cf_lval.i = -val; - return ENUM; + return ENUM_TOKEN; } case SYM_METHOD: return (sym->method->arg_num > 1) ? CF_SYM_METHOD_ARGS : CF_SYM_METHOD_BARE; diff --git a/conf/confbase.Y b/conf/confbase.Y index cdbdf1ce..1011a57c 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -105,7 +105,7 @@ CF_DECLS %token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT %token GEQ LEQ NEQ AND OR IMP %token PO PC -%token NUM ENUM +%token NUM ENUM_TOKEN %token IP4 %token IP6 %token VPN_RD diff --git a/conf/gen_keywords.m4 b/conf/gen_keywords.m4 index 4e8651f6..e81589dc 100644 --- a/conf/gen_keywords.m4 +++ b/conf/gen_keywords.m4 @@ -35,10 +35,11 @@ m4_define(CF_CLI, `CF_KEYWORDS(m4_translit($1, [[ ]], [[,]])) # Enums are translated to C initializers: use CF_ENUM(typename, prefix, values) # For different prefix: CF_ENUM_PX(typename, external prefix, C prefix, values) +# The typename is converted to a keyword by removing T_ENUM_ prefix m4_define(CF_enum, `m4_divert(1){ "CF_enum_prefix_ext[[]]$1", -((CF_enum_type<<16) | CF_enum_prefix_int[[]]$1) }, m4_divert(-1)') -m4_define(CF_ENUM, `m4_define([[CF_enum_type]],$1)m4_define([[CF_enum_prefix_ext]],$2)m4_define([[CF_enum_prefix_int]],$2)CF_iterate([[CF_enum]], [[m4_shift(m4_shift($@))]])DNL') -m4_define(CF_ENUM_PX, `m4_define([[CF_enum_type]],$1)m4_define([[CF_enum_prefix_ext]],$2)m4_define([[CF_enum_prefix_int]],$3)CF_iterate([[CF_enum]], [[m4_shift(m4_shift(m4_shift($@)))]])DNL') +m4_define(CF_ENUM, `CF_keywd(m4_substr($1, 7))m4_define([[CF_enum_type]],$1)m4_define([[CF_enum_prefix_ext]],$2)m4_define([[CF_enum_prefix_int]],$2)CF_iterate([[CF_enum]], [[m4_shift(m4_shift($@))]])DNL') +m4_define(CF_ENUM_PX, `CF_keywd(m4_substr($1, 7))m4_define([[CF_enum_type]],$1)m4_define([[CF_enum_prefix_ext]],$2)m4_define([[CF_enum_prefix_int]],$3)CF_iterate([[CF_enum]], [[m4_shift(m4_shift(m4_shift($@)))]])DNL') # After all configuration templates end, we generate the m4_m4wrap(` diff --git a/conf/gen_parser.m4 b/conf/gen_parser.m4 index 48c2ca50..e41eb7f7 100644 --- a/conf/gen_parser.m4 +++ b/conf/gen_parser.m4 @@ -52,8 +52,10 @@ m4_define(CF_CLI_OPT, `') m4_define(CF_CLI_HELP, `') # ENUM declarations are ignored -m4_define(CF_ENUM, `') -m4_define(CF_ENUM_PX, `') +m4_define(CF_token, `m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)%token $1]])') +m4_define(CF_enum, `CF_append([[CF_enum_type]],[[$1 { $$ = $2; }]],[[ | ]])CF_token($1)') +m4_define(CF_ENUM, `CF_enum(m4_substr($1, 7), $1)') +m4_define(CF_ENUM_PX, `CF_enum(m4_substr($1, 7), $1)') # After all configuration templates end, we finally generate the grammar file. m4_m4wrap(` @@ -65,9 +67,11 @@ m4_undivert(1)DNL m4_undivert(2)DNL %type KEYWORD +%type enum_type %% KEYWORD: CF_kw_rule; +enum_type: CF_enum_type; m4_undivert(3)DNL diff --git a/filter/config.Y b/filter/config.Y index d656a726..3b4d669f 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -357,7 +357,7 @@ CF_DECLS CF_KEYWORDS_EXCLUSIVE(IN) CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, ACCEPT, REJECT, ERROR, - INT, BOOL, IP, PREFIX, RD, PAIR, QUAD, EC, LC, + INT, BOOL, IP, PREFIX, RD, PAIR, QUAD, EC, LC, ENUM, SET, STRING, BYTESTRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST, IF, THEN, ELSE, CASE, FOR, DO, @@ -473,6 +473,7 @@ type: case T_INT: case T_PAIR: case T_QUAD: + case T_ENUM: case T_EC: case T_LC: case T_RD: @@ -488,6 +489,7 @@ type: cf_error( "You can't create sets of this type." ); } } + | ENUM enum_type { $$ = $2; }; ; function_argsn: @@ -640,7 +642,7 @@ set_atom0: NUM { $$.type = T_INT; $$.val.i = $1; } | fipa { $$ = $1; } | VPN_RD { $$.type = T_RD; $$.val.ec = $1; } - | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } + | ENUM_TOKEN { $$.type = pair_a($1); $$.val.i = pair_b($1); } | '(' term ')' { $$ = cf_eval($2, T_VOID); if (!f_valid_set_type($$.type)) @@ -808,7 +810,7 @@ constant: DBG( "ook\n" ); } | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PREFIX_SET, .val.ti = $2, }); } - | ENUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = $1 >> 16, .val.i = $1 & 0xffff, }); } + | ENUM_TOKEN { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = $1 >> 16, .val.i = $1 & 0xffff, }); } ; constructor: diff --git a/filter/data.c b/filter/data.c index 282206eb..10084448 100644 --- a/filter/data.c +++ b/filter/data.c @@ -44,6 +44,7 @@ static const char * const f_type_str[] = { [T_ENUM_NETTYPE] = "enum nettype", [T_ENUM_RA_PREFERENCE] = "enum ra_preference", [T_ENUM_AF] = "enum af", + [T_ENUM_MPLS_POLICY] = "enum mpls_policy", [T_IP] = "ip", [T_NET] = "prefix", diff --git a/filter/test.conf b/filter/test.conf index 0361a1c9..c27c04ed 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -471,12 +471,31 @@ bt_test_suite(t_ip_set, "Testing sets of ip address"); function t_enum() { + enum rts ev0 = RTS_STATIC; + enum rtd ev1 = RTD_UNICAST; + enum scope ev2 = SCOPE_UNIVERSE; + enum roa ev3 = ROA_VALID; + enum aspa ev4 = ASPA_VALID; + enum af ev5 = AF_IPV6; + enum nettype ev6 = NET_IP6; + enum bgp_origin ev7 = ORIGIN_IGP; + enum ra_preference ev8 = RA_PREF_LOW; + enum mpls_policy ev9 = MPLS_POLICY_STATIC; + + enum nettype set es = [NET_IP6, NET_VPN6]; + bt_assert(format(RTS_STATIC) = "(enum 30)1"); bt_assert(format(NET_IP4) = "(enum 36)1"); bt_assert(format(NET_VPN6) = "(enum 36)4"); + bt_assert(format(ev6) = "(enum 36)2"); + + bt_assert(ev0 = RTS_STATIC); + bt_assert(ev6 = NET_IP6); bt_assert(RTS_STATIC ~ [RTS_STATIC, RTS_DEVICE]); bt_assert(RTS_BGP !~ [RTS_STATIC, RTS_DEVICE]); + bt_assert(NET_IP6 ~ es); + bt_assert(NET_IP4 !~ es); } bt_test_suite(t_enum, "Testing enums"); diff --git a/nest/config.Y b/nest/config.Y index 6b89f5d8..118c112e 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -132,6 +132,7 @@ CF_KEYWORDS(ASPA_PROVIDERS) /* For r_args_channel */ CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC, ASPA) +CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, IP6_SADR, MPLS, ASPA) CF_ENUM(T_ENUM_RTS, RTS_, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT, RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE, BABEL, RPKI, L3VPN, AGGREGATED) @@ -211,8 +212,6 @@ net_type: | MPLS { $$ = NET_MPLS; } ; -CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, IP6_SADR, MPLS, ASPA) - /* Creation of routing tables */