The kernel supports bitwise shift operations, so add support to the netlink linearization and delinearization code. Signed-off-by: Jeremy Sowden <jeremy@xxxxxxxxxx> --- include/linux/netfilter/nf_tables.h | 4 +++ src/netlink_delinearize.c | 19 +++++++++++++ src/netlink_linearize.c | 42 ++++++++++++++++++++++++++--- 3 files changed, 62 insertions(+), 3 deletions(-) diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h index c556ccd3dbf7..12dbb2adbbdf 100644 --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h @@ -490,6 +490,8 @@ enum nft_immediate_attributes { * @NFTA_BITWISE_LEN: length of operands (NLA_U32) * @NFTA_BITWISE_MASK: mask value (NLA_NESTED: nft_data_attributes) * @NFTA_BITWISE_XOR: xor value (NLA_NESTED: nft_data_attributes) + * @NFTA_BITWISE_LSHIFT: left shift value (NLA_U32) + * @NFTA_BITWISE_RSHIFT: right shift value (NLA_U32) * * The bitwise expression performs the following operation: * @@ -510,6 +512,8 @@ enum nft_bitwise_attributes { NFTA_BITWISE_LEN, NFTA_BITWISE_MASK, NFTA_BITWISE_XOR, + NFTA_BITWISE_LSHIFT, + NFTA_BITWISE_RSHIFT, __NFTA_BITWISE_MAX }; #define NFTA_BITWISE_MAX (__NFTA_BITWISE_MAX - 1) diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 8f2a5dfacd3e..a45ad924b216 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -372,6 +372,24 @@ static void netlink_parse_bitwise(struct netlink_parse_ctx *ctx, "Bitwise expression has no left " "hand side"); + nld.value = nftnl_expr_get(nle, NFTNL_EXPR_BITWISE_LSHIFT, &nld.len); + if (nld.value != NULL) { + struct expr *right = netlink_alloc_value(loc, &nld); + + expr = binop_expr_alloc(loc, OP_LSHIFT, left, right); + expr->len = left->len; + goto dreg; + } + + nld.value = nftnl_expr_get(nle, NFTNL_EXPR_BITWISE_RSHIFT, &nld.len); + if (nld.value != NULL) { + struct expr *right = netlink_alloc_value(loc, &nld); + + expr = binop_expr_alloc(loc, OP_RSHIFT, left, right); + expr->len = left->len; + goto dreg; + } + expr = left; nld.value = nftnl_expr_get(nle, NFTNL_EXPR_BITWISE_MASK, &nld.len); @@ -423,6 +441,7 @@ static void netlink_parse_bitwise(struct netlink_parse_ctx *ctx, mpz_clear(x); mpz_clear(o); +dreg: dreg = netlink_parse_register(nle, NFTNL_EXPR_BITWISE_DREG); netlink_set_register(ctx, dreg, expr); } diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index d5e177d5e75c..19a513021fcb 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -545,9 +545,29 @@ static void combine_binop(mpz_t mask, mpz_t xor, const mpz_t m, const mpz_t x) mpz_and(mask, mask, m); } -static void netlink_gen_binop(struct netlink_linearize_ctx *ctx, +static void netlink_gen_shift(struct netlink_linearize_ctx *ctx, const struct expr *expr, enum nft_registers dreg) +{ + enum nft_bitwise_attributes shift_attr = expr->op == OP_LSHIFT ? + NFTNL_EXPR_BITWISE_LSHIFT : NFTNL_EXPR_BITWISE_RSHIFT; + unsigned int len = div_round_up(expr->len, BITS_PER_BYTE); + struct nftnl_expr *nle; + + netlink_gen_expr(ctx, expr->left, dreg); + + nle = alloc_nft_expr("bitwise"); + netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG, dreg); + netlink_put_register(nle, NFTNL_EXPR_BITWISE_DREG, dreg); + nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, len); + nftnl_expr_set_u32(nle, shift_attr, mpz_get_uint32(expr->right->value)); + + nftnl_rule_add_expr(ctx->nlr, nle); +} + +static void netlink_gen_bitwise(struct netlink_linearize_ctx *ctx, + const struct expr *expr, + enum nft_registers dreg) { struct nftnl_expr *nle; struct nft_data_linearize nld; @@ -562,8 +582,9 @@ static void netlink_gen_binop(struct netlink_linearize_ctx *ctx, mpz_init(val); mpz_init(tmp); - binops[n++] = left = (void *)expr; - while (left->etype == EXPR_BINOP && left->left != NULL) + binops[n++] = left = (struct expr *) expr; + while (left->etype == EXPR_BINOP && left->left != NULL && + (left->op == OP_AND || left->op == OP_OR || left->op == OP_XOR)) binops[n++] = left = left->left; n--; @@ -613,6 +634,21 @@ static void netlink_gen_binop(struct netlink_linearize_ctx *ctx, nftnl_rule_add_expr(ctx->nlr, nle); } +static void netlink_gen_binop(struct netlink_linearize_ctx *ctx, + const struct expr *expr, + enum nft_registers dreg) +{ + switch(expr->op) { + case OP_LSHIFT: + case OP_RSHIFT: + netlink_gen_shift(ctx, expr, dreg); + break; + default: + netlink_gen_bitwise(ctx, expr, dreg); + break; + } +} + static enum nft_byteorder_ops netlink_gen_unary_op(enum ops op) { switch (op) { -- 2.24.1