]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: support of dynamic map addition and update of elements
authorLaura Garcia Liebana <nevola@gmail.com>
Thu, 15 Mar 2018 08:23:21 +0000 (09:23 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 15 Mar 2018 18:45:46 +0000 (19:45 +0100)
The support of dynamic adds and updates are only available for sets
and meters. This patch gives such abilities to maps as well.

This patch is useful in cases where dynamic population of maps are
required, for example, to maintain a persistence during some period
of time.

Example:

table ip nftlb {
    map persistencia {
        type ipv4_addr : mark
        timeout 1h
        elements = { 192.168.1.132 expires 59m55s : 0x00000064,
                     192.168.56.101 expires 59m24s : 0x00000065 }
    }

    chain pre {
        type nat hook prerouting priority 0; policy accept;
        map update \
            { @nh,96,32 : numgen inc mod 2 offset 100 } @persistencia
    }
}

An example of the netlink generated sequence:

 nft --debug=netlink add rule ip nftlb pre map add \
    { ip saddr : numgen inc mod 2 offset 100 } @persistencia
ip nftlb pre
  [ payload load 4b @ network header + 12 => reg 1 ]
  [ numgen reg 2 = inc mod 2 offset 100 ]
  [ dynset add reg_key 1 set persistencia sreg_data 2 ]

Signed-off-by: Laura Garcia Liebana <nevola@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/statement.h
src/evaluate.c
src/netlink_delinearize.c
src/netlink_linearize.c
src/parser_bison.y
src/statement.c

index 27c735677df2dc7c0d5e377fe27b261d2ad8f18c..bb4af9d341228b4aa8c9f9f551ee37a14045fec5 100644 (file)
@@ -171,6 +171,14 @@ struct set_stmt {
 
 extern struct stmt *set_stmt_alloc(const struct location *loc);
 
+struct map_stmt {
+       struct expr             *set;
+       struct expr             *map;
+       enum nft_dynset_ops     op;
+};
+
+extern struct stmt *map_stmt_alloc(const struct location *loc);
+
 struct meter_stmt {
        struct expr             *set;
        struct expr             *key;
@@ -238,6 +246,7 @@ extern struct stmt *xt_stmt_alloc(const struct location *loc);
  * @STMT_OBJREF:       stateful object reference statement
  * @STMT_EXTHDR:       extension header statement
  * @STMT_FLOW_OFFLOAD: flow offload statement
+ * @STMT_MAP:          map statement
  */
 enum stmt_types {
        STMT_INVALID,
@@ -264,6 +273,7 @@ enum stmt_types {
        STMT_OBJREF,
        STMT_EXTHDR,
        STMT_FLOW_OFFLOAD,
+       STMT_MAP,
 };
 
 /**
@@ -325,6 +335,7 @@ struct stmt {
                struct xt_stmt          xt;
                struct objref_stmt      objref;
                struct flow_stmt        flow;
+               struct map_stmt         map;
        };
 };
 
index a2c1c7283d6ad126c99c15370e20ff4abeeeb3e7..b71b67b96fc65c8bcaf62cded6b622c3225e94f0 100644 (file)
@@ -2681,6 +2681,14 @@ static int stmt_evaluate_set(struct eval_ctx *ctx, struct stmt *stmt)
        return 0;
 }
 
+static int stmt_evaluate_map(struct eval_ctx *ctx, struct stmt *stmt)
+{
+       if (expr_evaluate(ctx, &stmt->map.map->map) < 0)
+               return -1;
+
+       return 0;
+}
+
 static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt)
 {
        struct expr *map = stmt->objref.expr;
@@ -2822,6 +2830,8 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
                return stmt_evaluate_set(ctx, stmt);
        case STMT_OBJREF:
                return stmt_evaluate_objref(ctx, stmt);
+       case STMT_MAP:
+               return stmt_evaluate_map(ctx, stmt);
        default:
                BUG("unknown statement type %s\n", stmt->ops->name);
        }
index d65aacf8b61683ec56ab4ee5c604ca8fe1e57ad7..d225b3e4b43fefba7bd6d53dd80ff2b47037aae0 100644 (file)
@@ -1150,11 +1150,11 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
                                 const struct location *loc,
                                 const struct nftnl_expr *nle)
 {
+       struct expr *expr, *expr_data = NULL;
+       enum nft_registers sreg, sreg_data;
        const struct nftnl_expr *dnle;
-       struct expr *expr;
        struct stmt *stmt, *dstmt;
        struct set *set;
-       enum nft_registers sreg;
        const char *name;
 
        name = nftnl_expr_get_str(nle, NFTNL_EXPR_DYNSET_SET_NAME);
@@ -1191,11 +1191,21 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
                dstmt = ctx->stmt;
        }
 
+       if (nftnl_expr_is_set(nle, NFTNL_EXPR_DYNSET_SREG_DATA)) {
+               sreg_data = netlink_parse_register(nle, NFTNL_EXPR_DYNSET_SREG_DATA);
+               expr_data = netlink_get_register(ctx, loc, sreg_data);
+       }
+
        if (dstmt != NULL) {
                stmt = meter_stmt_alloc(loc);
                stmt->meter.set  = set_ref_expr_alloc(loc, set);
                stmt->meter.key  = expr;
                stmt->meter.stmt = dstmt;
+       } else if (expr_data != NULL) {
+               stmt = map_stmt_alloc(loc);
+               stmt->map.set   = set_ref_expr_alloc(loc, set);
+               stmt->map.map   = map_expr_alloc(loc, expr, expr_data);
+               stmt->map.op    = nftnl_expr_get_u32(nle, NFTNL_EXPR_DYNSET_OP);
        } else {
                stmt = set_stmt_alloc(loc);
                stmt->set.set   = set_ref_expr_alloc(loc, set);
index 5edb2d3d6fe86956e0ac83351ef27f44efaf8fdf..be1c750cf452640a8ce5c2b2d09f1235e5bb7020 100644 (file)
@@ -1234,6 +1234,33 @@ static void netlink_gen_set_stmt(struct netlink_linearize_ctx *ctx,
        nftnl_rule_add_expr(ctx->nlr, nle);
 }
 
+static void netlink_gen_map_stmt(struct netlink_linearize_ctx *ctx,
+                                const struct stmt *stmt)
+{
+       struct nftnl_expr *nle;
+       enum nft_registers sreg_key;
+       enum nft_registers sreg_data;
+
+       sreg_key = get_register(ctx, stmt->map.map->map->key);
+       netlink_gen_expr(ctx, stmt->map.map->map->key, sreg_key);
+
+       sreg_data = get_register(ctx, stmt->map.map->mappings);
+       netlink_gen_expr(ctx, stmt->map.map->mappings, sreg_data);
+
+       release_register(ctx, stmt->map.map->map->key);
+       release_register(ctx, stmt->map.map->mappings);
+
+       nle = alloc_nft_expr("dynset");
+       netlink_put_register(nle, NFTNL_EXPR_DYNSET_SREG_KEY, sreg_key);
+       netlink_put_register(nle, NFTNL_EXPR_DYNSET_SREG_DATA, sreg_data);
+
+       nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_OP, stmt->map.op);
+       nftnl_expr_set_str(nle, NFTNL_EXPR_DYNSET_SET_NAME, stmt->map.set->identifier);
+       nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_SET_ID, stmt->map.set->set->handle.set_id);
+
+       nftnl_rule_add_expr(ctx->nlr, nle);
+}
+
 static void netlink_gen_meter_stmt(struct netlink_linearize_ctx *ctx,
                                   const struct stmt *stmt)
 {
@@ -1315,6 +1342,8 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
                return netlink_gen_flow_offload_stmt(ctx, stmt);
        case STMT_OBJREF:
                return netlink_gen_objref_stmt(ctx, stmt);
+       case STMT_MAP:
+               return netlink_gen_map_stmt(ctx, stmt);
        default:
                BUG("unknown statement type %s\n", stmt->ops->name);
        }
index 5f84d794079a76e18911bfb13a32c881c791c13a..6fba7e59555ca07242b56405688dc1e157bd54be 100644 (file)
@@ -577,6 +577,8 @@ int nft_lex(void *, void *, void *);
 %type <stmt>                   set_stmt
 %destructor { stmt_free($$); } set_stmt
 %type <val>                    set_stmt_op
+%type <stmt>                   map_stmt
+%destructor { stmt_free($$); } map_stmt
 %type <stmt>                   meter_stmt meter_stmt_alloc flow_stmt_legacy_alloc
 %destructor { stmt_free($$); } meter_stmt meter_stmt_alloc flow_stmt_legacy_alloc
 
@@ -2046,6 +2048,7 @@ stmt                      :       verdict_stmt
                        |       dup_stmt
                        |       fwd_stmt
                        |       set_stmt
+                       |       map_stmt
                        ;
 
 verdict_stmt           :       verdict_expr
@@ -2716,6 +2719,15 @@ set_stmt_op              :       ADD     { $$ = NFT_DYNSET_OP_ADD; }
                        |       UPDATE  { $$ = NFT_DYNSET_OP_UPDATE; }
                        ;
 
+map_stmt               :       set_stmt_op     MAP '{' set_elem_expr_stmt      COLON   set_elem_expr_stmt      '}'     symbol_expr
+                       {
+                               $$ = map_stmt_alloc(&@$);
+                               $$->map.op  = $1;
+                               $$->map.map = map_expr_alloc(&@$, $4, $6);
+                               $$->map.set = $8;
+                       }
+                       ;
+
 meter_stmt             :       flow_stmt_legacy_alloc          flow_stmt_opts  '{' meter_key_expr stmt '}'
                        {
                                $1->meter.key  = $4;
index 701337d7713bb0467ac2ff313f3a8c70d7516541..61ba643becc3613dd5e89e7ac9af13f0ca4ffa0d 100644 (file)
@@ -639,6 +639,34 @@ struct stmt *set_stmt_alloc(const struct location *loc)
        return stmt_alloc(loc, &set_stmt_ops);
 }
 
+static void map_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+       nft_print(octx, "%s map { ", set_stmt_op_names[stmt->map.op]);
+       expr_print(stmt->map.map->map->key, octx);
+       nft_print(octx, " : ");
+       expr_print(stmt->map.map->mappings, octx);
+       nft_print(octx, " } ");
+       expr_print(stmt->map.set, octx);
+}
+
+static void map_stmt_destroy(struct stmt *stmt)
+{
+       expr_free(stmt->map.map);
+       expr_free(stmt->map.set);
+}
+
+static const struct stmt_ops map_stmt_ops = {
+       .type           = STMT_MAP,
+       .name           = "map",
+       .print          = map_stmt_print,
+       .destroy        = map_stmt_destroy,
+};
+
+struct stmt *map_stmt_alloc(const struct location *loc)
+{
+       return stmt_alloc(loc, &map_stmt_ops);
+}
+
 static void dup_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
 {
        nft_print(octx, "dup");