net: filter: improve test case framework
authorDaniel Borkmann <dborkman@redhat.com>
Fri, 23 May 2014 16:44:00 +0000 (18:44 +0200)
committerDavid S. Miller <davem@davemloft.net>
Fri, 23 May 2014 20:48:06 +0000 (16:48 -0400)
This patch simplifies and refactors the test case code a
bit and also adds a summary of all test that passed or
failed in the kernel log, so that it's easier to spot if
something has failed.

Future work could further extend the test framework to also
support different input 'stimuli' i.e. related structures
to seccomp.

Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Acked-by: Alexei Starovoitov <ast@plumgrid.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
lib/test_bpf.c

index e03991e..da34e33 100644 (file)
 #include <linux/netdevice.h>
 #include <linux/if_vlan.h>
 
+/* General test specific settings */
 #define MAX_SUBTESTS   3
+#define MAX_TESTRUNS   10000
 #define MAX_DATA       128
 #define MAX_INSNS      512
 #define MAX_K          0xffffFFFF
 
-/* define few constants used to init test 'skb' */
+/* Few constants used to init test 'skb' */
 #define SKB_TYPE       3
 #define SKB_MARK       0x1234aaaa
 #define SKB_HASH       0x1234aaab
 #define SKB_DEV_IFINDEX        577
 #define SKB_DEV_TYPE   588
 
-/* redefine REGs to make tests less verbose */
-#define R0 BPF_REG_0
-#define R1 BPF_REG_1
-#define R2 BPF_REG_2
-#define R3 BPF_REG_3
-#define R4 BPF_REG_4
-#define R5 BPF_REG_5
-#define R6 BPF_REG_6
-#define R7 BPF_REG_7
-#define R8 BPF_REG_8
-#define R9 BPF_REG_9
-#define R10 BPF_REG_10
+/* Redefine REGs to make tests less verbose */
+#define R0             BPF_REG_0
+#define R1             BPF_REG_1
+#define R2             BPF_REG_2
+#define R3             BPF_REG_3
+#define R4             BPF_REG_4
+#define R5             BPF_REG_5
+#define R6             BPF_REG_6
+#define R7             BPF_REG_7
+#define R8             BPF_REG_8
+#define R9             BPF_REG_9
+#define R10            BPF_REG_10
+
+/* Flags that can be passed to test cases */
+#define FLAG_NO_DATA           BIT(0)
+#define FLAG_EXPECTED_FAIL     BIT(1)
+
+enum {
+       CLASSIC  = BIT(6),      /* Old BPF instructions only. */
+       INTERNAL = BIT(7),      /* Extended instruction set.  */
+};
+
+#define TEST_TYPE_MASK         (CLASSIC | INTERNAL)
 
 struct bpf_test {
        const char *descr;
@@ -55,12 +68,7 @@ struct bpf_test {
                struct sock_filter insns[MAX_INSNS];
                struct sock_filter_int insns_int[MAX_INSNS];
        } u;
-       enum {
-               NO_DATA,
-               EXPECTED_FAIL,
-               SKB,
-               SKB_INT
-       } data_type;
+       __u8 aux;
        __u8 data[MAX_DATA];
        struct {
                int data_size;
@@ -84,7 +92,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_LD | BPF_B | BPF_IND, 1),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
+               CLASSIC,
                { 10, 20, 30, 40, 50 },
                { { 2, 10 }, { 3, 20 }, { 4, 30 } },
        },
@@ -96,7 +104,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0),
                        BPF_STMT(BPF_RET | BPF_A, 0) /* A == len * 2 */
                },
-               SKB,
+               CLASSIC,
                { 10, 20, 30, 40, 50 },
                { { 1, 2 }, { 3, 6 }, { 4, 8 } },
        },
@@ -111,7 +119,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_ALU | BPF_MUL | BPF_K, 3),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               0,
+               CLASSIC | FLAG_NO_DATA,
                { },
                { { 0, 0xfffffffd } }
        },
@@ -129,7 +137,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               0,
+               CLASSIC | FLAG_NO_DATA,
                { },
                { { 0, 0x40000001 } }
        },
@@ -145,7 +153,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               0,
+               CLASSIC | FLAG_NO_DATA,
                { },
                { { 0, 0x800000ff }, { 1, 0x800000ff } },
        },
@@ -156,7 +164,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_LD | BPF_H | BPF_IND, MAX_K),
                        BPF_STMT(BPF_RET | BPF_K, 1)
                },
