On Mon, Jul 22, 2019 at 06:02:37PM +0200, Fernando Fernandez Mancera wrote: > diff --git a/include/rule.h b/include/rule.h > index 67c3d33..c6e8716 100644 [...] >+const struct datatype priority_type = { Please, add here something like on top of the definition: /* This datatype is not registered via datatype_register() * since this datatype should not ever be used from either * rules or elements. */ or alike, so we don't forget that missing datatype_register() is not a bug. [...] > --- a/include/rule.h > +++ b/include/rule.h > @@ -174,13 +174,13 @@ enum chain_flags { > * struct prio_spec - extendend priority specification for mixed > * textual/numerical parsing. > * > - * @str: name of the standard priority value > - * @num: Numerical value. This MUST contain the parsed value of str after > + * @expr: expr of the standard priority value > + * @num: Numerical value. This MUST contain the parsed value of expr after > * evaluation. There must be a way to avoid this num field. > */ > struct prio_spec { > - const char *str; > - int num; > + struct expr *expr; > + int num; > struct location loc; > }; > > diff --git a/src/datatype.c b/src/datatype.c > index 6d6826e..b7418e7 100644 > --- a/src/datatype.c > +++ b/src/datatype.c > @@ -1246,3 +1246,29 @@ const struct datatype boolean_type = { > .sym_tbl = &boolean_tbl, > .json = boolean_type_json, > }; > + > +static struct error_record *priority_type_parse(const struct expr *sym, > + struct expr **res) > +{ > + int num; > + > + if (isdigit(sym->identifier[0])) { > + num = atoi(sym->identifier); > + *res = constant_expr_alloc(&sym->location, &integer_type, > + BYTEORDER_HOST_ENDIAN, > + sizeof(int) * BITS_PER_BYTE, > + &num); > + } else > + *res = constant_expr_alloc(&sym->location, &string_type, > + BYTEORDER_HOST_ENDIAN, > + strlen(sym->identifier) * > + BITS_PER_BYTE, sym->identifier); I'd suggest you call integer_datatype_parse() first, check if erec == NULL, then all good, this is an integer. Otherwise, release erec object and parse this as a string via string_datatype_parse(). > + return NULL; > +} > + > +const struct datatype priority_type = { > + .type = TYPE_STRING, > + .name = "priority", > + .desc = "priority type", > + .parse = priority_type_parse, > +}; > diff --git a/src/evaluate.c b/src/evaluate.c > old mode 100644 > new mode 100755 > index 69b853f..d2faee8 > --- a/src/evaluate.c > +++ b/src/evaluate.c > @@ -3193,15 +3193,36 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set) > return 0; > } > > -static bool evaluate_priority(struct prio_spec *prio, int family, int hook) > +static bool evaluate_priority(struct eval_ctx *ctx, struct prio_spec *prio, > + int family, int hook) > { > int priority; > + char prio_str[NFT_NAME_MAXLEN]; > > /* A numeric value has been used to specify priority. */ > - if (prio->str == NULL) > + if (prio->expr == NULL) If we always use an expression, as described below, this won't be needed. > return true; > > - priority = std_prio_lookup(prio->str, family, hook); > + ctx->ectx.dtype = &priority_type; > + ctx->ectx.len = NFT_NAME_MAXLEN * BITS_PER_BYTE; > + if (expr_evaluate(ctx, &prio->expr) < 0) > + return false; > + if (prio->expr->etype != EXPR_VALUE) { > + expr_error(ctx->msgs, prio->expr, "%s is not a valid " > + "priority expression", expr_name(prio->expr)); > + return false; > + } > + > + if (prio->expr->dtype->type == TYPE_INTEGER) { > + mpz_export_data(&prio->num, prio->expr->value, > + BYTEORDER_HOST_ENDIAN, sizeof(int)); > + return true; > + } > + mpz_export_data(prio_str, prio->expr->value, If you use symbol expression, as I describe below. You don't need to convert this constant expression back to string again. You can just use the symbol identify sym->identifier. > + BYTEORDER_HOST_ENDIAN, > + NFT_NAME_MAXLEN); > + > + priority = std_prio_lookup(prio_str, family, hook); > if (priority == NF_IP_PRI_LAST) > return false; > prio->num += priority; > @@ -3223,10 +3244,10 @@ static int flowtable_evaluate(struct eval_ctx *ctx, struct flowtable *ft) > if (ft->hooknum == NF_INET_NUMHOOKS) > return chain_error(ctx, ft, "invalid hook %s", ft->hookstr); > > - if (!evaluate_priority(&ft->priority, NFPROTO_NETDEV, ft->hooknum)) > + if (!evaluate_priority(ctx, &ft->priority, NFPROTO_NETDEV, ft->hooknum)) > return __stmt_binary_error(ctx, &ft->priority.loc, NULL, > - "'%s' is invalid priority.", > - ft->priority.str); > + "invalid priority expression %s.", > + expr_name(ft->priority.expr)); > > if (!ft->dev_expr) > return chain_error(ctx, ft, "Unbound flowtable not allowed (must specify devices)"); > @@ -3422,11 +3443,11 @@ static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain) > return chain_error(ctx, chain, "invalid hook %s", > chain->hookstr); > > - if (!evaluate_priority(&chain->priority, chain->handle.family, > - chain->hooknum)) > + if (!evaluate_priority(ctx, &chain->priority, > + chain->handle.family, chain->hooknum)) > return __stmt_binary_error(ctx, &chain->priority.loc, NULL, > - "'%s' is invalid priority in this context.", > - chain->priority.str); > + "invalid priority expression %s in this context.", > + expr_name(chain->priority.expr)); > } > > list_for_each_entry(rule, &chain->rules, list) { > diff --git a/src/parser_bison.y b/src/parser_bison.y > index 53e6695..ed7bd89 100644 > --- a/src/parser_bison.y > +++ b/src/parser_bison.y > @@ -636,8 +636,8 @@ int nft_lex(void *, void *, void *); > %type <stmt> meter_stmt meter_stmt_alloc flow_stmt_legacy_alloc > %destructor { stmt_free($$); } meter_stmt meter_stmt_alloc flow_stmt_legacy_alloc > > -%type <expr> symbol_expr verdict_expr integer_expr variable_expr chain_expr > -%destructor { expr_free($$); } symbol_expr verdict_expr integer_expr variable_expr chain_expr > +%type <expr> symbol_expr verdict_expr integer_expr variable_expr chain_expr prio_expr > +%destructor { expr_free($$); } symbol_expr verdict_expr integer_expr variable_expr chain_expr prio_expr > %type <expr> primary_expr shift_expr and_expr > %destructor { expr_free($$); } primary_expr shift_expr and_expr > %type <expr> exclusive_or_expr inclusive_or_expr > @@ -1969,30 +1969,44 @@ extended_prio_name : OUT > | STRING > ; > > +prio_expr : variable_expr > + { > + datatype_set($1->sym->expr, &priority_type); Can you use symbol_expr_alloc() here, both for variable_expr and extended_prio_name. Then, from the evaluation phase you can turn this symbol expression into a constant using the priority_type_parse() function. I think this will allow you to skip the num field in prio_spec. Thanks!