summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/expression.h1
-rw-r--r--src/evaluate.c8
-rw-r--r--src/expression.c1
-rw-r--r--src/netlink_delinearize.c14
-rw-r--r--src/netlink_linearize.c9
-rw-r--r--src/parser_bison.y1
-rw-r--r--tests/py/any/ct.t1
-rw-r--r--tests/py/any/ct.t.payload6
8 files changed, 36 insertions, 5 deletions
diff --git a/include/expression.h b/include/expression.h
index 718dac5a..2d07f3d9 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -93,6 +93,7 @@ enum ops {
OP_GT,
OP_LTE,
OP_GTE,
+ OP_NEG,
__OP_MAX
};
#define OP_MAX (__OP_MAX - 1)
diff --git a/src/evaluate.c b/src/evaluate.c
index ccee7e21..030bbde4 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1958,6 +1958,14 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
/* fall through */
case OP_NEQ:
+ case OP_NEG:
+ if (rel->op == OP_NEG &&
+ (right->etype != EXPR_VALUE ||
+ right->dtype->basetype == NULL ||
+ right->dtype->basetype->type != TYPE_BITMASK))
+ return expr_binary_error(ctx->msgs, left, right,
+ "negation can only be used with singleton bitmask values");
+
switch (right->etype) {
case EXPR_RANGE:
if (byteorder_conversion(ctx, &rel->left, BYTEORDER_BIG_ENDIAN) < 0)
diff --git a/src/expression.c b/src/expression.c
index 58d73e95..a90a89ca 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -560,6 +560,7 @@ const char *expr_op_symbols[] = {
[OP_GT] = ">",
[OP_LTE] = "<=",
[OP_GTE] = ">=",
+ [OP_NEG] = "!",
};
static void unary_expr_print(const struct expr *expr, struct output_ctx *octx)
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 04560b97..7cd7d403 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -2167,7 +2167,7 @@ static void relational_binop_postprocess(struct rule_pp_ctx *ctx, struct expr *e
{
struct expr *binop = expr->left, *value = expr->right;
- if (binop->op == OP_AND && expr->op == OP_NEQ &&
+ if (binop->op == OP_AND && (expr->op == OP_NEQ || expr->op == OP_EQ) &&
value->dtype->basetype &&
value->dtype->basetype->type == TYPE_BITMASK &&
!mpz_cmp_ui(value->value, 0)) {
@@ -2180,8 +2180,16 @@ static void relational_binop_postprocess(struct rule_pp_ctx *ctx, struct expr *e
expr->left = expr_get(binop->left);
expr->right = binop_tree_to_list(NULL, binop->right);
- expr->op = OP_IMPLICIT;
-
+ switch (expr->op) {
+ case OP_NEQ:
+ expr->op = OP_IMPLICIT;
+ break;
+ case OP_EQ:
+ expr->op = OP_NEG;
+ break;
+ default:
+ BUG("unknown operation type %d\n", expr->op);
+ }
expr_free(binop);
} else if (binop->left->dtype->flags & DTYPE_F_PREFIX &&
binop->op == OP_AND && expr->right->etype == EXPR_VALUE &&
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index f1b3ff69..21bc492e 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -490,7 +490,11 @@ static void netlink_gen_flagcmp(struct netlink_linearize_ctx *ctx,
nle = alloc_nft_expr("cmp");
netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
- nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP, NFT_CMP_NEQ);
+ if (expr->op == OP_NEG)
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP, NFT_CMP_EQ);
+ else
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP, NFT_CMP_NEQ);
+
nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, nld.len);
nft_rule_add_expr(ctx, nle, &expr->location);
@@ -518,6 +522,7 @@ static void netlink_gen_relational(struct netlink_linearize_ctx *ctx,
case OP_GT:
case OP_LTE:
case OP_GTE:
+ case OP_NEG:
break;
default:
BUG("invalid relational operation %u\n", expr->op);
@@ -547,7 +552,7 @@ static void netlink_gen_relational(struct netlink_linearize_ctx *ctx,
}
break;
default:
- if (expr->op == OP_IMPLICIT &&
+ if ((expr->op == OP_IMPLICIT || expr->op == OP_NEG) &&
expr->right->dtype->basetype != NULL &&
expr->right->dtype->basetype->type == TYPE_BITMASK)
return netlink_gen_flagcmp(ctx, expr, dreg);
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 519e8efe..11e899ff 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -4639,6 +4639,7 @@ relational_op : EQ { $$ = OP_EQ; }
| GT { $$ = OP_GT; }
| GTE { $$ = OP_GTE; }
| LTE { $$ = OP_LTE; }
+ | NOT { $$ = OP_NEG; }
;
verdict_expr : ACCEPT
diff --git a/tests/py/any/ct.t b/tests/py/any/ct.t
index 0ec027f5..a44142ac 100644
--- a/tests/py/any/ct.t
+++ b/tests/py/any/ct.t
@@ -30,6 +30,7 @@ ct status != {expected, seen-reply, assured, confirmed, dying};ok
ct status expected,seen-reply,assured,confirmed,snat,dnat,dying;ok
ct status snat;ok
ct status dnat;ok
+ct status ! dnat;ok
ct status xxx;fail
ct mark 0;ok;ct mark 0x00000000
diff --git a/tests/py/any/ct.t.payload b/tests/py/any/ct.t.payload
index 9223201f..a80e5a8d 100644
--- a/tests/py/any/ct.t.payload
+++ b/tests/py/any/ct.t.payload
@@ -502,3 +502,9 @@ ip test-ip4 output
[ ct load unknown => reg 1 ]
[ cmp eq reg 1 0x39300000 ]
+# ct status ! dnat
+ip6
+ [ ct load status => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000020 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+