-               SKB,
+               CLASSIC,
                { },
                { { 1, 0 }, { 10, 0 }, { 60, 0 } },
        },
@@ -166,7 +174,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 1000),
                        BPF_STMT(BPF_RET | BPF_K, 1)
                },
-               SKB,
+               CLASSIC,
                { },
                { { 1, 0 }, { 10, 0 }, { 60, 0 } },
        },
@@ -179,7 +187,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
+               CLASSIC,
                { 1, 2, 3 },
                { { 1, 0 }, { 2, 3 } },
        },
@@ -193,7 +201,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
+               CLASSIC,
                { 1, 2, 3, 0xff },
                { { 1, 1 }, { 3, 3 }, { 4, 0xff } },
        },
@@ -206,7 +214,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
+               CLASSIC,
                { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 },
                { { 15, 0 }, { 16, 3 } },
        },
@@ -220,7 +228,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
+               CLASSIC,
                { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 },
                { { 14, 0 }, { 15, 1 }, { 17, 3 } },
        },
@@ -241,7 +249,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_RET | BPF_K, 1),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
+               CLASSIC,
                { },
                { { 1, 3 }, { 10, 3 } },
        },
@@ -252,7 +260,7 @@ static struct bpf_test tests[] = {
                                 SKF_AD_OFF + SKF_AD_MARK),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
+               CLASSIC,
                { },
                { { 1, SKB_MARK}, { 10, SKB_MARK} },
        },
@@ -263,7 +271,7 @@ static struct bpf_test tests[] = {
                                 SKF_AD_OFF + SKF_AD_RXHASH),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
+               CLASSIC,
                { },
                { { 1, SKB_HASH}, { 10, SKB_HASH} },
        },
@@ -274,7 +282,7 @@ static struct bpf_test tests[] = {
                                 SKF_AD_OFF + SKF_AD_QUEUE),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
+               CLASSIC,
                { },
                { { 1, SKB_QUEUE_MAP }, { 10, SKB_QUEUE_MAP } },
        },
@@ -293,7 +301,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_MISC | BPF_TXA, 0),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
+               CLASSIC,
                { 10, 20, 30 },
                { { 10, ETH_P_IP }, { 100, ETH_P_IP } },
        },
@@ -304,7 +312,7 @@ static struct bpf_test tests[] = {
                                 SKF_AD_OFF + SKF_AD_VLAN_TAG),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
+               CLASSIC,
                { },
                {
                        { 1, SKB_VLAN_TCI & ~VLAN_TAG_PRESENT },
@@ -318,7 +326,7 @@ static struct bpf_test tests[] = {
                                 SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
+               CLASSIC,
                { },
                {
                        { 1, !!(SKB_VLAN_TCI & VLAN_TAG_PRESENT) },
@@ -332,7 +340,7 @@ static struct bpf_test tests[] = {
                                 SKF_AD_OFF + SKF_AD_IFINDEX),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
+               CLASSIC,
                { },
                { { 1, SKB_DEV_IFINDEX }, { 10, SKB_DEV_IFINDEX } },
        },
@@ -343,7 +351,7 @@ static struct bpf_test tests[] = {
                                 SKF_AD_OFF + SKF_AD_HATYPE),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
+               CLASSIC,
                { },
                { { 1, SKB_DEV_TYPE }, { 10, SKB_DEV_TYPE } },
        },
@@ -358,7 +366,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_ALU | BPF_SUB | BPF_X, 0),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
+               CLASSIC,
                { },
                { { 1, 0 }, { 10, 0 } },
        },
@@ -372,7 +380,7 @@ static struct bpf_test tests[] = {
                                 SKF_AD_OFF + SKF_AD_NLATTR),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
+               CLASSIC,
                { 0xff, 4, 0, 2, 0, 4, 0, 3, 0 },
                { { 4, 0 }, { 20, 5 } },
        },
@@ -406,7 +414,7 @@ static struct bpf_test tests[] = {
                                 SKF_AD_OFF + SKF_AD_NLATTR_NEST),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
+               CLASSIC,
                { 0xff, 12, 0, 1, 0, 4, 0, 2, 0, 4, 0, 3, 0 },
                { { 4, 0 }, { 20, 9 } },
        },
@@ -425,7 +433,7 @@ static struct bpf_test tests[] = {
                                 SKF_AD_OFF + SKF_AD_PAY_OFFSET),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
