summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/netlink.h5
-rw-r--r--src/netlink_linearize.c43
2 files changed, 44 insertions, 4 deletions
diff --git a/include/netlink.h b/include/netlink.h
index 9f24ea5e..9b42fdbd 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -53,6 +53,11 @@ struct nft_data_delinearize {
int verdict;
};
+static inline unsigned int netlink_register_space(unsigned int size)
+{
+ return div_round_up(size, NFT_REG32_SIZE * BITS_PER_BYTE);
+}
+
extern void netlink_gen_data(const struct expr *expr,
struct nft_data_linearize *data);
extern void netlink_gen_raw_data(const mpz_t value, enum byteorder byteorder,
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index beeb0c22..6930b39d 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -27,21 +27,54 @@ 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,
+ unsigned int size)
+{
+ 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);
+
+ reg = ctx->reg_low;
+ ctx->reg_low += n;
+ return reg;
+}
+
+static void __release_register(struct netlink_linearize_ctx *ctx,
+ unsigned int size)
+{
+ 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 (ctx->reg_low > NFT_REG_MAX)
- BUG("register reg_low %u invalid\n", ctx->reg_low);
- return ctx->reg_low++;
+ return __get_register(ctx, NFT_REG_SIZE * BITS_PER_BYTE);
}
static void release_register(struct netlink_linearize_ctx *ctx,
const struct expr *expr)
{
- ctx->reg_low--;
+ __release_register(ctx, NFT_REG_SIZE * BITS_PER_BYTE);
}
static void netlink_gen_expr(struct netlink_linearize_ctx *ctx,
@@ -509,6 +542,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: