diff options
author | Patrick McHardy <kaber@trash.net> | 2015-06-13 14:48:56 +0200 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2015-06-13 14:48:56 +0200 |
commit | 077509fdea3aa009823491be7096749c84795874 (patch) | |
tree | 07287fb0971df4011b33135d25ef8b0c0848e099 /src/netlink_linearize.c | |
parent | 45cabc474e46c74c27b645582d37a55d5d076051 (diff) | |
parent | a93bc1795b272174a10d90961a248f2c620bfa2c (diff) |
Merge remote-tracking branch 'origin/next-4.1'
Diffstat (limited to 'src/netlink_linearize.c')
-rw-r--r-- | src/netlink_linearize.c | 105 |
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); |