+               CLASSIC,
                /* 00:00:00:00:00:00 > 00:00:00:00:00:00, ethtype IPv4 (0x0800),
                 * length 98: 127.0.0.1 > 127.0.0.1: ICMP echo request,
                 * id 9737, seq 1, length 64
@@ -446,7 +454,7 @@ static struct bpf_test tests[] = {
                                 SKF_AD_OFF + SKF_AD_ALU_XOR_X),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
+               CLASSIC,
                { },
                { { 4, 10 ^ 300 }, { 20, 10 ^ 300 } },
        },
@@ -468,7 +476,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_ALU | BPF_XOR | BPF_X, 0),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
+               CLASSIC,
                { },
                { { 1, 0x80000001 }, { 2, 0x80000002 }, { 60, 0x80000000 ^ 60 } }
        },
@@ -481,7 +489,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_RET | BPF_K, 1),
                        BPF_STMT(BPF_RET | BPF_K, MAX_K)
                },
-               SKB,
+               CLASSIC,
                { 3, 3, 3, 3, 3 },
                { { 1, 0 }, { 3, 1 }, { 4, MAX_K } },
        },
@@ -494,7 +502,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_RET | BPF_K, 1),
                        BPF_STMT(BPF_RET | BPF_K, MAX_K)
                },
-               SKB,
+               CLASSIC,
                { 4, 4, 4, 3, 3 },
                { { 2, 0 }, { 3, 1 }, { 4, MAX_K } },
        },
@@ -513,7 +521,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_RET | BPF_K, 40),
                        BPF_STMT(BPF_RET | BPF_K, MAX_K)
                },
-               SKB,
+               CLASSIC,
                { 1, 2, 3, 4, 5 },
                { { 1, 20 }, { 3, 40 }, { 5, MAX_K } },
        },
@@ -545,7 +553,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_RET | BPF_K, 30),
                        BPF_STMT(BPF_RET | BPF_K, MAX_K)
                },
-               SKB,
+               CLASSIC,
                { 0, 0xAA, 0x55, 1 },
                { { 4, 10 }, { 5, 20 }, { 6, MAX_K } },
        },
@@ -577,7 +585,7 @@ static struct bpf_test tests[] = {
                        { 0x06,  0,  0, 0x0000ffff },
                        { 0x06,  0,  0, 0x00000000 },
                },
-               SKB,
+               CLASSIC,
                /* 3c:07:54:43:e5:76 > 10:bf:48:d6:43:d6, ethertype IPv4(0x0800)
                 * length 114: 10.1.1.149.49700 > 10.1.2.10.22: Flags [P.],
                 * seq 1305692979:1305693027, ack 3650467037, win 65535,
@@ -635,7 +643,7 @@ static struct bpf_test tests[] = {
                        { 0x06,  0,  0, 0x0000ffff },
                        { 0x06,  0,  0, 0x00000000 },
                },
-               SKB,
+               CLASSIC,
                { 0x10, 0xbf, 0x48, 0xd6, 0x43, 0xd6,
                  0x3c, 0x07, 0x54, 0x43, 0xe5, 0x76,
                  0x08, 0x00,
@@ -654,8 +662,8 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_MISC | BPF_TXA, 0),
                        BPF_STMT(BPF_RET | BPF_A, 0)
                },
-               SKB,
-               {},
+               CLASSIC,
+               { },
                { {1, 0}, {2, 0} },
        },
        {
@@ -670,7 +678,7 @@ static struct bpf_test tests[] = {
                        BPF_ALU64_REG(BPF_MOV, R0, R1),
                        BPF_EXIT_INSN(),
                },
-               SKB_INT,
+               INTERNAL,
                { },
                { { 0, 0xfffffffd } }
        },
@@ -686,7 +694,7 @@ static struct bpf_test tests[] = {
                        BPF_ALU64_IMM(BPF_MOV, R0, 1),
                        BPF_EXIT_INSN(),
                },
-               SKB_INT,
+               INTERNAL,
                { },
                { { 0, 1 } }
        },
@@ -703,7 +711,7 @@ static struct bpf_test tests[] = {
                        BPF_ALU32_IMM(BPF_MOV, R0, 1),
                        BPF_EXIT_INSN(),
                },
-               SKB_INT,
+               INTERNAL,
                { },
                { { 0, 1 } }
        },
@@ -720,7 +728,7 @@ static struct bpf_test tests[] = {
                        BPF_ALU32_IMM(BPF_MOV, R0, 1),
                        BPF_EXIT_INSN(),
                },
-               SKB_INT,
+               INTERNAL,
                { },
                { { 0, 1 } }
        },
@@ -882,7 +890,7 @@ static struct bpf_test tests[] = {
                        BPF_ALU64_REG(BPF_MOV, R0, R9),
                        BPF_EXIT_INSN(),
                },
-               SKB_INT,
+               INTERNAL,
                { },
                { { 0, 2957380 } }
        },
@@ -1028,7 +1036,7 @@ static struct bpf_test tests[] = {
                        BPF_ALU32_REG(BPF_MOV, R0, R9),
                        BPF_EXIT_INSN(),
                },
-               SKB_INT,
+               INTERNAL,
                { },
                { { 0, 2957380 } }
        },
@@ -1161,7 +1169,7 @@ static struct bpf_test tests[] = {
                        BPF_ALU64_REG(BPF_SUB, R0, R9),
                        BPF_EXIT_INSN(),
                },
-               SKB_INT,
+               INTERNAL,
                { },
                { { 0, 11 } }
        },
@@ -1227,7 +1235,7 @@ static struct bpf_test tests[] = {
                        BPF_ALU64_IMM(BPF_MOV, R0, 1),
                        BPF_EXIT_INSN(),
                },
-               SKB_INT,
+               INTERNAL,
                { },
                { { 0, 1 } }
        },
@@ -1289,7 +1297,7 @@ static struct bpf_test tests[] = {
                        BPF_ALU64_REG(BPF_MOV, R0, R2),
                        BPF_EXIT_INSN(),
                },
-               SKB_INT,
+               INTERNAL,
                { },
                { { 0, 0x35d97ef2 } }
        },
@@ -1309,7 +1317,7 @@ static struct bpf_test tests[] = {
                        BPF_ALU64_IMM(BPF_MOV, R0, -1),
                        BPF_EXIT_INSN(),
                },
-               SKB_INT,
+               INTERNAL,
                { },
                { { 0, -1 } }
        },
@@ -1326,7 +1334,7 @@ static struct bpf_test tests[] = {
                        BPF_LD_IND(BPF_B, R8, -70),
                        BPF_EXIT_INSN(),
                },
-               SKB_INT,
+               INTERNAL,
                { 10, 20, 30, 40, 50 },
                { { 4, 0 }, { 5, 10 } }
        },
@@ -1339,7 +1347,7 @@ static struct bpf_test tests[] = {
                        BPF_ALU32_REG(BPF_DIV, R0, R7),
                        BPF_EXIT_INSN(),
                },
-               SKB_INT,
+               INTERNAL,
                { 10, 20, 30, 40, 50 },
                { { 3, 0 }, { 4, 0 } }
        },
@@ -1348,7 +1356,7 @@ static struct bpf_test tests[] = {
                .u.insns = {
                        BPF_STMT(BPF_LD | BPF_IMM, 1),
                },
-               EXPECTED_FAIL,
+               CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL,
                { },
                { }
        },
@@ -1358,7 +1366,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_ALU | BPF_DIV | BPF_K, 0),
                        BPF_STMT(BPF_RET | BPF_K, 0)
                },
-               EXPECTED_FAIL,
+               CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL,
                { },
                { }
        },
@@ -1369,7 +1377,7 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_LDX | BPF_W | BPF_ABS, 0),
                        BPF_STMT(BPF_RET | BPF_K, 0)
                },
-               EXPECTED_FAIL,
+               CLASSIC | FLAG_EXPECTED_FAIL,
                { },
                { }
        },
@@ -1379,26 +1387,15 @@ static struct bpf_test tests[] = {
                        BPF_STMT(BPF_STX, 16),
                        BPF_STMT(BPF_RET | BPF_K, 0)
                },
-               EXPECTED_FAIL,
+               CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL,
                { },
                { }
        },
 };
 
-static int get_length(struct sock_filter *fp)
-{
-       int len = 0;
-
-       while (fp->code != 0 || fp->k != 0) {
-               fp++;
-               len++;
-       }
-
-       return len;
-}
+static struct net_device dev;
 
-struct net_device dev;
-struct sk_buff *populate_skb(char *buf, int size)
+static struct sk_buff *populate_skb(char *buf, int size)
 {
        struct sk_buff *skb;
 
@@ -1410,6 +1407,8 @@ struct sk_buff *populate_skb(char *buf, int size)
                return NULL;
 
        memcpy(__skb_put(skb, size), buf, size);
+
+       /* Initialize a fake skb with test pattern. */
        skb_reset_mac_header(skb);
        skb->protocol = htons(ETH_P_IP);
        skb->pkt_type = SKB_TYPE;
