Hi Jeremy, I've been looking into (ab)using bitwise to implement add/sub. I would like to not add nft_arith for only this, and it seems to me much of your code can be reused. Do you think something like this would work? Thanks.
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index 065218a20bb7..c4078359b6e4 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@ -508,11 +508,15 @@ enum nft_immediate_attributes { * XOR boolean operations * @NFT_BITWISE_LSHIFT: left-shift operation * @NFT_BITWISE_RSHIFT: right-shift operation + * @NFT_BITWISE_ADD: add operation + * @NFT_BITWISE_SUB: subtract operation */ enum nft_bitwise_ops { NFT_BITWISE_BOOL, NFT_BITWISE_LSHIFT, NFT_BITWISE_RSHIFT, + NFT_BITWISE_ADD, + NFT_BITWISE_SUB, }; /** diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c index 0ed2281f03be..fd0cd2b4722a 100644 --- a/net/netfilter/nft_bitwise.c +++ b/net/netfilter/nft_bitwise.c @@ -60,6 +60,38 @@ static void nft_bitwise_eval_rshift(u32 *dst, const u32 *src, } } +static void nft_bitwise_eval_add(u32 *dst, const u32 *src, + const struct nft_bitwise *priv) +{ + u32 delta = priv->data.data[0]; + unsigned int i, words; + u32 tmp = 0; + + words = DIV_ROUND_UP(priv->len, sizeof(u32)); + for (i = 0; i < words; i++) { + tmp = src[i]; + dst[i] = src[i] + delta; + if (dst[i] < tmp && i + 1 < words) + dst[i + 1]++; + } +} + +static void nft_bitwise_eval_sub(u32 *dst, const u32 *src, + const struct nft_bitwise *priv) +{ + u32 delta = priv->data.data[0]; + unsigned int i, words; + u32 tmp = 0; + + words = DIV_ROUND_UP(priv->len, sizeof(u32)); + for (i = 0; i < words; i++) { + tmp = src[i]; + dst[i] = src[i] - delta; + if (dst[i] > tmp && i + 1 < words) + dst[i + 1]--; + } +} + void nft_bitwise_eval(const struct nft_expr *expr, struct nft_regs *regs, const struct nft_pktinfo *pkt) { @@ -77,6 +109,12 @@ void nft_bitwise_eval(const struct nft_expr *expr, case NFT_BITWISE_RSHIFT: nft_bitwise_eval_rshift(dst, src, priv); break; + case NFT_BITWISE_ADD: + nft_bitwise_eval_add(dst, src, priv); + break; + case NFT_BITWISE_SUB: + nft_bitwise_eval_sub(dst, src, priv); + break; } } @@ -129,8 +167,8 @@ static int nft_bitwise_init_bool(struct nft_bitwise *priv, return err; } -static int nft_bitwise_init_shift(struct nft_bitwise *priv, - const struct nlattr *const tb[]) +static int nft_bitwise_init_data(struct nft_bitwise *priv, + const struct nlattr *const tb[]) { struct nft_data_desc d; int err; @@ -191,6 +229,8 @@ static int nft_bitwise_init(const struct nft_ctx *ctx, case NFT_BITWISE_BOOL: case NFT_BITWISE_LSHIFT: case NFT_BITWISE_RSHIFT: + case NFT_BITWISE_ADD: + case NFT_BITWISE_SUB: break; default: return -EOPNOTSUPP; @@ -205,7 +245,9 @@ static int nft_bitwise_init(const struct nft_ctx *ctx, break; case NFT_BITWISE_LSHIFT: case NFT_BITWISE_RSHIFT: - err = nft_bitwise_init_shift(priv, tb); + case NFT_BITWISE_ADD: + case NFT_BITWISE_SUB: + err = nft_bitwise_init_data(priv, tb); break; } @@ -226,8 +268,8 @@ static int nft_bitwise_dump_bool(struct sk_buff *skb, return 0; } -static int nft_bitwise_dump_shift(struct sk_buff *skb, - const struct nft_bitwise *priv) +static int nft_bitwise_dump_data(struct sk_buff *skb, + const struct nft_bitwise *priv) { if (nft_data_dump(skb, NFTA_BITWISE_DATA, &priv->data, NFT_DATA_VALUE, sizeof(u32)) < 0) @@ -255,7 +297,9 @@ static int nft_bitwise_dump(struct sk_buff *skb, const struct nft_expr *expr) break; case NFT_BITWISE_LSHIFT: case NFT_BITWISE_RSHIFT: - err = nft_bitwise_dump_shift(skb, priv); + case NFT_BITWISE_ADD: + case NFT_BITWISE_SUB: + err = nft_bitwise_dump_data(skb, priv); break; }