diff options
author | Willem de Bruijn <willemb@google.com> | 2015-08-14 22:31:36 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-08-17 17:22:48 -0400 |
commit | 95e22792fa5460e579a69171777ff79d8725be29 (patch) | |
tree | 374142e4d685e7a97d8a4160ccab2247dfa14536 /tools/testing/selftests/net | |
parent | f2e520956a1ab636698f8160194c9b8ac0989aab (diff) |
selftests/net: test classic bpf fanout mode
Test PACKET_FANOUT_CBPF by inserting a cBPF program that selects a
socket by payload. Requires modifying the test program to send
packets with multiple payloads.
Also fix a bug in testing the return value of mmap()
Signed-off-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'tools/testing/selftests/net')
-rw-r--r-- | tools/testing/selftests/net/psock_fanout.c | 16 | ||||
-rw-r--r-- | tools/testing/selftests/net/psock_lib.h | 29 |
2 files changed, 33 insertions, 12 deletions
diff --git a/tools/testing/selftests/net/psock_fanout.c b/tools/testing/selftests/net/psock_fanout.c index 08c2a36ef7a9..baf46a20e1b3 100644 --- a/tools/testing/selftests/net/psock_fanout.c +++ b/tools/testing/selftests/net/psock_fanout.c | |||
@@ -19,6 +19,7 @@ | |||
19 | * - PACKET_FANOUT_LB | 19 | * - PACKET_FANOUT_LB |
20 | * - PACKET_FANOUT_CPU | 20 | * - PACKET_FANOUT_CPU |
21 | * - PACKET_FANOUT_ROLLOVER | 21 | * - PACKET_FANOUT_ROLLOVER |
22 | * - PACKET_FANOUT_CBPF | ||
22 | * | 23 | * |
23 | * Todo: | 24 | * Todo: |
24 | * - functionality: PACKET_FANOUT_FLAG_DEFRAG | 25 | * - functionality: PACKET_FANOUT_FLAG_DEFRAG |
@@ -115,8 +116,8 @@ static char *sock_fanout_open_ring(int fd) | |||
115 | 116 | ||
116 | ring = mmap(0, req.tp_block_size * req.tp_block_nr, | 117 | ring = mmap(0, req.tp_block_size * req.tp_block_nr, |
117 | PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); | 118 | PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); |
118 | if (!ring) { | 119 | if (ring == MAP_FAILED) { |
119 | fprintf(stderr, "packetsock ring mmap\n"); | 120 | perror("packetsock ring mmap"); |
120 | exit(1); | 121 | exit(1); |
121 | } | 122 | } |
122 | 123 | ||
@@ -209,6 +210,7 @@ static int test_datapath(uint16_t typeflags, int port_off, | |||
209 | { | 210 | { |
210 | const int expect0[] = { 0, 0 }; | 211 | const int expect0[] = { 0, 0 }; |
211 | char *rings[2]; | 212 | char *rings[2]; |
213 | uint8_t type = typeflags & 0xFF; | ||
212 | int fds[2], fds_udp[2][2], ret; | 214 | int fds[2], fds_udp[2][2], ret; |
213 | 215 | ||
214 | fprintf(stderr, "test: datapath 0x%hx\n", typeflags); | 216 | fprintf(stderr, "test: datapath 0x%hx\n", typeflags); |
@@ -219,6 +221,9 @@ static int test_datapath(uint16_t typeflags, int port_off, | |||
219 | fprintf(stderr, "ERROR: failed open\n"); | 221 | fprintf(stderr, "ERROR: failed open\n"); |
220 | exit(1); | 222 | exit(1); |
221 | } | 223 | } |
224 | if (type == PACKET_FANOUT_CBPF) | ||
225 | sock_setfilter(fds[0], SOL_PACKET, PACKET_FANOUT_DATA); | ||
226 | |||
222 | rings[0] = sock_fanout_open_ring(fds[0]); | 227 | rings[0] = sock_fanout_open_ring(fds[0]); |
223 | rings[1] = sock_fanout_open_ring(fds[1]); | 228 | rings[1] = sock_fanout_open_ring(fds[1]); |
224 | pair_udp_open(fds_udp[0], PORT_BASE); | 229 | pair_udp_open(fds_udp[0], PORT_BASE); |
@@ -227,11 +232,11 @@ static int test_datapath(uint16_t typeflags, int port_off, | |||
227 | 232 | ||
228 | /* Send data, but not enough to overflow a queue */ | 233 | /* Send data, but not enough to overflow a queue */ |
229 | pair_udp_send(fds_udp[0], 15); | 234 | pair_udp_send(fds_udp[0], 15); |
230 | pair_udp_send(fds_udp[1], 5); | 235 | pair_udp_send_char(fds_udp[1], 5, DATA_CHAR_1); |
231 | ret = sock_fanout_read(fds, rings, expect1); | 236 | ret = sock_fanout_read(fds, rings, expect1); |
232 | 237 | ||
233 | /* Send more data, overflow the queue */ | 238 | /* Send more data, overflow the queue */ |
234 | pair_udp_send(fds_udp[0], 15); | 239 | pair_udp_send_char(fds_udp[0], 15, DATA_CHAR_1); |
235 | /* TODO: ensure consistent order between expect1 and expect2 */ | 240 | /* TODO: ensure consistent order between expect1 and expect2 */ |
236 | ret |= sock_fanout_read(fds, rings, expect2); | 241 | ret |= sock_fanout_read(fds, rings, expect2); |
237 | 242 | ||
@@ -275,6 +280,7 @@ int main(int argc, char **argv) | |||
275 | const int expect_rb[2][2] = { { 15, 5 }, { 20, 15 } }; | 280 | const int expect_rb[2][2] = { { 15, 5 }, { 20, 15 } }; |
276 | const int expect_cpu0[2][2] = { { 20, 0 }, { 20, 0 } }; | 281 | const int expect_cpu0[2][2] = { { 20, 0 }, { 20, 0 } }; |
277 | const int expect_cpu1[2][2] = { { 0, 20 }, { 0, 20 } }; | 282 | const int expect_cpu1[2][2] = { { 0, 20 }, { 0, 20 } }; |
283 | const int expect_bpf[2][2] = { { 15, 5 }, { 15, 20 } }; | ||
278 | int port_off = 2, tries = 5, ret; | 284 | int port_off = 2, tries = 5, ret; |
279 | 285 | ||
280 | test_control_single(); | 286 | test_control_single(); |
@@ -295,6 +301,8 @@ int main(int argc, char **argv) | |||
295 | port_off, expect_lb[0], expect_lb[1]); | 301 | port_off, expect_lb[0], expect_lb[1]); |
296 | ret |= test_datapath(PACKET_FANOUT_ROLLOVER, | 302 | ret |= test_datapath(PACKET_FANOUT_ROLLOVER, |
297 | port_off, expect_rb[0], expect_rb[1]); | 303 | port_off, expect_rb[0], expect_rb[1]); |
304 | ret |= test_datapath(PACKET_FANOUT_CBPF, | ||
305 | port_off, expect_bpf[0], expect_bpf[1]); | ||
298 | 306 | ||
299 | set_cpuaffinity(0); | 307 | set_cpuaffinity(0); |
300 | ret |= test_datapath(PACKET_FANOUT_CPU, port_off, | 308 | ret |= test_datapath(PACKET_FANOUT_CPU, port_off, |
diff --git a/tools/testing/selftests/net/psock_lib.h b/tools/testing/selftests/net/psock_lib.h index 37da54ac85a9..24bc7ec1be7d 100644 --- a/tools/testing/selftests/net/psock_lib.h +++ b/tools/testing/selftests/net/psock_lib.h | |||
@@ -30,6 +30,7 @@ | |||
30 | 30 | ||
31 | #define DATA_LEN 100 | 31 | #define DATA_LEN 100 |
32 | #define DATA_CHAR 'a' | 32 | #define DATA_CHAR 'a' |
33 | #define DATA_CHAR_1 'b' | ||
33 | 34 | ||
34 | #define PORT_BASE 8000 | 35 | #define PORT_BASE 8000 |
35 | 36 | ||
@@ -37,29 +38,36 @@ | |||
37 | # define __maybe_unused __attribute__ ((__unused__)) | 38 | # define __maybe_unused __attribute__ ((__unused__)) |
38 | #endif | 39 | #endif |
39 | 40 | ||
40 | static __maybe_unused void pair_udp_setfilter(int fd) | 41 | static __maybe_unused void sock_setfilter(int fd, int lvl, int optnum) |
41 | { | 42 | { |
42 | struct sock_filter bpf_filter[] = { | 43 | struct sock_filter bpf_filter[] = { |
43 | { 0x80, 0, 0, 0x00000000 }, /* LD pktlen */ | 44 | { 0x80, 0, 0, 0x00000000 }, /* LD pktlen */ |
44 | { 0x35, 0, 5, DATA_LEN }, /* JGE DATA_LEN [f goto nomatch]*/ | 45 | { 0x35, 0, 4, DATA_LEN }, /* JGE DATA_LEN [f goto nomatch]*/ |
45 | { 0x30, 0, 0, 0x00000050 }, /* LD ip[80] */ | 46 | { 0x30, 0, 0, 0x00000050 }, /* LD ip[80] */ |
46 | { 0x15, 0, 3, DATA_CHAR }, /* JEQ DATA_CHAR [f goto nomatch]*/ | 47 | { 0x15, 1, 0, DATA_CHAR }, /* JEQ DATA_CHAR [t goto match]*/ |
47 | { 0x30, 0, 0, 0x00000051 }, /* LD ip[81] */ | 48 | { 0x15, 0, 1, DATA_CHAR_1}, /* JEQ DATA_CHAR_1 [t goto match]*/ |
48 | { 0x15, 0, 1, DATA_CHAR }, /* JEQ DATA_CHAR [f goto nomatch]*/ | ||
49 | { 0x06, 0, 0, 0x00000060 }, /* RET match */ | 49 | { 0x06, 0, 0, 0x00000060 }, /* RET match */ |
50 | { 0x06, 0, 0, 0x00000000 }, /* RET no match */ | 50 | { 0x06, 0, 0, 0x00000000 }, /* RET no match */ |
51 | }; | 51 | }; |
52 | struct sock_fprog bpf_prog; | 52 | struct sock_fprog bpf_prog; |
53 | 53 | ||
54 | if (lvl == SOL_PACKET && optnum == PACKET_FANOUT_DATA) | ||
55 | bpf_filter[5].code = 0x16; /* RET A */ | ||
56 | |||
54 | bpf_prog.filter = bpf_filter; | 57 | bpf_prog.filter = bpf_filter; |
55 | bpf_prog.len = sizeof(bpf_filter) / sizeof(struct sock_filter); | 58 | bpf_prog.len = sizeof(bpf_filter) / sizeof(struct sock_filter); |
56 | if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf_prog, | 59 | if (setsockopt(fd, lvl, optnum, &bpf_prog, |
57 | sizeof(bpf_prog))) { | 60 | sizeof(bpf_prog))) { |
58 | perror("setsockopt SO_ATTACH_FILTER"); | 61 | perror("setsockopt SO_ATTACH_FILTER"); |
59 | exit(1); | 62 | exit(1); |
60 | } | 63 | } |
61 | } | 64 | } |
62 | 65 | ||
66 | static __maybe_unused void pair_udp_setfilter(int fd) | ||
67 | { | ||
68 | sock_setfilter(fd, SOL_SOCKET, SO_ATTACH_FILTER); | ||
69 | } | ||
70 | |||
63 | static __maybe_unused void pair_udp_open(int fds[], uint16_t port) | 71 | static __maybe_unused void pair_udp_open(int fds[], uint16_t port) |
64 | { | 72 | { |
65 | struct sockaddr_in saddr, daddr; | 73 | struct sockaddr_in saddr, daddr; |
@@ -96,11 +104,11 @@ static __maybe_unused void pair_udp_open(int fds[], uint16_t port) | |||
96 | } | 104 | } |
97 | } | 105 | } |
98 | 106 | ||
99 | static __maybe_unused void pair_udp_send(int fds[], int num) | 107 | static __maybe_unused void pair_udp_send_char(int fds[], int num, char payload) |
100 | { | 108 | { |
101 | char buf[DATA_LEN], rbuf[DATA_LEN]; | 109 | char buf[DATA_LEN], rbuf[DATA_LEN]; |
102 | 110 | ||
103 | memset(buf, DATA_CHAR, sizeof(buf)); | 111 | memset(buf, payload, sizeof(buf)); |
104 | while (num--) { | 112 | while (num--) { |
105 | /* Should really handle EINTR and EAGAIN */ | 113 | /* Should really handle EINTR and EAGAIN */ |
106 | if (write(fds[0], buf, sizeof(buf)) != sizeof(buf)) { | 114 | if (write(fds[0], buf, sizeof(buf)) != sizeof(buf)) { |
@@ -118,6 +126,11 @@ static __maybe_unused void pair_udp_send(int fds[], int num) | |||
118 | } | 126 | } |
119 | } | 127 | } |
120 | 128 | ||
129 | static __maybe_unused void pair_udp_send(int fds[], int num) | ||
130 | { | ||
131 | return pair_udp_send_char(fds, num, DATA_CHAR); | ||
132 | } | ||
133 | |||
121 | static __maybe_unused void pair_udp_close(int fds[]) | 134 | static __maybe_unused void pair_udp_close(int fds[]) |
122 | { | 135 | { |
123 | close(fds[0]); | 136 | close(fds[0]); |