@@ -1425,43 +1424,149 @@ struct sk_buff *populate_skb(char *buf, int size)
        return skb;
 }
 
-static int run_one(struct sk_filter *fp, struct bpf_test *t)
+static void *generate_test_data(struct bpf_test *test, int sub)
 {
-       u64 start, finish, res, cnt = 100000;
-       int err_cnt = 0, err, i, j;
-       u32 ret = 0;
-       void *data;
+       if (test->aux & FLAG_NO_DATA)
+               return NULL;
 
-       for (i = 0; i < MAX_SUBTESTS; i++) {
-               if (t->test[i].data_size == 0 &&
-                   t->test[i].result == 0)
-                       break;
-               if (t->data_type == SKB ||
-                   t->data_type == SKB_INT) {
-                       data = populate_skb(t->data, t->test[i].data_size);
-                       if (!data)
-                               return -ENOMEM;
-               } else {
-                       data = NULL;
+       /* Test case expects an skb, so populate one. Various
+        * subtests generate skbs of different sizes based on
+        * the same data.
+        */
+       return populate_skb(test->data, test->test[sub].data_size);
+}
+
+static void release_test_data(const struct bpf_test *test, void *data)
+{
+       if (test->aux & FLAG_NO_DATA)
+               return;
+
+       kfree_skb(data);
+}
+
+static int probe_filter_length(struct sock_filter *fp)
+{
+       int len = 0;
+
+       while (fp->code != 0 || fp->k != 0) {
+               fp++;
+               len++;
+       }
+
+       return len;
+}
+
+static struct sk_filter *generate_filter(int which, int *err)
+{
+       struct sk_filter *fp;
+       struct sock_fprog_kern fprog;
+       unsigned int flen = probe_filter_length(tests[which].u.insns);
+       __u8 test_type = tests[which].aux & TEST_TYPE_MASK;
+
+       switch (test_type) {
+       case CLASSIC:
+               fprog.filter = tests[which].u.insns;
+               fprog.len = flen;
+
+               *err = sk_unattached_filter_create(&fp, &fprog);
+               if (tests[which].aux & FLAG_EXPECTED_FAIL) {
+                       if (*err == -EINVAL) {
+                               pr_cont("PASS\n");
+                               /* Verifier rejected filter as expected. */
+                               *err = 0;
+                               return NULL;
+                       } else {
+                               pr_cont("UNEXPECTED_PASS\n");
+                               /* Verifier didn't reject the test that's
+                                * bad enough, just return!
+                                */
+                               *err = -EINVAL;
+                               return NULL;
+                       }
+               }
+               /* We don't expect to fail. */
+               if (*err) {
+                       pr_cont("FAIL to attach err=%d len=%d\n",
+                               *err, fprog.len);
+                       return NULL;
+               }
+               break;
+
+       case INTERNAL:
+               fp = kzalloc(sk_filter_size(flen), GFP_KERNEL);
+               if (fp == NULL) {
+                       pr_cont("UNEXPECTED_FAIL no memory left\n");
+                       *err = -ENOMEM;
+                       return NULL;
                }
 
-               start = ktime_to_us(ktime_get());
-               for (j = 0; j < cnt; j++)
-                       ret = SK_RUN_FILTER(fp, data);
-               finish = ktime_to_us(ktime_get());
+               fp->len = flen;
+               memcpy(fp->insnsi, tests[which].u.insns_int,
+                      fp->len * sizeof(struct sock_filter_int));
 
-               res = (finish - start) * 1000;
-               do_div(res, cnt);
+               sk_filter_select_runtime(fp);
+               break;
+       }
 
-               err = ret != t->test[i].result;
-               if (!err)
-                       pr_cont("%lld ", res);
+       *err = 0;
+       return fp;
+}
 
-               if (t->data_type == SKB || t->data_type == SKB_INT)
-                       kfree_skb(data);
+static void release_filter(struct sk_filter *fp, int which)
+{
+       __u8 test_type = tests[which].aux & TEST_TYPE_MASK;
 
-               if (err) {
-                       pr_cont("ret %d != %d ", ret, t->test[i].result);
+       switch (test_type) {
+       case CLASSIC:
+               sk_unattached_filter_destroy(fp);
+               break;
+       case INTERNAL:
+               sk_filter_free(fp);
+               break;
+       }
+}
+
+static int __run_one(const struct sk_filter *fp, const void *data,
+                    int runs, u64 *duration)
+{
+       u64 start, finish;
+       int ret, i;
+
+       start = ktime_to_us(ktime_get());
+
+       for (i = 0; i < runs; i++)
+               ret = SK_RUN_FILTER(fp, data);
+
+       finish = ktime_to_us(ktime_get());
+
+       *duration = (finish - start) * 1000ULL;
+       do_div(*duration, runs);
+
+       return ret;
+}
+
+static int run_one(const struct sk_filter *fp, struct bpf_test *test)
+{
+       int err_cnt = 0, i, runs = MAX_TESTRUNS;
+
+       for (i = 0; i < MAX_SUBTESTS; i++) {
+               void *data;
+               u64 duration;
+               u32 ret;
+
+               if (test->test[i].data_size == 0 &&
+                   test->test[i].result == 0)
+                       break;
+
+               data = generate_test_data(test, i);
+               ret = __run_one(fp, data, runs, &duration);
+               release_test_data(test, data);
+
+               if (ret == test->test[i].result) {
+                       pr_cont("%lld ", duration);
+               } else {
+                       pr_cont("ret %d != %d ", ret,
+                               test->test[i].result);
                        err_cnt++;
                }
        }
@@ -1471,65 +1576,37 @@ static int run_one(struct sk_filter *fp, struct bpf_test *t)
 
 static __init int test_bpf(void)
 {
-       struct sk_filter *fp, *fp_ext = NULL;
-       struct sock_fprog_kern fprog;
-       int err, i, err_cnt = 0;
+       int i, err_cnt = 0, pass_cnt = 0;
 
        for (i = 0; i < ARRAY_SIZE(tests); i++) {
-               pr_info("#%d %s ", i, tests[i].descr);
+               struct sk_filter *fp;
+               int err;
 
-               fprog.filter = tests[i].u.insns;
-               fprog.len = get_length(fprog.filter);
+               pr_info("#%d %s ", i, tests[i].descr);
 
-               if (tests[i].data_type == SKB_INT) {
-                       fp_ext = kzalloc(4096, GFP_KERNEL);
-                       if (!fp_ext)
-                               return -ENOMEM;
-                       fp = fp_ext;
-                       memcpy(fp_ext->insns, tests[i].u.insns_int,
-                              fprog.len * 8);
-                       fp->len = fprog.len;
-                       sk_filter_select_runtime(fp);
-               } else {
-                       err = sk_unattached_filter_create(&fp, &fprog);
-                       if (tests[i].data_type == EXPECTED_FAIL) {
-                               if (err == -EINVAL) {
-                                       pr_cont("PASS\n");
-                                       continue;
-                               } else {
-                                       pr_cont("UNEXPECTED_PASS\n");
-                                       /* verifier didn't reject the test
-                                        * that's bad enough, just return
-                                        */
-                                       return -EINVAL;
-                               }
-                       }
-                       if (err) {
-                               pr_cont("FAIL to attach err=%d len=%d\n",
-                                       err, fprog.len);
-                               return err;
+               fp = generate_filter(i, &err);
+               if (fp == NULL) {
+                       if (err == 0) {
+                               pass_cnt++;
+                               continue;
                        }
-               }
 
+                       return err;
+               }
                err = run_one(fp, &tests[i]);
-
-               if (tests[i].data_type != SKB_INT)
-                       sk_unattached_filter_destroy(fp);
-               else
-                       sk_filter_free(fp);
+               release_filter(fp, i);
 
                if (err) {
-                       pr_cont("FAIL %d\n", err);
+                       pr_cont("FAIL (%d times)\n", err);
                        err_cnt++;
                } else {
                        pr_cont("PASS\n");
+                       pass_cnt++;
                }
        }
 
-       if (err_cnt)
-               return -EINVAL;
-       else
-               return 0;
+       pr_info("Summary: %d PASSED, %d FAILED\n", pass_cnt, err_cnt);
+       return err_cnt ? -EINVAL : 0;
 }
 
 static int __init test_bpf_init(void)
@@ -1543,4 +1620,5 @@ static void __exit test_bpf_exit(void)
 
 module_init(test_bpf_init);
 module_exit(test_bpf_exit);
+
 MODULE_LICENSE("GPL");