From 83e230739cb578049f62c626946e04a79b46c85b Mon Sep 17 00:00:00 2001
From: Kevin Mihelich <kevin@archlinuxarm.org>
Date: Mon, 29 Sep 2014 12:14:00 -0600
Subject: [PATCH] Backport BFP XOR operation

Squashed commit of the following:

commit 210b6dd797945571a92ae1f502be6b885cdeae23
Author: Daniel Borkmann <dxchgb@gmail.com>
Date:   Mon Sep 24 02:23:59 2012 +0000

    filter: add XOR instruction for use with X/K

    SKF_AD_ALU_XOR_X has been added a while ago, but as an 'ancillary'
    operation that is invoked through a negative offset in K within BPF
    load operations. Since BPF_MOD has recently been added, BPF_XOR should
    also be part of the common ALU operations. Removing SKF_AD_ALU_XOR_X
    might not be an option since this is exposed to user space.

    Signed-off-by: Daniel Borkmann <daniel.borkmann@tik.ee.ethz.ch>
    Acked-by: Eric Dumazet <edumazet@google.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 11acc6e3fc94f8b18483af729760b9025d708409
Author: Eric Dumazet <edumazet@google.com>
Date:   Fri Sep 7 22:03:35 2012 +0000

    filter: add MOD operation

    Add a new ALU opcode, to compute a modulus.

    Commit ffe06c17afbbb 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>

commit 3026fca84f0230d96693ba6d3e6089343874ca09
Author: Daniel Borkmann <dxchgb@gmail.com>
Date:   Mon Sep 24 07:34:51 2012 +0000

    x86: bpf_jit_comp: add XOR instruction for BPF JIT

    This patch is a follow-up for patch "filter: add XOR instruction for use
    with X/K" that implements BPF x86 JIT parts for the BPF XOR operation.

    Signed-off-by: Daniel Borkmann <daniel.borkmann@tik.ee.ethz.ch>
    Acked-by: Eric Dumazet <edumazet@google.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit cf2f055d4abff198aaa0128aa06e458a6ff767d7
Author: Eric Dumazet <edumazet@google.com>
Date:   Mon Jun 4 21:26:30 2012 +0000

    x86 bpf_jit: support BPF_S_ANC_ALU_XOR_X instruction

    commit ffe06c17afbb  (filter: add XOR operation) added generic support
    for XOR operation.

    This patch implements the XOR instruction in x86 jit.

    Signed-off-by: Eric Dumazet <edumazet@google.com>
    Cc: Jiri Pirko <jpirko@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e0d7a646c8684dac88c6ebbeb155313ad7fc624d
Author: Jiri Pirko <jpirko@redhat.com>
Date:   Sat Mar 31 11:01:20 2012 +0000

    filter: add XOR operation

    Add XOR instruction fo BPF machine. Needed for computing packet hashes.

    Signed-off-by: Jiri Pirko <jpirko@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
---
 arch/x86/net/bpf_jit_comp.c | 13 +++++++++++++
 include/linux/filter.h      | 11 ++++++++++-
 net/core/filter.c           | 25 +++++++++++++++++++++++++
 3 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 0597f95..db99f9a 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -309,6 +309,19 @@ void bpf_jit_compile(struct sk_filter *fp)
 				else
 					EMIT1_off32(0x0d, K);	/* or imm32,%eax */
 				break;
