]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
expr: add set_elem_expr as container for set element attributes
authorPatrick McHardy <kaber@trash.net>
Sat, 11 Apr 2015 16:02:13 +0000 (17:02 +0100)
committerPatrick McHardy <kaber@trash.net>
Sun, 12 Apr 2015 18:59:27 +0000 (19:59 +0100)
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>
include/expression.h
src/evaluate.c
src/expression.c
src/netlink.c
src/netlink_delinearize.c
src/netlink_linearize.c
src/parser_bison.y
src/segtree.c

index 7477c3e6c846aa7ef2af79d679f6553e30162ec6..d481f288d2cb3c91f712e2d0659d08e84bb52918 100644 (file)
@@ -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,
@@ -229,6 +231,10 @@ struct expr {
                        /* EXPR_SET_REF */
                        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);
index 7ecb7939ba5e08251ef3474cf474b2f061a4a155..37db107b93c7e8549bf2a95948857233192b5bd1 100644 (file)
@@ -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:
index 5b848da7a10d73d4909e7975a38d38db9064eef2..678939681c590b22c588945589ac70aedd5a648d 100644 (file)
@@ -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);
        }
index 343d8bea4e1bd9466d43ec35f951285f4d334c8c..0827034e597dbe05c96cb3a036632dc237b6d26a 100644 (file)
@@ -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;
index ec1a9646eabfcf3978fcd1a52751a5006e0acfbd..c564a8a590fff69cd30874523ea63d2f0eb1dfd3 100644 (file)
@@ -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:
index 9bef67b38c9adbd925c6194dfa7a288468e3f1e2..d1414c149c603ad184eeb8cb5adfd5a77de1a004 100644 (file)
@@ -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);
        }
index c934533d7108f1f437f26cc5ea8010314cc95284..9fbc590c1963c9eb9e3c5d50e08c6eb1081195b2 100644 (file)
@@ -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
                        ;
index 65221e9da549566810aacfdbd7dbe0c101597900..060951c026c9ba208f5750879c8119567029928c 100644 (file)
@@ -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);