summaryrefslogtreecommitdiffstats
path: root/src/netlink_linearize.c
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2015-06-13 14:48:56 +0200
committerPatrick McHardy <kaber@trash.net>2015-06-13 14:48:56 +0200
commit077509fdea3aa009823491be7096749c84795874 (patch)
tree07287fb0971df4011b33135d25ef8b0c0848e099 /src/netlink_linearize.c
parent45cabc474e46c74c27b645582d37a55d5d076051 (diff)
parenta93bc1795b272174a10d90961a248f2c620bfa2c (diff)
Merge remote-tracking branch 'origin/next-4.1'
Diffstat (limited to 'src/netlink_linearize.c')
-rw-r--r--src/netlink_linearize.c105
1 files changed, 75 insertions, 30 deletions
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index fbc6ae12..bf1e56be 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -27,19 +27,60 @@ struct netlink_linearize_ctx {
static void netlink_put_register(struct nft_rule_expr *nle,
uint32_t attr, uint32_t reg)
{
+ /* Convert to 128 bit register numbers if possible for compatibility */
+ if (reg != NFT_REG_VERDICT) {
+ reg -= NFT_REG_1;
+ if (reg % (NFT_REG_SIZE / NFT_REG32_SIZE) == 0)
+ reg = NFT_REG_1 + reg / (NFT_REG_SIZE / NFT_REG32_SIZE);
+ else
+ reg += NFT_REG32_00;
+ }
+
nft_rule_expr_set_u32(nle, attr, reg);
}
-static enum nft_registers get_register(struct netlink_linearize_ctx *ctx)
+static enum nft_registers __get_register(struct netlink_linearize_ctx *ctx,
+ unsigned int size)
{
- if (ctx->reg_low > NFT_REG_MAX)
+ unsigned int reg, n;
+
+ n = netlink_register_space(size);
+ if (ctx->reg_low + n > NFT_REG_1 + NFT_REG32_15 - NFT_REG32_00 + 1)
BUG("register reg_low %u invalid\n", ctx->reg_low);
- return ctx->reg_low++;
+
+ reg = ctx->reg_low;
+ ctx->reg_low += n;
+ return reg;
}
-static void release_register(struct netlink_linearize_ctx *ctx)
+static void __release_register(struct netlink_linearize_ctx *ctx,
+ unsigned int size)
{
- ctx->reg_low--;
+ unsigned int n;
+
+ n = netlink_register_space(size);
+ if (ctx->reg_low < NFT_REG_1 + n)
+ BUG("register reg_low %u invalid\n", ctx->reg_low);
+
+ ctx->reg_low -= n;
+}
+
+static enum nft_registers get_register(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr)
+{
+ if (expr && expr->ops->type == EXPR_CONCAT)
+ return __get_register(ctx, expr->len);
+ else
+ return __get_register(ctx, NFT_REG_SIZE * BITS_PER_BYTE);
+}
+
+static void release_register(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr)
+{
+ if (expr && expr->ops->type == EXPR_CONCAT)
+ __release_register(ctx, expr->len);
+ else
+ __release_register(ctx, NFT_REG_SIZE * BITS_PER_BYTE);
}
static void netlink_gen_expr(struct netlink_linearize_ctx *ctx,
@@ -52,8 +93,10 @@ static void netlink_gen_concat(struct netlink_linearize_ctx *ctx,
{
const struct expr *i;
- list_for_each_entry(i, &expr->expressions, list)
+ list_for_each_entry(i, &expr->expressions, list) {
netlink_gen_expr(ctx, i, dreg);
+ dreg += netlink_register_space(i->len);
+ }
}
static void netlink_gen_payload(struct netlink_linearize_ctx *ctx,
@@ -124,7 +167,7 @@ static void netlink_gen_map(struct netlink_linearize_ctx *ctx,
assert(expr->mappings->ops->type == EXPR_SET_REF);
if (dreg == NFT_REG_VERDICT)
- sreg = get_register(ctx);
+ sreg = get_register(ctx, expr->map);
else
sreg = dreg;
@@ -139,7 +182,7 @@ static void netlink_gen_map(struct netlink_linearize_ctx *ctx,
expr->mappings->set->handle.set_id);
if (dreg == NFT_REG_VERDICT)
- release_register(ctx);
+ release_register(ctx, expr->map);
nft_rule_add_expr(ctx->nlr, nle);
}
@@ -154,7 +197,7 @@ static void netlink_gen_lookup(struct netlink_linearize_ctx *ctx,
assert(expr->right->ops->type == EXPR_SET_REF);
assert(dreg == NFT_REG_VERDICT);
- sreg = get_register(ctx);
+ sreg = get_register(ctx, expr->left);
netlink_gen_expr(ctx, expr->left, sreg);
nle = alloc_nft_expr("lookup");
@@ -164,7 +207,7 @@ static void netlink_gen_lookup(struct netlink_linearize_ctx *ctx,
nft_rule_expr_set_u32(nle, NFT_EXPR_LOOKUP_SET_ID,
expr->right->set->handle.set_id);
- release_register(ctx);
+ release_register(ctx, expr->left);
nft_rule_add_expr(ctx->nlr, nle);
}
@@ -206,7 +249,7 @@ static void netlink_gen_cmp(struct netlink_linearize_ctx *ctx,
if (expr->right->ops->type == EXPR_RANGE)
return netlink_gen_range(ctx, expr, dreg);
- sreg = get_register(ctx);
+ sreg = get_register(ctx, expr->left);
netlink_gen_expr(ctx, expr->left, sreg);
switch (expr->right->ops->type) {
@@ -242,7 +285,7 @@ static void netlink_gen_cmp(struct netlink_linearize_ctx *ctx,
netlink_gen_cmp_op(expr->op));
netlink_gen_data(right, &nld);
nft_rule_expr_set(nle, NFT_EXPR_CMP_DATA, nld.value, nld.len);
- release_register(ctx);
+ release_register(ctx, expr->left);
nft_rule_add_expr(ctx->nlr, nle);
}
@@ -258,7 +301,7 @@ static void netlink_gen_range(struct netlink_linearize_ctx *ctx,
assert(dreg == NFT_REG_VERDICT);
- sreg = get_register(ctx);
+ sreg = get_register(ctx, expr->left);
netlink_gen_expr(ctx, expr->left, sreg);
nle = alloc_nft_expr("cmp");
@@ -301,7 +344,7 @@ static void netlink_gen_range(struct netlink_linearize_ctx *ctx,
nft_rule_expr_set(nle, NFT_EXPR_CMP_DATA, nld.value, nld.len);
nft_rule_add_expr(ctx->nlr, nle);
- release_register(ctx);
+ release_register(ctx, expr->left);
}
static void netlink_gen_flagcmp(struct netlink_linearize_ctx *ctx,
@@ -316,7 +359,7 @@ static void netlink_gen_flagcmp(struct netlink_linearize_ctx *ctx,
assert(dreg == NFT_REG_VERDICT);
- sreg = get_register(ctx);
+ sreg = get_register(ctx, expr->left);
netlink_gen_expr(ctx, expr->left, sreg);
len = div_round_up(expr->left->len, BITS_PER_BYTE);
@@ -340,7 +383,7 @@ static void netlink_gen_flagcmp(struct netlink_linearize_ctx *ctx,
nft_rule_add_expr(ctx->nlr, nle);
mpz_clear(zero);
- release_register(ctx);
+ release_register(ctx, expr->left);
}
static void netlink_gen_relational(struct netlink_linearize_ctx *ctx,
@@ -507,6 +550,8 @@ static void netlink_gen_expr(struct netlink_linearize_ctx *ctx,
const struct expr *expr,
enum nft_registers dreg)
{
+ assert(dreg < ctx->reg_low);
+
switch (expr->ops->type) {
case EXPR_VERDICT:
case EXPR_VALUE:
@@ -565,9 +610,9 @@ static void netlink_gen_meta_stmt(struct netlink_linearize_ctx *ctx,
struct nft_rule_expr *nle;
enum nft_registers sreg;
- sreg = get_register(ctx);
+ sreg = get_register(ctx, stmt->meta.expr);
netlink_gen_expr(ctx, stmt->meta.expr, sreg);
- release_register(ctx);
+ release_register(ctx, stmt->meta.expr);
nle = alloc_nft_expr("meta");
netlink_put_register(nle, NFT_EXPR_META_SREG, sreg);
@@ -647,11 +692,11 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
nft_rule_expr_set_u32(nle, NFT_EXPR_NAT_FLAGS, stmt->nat.flags);
if (stmt->nat.addr) {
- amin_reg = get_register(ctx);
+ amin_reg = get_register(ctx, NULL);
registers++;
if (stmt->nat.addr->ops->type == EXPR_RANGE) {
- amax_reg = get_register(ctx);
+ amax_reg = get_register(ctx, NULL);
registers++;
netlink_gen_expr(ctx, stmt->nat.addr->left, amin_reg);
@@ -669,11 +714,11 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
}
if (stmt->nat.proto) {
- pmin_reg = get_register(ctx);
+ pmin_reg = get_register(ctx, NULL);
registers++;
if (stmt->nat.proto->ops->type == EXPR_RANGE) {
- pmax_reg = get_register(ctx);
+ pmax_reg = get_register(ctx, NULL);
registers++;
netlink_gen_expr(ctx, stmt->nat.proto->left, pmin_reg);
@@ -690,7 +735,7 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
}
while (registers > 0) {
- release_register(ctx);
+ release_register(ctx, NULL);
registers--;
}
@@ -724,11 +769,11 @@ static void netlink_gen_redir_stmt(struct netlink_linearize_ctx *ctx,
stmt->redir.flags);
if (stmt->redir.proto) {
- pmin_reg = get_register(ctx);
+ pmin_reg = get_register(ctx, NULL);
registers++;
if (stmt->redir.proto->ops->type == EXPR_RANGE) {
- pmax_reg = get_register(ctx);
+ pmax_reg = get_register(ctx, NULL);
registers++;
netlink_gen_expr(ctx, stmt->redir.proto->left,
@@ -750,7 +795,7 @@ static void netlink_gen_redir_stmt(struct netlink_linearize_ctx *ctx,
}
while (registers > 0) {
- release_register(ctx);
+ release_register(ctx, NULL);
registers--;
}
@@ -791,9 +836,9 @@ static void netlink_gen_ct_stmt(struct netlink_linearize_ctx *ctx,
struct nft_rule_expr *nle;
enum nft_registers sreg;
- sreg = get_register(ctx);
+ sreg = get_register(ctx, stmt->ct.expr);
netlink_gen_expr(ctx, stmt->ct.expr, sreg);
- release_register(ctx);
+ release_register(ctx, stmt->ct.expr);
nle = alloc_nft_expr("ct");
netlink_put_register(nle, NFT_EXPR_CT_SREG, sreg);
@@ -807,9 +852,9 @@ static void netlink_gen_set_stmt(struct netlink_linearize_ctx *ctx,
struct nft_rule_expr *nle;
enum nft_registers sreg_key;
- sreg_key = get_register(ctx);
+ sreg_key = get_register(ctx, stmt->set.key);
netlink_gen_expr(ctx, stmt->set.key, sreg_key);
- release_register(ctx);
+ release_register(ctx, stmt->set.key);
nle = alloc_nft_expr("dynset");
netlink_put_register(nle, NFT_EXPR_DYNSET_SREG_KEY, sreg_key);