+			case BPF_S_ANC_ALU_XOR_X: /* A ^= X; */
+			case BPF_S_ALU_XOR_X:
+				seen |= SEEN_XREG;
+				EMIT2(0x31, 0xd8);		/* xor %ebx,%eax */
+				break;
+			case BPF_S_ALU_XOR_K: /* A ^= K; */
+				if (K == 0)
+					break;
+				if (is_imm8(K))
+					EMIT3(0x83, 0xf0, K);	/* xor imm8,%eax */
+				else
+					EMIT1_off32(0x35, K);	/* xor imm32,%eax */
+				break;
 			case BPF_S_ALU_LSH_X: /* A <<= X; */
 				seen |= SEEN_XREG;
 				EMIT4(0x89, 0xd9, 0xd3, 0xe0);	/* mov %ebx,%ecx; shl %cl,%eax */
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 8eeb205..0031feb 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -73,6 +73,9 @@ struct sock_fprog {	/* Required for SO_ATTACH_FILTER. */
 #define         BPF_LSH         0x60
 #define         BPF_RSH         0x70
 #define         BPF_NEG         0x80
+#define		BPF_MOD		0x90
+#define		BPF_XOR		0xa0
+
 #define         BPF_JA          0x00
 #define         BPF_JEQ         0x10
 #define         BPF_JGT         0x20
@@ -126,7 +129,8 @@ struct sock_fprog {	/* Required for SO_ATTACH_FILTER. */
 #define SKF_AD_HATYPE	28
 #define SKF_AD_RXHASH	32
 #define SKF_AD_CPU	36
-#define SKF_AD_MAX	40
+#define SKF_AD_ALU_XOR_X	40
+#define SKF_AD_MAX	44
 #define SKF_NET_OFF   (-0x100000)
 #define SKF_LL_OFF    (-0x200000)
 
@@ -181,10 +185,14 @@ enum {
 	BPF_S_ALU_MUL_K,
 	BPF_S_ALU_MUL_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_X,
 	BPF_S_ALU_OR_K,
 	BPF_S_ALU_OR_X,
+	BPF_S_ALU_XOR_K,
+	BPF_S_ALU_XOR_X,
 	BPF_S_ALU_LSH_K,
 	BPF_S_ALU_LSH_X,
 	BPF_S_ALU_RSH_K,
@@ -228,6 +236,7 @@ enum {
 	BPF_S_ANC_HATYPE,
 	BPF_S_ANC_RXHASH,
 	BPF_S_ANC_CPU,
+	BPF_S_ANC_ALU_XOR_X,
 };
 
 #endif /* __KERNEL__ */
diff --git a/net/core/filter.c b/net/core/filter.c
index 3b7398a..26c7bbe 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -158,6 +158,14 @@ unsigned int sk_run_filter(const struct sk_buff *skb,
 		case BPF_S_ALU_DIV_K:
 			A = reciprocal_divide(A, K);
 			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:
 			A &= X;
 			continue;
@@ -170,6 +178,13 @@ unsigned int sk_run_filter(const struct sk_buff *skb,
 		case BPF_S_ALU_OR_K:
 			A |= K;
 			continue;
+		case BPF_S_ANC_ALU_XOR_X:
+		case BPF_S_ALU_XOR_X:
+			A ^= X;
+			continue;
+		case BPF_S_ALU_XOR_K:
+			A ^= K;
+			continue;
 		case BPF_S_ALU_LSH_X:
 			A <<= X;
 			continue;
@@ -456,10 +471,14 @@ 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_X]  = BPF_S_ALU_MUL_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_X]  = BPF_S_ALU_AND_X,
 		[BPF_ALU|BPF_OR|BPF_K]   = BPF_S_ALU_OR_K,
 		[BPF_ALU|BPF_OR|BPF_X]   = BPF_S_ALU_OR_X,
+		[BPF_ALU|BPF_XOR|BPF_K]  = BPF_S_ALU_XOR_K,
+		[BPF_ALU|BPF_XOR|BPF_X]  = BPF_S_ALU_XOR_X,
 		[BPF_ALU|BPF_LSH|BPF_K]  = BPF_S_ALU_LSH_K,
 		[BPF_ALU|BPF_LSH|BPF_X]  = BPF_S_ALU_LSH_X,
 		[BPF_ALU|BPF_RSH|BPF_K]  = BPF_S_ALU_RSH_K,
@@ -518,6 +537,11 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen)
 				return -EINVAL;
 			ftest->k = reciprocal_value(ftest->k);
 			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_LDX_MEM:
 		case BPF_S_ST:
@@ -565,6 +589,7 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen)
 			ANCILLARY(HATYPE);
 			ANCILLARY(RXHASH);
 			ANCILLARY(CPU);
+			ANCILLARY(ALU_XOR_X);
 			}
 		}
 		ftest->code = code;
-- 
2.1.1