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:
commit
3c62181840
711
lib/test_bpf.c
711
lib/test_bpf.c
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue