Merge branch 'test-bpf-next'

Nicolas Schichan says:

====================
test_bpf improvements

Please find below the patch series with my latest changes to test_bpf.

The first patch checks for unexpected NULL generated skbs before
running the filter.

The second patch adds the possibility for tests to generate fragmented
skbs.

The third patch tests LD_ABS and LD_IND on fragmented skbs.

The fourth patch adds the possibility to restrict the tests being run
by specifying the name/id/range of the test(s) to run via module
parameters.

The fifth patch tests LD_ABS and LD_IND on non fragmented skbs with
various sizes and alignments.

The sixth and final patch checks that the interpreter or JIT correctly
resets A and X to 0.

This serie is against today's net-next tree.

Changes in V2:

* move declaration of 'ptr' in if() block in patch 2/6.

* fix various typos in patch 4/6

* rework default init of test_range array and cleanup exclude_test()
  return condition in patch 4/6.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2015-08-06 22:02:32 -07:00
commit 3c62181840
1 changed files with 710 additions and 1 deletions

View File

@ -23,6 +23,7 @@
#include <linux/netdevice.h>
#include <linux/if_vlan.h>
#include <linux/random.h>
#include <linux/highmem.h>
/* General test specific settings */
#define MAX_SUBTESTS 3
@ -56,6 +57,7 @@
/* Flags that can be passed to test cases */
#define FLAG_NO_DATA BIT(0)
#define FLAG_EXPECTED_FAIL BIT(1)
#define FLAG_SKB_FRAG BIT(2)
enum {
CLASSIC = BIT(6), /* Old BPF instructions only. */
@ -81,6 +83,7 @@ struct bpf_test {
__u32 result;
} test[MAX_SUBTESTS];
int (*fill_helper)(struct bpf_test *self);
__u8 frag_data[MAX_DATA];
};
/* Large test cases need separate allocation and fill handler. */
@ -4490,6 +4493,602 @@ static struct bpf_test tests[] = {
{ { 1, 0xbef } },
.fill_helper = bpf_fill_ld_abs_vlan_push_pop,
},
/*
* LD_IND / LD_ABS on fragmented SKBs
*/
{
"LD_IND byte frag",
.u.insns = {
BPF_STMT(BPF_LDX | BPF_IMM, 0x40),
BPF_STMT(BPF_LD | BPF_IND | BPF_B, 0x0),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC | FLAG_SKB_FRAG,
{ },
{ {0x40, 0x42} },
.frag_data = {
0x42, 0x00, 0x00, 0x00,
0x43, 0x44, 0x00, 0x00,
0x21, 0x07, 0x19, 0x83,
},
},
{
"LD_IND halfword frag",
.u.insns = {
BPF_STMT(BPF_LDX | BPF_IMM, 0x40),
BPF_STMT(BPF_LD | BPF_IND | BPF_H, 0x4),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC | FLAG_SKB_FRAG,
{ },
{ {0x40, 0x4344} },
.frag_data = {
0x42, 0x00, 0x00, 0x00,
0x43, 0x44, 0x00, 0x00,
0x21, 0x07, 0x19, 0x83,
},
},
{
"LD_IND word frag",
.u.insns = {
BPF_STMT(BPF_LDX | BPF_IMM, 0x40),
BPF_STMT(BPF_LD | BPF_IND | BPF_W, 0x8),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC | FLAG_SKB_FRAG,
{ },
{ {0x40, 0x21071983} },
.frag_data = {
0x42, 0x00, 0x00, 0x00,
0x43, 0x44, 0x00, 0x00,
0x21, 0x07, 0x19, 0x83,
},
},
{
"LD_IND halfword mixed head/frag",
.u.insns = {
BPF_STMT(BPF_LDX | BPF_IMM, 0x40),
BPF_STMT(BPF_LD | BPF_IND | BPF_H, -0x1),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC | FLAG_SKB_FRAG,
{ [0x3e] = 0x25, [0x3f] = 0x05, },
{ {0x40, 0x0519} },
.frag_data = { 0x19, 0x82 },
},
{
"LD_IND word mixed head/frag",
.u.insns = {
BPF_STMT(BPF_LDX | BPF_IMM, 0x40),
BPF_STMT(BPF_LD | BPF_IND | BPF_W, -0x2),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC | FLAG_SKB_FRAG,
{ [0x3e] = 0x25, [0x3f] = 0x05, },
{ {0x40, 0x25051982} },
.frag_data = { 0x19, 0x82 },
},
{
"LD_ABS byte frag",
.u.insns = {
BPF_STMT(BPF_LD | BPF_ABS | BPF_B, 0x40),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC | FLAG_SKB_FRAG,
{ },
{ {0x40, 0x42} },
.frag_data = {
0x42, 0x00, 0x00, 0x00,
0x43, 0x44, 0x00, 0x00,
0x21, 0x07, 0x19, 0x83,
},
},
{
"LD_ABS halfword frag",
.u.insns = {
BPF_STMT(BPF_LD | BPF_ABS | BPF_H, 0x44),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC | FLAG_SKB_FRAG,
{ },
{ {0x40, 0x4344} },
.frag_data = {
0x42, 0x00, 0x00, 0x00,
0x43, 0x44, 0x00, 0x00,
0x21, 0x07, 0x19, 0x83,
},
},
{
"LD_ABS word frag",
.u.insns = {
BPF_STMT(BPF_LD | BPF_ABS | BPF_W, 0x48),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC | FLAG_SKB_FRAG,
{ },
{ {0x40, 0x21071983} },
.frag_data = {
0x42, 0x00, 0x00, 0x00,
0x43, 0x44, 0x00, 0x00,
0x21, 0x07, 0x19, 0x83,
},
},
{
"LD_ABS halfword mixed head/frag",
.u.insns = {
BPF_STMT(BPF_LD | BPF_ABS | BPF_H, 0x3f),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC | FLAG_SKB_FRAG,
{ [0x3e] = 0x25, [0x3f] = 0x05, },
{ {0x40, 0x0519} },
.frag_data = { 0x19, 0x82 },
},
{
"LD_ABS word mixed head/frag",
.u.insns = {
BPF_STMT(BPF_LD | BPF_ABS | BPF_W, 0x3e),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC | FLAG_SKB_FRAG,
{ [0x3e] = 0x25, [0x3f] = 0x05, },
{ {0x40, 0x25051982} },
.frag_data = { 0x19, 0x82 },
},
/*
* LD_IND / LD_ABS on non fragmented SKBs
*/
{
/*
* this tests that the JIT/interpreter correctly resets X
* before using it in an LD_IND instruction.
*/
"LD_IND byte default X",
.u.insns = {
BPF_STMT(BPF_LD | BPF_IND | BPF_B, 0x1),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC,
{ [0x1] = 0x42 },
{ {0x40, 0x42 } },
},
{
"LD_IND byte positive offset",
.u.insns = {
BPF_STMT(BPF_LDX | BPF_IMM, 0x3e),
BPF_STMT(BPF_LD | BPF_IND | BPF_B, 0x1),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC,
{ [0x3c] = 0x25, [0x3d] = 0x05, [0x3e] = 0x19, [0x3f] = 0x82 },
{ {0x40, 0x82 } },
},
{
"LD_IND byte negative offset",
.u.insns = {
BPF_STMT(BPF_LDX | BPF_IMM, 0x3e),
BPF_STMT(BPF_LD | BPF_IND | BPF_B, -0x1),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC,
{ [0x3c] = 0x25, [0x3d] = 0x05, [0x3e] = 0x19, [0x3f] = 0x82 },
{ {0x40, 0x05 } },
},
{
"LD_IND halfword positive offset",
.u.insns = {
BPF_STMT(BPF_LDX | BPF_IMM, 0x20),
BPF_STMT(BPF_LD | BPF_IND | BPF_H, 0x2),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC,
{
[0x1c] = 0xaa, [0x1d] = 0x55,
[0x1e] = 0xbb, [0x1f] = 0x66,
[0x20] = 0xcc, [0x21] = 0x77,
[0x22] = 0xdd, [0x23] = 0x88,
},
{ {0x40, 0xdd88 } },
},
{
"LD_IND halfword negative offset",
.u.insns = {
BPF_STMT(BPF_LDX | BPF_IMM, 0x20),
BPF_STMT(BPF_LD | BPF_IND | BPF_H, -0x2),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC,
{
[0x1c] = 0xaa, [0x1d] = 0x55,
[0x1e] = 0xbb, [0x1f] = 0x66,
[0x20] = 0xcc, [0x21] = 0x77,
[0x22] = 0xdd, [0x23] = 0x88,
},
{ {0x40, 0xbb66 } },
},
{
"LD_IND halfword unaligned",
.u.insns = {
BPF_STMT(BPF_LDX | BPF_IMM, 0x20),
BPF_STMT(BPF_LD | BPF_IND | BPF_H, -0x1),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC,
{
[0x1c] = 0xaa, [0x1d] = 0x55,
[0x1e] = 0xbb, [0x1f] = 0x66,
[0x20] = 0xcc, [0x21] = 0x77,
[0x22] = 0xdd, [0x23] = 0x88,
},
{ {0x40, 0x66cc } },
},
{
"LD_IND word positive offset",
.u.insns = {
BPF_STMT(BPF_LDX | BPF_IMM, 0x20),
BPF_STMT(BPF_LD | BPF_IND | BPF_W, 0x4),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC,
{
[0x1c] = 0xaa, [0x1d] = 0x55,
[0x1e] = 0xbb, [0x1f] = 0x66,
[0x20] = 0xcc, [0x21] = 0x77,
[0x22] = 0xdd, [0x23] = 0x88,
[0x24] = 0xee, [0x25] = 0x99,
[0x26] = 0xff, [0x27] = 0xaa,
},
{ {0x40, 0xee99ffaa } },
},
{
"LD_IND word negative offset",
.u.insns = {
BPF_STMT(BPF_LDX | BPF_IMM, 0x20),
BPF_STMT(BPF_LD | BPF_IND | BPF_W, -0x4),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC,
{
[0x1c] = 0xaa, [0x1d] = 0x55,
[0x1e] = 0xbb, [0x1f] = 0x66,
[0x20] = 0xcc, [0x21] = 0x77,
[0x22] = 0xdd, [0x23] = 0x88,
[0x24] = 0xee, [0x25] = 0x99,
[0x26] = 0xff, [0x27] = 0xaa,
},
{ {0x40, 0xaa55bb66 } },
},
{
"LD_IND word unaligned (addr & 3 == 2)",
.u.insns = {
BPF_STMT(BPF_LDX | BPF_IMM, 0x20),
BPF_STMT(BPF_LD | BPF_IND | BPF_W, -0x2),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC,
{
[0x1c] = 0xaa, [0x1d] = 0x55,
[0x1e] = 0xbb, [0x1f] = 0x66,
[0x20] = 0xcc, [0x21] = 0x77,
[0x22] = 0xdd, [0x23] = 0x88,
[0x24] = 0xee, [0x25] = 0x99,
[0x26] = 0xff, [0x27] = 0xaa,
},
{ {0x40, 0xbb66cc77 } },
},
{
"LD_IND word unaligned (addr & 3 == 1)",
.u.insns = {
BPF_STMT(BPF_LDX | BPF_IMM, 0x20),
BPF_STMT(BPF_LD | BPF_IND | BPF_W, -0x3),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC,
{
[0x1c] = 0xaa, [0x1d] = 0x55,
[0x1e] = 0xbb, [0x1f] = 0x66,
[0x20] = 0xcc, [0x21] = 0x77,
[0x22] = 0xdd, [0x23] = 0x88,
[0x24] = 0xee, [0x25] = 0x99,
[0x26] = 0xff, [0x27] = 0xaa,
},
{ {0x40, 0x55bb66cc } },
},
{
"LD_IND word unaligned (addr & 3 == 3)",
.u.insns = {
BPF_STMT(BPF_LDX | BPF_IMM, 0x20),
BPF_STMT(BPF_LD | BPF_IND | BPF_W, -0x1),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC,
{
[0x1c] = 0xaa, [0x1d] = 0x55,
[0x1e] = 0xbb, [0x1f] = 0x66,
[0x20] = 0xcc, [0x21] = 0x77,
[0x22] = 0xdd, [0x23] = 0x88,
[0x24] = 0xee, [0x25] = 0x99,
[0x26] = 0xff, [0x27] = 0xaa,
},
{ {0x40, 0x66cc77dd } },
},
{
"LD_ABS byte",
.u.insns = {
BPF_STMT(BPF_LD | BPF_ABS | BPF_B, 0x20),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC,
{
[0x1c] = 0xaa, [0x1d] = 0x55,
[0x1e] = 0xbb, [0x1f] = 0x66,
[0x20] = 0xcc, [0x21] = 0x77,
[0x22] = 0xdd, [0x23] = 0x88,
[0x24] = 0xee, [0x25] = 0x99,
[0x26] = 0xff, [0x27] = 0xaa,
},
{ {0x40, 0xcc } },
},
{
"LD_ABS halfword",
.u.insns = {
BPF_STMT(BPF_LD | BPF_ABS | BPF_H, 0x22),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC,
{
[0x1c] = 0xaa, [0x1d] = 0x55,
[0x1e] = 0xbb, [0x1f] = 0x66,
[0x20] = 0xcc, [0x21] = 0x77,
[0x22] = 0xdd, [0x23] = 0x88,
[0x24] = 0xee, [0x25] = 0x99,
[0x26] = 0xff, [0x27] = 0xaa,
},
{ {0x40, 0xdd88 } },
},
{
"LD_ABS halfword unaligned",
.u.insns = {
BPF_STMT(BPF_LD | BPF_ABS | BPF_H, 0x25),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC,
{
[0x1c] = 0xaa, [0x1d] = 0x55,
[0x1e] = 0xbb, [0x1f] = 0x66,
[0x20] = 0xcc, [0x21] = 0x77,
[0x22] = 0xdd, [0x23] = 0x88,
[0x24] = 0xee, [0x25] = 0x99,
[0x26] = 0xff, [0x27] = 0xaa,
},
{ {0x40, 0x99ff } },
},
{
"LD_ABS word",
.u.insns = {
BPF_STMT(BPF_LD | BPF_ABS | BPF_W, 0x1c),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC,
{
[0x1c] = 0xaa, [0x1d] = 0x55,
[0x1e] = 0xbb, [0x1f] = 0x66,
[0x20] = 0xcc, [0x21] = 0x77,
[0x22] = 0xdd, [0x23] = 0x88,
[0x24] = 0xee, [0x25] = 0x99,
[0x26] = 0xff, [0x27] = 0xaa,
},
{ {0x40, 0xaa55bb66 } },
},
{
"LD_ABS word unaligned (addr & 3 == 2)",
.u.insns = {
BPF_STMT(BPF_LD | BPF_ABS | BPF_W, 0x22),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC,
{
[0x1c] = 0xaa, [0x1d] = 0x55,
[0x1e] = 0xbb, [0x1f] = 0x66,
[0x20] = 0xcc, [0x21] = 0x77,
[0x22] = 0xdd, [0x23] = 0x88,
[0x24] = 0xee, [0x25] = 0x99,
[0x26] = 0xff, [0x27] = 0xaa,
},
{ {0x40, 0xdd88ee99 } },
},
{
"LD_ABS word unaligned (addr & 3 == 1)",
.u.insns = {
BPF_STMT(BPF_LD | BPF_ABS | BPF_W, 0x21),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC,
{
[0x1c] = 0xaa, [0x1d] = 0x55,
[0x1e] = 0xbb, [0x1f] = 0x66,
[0x20] = 0xcc, [0x21] = 0x77,
[0x22] = 0xdd, [0x23] = 0x88,
[0x24] = 0xee, [0x25] = 0x99,
[0x26] = 0xff, [0x27] = 0xaa,
},
{ {0x40, 0x77dd88ee } },
},
{
"LD_ABS word unaligned (addr & 3 == 3)",
.u.insns = {
BPF_STMT(BPF_LD | BPF_ABS | BPF_W, 0x23),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC,
{
[0x1c] = 0xaa, [0x1d] = 0x55,
[0x1e] = 0xbb, [0x1f] = 0x66,
[0x20] = 0xcc, [0x21] = 0x77,
[0x22] = 0xdd, [0x23] = 0x88,
[0x24] = 0xee, [0x25] = 0x99,
[0x26] = 0xff, [0x27] = 0xaa,
},
{ {0x40, 0x88ee99ff } },
},
/*
* verify that the interpreter or JIT correctly sets A and X
* to 0.
*/
{
"ADD default X",
.u.insns = {
/*
* A = 0x42
* A = A + X
* ret A
*/
BPF_STMT(BPF_LD | BPF_IMM, 0x42),
BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC | FLAG_NO_DATA,
{},
{ {0x1, 0x42 } },
},
{
"ADD default A",
.u.insns = {
/*
* A = A + 0x42
* ret A
*/
BPF_STMT(BPF_ALU | BPF_ADD | BPF_K, 0x42),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC | FLAG_NO_DATA,
{},
{ {0x1, 0x42 } },
},
{
"SUB default X",
.u.insns = {
/*
* A = 0x66
* A = A - X
* ret A
*/
BPF_STMT(BPF_LD | BPF_IMM, 0x66),
BPF_STMT(BPF_ALU | BPF_SUB | BPF_X, 0),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC | FLAG_NO_DATA,
{},
{ {0x1, 0x66 } },
},
{
"SUB default A",
.u.insns = {
/*
* A = A - -0x66
* ret A
*/
BPF_STMT(BPF_ALU | BPF_SUB | BPF_K, -0x66),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC | FLAG_NO_DATA,
{},
{ {0x1, 0x66 } },
},
{
"MUL default X",
.u.insns = {
/*
* A = 0x42
* A = A * X
* ret A
*/
BPF_STMT(BPF_LD | BPF_IMM, 0x42),
BPF_STMT(BPF_ALU | BPF_MUL | BPF_X, 0),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC | FLAG_NO_DATA,
{},
{ {0x1, 0x0 } },
},
{
"MUL default A",
.u.insns = {
/*
* A = A * 0x66
* ret A
*/
BPF_STMT(BPF_ALU | BPF_MUL | BPF_K, 0x66),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC | FLAG_NO_DATA,
{},
{ {0x1, 0x0 } },
},
{
"DIV default X",
.u.insns = {
/*
* A = 0x42
* A = A / X ; this halt the filter execution if X is 0
* ret 0x42
*/
BPF_STMT(BPF_LD | BPF_IMM, 0x42),
BPF_STMT(BPF_ALU | BPF_DIV | BPF_X, 0),
BPF_STMT(BPF_RET | BPF_K, 0x42),
},
CLASSIC | FLAG_NO_DATA,
{},
{ {0x1, 0x0 } },
},
{
"DIV default A",
.u.insns = {
/*
* A = A / 1
* ret A
*/
BPF_STMT(BPF_ALU | BPF_DIV | BPF_K, 0x1),
BPF_STMT(BPF_RET | BPF_A, 0x0),
},
CLASSIC | FLAG_NO_DATA,
{},
{ {0x1, 0x0 } },
},
{
"JMP EQ default A",
.u.insns = {
/*
* cmp A, 0x0, 0, 1
* ret 0x42
* ret 0x66
*/
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0, 0, 1),
BPF_STMT(BPF_RET | BPF_K, 0x42),
BPF_STMT(BPF_RET | BPF_K, 0x66),
},
CLASSIC | FLAG_NO_DATA,
{},
{ {0x1, 0x42 } },
},
{
"JMP EQ default X",
.u.insns = {
/*
* A = 0x0
* cmp A, X, 0, 1
* ret 0x42
* ret 0x66
*/
BPF_STMT(BPF_LD | BPF_IMM, 0x0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0x0, 0, 1),
BPF_STMT(BPF_RET | BPF_K, 0x42),
BPF_STMT(BPF_RET | BPF_K, 0x66),
},
CLASSIC | FLAG_NO_DATA,
{},
{ {0x1, 0x42 } },
},
};
static struct net_device dev;
@ -4525,6 +5124,9 @@ static struct sk_buff *populate_skb(char *buf, int size)
static void *generate_test_data(struct bpf_test *test, int sub)
{
struct sk_buff *skb;
struct page *page;
if (test->aux & FLAG_NO_DATA)
return NULL;
@ -4532,7 +5134,38 @@ static void *generate_test_data(struct bpf_test *test, int sub)
* subtests generate skbs of different sizes based on
* the same data.
*/
return populate_skb(test->data, test->test[sub].data_size);
skb = populate_skb(test->data, test->test[sub].data_size);
if (!skb)
return NULL;
if (test->aux & FLAG_SKB_FRAG) {
/*
* when the test requires a fragmented skb, add a
* single fragment to the skb, filled with
* test->frag_data.
*/
void *ptr;
page = alloc_page(GFP_KERNEL);
if (!page)
goto err_kfree_skb;
ptr = kmap(page);
if (!ptr)
goto err_free_page;
memcpy(ptr, test->frag_data, MAX_DATA);
kunmap(page);
skb_add_rx_frag(skb, 0, page, 0, MAX_DATA, MAX_DATA);
}
return skb;
err_free_page:
__free_page(page);
err_kfree_skb:
kfree_skb(skb);
return NULL;
}
static void release_test_data(const struct bpf_test *test, void *data)
@ -4672,6 +5305,11 @@ static int run_one(const struct bpf_prog *fp, struct bpf_test *test)
break;
data = generate_test_data(test, i);
if (!data && !(test->aux & FLAG_NO_DATA)) {
pr_cont("data generation failed ");
err_cnt++;
break;
}
ret = __run_one(fp, data, runs, &duration);
release_test_data(test, data);
@ -4687,10 +5325,73 @@ static int run_one(const struct bpf_prog *fp, struct bpf_test *test)
return err_cnt;
}
static char test_name[64];
module_param_string(test_name, test_name, sizeof(test_name), 0);
static int test_id = -1;
module_param(test_id, int, 0);
static int test_range[2] = { 0, ARRAY_SIZE(tests) - 1 };
module_param_array(test_range, int, NULL, 0);
static __init int find_test_index(const char *test_name)
{
int i;
for (i = 0; i < ARRAY_SIZE(tests); i++) {
if (!strcmp(tests[i].descr, test_name))
return i;
}
return -1;
}
static __init int prepare_bpf_tests(void)
{
int i;
if (test_id >= 0) {
/*
* if a test_id was specified, use test_range to
* cover only that test.
*/
if (test_id >= ARRAY_SIZE(tests)) {
pr_err("test_bpf: invalid test_id specified.\n");
return -EINVAL;
}
test_range[0] = test_id;
test_range[1] = test_id;
} else if (*test_name) {
/*
* if a test_name was specified, find it and setup
* test_range to cover only that test.
*/
int idx = find_test_index(test_name);
if (idx < 0) {
pr_err("test_bpf: no test named '%s' found.\n",
test_name);
return -EINVAL;
}
test_range[0] = idx;
test_range[1] = idx;
} else {
/*
* check that the supplied test_range is valid.
*/
if (test_range[0] >= ARRAY_SIZE(tests) ||
test_range[1] >= ARRAY_SIZE(tests) ||
test_range[0] < 0 || test_range[1] < 0) {
pr_err("test_bpf: test_range is out of bound.\n");
return -EINVAL;
}
if (test_range[1] < test_range[0]) {
pr_err("test_bpf: test_range is ending before it starts.\n");
return -EINVAL;
}
}
for (i = 0; i < ARRAY_SIZE(tests); i++) {
if (tests[i].fill_helper &&
tests[i].fill_helper(&tests[i]) < 0)
@ -4710,6 +5411,11 @@ static __init void destroy_bpf_tests(void)
}
}
static bool exclude_test(int test_id)
{
return test_id < test_range[0] || test_id > test_range[1];
}
static __init int test_bpf(void)
{
int i, err_cnt = 0, pass_cnt = 0;
@ -4719,6 +5425,9 @@ static __init int test_bpf(void)
struct bpf_prog *fp;
int err;
if (exclude_test(i))
continue;
pr_info("#%d %s ", i, tests[i].descr);
fp = generate_filter(i, &err);