filter: add MOD operation

Add a new ALU opcode, to compute a modulus.

Commit ffe06c17af used an ancillary to implement XOR_X,
but here we reserve one of the available ALU opcode to implement both
MOD_X and MOD_K

Signed-off-by: Eric Dumazet <edumazet@google.com>
Suggested-by: George Bakos <gbakos@alpinista.org>
Cc: Jay Schulist <jschlst@samba.org>
Cc: Jiri Pirko <jpirko@redhat.com>
Cc: Andi Kleen <ak@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Eric Dumazet 2012-09-07 22:03:35 +00:00 committed by David S. Miller
parent c6bb8136c9
commit b6069a9570
2 changed files with 19 additions and 0 deletions

View File

@ -74,6 +74,8 @@ struct sock_fprog { /* Required for SO_ATTACH_FILTER. */
#define BPF_LSH 0x60 #define BPF_LSH 0x60
#define BPF_RSH 0x70 #define BPF_RSH 0x70
#define BPF_NEG 0x80 #define BPF_NEG 0x80
#define BPF_MOD 0x90
#define BPF_JA 0x00 #define BPF_JA 0x00
#define BPF_JEQ 0x10 #define BPF_JEQ 0x10
#define BPF_JGT 0x20 #define BPF_JGT 0x20
@ -196,6 +198,8 @@ enum {
BPF_S_ALU_MUL_K, BPF_S_ALU_MUL_K,
BPF_S_ALU_MUL_X, BPF_S_ALU_MUL_X,
BPF_S_ALU_DIV_X, BPF_S_ALU_DIV_X,
BPF_S_ALU_MOD_K,
BPF_S_ALU_MOD_X,
BPF_S_ALU_AND_K, BPF_S_ALU_AND_K,
BPF_S_ALU_AND_X, BPF_S_ALU_AND_X,
BPF_S_ALU_OR_K, BPF_S_ALU_OR_K,

View File

@ -167,6 +167,14 @@ unsigned int sk_run_filter(const struct sk_buff *skb,
case BPF_S_ALU_DIV_K: case BPF_S_ALU_DIV_K:
A = reciprocal_divide(A, K); A = reciprocal_divide(A, K);
continue; continue;
case BPF_S_ALU_MOD_X:
if (X == 0)
return 0;
A %= X;
continue;
case BPF_S_ALU_MOD_K:
A %= K;
continue;
case BPF_S_ALU_AND_X: case BPF_S_ALU_AND_X:
A &= X; A &= X;
continue; continue;
@ -469,6 +477,8 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen)
[BPF_ALU|BPF_MUL|BPF_K] = BPF_S_ALU_MUL_K, [BPF_ALU|BPF_MUL|BPF_K] = BPF_S_ALU_MUL_K,
[BPF_ALU|BPF_MUL|BPF_X] = BPF_S_ALU_MUL_X, [BPF_ALU|BPF_MUL|BPF_X] = BPF_S_ALU_MUL_X,
[BPF_ALU|BPF_DIV|BPF_X] = BPF_S_ALU_DIV_X, [BPF_ALU|BPF_DIV|BPF_X] = BPF_S_ALU_DIV_X,
[BPF_ALU|BPF_MOD|BPF_K] = BPF_S_ALU_MOD_K,
[BPF_ALU|BPF_MOD|BPF_X] = BPF_S_ALU_MOD_X,
[BPF_ALU|BPF_AND|BPF_K] = BPF_S_ALU_AND_K, [BPF_ALU|BPF_AND|BPF_K] = BPF_S_ALU_AND_K,
[BPF_ALU|BPF_AND|BPF_X] = BPF_S_ALU_AND_X, [BPF_ALU|BPF_AND|BPF_X] = BPF_S_ALU_AND_X,
[BPF_ALU|BPF_OR|BPF_K] = BPF_S_ALU_OR_K, [BPF_ALU|BPF_OR|BPF_K] = BPF_S_ALU_OR_K,
@ -531,6 +541,11 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen)
return -EINVAL; return -EINVAL;
ftest->k = reciprocal_value(ftest->k); ftest->k = reciprocal_value(ftest->k);
break; break;
case BPF_S_ALU_MOD_K:
/* check for division by zero */
if (ftest->k == 0)
return -EINVAL;
break;
case BPF_S_LD_MEM: case BPF_S_LD_MEM:
case BPF_S_LDX_MEM: case BPF_S_LDX_MEM:
case BPF_S_ST: case BPF_S_ST: