On Tue, Jun 27, 2023 at 2:13 AM Alexander Zubkov <gr...@qrator.net> wrote: > > On Mon, Jun 26, 2023 at 5:54 PM Alexander Zubkov <gr...@qrator.net> wrote: > > > > On Mon, Jun 26, 2023 at 5:43 PM Ondrej Zajicek <santi...@crfreenet.org> > > wrote: > > > > > > On Mon, Jun 26, 2023 at 03:24:47AM +0200, Alexander Zubkov wrote: > > > > On Sat, Jun 24, 2023 at 3:16 PM Ondrej Zajicek <santi...@crfreenet.org> > > > > wrote: > > > > > > > > > > On Sat, Jun 24, 2023 at 02:20:03AM +0200, Alexander Zubkov wrote: > > > > > > > Yes, the original idea there was to add bytestring as a data > > > > > > > type, make > > > > > > > hex() a regular (filter) function instead of special function-like > > > > > > > syntax, and add equivalent of 'expr' grammar term for other data > > > > > > > types. > > > > > > > > > > > > > > > > > > > I see. I think I can look into preparing a patch for that too. > > > > > > But for such variant I would suggest using function names like > > > > > > "from_hex/base64" instead of "hex/base64", or something including > > > > > > bytestring reference: "bs_hex". Because the simple variants could be > > > > > > misleading when used not only in the limited set of scopes. > > > > > > they can be thought of converting to hex/base64 representation too. > > > > > > Or they > > > > > > could collide with "hex" function to convert from string to int, > > > > > > which > > > > > > someone would need to implement in the future. > > > > > > > > > > Yes, that is true. > > > > > > > > > > You can try it if you are brave enough to add new f_val type. > > > > > > > > Take a look at the patch, please. Waiting for the critics and > > > > improvement suggestions. > > > > > > Hi > > > > > > It looks pretty good. First, could you split it to at least four patches? > > > > Sure. I'll provide split patches later. > > > > > > > > 1) unrelated changes, like the newline-in-string-constant > > > 2) preparatory changes (functions in lib/bytestring.c, change to > > > BYTESTRING lexer) > > > 3) adding bytestring type to filter code (including FI_FROM_HEX inst) > > Added patches up to this point. There are also some fixes and > modification. For example, I noted that 'bytestring' symbol for the > type name conflicts with lexer's BYTESTRING id. So I had to rename > lexer's BYTESTRING to BYTETEXT (like it is done for strings). > For the following patches it is better to decide the structure of the > new *eval* functions. > > > > 4) change to parser related to f_eval_val(), bytestring nonterminal and > > > so on.
Final patches to modify current f_eval_int() to generic approach. And for nonterminal bytestring. Again, waiting for comments/suggestions. Also feel free, of course, to fix naming/etc when applying. Next, I will be able to move forward with patches to the documentation. > > > > > > Some more comments: > > > > > > > It was needed to add another function like f_eval_int(), so I decided > > > > to do some more generic approach and replaced all occurences of > > > > f_eval_int() with it. > > > > > > That is good approach, although it would be probably better to call this > > > function like cf_eval(), associated macro as cf_eval_val, and keep some > > > inline functions like cf_eval_int(), cf_eval_bs() and so on. > > > > > > Or perhaps cf_eval() could return f_val as return value, and have > > > shorthand functions like: > > > > > > static inline cf_eval_int(..) { return cf_eval(.., T_INT).i; } > > I actually tried first to return the struct instead of modifying it by > a reference. But for that we need to have "struct f_val" known in > filter/filter.h, which is defined in filter/data.h. But that causes > some circular dependencies problem. I didn't dig deep into it, but > maybe it is possible to solve the conflict in a clean way. Looked at it again. It seems safe to include filter/data.h into filter/filter.h. I probably had problems when trying to incude it somewhere else, until it all finalized into filter.h > > > > > > > I will give more comments later. > > > > > > -- > > > Elen sila lumenn' omentielvo > > > > > > Ondrej 'Santiago' Zajicek (email: santi...@crfreenet.org) > > > OpenPGP encrypted e-mails preferred (KeyID 0x11DEADC3, wwwkeys.pgp.net) > > > "To err is human -- to blame it on a computer is even more so."
From 63f9dcc924599915a93cb71f1f9e9cbb8ebd087b Mon Sep 17 00:00:00 2001 From: Alexander Zubkov <gr...@qrator.net> Date: Thu, 29 Jun 2023 13:00:12 +0200 Subject: [PATCH] Conf: use more generic approach for intra-config expression evaluation Replace f_eval_int() function with a type-generic variant: cf_eval(). And implement similar fuction: cf_eval_int() via inline call to cf_eval(). --- conf/confbase.Y | 4 ++-- filter/config.Y | 8 ++++---- filter/filter.c | 22 +++++++--------------- filter/filter.h | 8 +++++--- nest/config.Y | 2 +- 5 files changed, 19 insertions(+), 25 deletions(-) diff --git a/conf/confbase.Y b/conf/confbase.Y index da750d38..e109ddf5 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -155,14 +155,14 @@ conf: definition ; definition: DEFINE symbol '=' term ';' { struct f_val *val = cfg_allocz(sizeof(struct f_val)); - if (f_eval(f_linearize($4, 1), cfg_mem, val) > F_RETURN) cf_error("Runtime error"); + *val = cf_eval($4, T_VOID); cf_define_symbol($2, SYM_CONSTANT | val->type, val, val); } ; expr: NUM - | '(' term ')' { $$ = f_eval_int(f_linearize($2, 1)); } + | '(' term ')' { $$ = cf_eval_int($2); } | CF_SYM_KNOWN { if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number constant expected"); $$ = SYM_VAL($1).i; } diff --git a/filter/config.Y b/filter/config.Y index 7c52847b..960b173a 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -360,7 +360,7 @@ filter_def: conf: filter_eval ; filter_eval: - EVAL term { f_eval_int(f_linearize($2, 1)); } + EVAL term { cf_eval_int($2); } ; conf: custom_attr ; @@ -575,7 +575,7 @@ set_atom: | VPN_RD { $$.type = T_RD; $$.val.ec = $1; } | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } | '(' term ')' { - if (f_eval(f_linearize($2, 1), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error"); + $$ = cf_eval($2, T_VOID); if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type"); } | CF_SYM_KNOWN { @@ -587,13 +587,13 @@ set_atom: switch_atom: NUM { $$.type = T_INT; $$.val.i = $1; } - | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_linearize($2, 1)); } + | '(' term ')' { $$ = cf_eval($2, T_INT); } | fipa { $$ = $1; } | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } ; cnum: - term { $$ = f_eval_int(f_linearize($1, 1)); } + term { $$ = cf_eval_int($1); } pair_item: '(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); } diff --git a/filter/filter.c b/filter/filter.c index 20a380dc..d080cadc 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -373,30 +373,22 @@ f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres) } /* - * f_eval_int - get an integer value of a term + * cf_eval - evaluate a value of a term and check its type * Called internally from the config parser, uses its internal memory pool * for allocations. Do not call in other cases. */ -uint -f_eval_int(const struct f_line *expr) +struct f_val +cf_eval(const struct f_inst *inst, int type) { - /* Called independently in parse-time to eval expressions */ - filter_state = (struct filter_state) { - .stack = &filter_stack, - .pool = cfg_mem, - }; - struct f_val val; - LOG_BUFFER_INIT(filter_state.buf); - - if (interpret(&filter_state, expr, &val) > F_RETURN) + if (f_eval(f_linearize(inst, 1), cfg_mem, &val) > F_RETURN) cf_error("Runtime error while evaluating expression; see log for details"); - if (val.type != T_INT) - cf_error("Integer expression expected"); + if (type != T_VOID && val.type != type) + cf_error("Expression of type %s expected", f_type_name(type)); - return val.val.i; + return val; } /* diff --git a/filter/filter.h b/filter/filter.h index 26c1037b..91de696c 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -15,6 +15,7 @@ #include "lib/macro.h" #include "nest/route.h" #include "nest/attrs.h" +#include "filter/data.h" /* Possible return values of filter execution */ enum filter_return { @@ -40,9 +41,8 @@ static inline const char *filter_return_str(const enum filter_return fret) { } } -struct f_val; - /* The filter encapsulating structure to be pointed-to from outside */ +struct f_inst; struct f_line; struct filter { struct symbol *sym; @@ -53,9 +53,11 @@ struct rte; enum filter_return f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags); enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool); -uint f_eval_int(const struct f_line *expr); enum filter_return f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf); +struct f_val cf_eval(const struct f_inst *inst, int type); +static inline uint cf_eval_int(const struct f_inst *inst) { return cf_eval(inst, T_INT).val.i; }; + const char *filter_name(const struct filter *filter); int filter_same(const struct filter *new, const struct filter *old); int f_same(const struct f_line *f1, const struct f_line *f2); diff --git a/nest/config.Y b/nest/config.Y index 9197f985..610b1c01 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -167,7 +167,7 @@ rtrid: idval: NUM { $$ = $1; } - | '(' term ')' { $$ = f_eval_int(f_linearize($2, 1)); } + | '(' term ')' { $$ = cf_eval_int($2); } | IP4 { $$ = ip4_to_u32($1); } | CF_SYM_KNOWN { if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD)) -- 2.41.0
From fdb7c222bf234ab6cc9d1757642ac336fb39bbd8 Mon Sep 17 00:00:00 2001 From: Alexander Zubkov <gr...@qrator.net> Date: Thu, 29 Jun 2023 13:51:01 +0200 Subject: [PATCH] Conf: use nonterminal bytestring instead of BYTETEXT Nonterminal bytestring allows to provide expressions to be evaluated in places where BYTETEXT is used now: passwords, radv custom option. --- conf/confbase.Y | 40 ++++++++++++++++++++++++++++++++++++++++ nest/config.Y | 5 +---- proto/radv/config.Y | 4 ++-- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/conf/confbase.Y b/conf/confbase.Y index e109ddf5..5006c185 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -117,9 +117,12 @@ CF_DECLS %type <mls> label_stack_start label_stack %type <t> text opttext +%type <bs> bytestring %type <s> symbol %type <kw> kw_sym +%type <x> bytestring_inst + %nonassoc PREFIX_DUMMY %left AND OR %nonassoc '=' '<' '>' '~' GEQ LEQ NEQ NMA PO PC @@ -395,6 +398,43 @@ opttext: | /* empty */ { $$ = NULL; } ; +bytestring: + BYTETEXT + | TEXT { + int len = strlen($1); + struct bytestring *bs = cfg_allocz(sizeof(*bs) + len); + $$ = bs; + bs->length = len; + memcpy(bs->data, $1, len); + } + | bytestring_inst { + struct f_val val = cf_eval($1, T_VOID); + + switch (val.type) { + case T_BYTESTRING: + $$ = val.val.bs; + break; + + case T_STRING: + int len = strlen(val.val.s); + struct bytestring *bs = cfg_allocz(sizeof(*bs) + len); + $$ = bs; + bs->length = len; + memcpy(bs->data, val.val.s, len); + break; + + default: + cf_error("Bytestring value is expected"); + } + } + ; + +bytestring_inst: + symbol_value + | term_bs + | '(' term ')' { $$ = $2; } + ; + CF_CODE diff --git a/nest/config.Y b/nest/config.Y index 610b1c01..2fdbb991 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -546,10 +546,7 @@ password_item: pass_key: PASSWORD | KEY; -password_item_begin: - pass_key text { init_password_list(); init_password($2, strlen($2), password_id++); } - | pass_key BYTETEXT { init_password_list(); init_password($2->data, $2->length, password_id++); } -; +password_item_begin: pass_key bytestring { init_password_list(); init_password($2->data, $2->length, password_id++); }; password_item_params: /* empty */ { } diff --git a/proto/radv/config.Y b/proto/radv/config.Y index 9653cd7b..9c5e1761 100644 --- a/proto/radv/config.Y +++ b/proto/radv/config.Y @@ -73,7 +73,7 @@ radv_proto_item: | PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE this_radv_prefix); } | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &radv_dns_list); } | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &radv_dns_list); } - | CUSTOM OPTION TYPE expr VALUE BYTETEXT { radv_add_to_custom_list(&RADV_CFG->custom_list, $4, $6); } + | CUSTOM OPTION TYPE expr VALUE bytestring { radv_add_to_custom_list(&RADV_CFG->custom_list, $4, $6); } | TRIGGER net_ip6 { RADV_CFG->trigger = $2; } | PROPAGATE ROUTES bool { RADV_CFG->propagate_routes = $3; } ; @@ -138,7 +138,7 @@ radv_iface_item: | PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE this_radv_prefix); } | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_IFACE->rdnss_list, &radv_dns_list); } | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_IFACE->dnssl_list, &radv_dns_list); } - | CUSTOM OPTION TYPE expr VALUE BYTETEXT { radv_add_to_custom_list(&RADV_IFACE->custom_list, $4, $6); } + | CUSTOM OPTION TYPE expr VALUE bytestring { radv_add_to_custom_list(&RADV_IFACE->custom_list, $4, $6); } | RDNSS LOCAL bool { RADV_IFACE->rdnss_local = $3; } | DNSSL LOCAL bool { RADV_IFACE->dnssl_local = $3; } | CUSTOM OPTION LOCAL bool { RADV_IFACE->custom_local = $4; } -- 2.41.0