History

selftests/net: ignore background traffic in psock_fanout

The packet fanout test generates UDP traffic and reads this with a pair of packet sockets, testing the various fanout algorithms. Avoid non-determinism from reading unrelated background traffic. Fanout decisions are made before unrelated packets can be dropped with a filter, so that is an insufficient strategy [*]. Run the packet socket tests in a network namespace, similar to msg_zerocopy. It it still good practice to install a filter on a packet socket before accepting traffic. Because this is example code, demonstrate that pattern. Open the socket initially bound to no protocol, install a filter, and only then bind to ETH_P_IP. Another source of non-determinism is hash collisions in FANOUT_HASH. The hash function used to select a socket in the fanout group includes the pseudorandom number hashrnd, which is not visible from userspace. To work around this, the test tries to find a pair of UDP source ports that do not collide. It gives up too soon (5 times, every 32 runs) and output is confusing. Increase tries to 20 and revise the error msg. [*] another approach would be to add a third socket to the fanout group and direct all unexpected traffic here. This is possible only when reimplementing methods like RR or HASH alongside this extra catch-all bucket, using the BPF fanout method.

Willem de Bruijn committed 8 years ago

Commit cc30c931 parent 3c69f793 files · +51 −8Browse files

Unified · Split

3 files
  1. tools/testing/selftests/net/in_netns.sh +23 −0
  2. tools/testing/selftests/net/psock_fanout.c +26 −6
  3. tools/testing/selftests/net/run_afpackettests +2 −2
