History

selftests: fixes for UDP GRO

The current implementation for UDP GRO tests is racy: the receiver may flush the RX queue while the sending is still transmitting and incorrectly report RX errors, with a wrong number of packet received. Add explicit timeouts to the receiver for both connection activation (first packet received for UDP) and reception completion, so that in the above critical scenario the receiver will wait for the transfer completion.

Paolo Abeni committed 7 years ago

Commit ada641f1 parent d235c482 files · +33 −17Browse files

Unified · Split

2 files
  1. tools/testing/selftests/net/udpgro.sh +4 −4
  2. tools/testing/selftests/net/udpgso_bench_rx.c +29 −13
tools/testing/selftests/net/udpgro.sh+4−4
@@ -37,7 +37,7 @@ run_one() { · 36 unmodified lines
37 37
38 cfg_veth38 cfg_veth
39 39
40 ip netns exec "${PEER_NS}" ./udpgso_bench_rx ${rx_args} && \40 ip netns exec "${PEER_NS}" ./udpgso_bench_rx -C 1000 -R 10 ${rx_args} && \
41 echo "ok" || \41 echo "ok" || \
42 echo "failed" &42 echo "failed" &
43 43
@@ -81,7 +81,7 @@ run_one_nat() { · 37 unmodified lines
81 # will land on the 'plain' one81 # will land on the 'plain' one
82 ip netns exec "${PEER_NS}" ./udpgso_bench_rx -G ${family} -b ${addr1} -n 0 &82 ip netns exec "${PEER_NS}" ./udpgso_bench_rx -G ${family} -b ${addr1} -n 0 &
83 pid=$!83 pid=$!
84 ip netns exec "${PEER_NS}" ./udpgso_bench_rx ${family} -b ${addr2%/*} ${rx_args} && \84 ip netns exec "${PEER_NS}" ./udpgso_bench_rx -C 1000 -R 10 ${family} -b ${addr2%/*} ${rx_args} && \
85 echo "ok" || \85 echo "ok" || \
86 echo "failed"&86 echo "failed"&
87 87
@@ -99,8 +99,8 @@ run_one_2sock() { · 11 unmodified lines
99 99
100 cfg_veth100 cfg_veth
101 101
102 ip netns exec "${PEER_NS}" ./udpgso_bench_rx ${rx_args} -p 12345 &102 ip netns exec "${PEER_NS}" ./udpgso_bench_rx -C 1000 -R 10 ${rx_args} -p 12345 &
103 ip netns exec "${PEER_NS}" ./udpgso_bench_rx ${rx_args} && \103 ip netns exec "${PEER_NS}" ./udpgso_bench_rx -C 2000 -R 10 ${rx_args} && \
104 echo "ok" || \104 echo "ok" || \
105 echo "failed" &105 echo "failed" &
106 106
tools/testing/selftests/net/udpgso_bench_rx.c+29−13
@@ -45,6 +45,8 @@ static int cfg_alen = sizeof(struct sockaddr_in6); · 44 unmodified lines
45static int cfg_expected_pkt_nr;45static int cfg_expected_pkt_nr;
46static int cfg_expected_pkt_len;46static int cfg_expected_pkt_len;
47static int cfg_expected_gso_size;47static int cfg_expected_gso_size;
48static int cfg_connect_timeout_ms;
49static int cfg_rcv_timeout_ms;
48static struct sockaddr_storage cfg_bind_addr;50static struct sockaddr_storage cfg_bind_addr;
49 51
50static bool interrupted;52static bool interrupted;
@@ -87,7 +89,7 @@ static unsigned long gettimeofday_ms(void) · 36 unmodified lines
87 return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);89 return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
88}90}
89 91
90static void do_poll(int fd)92static void do_poll(int fd, int timeout_ms)
91{93{
92 struct pollfd pfd;94 struct pollfd pfd;
93 int ret;95 int ret;
@@ -102,8 +104,16 @@ static void do_poll(int fd) · 8 unmodified lines
102 break;104 break;
103 if (ret == -1)105 if (ret == -1)
104 error(1, errno, "poll");106 error(1, errno, "poll");
105 if (ret == 0)107 if (ret == 0) {
106 continue;108 if (!timeout_ms)
109 continue;
110
111 timeout_ms -= 10;
112 if (timeout_ms <= 0) {
113 interrupted = true;
114 break;
115 }
116 }
107 if (pfd.revents != POLLIN)117 if (pfd.revents != POLLIN)
108 error(1, errno, "poll: 0x%x expected 0x%x\n",118 error(1, errno, "poll: 0x%x expected 0x%x\n",
109 pfd.revents, POLLIN);119 pfd.revents, POLLIN);
@@ -134,7 +144,7 @@ static int do_socket(bool do_tcp) · 24 unmodified lines
134 if (listen(accept_fd, 1))144 if (listen(accept_fd, 1))
135 error(1, errno, "listen");145 error(1, errno, "listen");
136 146
137 do_poll(accept_fd);147 do_poll(accept_fd, cfg_connect_timeout_ms);
138 if (interrupted)148 if (interrupted)
139 exit(0);149 exit(0);
140 150
@@ -273,7 +283,9 @@ static void do_flush_udp(int fd) · 132 unmodified lines
273 283
274static void usage(const char *filepath)284static void usage(const char *filepath)
275{285{
276 error(1, 0, "Usage: %s [-Grtv] [-b addr] [-p port] [-l pktlen] [-n packetnr] [-S gsosize]", filepath);286 error(1, 0, "Usage: %s [-C connect_timeout] [-Grtv] [-b addr] [-p port]"
287 " [-l pktlen] [-n packetnr] [-R rcv_timeout] [-S gsosize]",
288 filepath);
277}289}
278 290
279static void parse_opts(int argc, char **argv)291static void parse_opts(int argc, char **argv)
@@ -282,7 +294,7 @@ static void parse_opts(int argc, char **argv) · 2 unmodified lines
282 294
283 /* bind to any by default */295 /* bind to any by default */
284 setup_sockaddr(PF_INET6, "::", &cfg_bind_addr);296 setup_sockaddr(PF_INET6, "::", &cfg_bind_addr);
285 while ((c = getopt(argc, argv, "4b:Gl:n:p:rS:tv")) != -1) {297 while ((c = getopt(argc, argv, "4b:C:Gl:n:p:rR:S:tv")) != -1) {
286 switch (c) {298 switch (c) {
287 case '4':299 case '4':
288 cfg_family = PF_INET;300 cfg_family = PF_INET;
@@ -292,6 +304,9 @@ static void parse_opts(int argc, char **argv) · 3 unmodified lines
292 case 'b':304 case 'b':
293 setup_sockaddr(cfg_family, optarg, &cfg_bind_addr);305 setup_sockaddr(cfg_family, optarg, &cfg_bind_addr);
294 break;306 break;
307 case 'C':
308 cfg_connect_timeout_ms = strtoul(optarg, NULL, 0);
309 break;
295 case 'G':310 case 'G':
296 cfg_gro_segment = true;311 cfg_gro_segment = true;
297 break;312 break;
@@ -307,6 +322,9 @@ static void parse_opts(int argc, char **argv) · 9 unmodified lines
307 case 'r':322 case 'r':
308 cfg_read_all = true;323 cfg_read_all = true;
309 break;324 break;
325 case 'R':
326 cfg_rcv_timeout_ms = strtoul(optarg, NULL, 0);
327 break;
310 case 'S':328 case 'S':
311 cfg_expected_gso_size = strtol(optarg, NULL, 0);329 cfg_expected_gso_size = strtol(optarg, NULL, 0);
312 break;330 break;
@@ -329,8 +347,9 @@ static void parse_opts(int argc, char **argv) · 16 unmodified lines
329 347
330static void do_recv(void)348static void do_recv(void)
331{349{
350 int timeout_ms = cfg_tcp ? cfg_rcv_timeout_ms : cfg_connect_timeout_ms;
332 unsigned long tnow, treport;351 unsigned long tnow, treport;
333 int fd, loop = 0;352 int fd;
334 353
335 fd = do_socket(cfg_tcp);354 fd = do_socket(cfg_tcp);
336 355
@@ -342,12 +361,7 @@ static void do_recv(void) · 5 unmodified lines
342 361
343 treport = gettimeofday_ms() + 1000;362 treport = gettimeofday_ms() + 1000;
344 do {363 do {
345 /* force termination after the second poll(); this cope both364 do_poll(fd, timeout_ms);
346 * with sender slower than receiver and missing packet errors
347 */
348 if (cfg_expected_pkt_nr && loop++)
349 interrupted = true;
350 do_poll(fd);
351 365
352 if (cfg_tcp)366 if (cfg_tcp)
353 do_flush_tcp(fd);367 do_flush_tcp(fd);
@@ -365,6 +379,8 @@ static void do_recv(void) · 11 unmodified lines
365 treport = tnow + 1000;379 treport = tnow + 1000;
366 }380 }
367 381
382 timeout_ms = cfg_rcv_timeout_ms;
383
368 } while (!interrupted);384 } while (!interrupted);
369 385
370 if (cfg_expected_pkt_nr && (packets != cfg_expected_pkt_nr))386 if (cfg_expected_pkt_nr && (packets != cfg_expected_pkt_nr))