evaluate: add support for set lookups inversion
From: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
---
include/expression.h | 1 +
src/evaluate.c | 13 +++++++++++++
src/expression.c | 1 +
src/netlink_delinearize.c | 9 +++++++++
src/netlink_linearize.c | 9 +++++++++
5 files changed, 33 insertions(+)
@@ -82,6 +82,7 @@ enum ops {
OP_FLAGCMP,
/* Set lookup */
OP_LOOKUP,
+ OP_LOOKUP_INV,
__OP_MAX
};
#define OP_MAX (__OP_MAX - 1)
@@ -1350,6 +1350,17 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
return -1;
right = rel->right;
+ if (rel->op == OP_NEQ) {
+ switch (right->ops->type) {
+ case EXPR_SET:
+ case EXPR_SET_REF:
+ rel->op = OP_LOOKUP_INV;
+ break;
+ default:
+ break;
+ }
+ }
+
if (rel->op == OP_IMPLICIT) {
switch (right->ops->type) {
case EXPR_RANGE:
@@ -1372,6 +1383,7 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
}
}
+
if (!expr_is_constant(right))
return expr_binary_error(ctx->msgs, right, rel,
"Right hand side of relational "
@@ -1385,6 +1397,7 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
switch (rel->op) {
case OP_LOOKUP:
+ case OP_LOOKUP_INV:
switch (right->ops->type) {
case EXPR_SET:
/* A literal set expression implicitly declares
@@ -451,6 +451,7 @@ const char *expr_op_symbols[] = {
[OP_GTE] = ">=",
[OP_RANGE] = "within range",
[OP_LOOKUP] = NULL,
+ [OP_LOOKUP_INV] = "!=",
};
static void unary_expr_print(const struct expr *expr)
@@ -259,6 +259,7 @@ static void netlink_parse_lookup(struct netlink_parse_ctx *ctx,
const char *name;
struct expr *expr, *left, *right;
struct set *set;
+ uint32_t flags;
name = nftnl_expr_get_str(nle, NFTNL_EXPR_LOOKUP_SET);
set = set_lookup(ctx->table, name);
@@ -281,13 +282,20 @@ static void netlink_parse_lookup(struct netlink_parse_ctx *ctx,
right = set_ref_expr_alloc(loc, set);
+ flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_LOOKUP_FLAGS);
+
if (nftnl_expr_is_set(nle, NFTNL_EXPR_LOOKUP_DREG)) {
dreg = netlink_parse_register(nle, NFTNL_EXPR_LOOKUP_DREG);
expr = map_expr_alloc(loc, left, right);
+ if (flags & NFT_LOOKUP_F_INV)
+ expr->op = OP_LOOKUP_INV;
+
if (dreg != NFT_REG_VERDICT)
return netlink_set_register(ctx, dreg, expr);
} else {
expr = relational_expr_alloc(loc, OP_LOOKUP, left, right);
+ if (flags & NFT_LOOKUP_F_INV)
+ expr->op = OP_LOOKUP_INV;
}
ctx->stmt = expr_stmt_alloc(loc, expr);
@@ -1168,6 +1176,7 @@ static void ct_meta_common_postprocess(const struct expr *expr)
switch (expr->op) {
case OP_LOOKUP:
+ case OP_LOOKUP_INV:
expr_set_type(right, left->dtype, left->byteorder);
if (right->dtype == &integer_type)
integer_type_postprocess(right);
@@ -191,6 +191,10 @@ static void netlink_gen_map(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_LOOKUP_SET_ID,
expr->mappings->set->handle.set_id);
+ if (expr->op == OP_LOOKUP_INV)
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_LOOKUP_FLAGS,
+ NFT_LOOKUP_F_INV);
+
if (dreg == NFT_REG_VERDICT)
release_register(ctx, expr->map);
@@ -217,6 +221,10 @@ static void netlink_gen_lookup(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_LOOKUP_SET_ID,
expr->right->set->handle.set_id);
+ if (expr->op == OP_LOOKUP_INV)
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_LOOKUP_FLAGS,
+ NFT_LOOKUP_F_INV);
+
release_register(ctx, expr->left);
nftnl_rule_add_expr(ctx->nlr, nle);
}
@@ -433,6 +441,7 @@ static void netlink_gen_relational(struct netlink_linearize_ctx *ctx,
case OP_FLAGCMP:
return netlink_gen_flagcmp(ctx, expr, dreg);
case OP_LOOKUP:
+ case OP_LOOKUP_INV:
return netlink_gen_lookup(ctx, expr, dreg);
default:
BUG("invalid relational operation %u\n", expr->op);