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;
* @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,
STMT_OBJREF,
STMT_EXTHDR,
STMT_FLOW_OFFLOAD,
+ STMT_MAP,
};
/**
struct xt_stmt xt;
struct objref_stmt objref;
struct flow_stmt flow;
+ struct map_stmt map;
};
};
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;
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);
}
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);
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);
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)
{
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);
}
%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
| dup_stmt
| fwd_stmt
| set_stmt
+ | map_stmt
;
verdict_stmt : verdict_expr
| 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;
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");