Netfilter-Devel Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH nf-next 0/3] netfilter: nft_bitwise: shift support
@ 2020-01-10 12:33 Jeremy Sowden
  2020-01-10 12:33 ` [PATCH nf-next 1/3] netfilter: nf_tables: white-space fixes Jeremy Sowden
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Jeremy Sowden @ 2020-01-10 12:33 UTC (permalink / raw)
  To: Netfilter Devel

The connmark xtables extension supports bit-shifts.  Add support for
shifts to nft_bitwise in order to allow nftables to do likewise, e.g.:

  nft add rule t c oif lo ct mark set meta mark << 8 | 0xab
  nft add rule t c iif lo meta mark & 0xff 0xab ct mark set meta mark >> 8

There are a couple of preliminary tidying-up patches first.

Jeremy Sowden (3):
  netfilter: nf_tables: white-space fixes.
  netfilter: bitwise: replace gotos with returns.
  netfilter: bitwise: add support for shifts.

 include/uapi/linux/netfilter/nf_tables.h |  9 ++-
 net/netfilter/nft_bitwise.c              | 97 ++++++++++++++++++++----
 net/netfilter/nft_set_bitmap.c           |  4 +-
 net/netfilter/nft_set_hash.c             |  2 +-
 4 files changed, 94 insertions(+), 18 deletions(-)

-- 
2.24.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH nf-next 1/3] netfilter: nf_tables: white-space fixes.
  2020-01-10 12:33 [PATCH nf-next 0/3] netfilter: nft_bitwise: shift support Jeremy Sowden
@ 2020-01-10 12:33 ` Jeremy Sowden
  2020-01-10 12:33 ` [PATCH nf-next 2/3] netfilter: bitwise: replace gotos with returns Jeremy Sowden
  2020-01-10 12:33 ` [PATCH nf-next 3/3] netfilter: bitwise: add support for shifts Jeremy Sowden
  2 siblings, 0 replies; 6+ messages in thread
From: Jeremy Sowden @ 2020-01-10 12:33 UTC (permalink / raw)
  To: Netfilter Devel

Indentation fixes for the parameters of a couple of nft set functions.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
---
 net/netfilter/nft_set_bitmap.c | 4 ++--
 net/netfilter/nft_set_hash.c   | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/net/netfilter/nft_set_bitmap.c b/net/netfilter/nft_set_bitmap.c
index 087a056e34d1..87e8d9ba0c9b 100644
--- a/net/netfilter/nft_set_bitmap.c
+++ b/net/netfilter/nft_set_bitmap.c
@@ -259,8 +259,8 @@ static u64 nft_bitmap_privsize(const struct nlattr * const nla[],
 }
 
 static int nft_bitmap_init(const struct nft_set *set,
-			 const struct nft_set_desc *desc,
-			 const struct nlattr * const nla[])
+			   const struct nft_set_desc *desc,
+			   const struct nlattr * const nla[])
 {
 	struct nft_bitmap *priv = nft_set_priv(set);
 
diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c
index b331a3c9a3a8..d350a7cd3af0 100644
--- a/net/netfilter/nft_set_hash.c
+++ b/net/netfilter/nft_set_hash.c
@@ -645,7 +645,7 @@ static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features,
 }
 
 static bool nft_hash_fast_estimate(const struct nft_set_desc *desc, u32 features,
-			      struct nft_set_estimate *est)
+				   struct nft_set_estimate *est)
 {
 	if (!desc->size)
 		return false;
-- 
2.24.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH nf-next 2/3] netfilter: bitwise: replace gotos with returns.
  2020-01-10 12:33 [PATCH nf-next 0/3] netfilter: nft_bitwise: shift support Jeremy Sowden
  2020-01-10 12:33 ` [PATCH nf-next 1/3] netfilter: nf_tables: white-space fixes Jeremy Sowden
@ 2020-01-10 12:33 ` Jeremy Sowden
  2020-01-10 12:33 ` [PATCH nf-next 3/3] netfilter: bitwise: add support for shifts Jeremy Sowden
  2 siblings, 0 replies; 6+ messages in thread
From: Jeremy Sowden @ 2020-01-10 12:33 UTC (permalink / raw)
  To: Netfilter Devel

When dumping a bitwise expression, if any of the puts fails, we use goto
to jump to a label.  However, no clean-up is required and the only
statement at the label is a return.  Drop the goto's and return
immediately instead.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
---
 net/netfilter/nft_bitwise.c | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c
index 10e9d50e4e19..d7724250be1f 100644
--- a/net/netfilter/nft_bitwise.c
+++ b/net/netfilter/nft_bitwise.c
@@ -107,24 +107,21 @@ static int nft_bitwise_dump(struct sk_buff *skb, const struct nft_expr *expr)
 	const struct nft_bitwise *priv = nft_expr_priv(expr);
 
 	if (nft_dump_register(skb, NFTA_BITWISE_SREG, priv->sreg))
-		goto nla_put_failure;
+		return -1;
 	if (nft_dump_register(skb, NFTA_BITWISE_DREG, priv->dreg))
-		goto nla_put_failure;
+		return -1;
 	if (nla_put_be32(skb, NFTA_BITWISE_LEN, htonl(priv->len)))
-		goto nla_put_failure;
+		return -1;
 
 	if (nft_data_dump(skb, NFTA_BITWISE_MASK, &priv->mask,
 			  NFT_DATA_VALUE, priv->len) < 0)
-		goto nla_put_failure;
+		return -1;
 
 	if (nft_data_dump(skb, NFTA_BITWISE_XOR, &priv->xor,
 			  NFT_DATA_VALUE, priv->len) < 0)
-		goto nla_put_failure;
+		return -1;
 
 	return 0;
-
-nla_put_failure:
-	return -1;
 }
 
 static struct nft_data zero;
-- 
2.24.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH nf-next 3/3] netfilter: bitwise: add support for shifts.
  2020-01-10 12:33 [PATCH nf-next 0/3] netfilter: nft_bitwise: shift support Jeremy Sowden
  2020-01-10 12:33 ` [PATCH nf-next 1/3] netfilter: nf_tables: white-space fixes Jeremy Sowden
  2020-01-10 12:33 ` [PATCH nf-next 2/3] netfilter: bitwise: replace gotos with returns Jeremy Sowden
@ 2020-01-10 12:33 ` Jeremy Sowden
  2020-01-13 21:59   ` Pablo Neira Ayuso
  2 siblings, 1 reply; 6+ messages in thread
From: Jeremy Sowden @ 2020-01-10 12:33 UTC (permalink / raw)
  To: Netfilter Devel

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@azazel.net>
---
 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


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH nf-next 3/3] netfilter: bitwise: add support for shifts.
  2020-01-10 12:33 ` [PATCH nf-next 3/3] netfilter: bitwise: add support for shifts Jeremy Sowden
