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!