diff options
| author | Willem de Bruijn <willemb@google.com> | 2013-03-19 16:42:44 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-03-20 12:33:18 -0400 |
| commit | 23a9072e3af0d9538e25837fb2b56bb94e4a8e67 (patch) | |
| tree | 225d85e6ad2d380ce077a470dbf5a0a93e62ea62 | |
| parent | b44540ea024b9280c9be9d055f084e0956bcfa44 (diff) | |
net: fix psock_fanout selftest hash collision
Fix flaky results with PACKET_FANOUT_HASH depending on whether the
two flows hash into the same packet socket or not.
Also adds tests for PACKET_FANOUT_LB and PACKET_FANOUT_CPU and
replaces the counting method with a packet ring.
Signed-off-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | tools/testing/selftests/net-afpacket/psock_fanout.c | 160 |
1 files changed, 120 insertions, 40 deletions
diff --git a/tools/testing/selftests/net-afpacket/psock_fanout.c b/tools/testing/selftests/net-afpacket/psock_fanout.c index af9b0196b0be..f765f09931bd 100644 --- a/tools/testing/selftests/net-afpacket/psock_fanout.c +++ b/tools/testing/selftests/net-afpacket/psock_fanout.c | |||
| @@ -16,11 +16,11 @@ | |||
| 16 | * The test currently runs for | 16 | * The test currently runs for |
| 17 | * - PACKET_FANOUT_HASH | 17 | * - PACKET_FANOUT_HASH |
| 18 | * - PACKET_FANOUT_HASH with PACKET_FANOUT_FLAG_ROLLOVER | 18 | * - PACKET_FANOUT_HASH with PACKET_FANOUT_FLAG_ROLLOVER |
| 19 | * - PACKET_FANOUT_LB | ||
| 20 | * - PACKET_FANOUT_CPU | ||
| 19 | * - PACKET_FANOUT_ROLLOVER | 21 | * - PACKET_FANOUT_ROLLOVER |
| 20 | * | 22 | * |
| 21 | * Todo: | 23 | * Todo: |
| 22 | * - datapath: PACKET_FANOUT_LB | ||
| 23 | * - datapath: PACKET_FANOUT_CPU | ||
| 24 | * - functionality: PACKET_FANOUT_FLAG_DEFRAG | 24 | * - functionality: PACKET_FANOUT_FLAG_DEFRAG |
| 25 | * | 25 | * |
| 26 | * License (GPLv2): | 26 | * License (GPLv2): |
| @@ -39,18 +39,23 @@ | |||
| 39 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | 39 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. |
| 40 | */ | 40 | */ |
| 41 | 41 | ||
| 42 | #define _GNU_SOURCE /* for sched_setaffinity */ | ||
| 43 | |||
| 42 | #include <arpa/inet.h> | 44 | #include <arpa/inet.h> |
| 43 | #include <errno.h> | 45 | #include <errno.h> |
| 46 | #include <fcntl.h> | ||
| 44 | #include <linux/filter.h> | 47 | #include <linux/filter.h> |
| 45 | #include <linux/if_packet.h> | 48 | #include <linux/if_packet.h> |
| 46 | #include <net/ethernet.h> | 49 | #include <net/ethernet.h> |
| 47 | #include <netinet/ip.h> | 50 | #include <netinet/ip.h> |
| 48 | #include <netinet/udp.h> | 51 | #include <netinet/udp.h> |
| 49 | #include <fcntl.h> | 52 | #include <poll.h> |
| 53 | #include <sched.h> | ||
| 50 | #include <stdint.h> | 54 | #include <stdint.h> |
| 51 | #include <stdio.h> | 55 | #include <stdio.h> |
| 52 | #include <stdlib.h> | 56 | #include <stdlib.h> |
| 53 | #include <string.h> | 57 | #include <string.h> |
| 58 | #include <sys/mman.h> | ||
| 54 | #include <sys/socket.h> | 59 | #include <sys/socket.h> |
| 55 | #include <sys/stat.h> | 60 | #include <sys/stat.h> |
| 56 | #include <sys/types.h> | 61 | #include <sys/types.h> |
| @@ -58,6 +63,8 @@ | |||
| 58 | 63 | ||
| 59 | #define DATA_LEN 100 | 64 | #define DATA_LEN 100 |
| 60 | #define DATA_CHAR 'a' | 65 | #define DATA_CHAR 'a' |
| 66 | #define RING_NUM_FRAMES 20 | ||
| 67 | #define PORT_BASE 8000 | ||
| 61 | 68 | ||
| 62 | static void pair_udp_open(int fds[], uint16_t port) | 69 | static void pair_udp_open(int fds[], uint16_t port) |
| 63 | { | 70 | { |
| @@ -162,37 +169,55 @@ static int sock_fanout_open(uint16_t typeflags, int num_packets) | |||
| 162 | return -1; | 169 | return -1; |
| 163 | } | 170 | } |
| 164 | 171 | ||
| 165 | val = sizeof(struct iphdr) + sizeof(struct udphdr) + DATA_LEN; | ||
| 166 | val *= num_packets; | ||
| 167 | /* hack: apparently, the above calculation is too small (TODO: fix) */ | ||
| 168 | val *= 3; | ||
| 169 | if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val))) { | ||
| 170 | perror("setsockopt SO_RCVBUF"); | ||
| 171 | exit(1); | ||
| 172 | } | ||
| 173 | |||
| 174 | sock_fanout_setfilter(fd); | 172 | sock_fanout_setfilter(fd); |
| 175 | return fd; | 173 | return fd; |
| 176 | } | 174 | } |
| 177 | 175 | ||
| 178 | static void sock_fanout_read(int fds[], const int expect[]) | 176 | static char *sock_fanout_open_ring(int fd) |
| 179 | { | 177 | { |
| 180 | struct tpacket_stats stats; | 178 | struct tpacket_req req = { |
| 181 | socklen_t ssize; | 179 | .tp_block_size = getpagesize(), |
| 182 | int ret[2]; | 180 | .tp_frame_size = getpagesize(), |
| 181 | .tp_block_nr = RING_NUM_FRAMES, | ||
| 182 | .tp_frame_nr = RING_NUM_FRAMES, | ||
| 183 | }; | ||
| 184 | char *ring; | ||
| 183 | 185 | ||
| 184 | ssize = sizeof(stats); | 186 | if (setsockopt(fd, SOL_PACKET, PACKET_RX_RING, (void *) &req, |
| 185 | if (getsockopt(fds[0], SOL_PACKET, PACKET_STATISTICS, &stats, &ssize)) { | 187 | sizeof(req))) { |
| 186 | perror("getsockopt statistics 0"); | 188 | perror("packetsock ring setsockopt"); |
| 187 | exit(1); | 189 | exit(1); |
| 188 | } | 190 | } |
| 189 | ret[0] = stats.tp_packets - stats.tp_drops; | 191 | |
| 190 | ssize = sizeof(stats); | 192 | ring = mmap(0, req.tp_block_size * req.tp_block_nr, |
| 191 | if (getsockopt(fds[1], SOL_PACKET, PACKET_STATISTICS, &stats, &ssize)) { | 193 | PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); |
| 192 | perror("getsockopt statistics 1"); | 194 | if (!ring) { |
| 195 | fprintf(stderr, "packetsock ring mmap\n"); | ||
| 193 | exit(1); | 196 | exit(1); |
| 194 | } | 197 | } |
| 195 | ret[1] = stats.tp_packets - stats.tp_drops; | 198 | |
| 199 | return ring; | ||
| 200 | } | ||
| 201 | |||
| 202 | static int sock_fanout_read_ring(int fd, void *ring) | ||
| 203 | { | ||
| 204 | struct tpacket_hdr *header = ring; | ||
| 205 | int count = 0; | ||
| 206 | |||
| 207 | while (header->tp_status & TP_STATUS_USER && count < RING_NUM_FRAMES) { | ||
| 208 | count++; | ||
| 209 | header = ring + (count * getpagesize()); | ||
| 210 | } | ||
| 211 | |||
| 212 | return count; | ||
| 213 | } | ||
| 214 | |||
| 215 | static int sock_fanout_read(int fds[], char *rings[], const int expect[]) | ||
| 216 | { | ||
| 217 | int ret[2]; | ||
| 218 | |||
| 219 | ret[0] = sock_fanout_read_ring(fds[0], rings[0]); | ||
| 220 | ret[1] = sock_fanout_read_ring(fds[1], rings[1]); | ||
| 196 | 221 | ||
| 197 | fprintf(stderr, "info: count=%d,%d, expect=%d,%d\n", | 222 | fprintf(stderr, "info: count=%d,%d, expect=%d,%d\n", |
| 198 | ret[0], ret[1], expect[0], expect[1]); | 223 | ret[0], ret[1], expect[0], expect[1]); |
| @@ -200,8 +225,10 @@ static void sock_fanout_read(int fds[], const int expect[]) | |||
| 200 | if ((!(ret[0] == expect[0] && ret[1] == expect[1])) && | 225 | if ((!(ret[0] == expect[0] && ret[1] == expect[1])) && |
| 201 | (!(ret[0] == expect[1] && ret[1] == expect[0]))) { | 226 | (!(ret[0] == expect[1] && ret[1] == expect[0]))) { |
| 202 | fprintf(stderr, "ERROR: incorrect queue lengths\n"); | 227 | fprintf(stderr, "ERROR: incorrect queue lengths\n"); |
| 203 | exit(1); | 228 | return 1; |
| 204 | } | 229 | } |
| 230 | |||
| 231 | return 0; | ||
| 205 | } | 232 | } |
| 206 | 233 | ||
| 207 | /* Test illegal mode + flag combination */ | 234 | /* Test illegal mode + flag combination */ |
| @@ -253,11 +280,12 @@ static void test_control_group(void) | |||
| 253 | } | 280 | } |
| 254 | } | 281 | } |
| 255 | 282 | ||
| 256 | static void test_datapath(uint16_t typeflags, | 283 | static int test_datapath(uint16_t typeflags, int port_off, |
| 257 | const int expect1[], const int expect2[]) | 284 | const int expect1[], const int expect2[]) |
| 258 | { | 285 | { |
| 259 | const int expect0[] = { 0, 0 }; | 286 | const int expect0[] = { 0, 0 }; |
| 260 | int fds[2], fds_udp[2][2]; | 287 | char *rings[2]; |
| 288 | int fds[2], fds_udp[2][2], ret; | ||
| 261 | 289 | ||