tools/testing/selftests/net/in_netns.sh+23−0
@@ -0,0 +1,23 @@
1#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0
3#
4# Execute a subprocess in a network namespace
5
6set -e
7
8readonly NETNS="ns-$(mktemp -u XXXXXX)"
9
10setup() {
11 ip netns add "${NETNS}"
12 ip -netns "${NETNS}" link set lo up
13}
14
15cleanup() {
16 ip netns del "${NETNS}"
17}
18
19trap cleanup EXIT
20setup
21
22"$@"
23exit "$?"
tools/testing/selftests/net/psock_fanout.c+26−6
@@ -50,6 +50,7 @@ · 49 unmodified lines
50#include <linux/filter.h>50#include <linux/filter.h>
51#include <linux/bpf.h>51#include <linux/bpf.h>
52#include <linux/if_packet.h>52#include <linux/if_packet.h>
53#include <net/if.h>
53#include <net/ethernet.h>54#include <net/ethernet.h>
54#include <netinet/ip.h>55#include <netinet/ip.h>
55#include <netinet/udp.h>56#include <netinet/udp.h>
@@ -73,14 +74,29 @@ · 17 unmodified lines
73 * @return -1 if mode is bad, a valid socket otherwise */74 * @return -1 if mode is bad, a valid socket otherwise */
74static int sock_fanout_open(uint16_t typeflags, uint16_t group_id)75static int sock_fanout_open(uint16_t typeflags, uint16_t group_id)
75{76{
77 struct sockaddr_ll addr = {0};
76 int fd, val;78 int fd, val;
77 79
78 fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));80 fd = socket(PF_PACKET, SOCK_RAW, 0);
79 if (fd < 0) {81 if (fd < 0) {
80 perror("socket packet");82 perror("socket packet");
81 exit(1);83 exit(1);
82 }84 }
83 85
86 pair_udp_setfilter(fd);
87
88 addr.sll_family = AF_PACKET;
89 addr.sll_protocol = htons(ETH_P_IP);
90 addr.sll_ifindex = if_nametoindex("lo");
91 if (addr.sll_ifindex == 0) {
92 perror("if_nametoindex");
93 exit(1);
94 }
95 if (bind(fd, (void *) &addr, sizeof(addr))) {
96 perror("bind packet");
97 exit(1);
98 }
99
84 val = (((int) typeflags) << 16) | group_id;100 val = (((int) typeflags) << 16) | group_id;
85 if (setsockopt(fd, SOL_PACKET, PACKET_FANOUT, &val, sizeof(val))) {101 if (setsockopt(fd, SOL_PACKET, PACKET_FANOUT, &val, sizeof(val))) {
86 if (close(fd)) {102 if (close(fd)) {
@@ -90,7 +106,6 @@ static int sock_fanout_open(uint16_t typeflags, uint16_t group_id) · 3 unmodified lines
90 return -1;106 return -1;
91 }107 }
92 108
93 pair_udp_setfilter(fd);
94 return fd;109 return fd;
95}110}
96 111
@@ -229,7 +244,7 @@ static int sock_fanout_read(int fds[], char *rings[], const int expect[]) · 132 unmodified lines
229 244
230 if ((!(ret[0] == expect[0] && ret[1] == expect[1])) &&245 if ((!(ret[0] == expect[0] && ret[1] == expect[1])) &&
231 (!(ret[0] == expect[1] && ret[1] == expect[0]))) {246 (!(ret[0] == expect[1] && ret[1] == expect[0]))) {
232 fprintf(stderr, "ERROR: incorrect queue lengths\n");247 fprintf(stderr, "warning: incorrect queue lengths\n");
233 return 1;248 return 1;
234 }249 }
235 250
@@ -348,7 +363,8 @@ static int test_datapath(uint16_t typeflags, int port_off, · 112 unmodified lines
348 uint8_t type = typeflags & 0xFF;363 uint8_t type = typeflags & 0xFF;
349 int fds[2], fds_udp[2][2], ret;364 int fds[2], fds_udp[2][2], ret;
350 365
351 fprintf(stderr, "test: datapath 0x%hx\n", typeflags);366 fprintf(stderr, "\ntest: datapath 0x%hx ports %hu,%hu\n",
367 typeflags, PORT_BASE, PORT_BASE + port_off);
352 368
353 fds[0] = sock_fanout_open(typeflags, 0);369 fds[0] = sock_fanout_open(typeflags, 0);
354 fds[1] = sock_fanout_open(typeflags, 0);370 fds[1] = sock_fanout_open(typeflags, 0);
@@ -419,7 +435,7 @@ int main(int argc, char **argv) · 64 unmodified lines
419 const int expect_cpu1[2][2] = { { 0, 20 }, { 0, 20 } };435 const int expect_cpu1[2][2] = { { 0, 20 }, { 0, 20 } };
420 const int expect_bpf[2][2] = { { 15, 5 }, { 15, 20 } };436 const int expect_bpf[2][2] = { { 15, 5 }, { 15, 20 } };
421 const int expect_uniqueid[2][2] = { { 20, 20}, { 20, 20 } };437 const int expect_uniqueid[2][2] = { { 20, 20}, { 20, 20 } };
422 int port_off = 2, tries = 5, ret;438 int port_off = 2, tries = 20, ret;
423 439
424 test_control_single();440 test_control_single();
425 test_control_group();441 test_control_group();
@@ -428,10 +444,14 @@ int main(int argc, char **argv) · 2 unmodified lines
428 /* find a set of ports that do not collide onto the same socket */444 /* find a set of ports that do not collide onto the same socket */
429 ret = test_datapath(PACKET_FANOUT_HASH, port_off,445 ret = test_datapath(PACKET_FANOUT_HASH, port_off,
430 expect_hash[0], expect_hash[1]);446 expect_hash[0], expect_hash[1]);
431 while (ret && tries--) {447 while (ret) {
432 fprintf(stderr, "info: trying alternate ports (%d)\n", tries);448 fprintf(stderr, "info: trying alternate ports (%d)\n", tries);
433 ret = test_datapath(PACKET_FANOUT_HASH, ++port_off,449 ret = test_datapath(PACKET_FANOUT_HASH, ++port_off,
434 expect_hash[0], expect_hash[1]);450 expect_hash[0], expect_hash[1]);
451 if (!--tries) {
452 fprintf(stderr, "too many collisions\n");
453 return 1;
454 }
435 }455 }
436 456
437 ret |= test_datapath(PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_ROLLOVER,457 ret |= test_datapath(PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_ROLLOVER,
tools/testing/selftests/net/run_afpackettests+2−2
@@ -9,7 +9,7 @@ fi · 8 unmodified lines
9echo "--------------------"9echo "--------------------"
10echo "running psock_fanout test"10echo "running psock_fanout test"
11echo "--------------------"11echo "--------------------"
12./psock_fanout12./in_netns.sh ./psock_fanout
13if [ $? -ne 0 ]; then13if [ $? -ne 0 ]; then
14 echo "[FAIL]"14 echo "[FAIL]"
15else15else
@@ -19,7 +19,7 @@ fi · 3 unmodified lines
19echo "--------------------"19echo "--------------------"
20echo "running psock_tpacket test"20echo "running psock_tpacket test"
21echo "--------------------"21echo "--------------------"
22./psock_tpacket22./in_netns.sh ./psock_tpacket
23if [ $? -ne 0 ]; then23if [ $? -ne 0 ]; then
24 echo "[FAIL]"24 echo "[FAIL]"
25else25else