@ 2020-01-13 21:59   ` Pablo Neira Ayuso
  0 siblings, 0 replies; 6+ messages in thread
From: Pablo Neira Ayuso @ 2020-01-13 21:59 UTC (permalink / raw)
  To: Jeremy Sowden; +Cc: Netfilter Devel

Hi Jeremy,

On Fri, Jan 10, 2020 at 12:33:12PM +0000, Jeremy Sowden wrote:
> 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@azazel.net>
> ---
>  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)

I'd suggest you add:

NFTA_BITWISE_OP

possible values are:

NFT_BITWISE_XOR (or _BOOL, you pick the more appropriate name for me)
NFT_BITWISE_RSHIFT
NFT_BITWISE_LSHIFT

You can introduce the NFTA_BITWISE_OP attribute in a initial
preparation patch.

If NFTA_BITWISE_OP is not specified, then default to NFT_BITWISE_XOR
to ensure backward compatibility with old userspace tooling.

>   *
> - * 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,

On top of NFTA_BITWISE_OP.

I'd suggest you add NFTA_BITWISE_DATA instead of NFTA_BITWISE_{R,L}SHIFT.

>  	__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) {

I'd suggest you turn this into something like:

        switch (priv->op) {
        case NFT_BITWISE_RSHIFT:
                nft_bitwise_rshift(...);
                break;
        case NFT_BITWISE_LSHIFT:
                nft_bitwise_lshift(...);
                break;
        case ...
        }

so these code below is store in a function.

> +		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];

Probably an initial preparation patch to move this code to a function
would be fine.

>  }
> @@ -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;
> +	}

I would like to see that the netlink interface really bails out for
combinations this does not support. That will make it easier later on
to extend it from userspace.

Therefore, something like:

        switch (priv->op) {
        case NFT_BITWISE_RSHIFT:
        case NFT_BITWISE_LSHIFT:
                if (!tb[NFTA_BITWISE_SHIFT])
                        return -EINVAL;

                if (tb[NFTA_BITWISE_MASK] ||
                    tb[NFTA_BITWISE_XOR])
                        return -EINVAL;

                break;
        case NFT_BITWISE_BOOL:
                if (!tb[NFTA_BITWISE_MASK] ||
                    !tb[NFTA_BITWISE_XOR])
                        return -EINVAL;

                if (tb[NFTA_BITWISE_SHIFT)
                        return -EINVAL;
                break;

> +	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;
> +	}

With one single NFTA_BITWISE_SHIFT, this will be consolidated.

Thanks for working on this.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH nf-next 3/3] netfilter: bitwise: add support for shifts.
  2020-01-14 21:28 [PATCH nf-next 0/3] netfilter: nft_bitwise: shift support Jeremy Sowden
@ 2020-01-14 21:29 ` Jeremy Sowden
  0 siblings, 0 replies; 6+ messages in thread
From: Jeremy Sowden @ 2020-01-14 21:29 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: Netfilter Devel

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@azazel.net>
---
 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


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, back to index

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-10 12:33 [PATCH nf-next 0/3] netfilter: nft_bitwise: shift support Jeremy Sowden
2020-01-10 12:33 ` [PATCH nf-next 1/3] netfilter: nf_tables: white-space fixes Jeremy Sowden
2020-01-10 12:33 ` [PATCH nf-next 2/3] netfilter: bitwise: replace gotos with returns Jeremy Sowden
2020-01-10 12:33 ` [PATCH nf-next 3/3] netfilter: bitwise: add support for shifts Jeremy Sowden
2020-01-13 21:59   ` Pablo Neira Ayuso
2020-01-14 21:28 [PATCH nf-next 0/3] netfilter: nft_bitwise: shift support Jeremy Sowden
2020-01-14 21:29 ` [PATCH nf-next 3/3] netfilter: bitwise: add support for shifts Jeremy Sowden

Netfilter-Devel Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/netfilter-devel/0 netfilter-devel/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 netfilter-devel netfilter-devel/ https://lore.kernel.org/netfilter-devel \
		netfilter-devel@vger.kernel.org
	public-inbox-index netfilter-devel

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.netfilter-devel


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git