Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Willem de Bruijn and committed by
David S. Miller
95e22792 f2e52095

+33 -12
+12 -4
tools/testing/selftests/net/psock_fanout.c
··· 19 19 * - PACKET_FANOUT_LB 20 20 * - PACKET_FANOUT_CPU 21 21 * - PACKET_FANOUT_ROLLOVER 22 + * - PACKET_FANOUT_CBPF 22 23 * 23 24 * Todo: 24 25 * - functionality: PACKET_FANOUT_FLAG_DEFRAG ··· 116 115 117 116 ring = mmap(0, req.tp_block_size * req.tp_block_nr, 118 117 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 119 - if (!ring) { 120 - fprintf(stderr, "packetsock ring mmap\n"); 118 + if (ring == MAP_FAILED) { 119 + perror("packetsock ring mmap"); 121 120 exit(1); 122 121 } 123 122 ··· 210 209 { 211 210 const int expect0[] = { 0, 0 }; 212 211 char *rings[2]; 212 + uint8_t type = typeflags & 0xFF; 213 213 int fds[2], fds_udp[2][2], ret; 214 214 215 215 fprintf(stderr, "test: datapath 0x%hx\n", typeflags); ··· 221 219 fprintf(stderr, "ERROR: failed open\n"); 222 220 exit(1); 223 221 } 222 + if (type == PACKET_FANOUT_CBPF) 223 + sock_setfilter(fds[0], SOL_PACKET, PACKET_FANOUT_DATA); 224 + 224 225 rings[0] = sock_fanout_open_ring(fds[0]); 225 226 rings[1] = sock_fanout_open_ring(fds[1]); 226 227 pair_udp_open(fds_udp[0], PORT_BASE); ··· 232 227 233 228 /* Send data, but not enough to overflow a queue */ 234 229 pair_udp_send(fds_udp[0], 15); 235 - pair_udp_send(fds_udp[1], 5); 230 + pair_udp_send_char(fds_udp[1], 5, DATA_CHAR_1); 236 231 ret = sock_fanout_read(fds, rings, expect1); 237 232 238 233 /* Send more data, overflow the queue */ 239 - pair_udp_send(fds_udp[0], 15); 234 + pair_udp_send_char(fds_udp[0], 15, DATA_CHAR_1); 240 235 /* TODO: ensure consistent order between expect1 and expect2 */ 241 236 ret |= sock_fanout_read(fds, rings, expect2); 242 237 ··· 280 275 const int expect_rb[2][2] = { { 15, 5 }, { 20, 15 } }; 281 276 const int expect_cpu0[2][2] = { { 20, 0 }, { 20, 0 } }; 282 277 const int expect_cpu1[2][2] = { { 0, 20 }, { 0, 20 } }; 278 + const int expect_bpf[2][2] = { { 15, 5 }, { 15, 20 } }; 283 279 int port_off = 2, tries = 5, ret; 284 280 285 281 test_control_single(); ··· 301 295 port_off, expect_lb[0], expect_lb[1]); 302 296 ret |= test_datapath(PACKET_FANOUT_ROLLOVER, 303 297 port_off, expect_rb[0], expect_rb[1]); 298 + ret |= test_datapath(PACKET_FANOUT_CBPF, 299 + port_off, expect_bpf[0], expect_bpf[1]); 304 300 305 301 set_cpuaffinity(0); 306 302 ret |= test_datapath(PACKET_FANOUT_CPU, port_off,
+21 -8
tools/testing/selftests/net/psock_lib.h
··· 30 30 31 31 #define DATA_LEN 100 32 32 #define DATA_CHAR 'a' 33 + #define DATA_CHAR_1 'b' 33 34 34 35 #define PORT_BASE 8000 35 36 ··· 38 37 # define __maybe_unused __attribute__ ((__unused__)) 39 38 #endif 40 39 41 - static __maybe_unused void pair_udp_setfilter(int fd) 40 + static __maybe_unused void sock_setfilter(int fd, int lvl, int optnum) 42 41 { 43 42 struct sock_filter bpf_filter[] = { 44 43 { 0x80, 0, 0, 0x00000000 }, /* LD pktlen */ 45 - { 0x35, 0, 5, DATA_LEN }, /* JGE DATA_LEN [f goto nomatch]*/ 44 + { 0x35, 0, 4, DATA_LEN }, /* JGE DATA_LEN [f goto nomatch]*/ 46 45 { 0x30, 0, 0, 0x00000050 }, /* LD ip[80] */ 47 - { 0x15, 0, 3, DATA_CHAR }, /* JEQ DATA_CHAR [f goto nomatch]*/ 48 - { 0x30, 0, 0, 0x00000051 }, /* LD ip[81] */ 49 - { 0x15, 0, 1, DATA_CHAR }, /* JEQ DATA_CHAR [f goto nomatch]*/ 46 + { 0x15, 1, 0, DATA_CHAR }, /* JEQ DATA_CHAR [t goto match]*/ 47 + { 0x15, 0, 1, DATA_CHAR_1}, /* JEQ DATA_CHAR_1 [t goto match]*/ 50 48 { 0x06, 0, 0, 0x00000060 }, /* RET match */ 51 49 { 0x06, 0, 0, 0x00000000 }, /* RET no match */ 52 50 }; 53 51 struct sock_fprog bpf_prog; 54 52 53 + if (lvl == SOL_PACKET && optnum == PACKET_FANOUT_DATA) 54 + bpf_filter[5].code = 0x16; /* RET A */ 55 + 55 56 bpf_prog.filter = bpf_filter; 56 57 bpf_prog.len = sizeof(bpf_filter) / sizeof(struct sock_filter); 57 - if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf_prog, 58 + if (setsockopt(fd, lvl, optnum, &bpf_prog, 58 59 sizeof(bpf_prog))) { 59 60 perror("setsockopt SO_ATTACH_FILTER"); 60 61 exit(1); 61 62 } 63 + } 64 + 65 + static __maybe_unused void pair_udp_setfilter(int fd) 66 + { 67 + sock_setfilter(fd, SOL_SOCKET, SO_ATTACH_FILTER); 62 68 } 63 69 64 70 static __maybe_unused void pair_udp_open(int fds[], uint16_t port) ··· 104 96 } 105 97 } 106 98 107 - static __maybe_unused void pair_udp_send(int fds[], int num) 99 + static __maybe_unused void pair_udp_send_char(int fds[], int num, char payload) 108 100 { 109 101 char buf[DATA_LEN], rbuf[DATA_LEN]; 110 102 111 - memset(buf, DATA_CHAR, sizeof(buf)); 103 + memset(buf, payload, sizeof(buf)); 112 104 while (num--) { 113 105 /* Should really handle EINTR and EAGAIN */ 114 106 if (write(fds[0], buf, sizeof(buf)) != sizeof(buf)) { ··· 124 116 exit(1); 125 117 } 126 118 } 119 + } 120 + 121 + static __maybe_unused void pair_udp_send(int fds[], int num) 122 + { 123 + return pair_udp_send_char(fds, num, DATA_CHAR); 127 124 } 128 125 129 126 static __maybe_unused void pair_udp_close(int fds[])