[PATCH nf-next 3/3] netfilter: bitwise: add support for shifts.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Currently nft_bitwise only supports boolean operations: NOT, AND, OR and
XOR.  Extend it to do shifts as well.

Signed-off-by: Jeremy Sowden <jeremy@xxxxxxxxxx>
---
 include/uapi/linux/netfilter/nf_tables.h |  9 ++-
 net/netfilter/nft_bitwise.c              | 84 ++++++++++++++++++++++--
 2 files changed, 86 insertions(+), 7 deletions(-)

diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index dd4611767933..8f244ada0ad3 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -492,12 +492,15 @@ 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:
+ * The bitwise expression supports boolean and shift operations.  It implements
+ * the boolean operations by performing the following operation:
  *
  * dreg = (sreg & mask) ^ xor
  *
- * which allow to express all bitwise operations:
+ * with these mask and xor values:
  *
  * 		mask	xor
  * NOT:		1	1
@@ -512,6 +515,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/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c
index d7724250be1f..e4db77057b0e 100644
--- a/net/netfilter/nft_bitwise.c
+++ b/net/netfilter/nft_bitwise.c
@@ -15,12 +15,20 @@
 #include <net/netfilter/nf_tables.h>
 #include <net/netfilter/nf_tables_offload.h>
 
+enum nft_bitwise_ops {
+	OP_BOOL,
+	OP_LSHIFT,
+	OP_RSHIFT,
+};
+
 struct nft_bitwise {
 	enum nft_registers	sreg:8;
 	enum nft_registers	dreg:8;
+	enum nft_bitwise_ops	op:8;
 	u8			len;
 	struct nft_data		mask;
 	struct nft_data		xor;
+	u8			shift;
 };
 
 void nft_bitwise_eval(const struct nft_expr *expr,
@@ -31,6 +39,26 @@ void nft_bitwise_eval(const struct nft_expr *expr,
 	u32 *dst = &regs->data[priv->dreg];
 	unsigned int i;
 
+	if (priv->op == OP_LSHIFT) {
+		u32 carry = 0;
+
+		for (i = DIV_ROUND_UP(priv->len, sizeof(u32)); i > 0; i--) {
+			dst[i - 1] = (src[i - 1] << priv->shift) | carry;
+			carry = src[i - 1] >> (32 - priv->shift);
+		}
+		return;
+	}
+
+	if (priv->op == OP_RSHIFT) {
+		u32 carry = 0;
+
+		for (i = 0; i < DIV_ROUND_UP(priv->len, sizeof(u32)); i++) {
+			dst[i] = carry | (src[i] >> priv->shift);
+			carry = src[i] << (32 - priv->shift);
+		}
+		return;
+	}
+
 	for (i = 0; i < DIV_ROUND_UP(priv->len, 4); i++)
 		dst[i] = (src[i] & priv->mask.data[i]) ^ priv->xor.data[i];
 }
@@ -41,6 +69,8 @@ static const struct nla_policy nft_bitwise_policy[NFTA_BITWISE_MAX + 1] = {
 	[NFTA_BITWISE_LEN]	= { .type = NLA_U32 },
 	[NFTA_BITWISE_MASK]	= { .type = NLA_NESTED },
 	[NFTA_BITWISE_XOR]	= { .type = NLA_NESTED },
+	[NFTA_BITWISE_LSHIFT]	= { .type = NLA_U32 },
+	[NFTA_BITWISE_RSHIFT]	= { .type = NLA_U32 },
 };
 
 static int nft_bitwise_init(const struct nft_ctx *ctx,
@@ -52,11 +82,9 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
 	u32 len;
 	int err;
 
-	if (tb[NFTA_BITWISE_SREG] == NULL ||
-	    tb[NFTA_BITWISE_DREG] == NULL ||
-	    tb[NFTA_BITWISE_LEN] == NULL ||
-	    tb[NFTA_BITWISE_MASK] == NULL ||
-	    tb[NFTA_BITWISE_XOR] == NULL)
+	if (!tb[NFTA_BITWISE_SREG] ||
+	    !tb[NFTA_BITWISE_DREG] ||
+	    !tb[NFTA_BITWISE_LEN])
 		return -EINVAL;
 
 	err = nft_parse_u32_check(tb[NFTA_BITWISE_LEN], U8_MAX, &len);
@@ -76,6 +104,36 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
 	if (err < 0)
 		return err;
 
+	if (tb[NFTA_BITWISE_LSHIFT]) {
+		u32 shift;
+
+		err = nft_parse_u32_check(tb[NFTA_BITWISE_LSHIFT], U8_MAX,
+					  &shift);
+		if (err < 0)
+			return err;
+
+		priv->shift = shift;
+		priv->op = OP_LSHIFT;
+		return 0;
+	}
+
+	if (tb[NFTA_BITWISE_RSHIFT]) {
+		u32 shift;
+
+		err = nft_parse_u32_check(tb[NFTA_BITWISE_RSHIFT], U8_MAX,
+					  &shift);
+		if (err < 0)
+			return err;
+
+		priv->shift = shift;
+		priv->op = OP_RSHIFT;
+		return 0;
+	}
+
+	if (!tb[NFTA_BITWISE_MASK] ||
+	    !tb[NFTA_BITWISE_XOR])
+		return -EINVAL;
+
 	err = nft_data_init(NULL, &priv->mask, sizeof(priv->mask), &d1,
 			    tb[NFTA_BITWISE_MASK]);
 	if (err < 0)
@@ -94,6 +152,7 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
 		goto err2;
 	}
 
+	priv->op = OP_BOOL;
 	return 0;
 err2:
 	nft_data_release(&priv->xor, d2.type);
@@ -113,6 +172,18 @@ static int nft_bitwise_dump(struct sk_buff *skb, const struct nft_expr *expr)
 	if (nla_put_be32(skb, NFTA_BITWISE_LEN, htonl(priv->len)))
 		return -1;
 
+	if (priv->op == OP_LSHIFT) {
+		if (nla_put_be32(skb, NFTA_BITWISE_LSHIFT, htonl(priv->shift)))
+			return -1;
+		return 0;
+	}
+
+	if (priv->op == OP_RSHIFT) {
+		if (nla_put_be32(skb, NFTA_BITWISE_RSHIFT, htonl(priv->shift)))
+			return -1;
+		return 0;
+	}
+
 	if (nft_data_dump(skb, NFTA_BITWISE_MASK, &priv->mask,
 			  NFT_DATA_VALUE, priv->len) < 0)
 		return -1;
@@ -133,6 +204,9 @@ static int nft_bitwise_offload(struct nft_offload_ctx *ctx,
 	const struct nft_bitwise *priv = nft_expr_priv(expr);
 	struct nft_offload_reg *reg = &ctx->regs[priv->dreg];
 
+	if (priv->op != OP_BOOL)
+		return -EOPNOTSUPP;
+
 	if (memcmp(&priv->xor, &zero, sizeof(priv->xor)) ||
 	    priv->sreg != priv->dreg || priv->len != reg->len)
 		return -EOPNOTSUPP;
-- 
2.24.1




[Index of Archives]     [Netfitler Users]     [Berkeley Packet Filter]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux