summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/statement.h11
-rw-r--r--src/evaluate.c10
-rw-r--r--src/netlink_delinearize.c14
-rw-r--r--src/netlink_linearize.c29
-rw-r--r--src/parser_bison.y12
-rw-r--r--src/statement.c28
6 files changed, 102 insertions, 2 deletions
diff --git a/include/statement.h b/include/statement.h
index 27c73567..bb4af9d3 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -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;
};
};
diff --git a/src/evaluate.c b/src/evaluate.c
index a2c1c728..b71b67b9 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -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);
}
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index d65aacf8..d225b3e4 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -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);
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 5edb2d3d..be1c750c 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -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);
}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 5f84d794..6fba7e59 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -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;
diff --git a/src/statement.c b/src/statement.c
index 701337d7..61ba643b 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -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");