summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2015-04-11 17:02:13 +0100
committerPatrick McHardy <kaber@trash.net>2015-04-12 19:59:27 +0100
commit52532335290457cc449564b7e011f73bef3a83e2 (patch)
tree95115c2b046266442900cb1e01103b3eaf6d9167
parent6aa18b5216a34a2cd29ad4a1997c37f705f76247 (diff)
expr: add set_elem_expr as container for set element attributes
Add a new expression type "set_elem_expr" that is used as container for the key in order to attach different attributes, such as timeout values, to the key. The expression hierarchy is as follows: Sets: elem | key Maps: mapping / \ elem data | key Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r--include/expression.h8
-rw-r--r--src/evaluate.c15
-rw-r--r--src/expression.c31
-rw-r--r--src/netlink.c53
-rw-r--r--src/netlink_delinearize.c3
-rw-r--r--src/netlink_linearize.c2
-rw-r--r--src/parser_bison.y19
-rw-r--r--src/segtree.c8
8 files changed, 109 insertions, 30 deletions
diff --git a/include/expression.h b/include/expression.h
index 7477c3e6..d481f288 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -27,6 +27,7 @@
* @EXPR_LIST: list of expressions
* @EXPR_SET: literal set
* @EXPR_SET_REF: set reference
+ * @EXPR_SET_ELEM: set element
* @EXPR_MAPPING: a single mapping (key : value)
* @EXPR_MAP: map operation (expr map { EXPR_MAPPING, ... })
* @EXPR_UNARY: byteorder conversion, generated during evaluation
@@ -48,6 +49,7 @@ enum expr_types {
EXPR_LIST,
EXPR_SET,
EXPR_SET_REF,
+ EXPR_SET_ELEM,
EXPR_MAPPING,
EXPR_MAP,
EXPR_UNARY,
@@ -230,6 +232,10 @@ struct expr {
struct set *set;
};
struct {
+ /* EXPR_SET_ELEM */
+ struct expr *key;
+ };
+ struct {
/* EXPR_UNARY */
struct expr *arg;
};
@@ -363,6 +369,8 @@ extern struct expr *map_expr_alloc(const struct location *loc,
extern struct expr *set_ref_expr_alloc(const struct location *loc,
struct set *set);
+extern struct expr *set_elem_expr_alloc(const struct location *loc,
+ struct expr *key);
extern void range_expr_value_low(mpz_t rop, const struct expr *expr);
extern void range_expr_value_high(mpz_t rop, const struct expr *expr);
diff --git a/src/evaluate.c b/src/evaluate.c
index 7ecb7939..37db107b 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -675,6 +675,19 @@ static int expr_evaluate_list(struct eval_ctx *ctx, struct expr **expr)
return 0;
}
+static int expr_evaluate_set_elem(struct eval_ctx *ctx, struct expr **expr)
+{
+ struct expr *elem = *expr;
+
+ if (expr_evaluate(ctx, &elem->key) < 0)
+ return -1;
+
+ elem->dtype = elem->key->dtype;
+ elem->len = elem->key->len;
+ elem->flags = elem->key->flags;
+ return 0;
+}
+
static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
{
struct expr *set = *expr, *i, *next;
@@ -1100,6 +1113,8 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
return expr_evaluate_list(ctx, expr);
case EXPR_SET:
return expr_evaluate_set(ctx, expr);
+ case EXPR_SET_ELEM:
+ return expr_evaluate_set_elem(ctx, expr);
case EXPR_MAP:
return expr_evaluate_map(ctx, expr);
case EXPR_MAPPING:
diff --git a/src/expression.c b/src/expression.c
index 5b848da7..67893968 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -886,6 +886,33 @@ struct expr *set_ref_expr_alloc(const struct location *loc, struct set *set)
return expr;
}
+static void set_elem_expr_print(const struct expr *expr)
+{
+ expr_print(expr->key);
+}
+
+static void set_elem_expr_destroy(struct expr *expr)
+{
+ expr_free(expr->key);
+}
+
+static const struct expr_ops set_elem_expr_ops = {
+ .type = EXPR_SET_ELEM,
+ .name = "set element",
+ .print = set_elem_expr_print,
+ .destroy = set_elem_expr_destroy,
+};
+
+struct expr *set_elem_expr_alloc(const struct location *loc, struct expr *key)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, &set_elem_expr_ops, key->dtype,
+ key->byteorder, key->len);
+ expr->key = key;
+ return expr;
+}
+
void range_expr_value_low(mpz_t rop, const struct expr *expr)
{
switch (expr->ops->type) {
@@ -897,6 +924,8 @@ void range_expr_value_low(mpz_t rop, const struct expr *expr)
return range_expr_value_low(rop, expr->left);
case EXPR_MAPPING:
return range_expr_value_low(rop, expr->left);
+ case EXPR_SET_ELEM:
+ return range_expr_value_low(rop, expr->key);
default:
BUG("invalid range expression type %s\n", expr->ops->name);
}
@@ -919,6 +948,8 @@ void range_expr_value_high(mpz_t rop, const struct expr *expr)
return range_expr_value_high(rop, expr->right);
case EXPR_MAPPING:
return range_expr_value_high(rop, expr->left);
+ case EXPR_SET_ELEM:
+ return range_expr_value_high(rop, expr->key);
default:
BUG("invalid range expression type %s\n", expr->ops->name);
}
diff --git a/src/netlink.c b/src/netlink.c
index 343d8bea..0827034e 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -205,6 +205,7 @@ struct nft_set *alloc_nft_set(const struct handle *h)
static struct nft_set_elem *alloc_nft_setelem(const struct expr *expr)
{
+ const struct expr *elem, *key, *data;
struct nft_set_elem *nlse;
struct nft_data_linearize nld;
@@ -212,24 +213,28 @@ static struct nft_set_elem *alloc_nft_setelem(const struct expr *expr)
if (nlse == NULL)
memory_allocation_error();
- if (expr->ops->type == EXPR_VALUE ||
- expr->flags & EXPR_F_INTERVAL_END) {
- netlink_gen_data(expr, &nld);
- nft_set_elem_attr_set(nlse, NFT_SET_ELEM_ATTR_KEY,
- &nld.value, nld.len);
+ data = NULL;
+ if (expr->ops->type == EXPR_MAPPING) {
+ elem = expr->left;
+ if (!(expr->flags & EXPR_F_INTERVAL_END))
+ data = expr->right;
} else {
- assert(expr->ops->type == EXPR_MAPPING);
- netlink_gen_data(expr->left, &nld);
- nft_set_elem_attr_set(nlse, NFT_SET_ELEM_ATTR_KEY,
- &nld.value, nld.len);
- netlink_gen_data(expr->right, &nld);
- switch (expr->right->ops->type) {
+ elem = expr;
+ }
+ key = elem->key;
+
+ netlink_gen_data(key, &nld);
+ nft_set_elem_attr_set(nlse, NFT_SET_ELEM_ATTR_KEY, &nld.value, nld.len);
+
+ if (data != NULL) {
+ netlink_gen_data(data, &nld);
+ switch (data->ops->type) {
case EXPR_VERDICT:
nft_set_elem_attr_set_u32(nlse, NFT_SET_ELEM_ATTR_VERDICT,
- expr->right->verdict);
- if (expr->chain != NULL)
+ data->verdict);
+ if (data->chain != NULL)
nft_set_elem_attr_set(nlse, NFT_SET_ELEM_ATTR_CHAIN,
- nld.chain, strlen(nld.chain));
+ nld.chain, strlen(nld.chain));
break;
case EXPR_VALUE:
nft_set_elem_attr_set(nlse, NFT_SET_ELEM_ATTR_DATA,
@@ -1368,7 +1373,7 @@ static int netlink_delinearize_setelem(struct nft_set_elem *nlse,
struct set *set)
{
struct nft_data_delinearize nld;
- struct expr *expr, *data;
+ struct expr *expr, *key, *data;
uint32_t flags = 0;
nld.value =
@@ -1376,17 +1381,19 @@ static int netlink_delinearize_setelem(struct nft_set_elem *nlse,
if (nft_set_elem_attr_is_set(nlse, NFT_SET_ELEM_ATTR_FLAGS))
flags = nft_set_elem_attr_get_u32(nlse, NFT_SET_ELEM_ATTR_FLAGS);
- expr = netlink_alloc_value(&netlink_location, &nld);
- expr->dtype = set->keytype;
- expr->byteorder = set->keytype->byteorder;
+ key = netlink_alloc_value(&netlink_location, &nld);
+ key->dtype = set->keytype;
+ key->byteorder = set->keytype->byteorder;
if (!(set->flags & SET_F_INTERVAL) &&
- expr->byteorder == BYTEORDER_HOST_ENDIAN)
- mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
+ key->byteorder == BYTEORDER_HOST_ENDIAN)
+ mpz_switch_byteorder(key->value, key->len / BITS_PER_BYTE);
+
+ if (key->dtype->basetype != NULL &&
+ key->dtype->basetype->type == TYPE_BITMASK)
+ key = bitmask_expr_to_binops(key);
- if (expr->dtype->basetype != NULL &&
- expr->dtype->basetype->type == TYPE_BITMASK)
- expr = bitmask_expr_to_binops(expr);
+ expr = set_elem_expr_alloc(&netlink_location, key);
if (flags & NFT_SET_ELEM_INTERVAL_END) {
expr->flags |= EXPR_F_INTERVAL_END;
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index ec1a9646..c564a8a5 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -1033,6 +1033,9 @@ static void expr_postprocess(struct rule_pp_ctx *ctx,
expr_postprocess(ctx, stmt, &expr->left);
expr_postprocess(ctx, stmt, &expr->right);
break;
+ case EXPR_SET_ELEM:
+ expr_postprocess(ctx, stmt, &expr->key);
+ break;
case EXPR_SET_REF:
case EXPR_EXTHDR:
case EXPR_META:
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 9bef67b3..d1414c14 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -528,6 +528,8 @@ static void netlink_gen_expr(struct netlink_linearize_ctx *ctx,
return netlink_gen_meta(ctx, expr, dreg);
case EXPR_CT:
return netlink_gen_ct(ctx, expr, dreg);
+ case EXPR_SET_ELEM:
+ return netlink_gen_expr(ctx, expr->key, dreg);
default:
BUG("unknown expression type %s\n", expr->ops->name);
}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index c934533d..9fbc590c 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -484,8 +484,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <expr> set_expr set_list_expr set_list_member_expr
%destructor { expr_free($$); } set_expr set_list_expr set_list_member_expr
-%type <expr> set_lhs_expr set_rhs_expr
-%destructor { expr_free($$); } set_lhs_expr set_rhs_expr
+%type <expr> set_elem_expr set_elem_expr_alloc set_lhs_expr set_rhs_expr
+%destructor { expr_free($$); } set_elem_expr set_elem_expr_alloc set_lhs_expr set_rhs_expr
%type <expr> expr initializer_expr
%destructor { expr_free($$); } expr initializer_expr
@@ -1299,7 +1299,7 @@ verdict_map_list_expr : verdict_map_list_member_expr
| verdict_map_list_expr COMMA opt_newline
;
-verdict_map_list_member_expr: opt_newline set_lhs_expr COLON verdict_expr opt_newline
+verdict_map_list_member_expr: opt_newline set_elem_expr COLON verdict_expr opt_newline
{
$$ = mapping_expr_alloc(&@$, $2, $4);
}
@@ -1755,16 +1755,25 @@ set_list_member_expr : opt_newline set_expr opt_newline
{
$$ = $2;
}
- | opt_newline set_lhs_expr opt_newline
+ | opt_newline set_elem_expr opt_newline
{
$$ = $2;
}
- | opt_newline set_lhs_expr COLON set_rhs_expr opt_newline
+ | opt_newline set_elem_expr COLON set_rhs_expr opt_newline
{
$$ = mapping_expr_alloc(&@$, $2, $4);
}
;
+set_elem_expr : set_elem_expr_alloc
+ ;
+
+set_elem_expr_alloc : set_lhs_expr
+ {
+ $$ = set_elem_expr_alloc(&@1, $1);
+ }
+ ;
+
set_lhs_expr : concat_expr
| multiton_expr
;
diff --git a/src/segtree.c b/src/segtree.c
index 65221e9d..060951c0 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -419,6 +419,7 @@ static void set_insert_interval(struct expr *set, struct seg_tree *tree,
expr = constant_expr_alloc(&internal_location, tree->keytype,
tree->byteorder, tree->keylen, NULL);
mpz_set(expr->value, ei->left);
+ expr = set_elem_expr_alloc(&internal_location, expr);
if (ei->expr != NULL && ei->expr->ops->type == EXPR_MAPPING)
expr = mapping_expr_alloc(&ei->expr->location, expr,
@@ -473,9 +474,9 @@ extern void interval_map_decompose(struct expr *set);
static struct expr *expr_value(struct expr *expr)
{
if (expr->ops->type == EXPR_MAPPING)
- return expr->left;
+ return expr->left->key;
else
- return expr;
+ return expr->key;
}
static int expr_value_cmp(const void *p1, const void *p2)
@@ -565,6 +566,7 @@ void interval_map_decompose(struct expr *set)
mpz_set(tmp->value, range);
tmp = range_expr_alloc(&low->location, expr_value(low), tmp);
+ tmp = set_elem_expr_alloc(&low->location, tmp);
if (low->ops->type == EXPR_MAPPING)
tmp = mapping_expr_alloc(&tmp->location, tmp, low->right);
@@ -576,6 +578,7 @@ void interval_map_decompose(struct expr *set)
prefix_len = expr_value(i)->len - mpz_scan0(range, 0);
prefix = prefix_expr_alloc(&low->location, expr_value(low),
prefix_len);
+ prefix = set_elem_expr_alloc(&low->location, prefix);
if (low->ops->type == EXPR_MAPPING)
prefix = mapping_expr_alloc(&low->location, prefix,
low->right);
@@ -598,6 +601,7 @@ void interval_map_decompose(struct expr *set)
mpz_init_bitmask(i->value, i->len);
i = range_expr_alloc(&low->location, expr_value(low), i);
+ i = set_elem_expr_alloc(&low->location, i);
if (low->ops->type == EXPR_MAPPING)
i = mapping_expr_alloc(&i->location, i, low->right);