1 /*
2 * Copyright (C) 2013-2021 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 * This code is a complete clean re-write of the stress tool by
19 * Colin Ian King <colin.king@canonical.com> and attempts to be
20 * backwardly compatible with the stress tool by Amos Waterland
21 * <apw@rossby.metr.ou.edu> but has more stress tests and more
22 * functionality.
23 *
24 */
25 #include "stress-ng.h"
26
27 /* See bugs section of udplite(7) */
28 #if !defined(SOL_UDPLITE)
29 #define SOL_UDPLITE (136)
30 #endif
31 #if !defined(UDPLITE_SEND_CSCOV)
32 #define UDPLITE_SEND_CSCOV (10)
33 #endif
34 #if !defined(UDPLITE_RECV_CSCOV)
35 #define UDPLITE_RECV_CSCOV (11)
36 #endif
37
38 static const stress_help_t help[] = {
39 { NULL, "udp N", "start N workers performing UDP send/receives " },
40 { NULL, "udp-ops N", "stop after N udp bogo operations" },
41 { NULL, "udp-domain D", "specify domain, default is ipv4" },
42 { NULL, "udp-lite", "use the UDP-Lite (RFC 3828) protocol" },
43 { NULL, "udp-port P", "use ports P to P + number of workers - 1" },
44 { NULL, NULL, NULL }
45 };
46
stress_set_udp_port(const char * opt)47 static int stress_set_udp_port(const char *opt)
48 {
49 int udp_port;
50
51 stress_set_net_port("udp-port", opt,
52 MIN_UDP_PORT, MAX_UDP_PORT - STRESS_PROCS_MAX,
53 &udp_port);
54 return stress_set_setting("udp-port", TYPE_ID_INT, &udp_port);
55 }
56
57 /*
58 * stress_set_udp_domain()
59 * set the udp domain option
60 */
stress_set_udp_domain(const char * name)61 static int stress_set_udp_domain(const char *name)
62 {
63 int ret, udp_domain;
64
65 ret = stress_set_net_domain(DOMAIN_INET | DOMAIN_INET6, "udp-domain", name, &udp_domain);
66 stress_set_setting("udp-domain", TYPE_ID_INT, &udp_domain);
67
68 return ret;
69 }
70
stress_set_udp_lite(const char * opt)71 static int stress_set_udp_lite(const char *opt)
72 {
73 bool udp_lite = true;
74
75 (void)opt;
76 return stress_set_setting("udp-lite", TYPE_ID_BOOL, &udp_lite);
77 }
78
79 /*
80 * stress_udp
81 * stress by heavy udp ops
82 */
stress_udp(const stress_args_t * args)83 static int stress_udp(const stress_args_t *args)
84 {
85 int udp_port = DEFAULT_UDP_PORT;
86 int udp_domain = AF_INET;
87 pid_t pid, ppid = getppid();
88 int rc = EXIT_SUCCESS;
89 int proto = 0;
90 #if defined(IPPROTO_UDPLITE)
91 bool udp_lite = false;
92 #endif
93
94 (void)stress_get_setting("udp-port", &udp_port);
95 (void)stress_get_setting("udp-domain", &udp_domain);
96 #if defined(IPPROTO_UDPLITE)
97 (void)stress_get_setting("udp-lite", &udp_lite);
98
99 proto = udp_lite ? IPPROTO_UDPLITE : IPPROTO_UDP;
100
101 if ((proto == IPPROTO_UDPLITE) &&
102 (udp_domain == AF_UNIX)) {
103 proto = 0;
104 if (args->instance == 0) {
105 pr_inf("%s: disabling UDP-Lite as it is not "
106 "available for UNIX domain UDP\n",
107 args->name);
108 }
109 }
110 #endif
111
112 pr_dbg("%s: process [%d] using udp port %d\n",
113 args->name, (int)args->pid, udp_port + (int)args->instance);
114
115 stress_set_proc_state(args->name, STRESS_STATE_RUN);
116 again:
117 pid = fork();
118 if (pid < 0) {
119 if (keep_stressing_flag() && (errno == EAGAIN))
120 goto again;
121 pr_fail("%s: fork failed, errno=%d (%s)\n",
122 args->name, errno, strerror(errno));
123 return EXIT_FAILURE;
124 } else if (pid == 0) {
125 /* Child, client */
126 struct sockaddr *addr = NULL;
127
128 (void)setpgid(0, g_pgrp);
129 stress_parent_died_alarm();
130 (void)sched_settings_apply(true);
131
132 do {
133 char buf[UDP_BUF];
134 socklen_t len;
135 int fd;
136 int j = 0;
137
138 if ((fd = socket(udp_domain, SOCK_DGRAM, proto)) < 0) {
139 pr_fail("%s: socket failed, errno=%d (%s)\n",
140 args->name, errno, strerror(errno));
141 /* failed, kick parent to finish */
142 (void)kill(getppid(), SIGALRM);
143 _exit(EXIT_FAILURE);
144 }
145 stress_set_sockaddr(args->name, args->instance, ppid,
146 udp_domain, udp_port,
147 &addr, &len, NET_ADDR_ANY);
148 #if defined(IPPROTO_UDPLITE) && \
149 defined(UDPLITE_SEND_CSCOV)
150 if (proto == IPPROTO_UDPLITE) {
151 int val = 8; /* Just the 8 byte header */
152 socklen_t slen;
153
154 slen = sizeof(val);
155 if (setsockopt(fd, SOL_UDPLITE, UDPLITE_SEND_CSCOV, &val, slen) < 0) {
156 pr_fail("%s: setsockopt failed, errno=%d (%s)\n",
157 args->name, errno, strerror(errno));
158 (void)close(fd);
159 (void)kill(getppid(), SIGALRM);
160 _exit(EXIT_FAILURE);
161 }
162 slen = sizeof(val);
163 (void)getsockopt(fd, SOL_UDPLITE, UDPLITE_SEND_CSCOV, &val, &slen);
164 }
165 #endif
166 #if defined(IPPROTO_UDPLITE) && \
167 defined(UDPLITE_RECV_CSCOV)
168 if (proto == IPPROTO_UDPLITE) {
169 int val;
170 socklen_t slen = sizeof(val);
171
172 (void)getsockopt(fd, proto, UDPLITE_RECV_CSCOV, &val, &slen);
173 }
174 #endif
175
176 #if defined(UDP_CORK)
177 {
178 int val, ret;
179 socklen_t slen = sizeof(val);
180
181 ret = getsockopt(fd, proto, UDP_CORK, &val, &slen);
182 if (ret == 0) {
183 slen = sizeof(val);
184 ret = setsockopt(fd, proto, UDP_CORK, &val, slen);
185 }
186 (void)ret;
187 }
188 #endif
189 #if defined(UDP_ENCAP)
190 {
191 int val, ret;
192 socklen_t slen = sizeof(val);
193
194 ret = getsockopt(fd, proto, UDP_ENCAP, &val, &slen);
195 if (ret == 0) {
196 slen = sizeof(val);
197 ret = setsockopt(fd, proto, UDP_ENCAP, &val, slen);
198 }
199 (void)ret;
200 }
201 #endif
202 #if defined(UDP_NO_CHECK6_TX)
203 {
204 int val, ret;
205 socklen_t slen = sizeof(val);
206
207 ret = getsockopt(fd, proto, UDP_NO_CHECK6_TX, &val, &slen);
208 if (ret == 0) {
209 slen = sizeof(val);
210 ret = setsockopt(fd, proto, UDP_NO_CHECK6_TX, &val, slen);
211 }
212 (void)ret;
213 }
214 #endif
215 #if defined(UDP_NO_CHECK6_RX)
216 {
217 int val, ret;
218 socklen_t slen = sizeof(val);
219 ret = getsockopt(fd, proto, UDP_NO_CHECK6_RX, &val, &slen);
220 if (ret == 0) {
221 slen = sizeof(val);
222 ret = setsockopt(fd, proto, UDP_NO_CHECK6_RX, &val, slen);
223 }
224 (void)ret;
225 }
226 #endif
227 #if defined(UDP_SEGMENT)
228 {
229 int val, ret;
230 socklen_t slen = sizeof(val);
231
232 ret = getsockopt(fd, proto, UDP_SEGMENT, &val, &slen);
233 if (ret == 0) {
234 slen = sizeof(val);
235 ret = setsockopt(fd, proto, UDP_SEGMENT, &val, slen);
236 }
237 (void)ret;
238 }
239 #endif
240 do {
241 size_t i;
242
243 for (i = 16; i < sizeof(buf); i += 16, j++) {
244 (void)memset(buf, 'A' + (j % 26), sizeof(buf));
245 ssize_t ret = sendto(fd, buf, i, 0, addr, len);
246 if (ret < 0) {
247 if ((errno == EINTR) || (errno == ENETUNREACH))
248 break;
249 pr_fail("%s: sendto failed, errno=%d (%s)\n",
250 args->name, errno, strerror(errno));
251 break;
252 }
253 }
254 #if defined(SIOCOUTQ)
255 {
256 int pending;
257
258 (void)ioctl(fd, SIOCOUTQ, &pending);
259 }
260 #endif
261 } while (keep_stressing(args));
262 (void)close(fd);
263 } while (keep_stressing(args));
264
265 #if defined(AF_UNIX) && \
266 defined(HAVE_SOCKADDR_UN)
267 if ((udp_domain == AF_UNIX) && addr) {
268 struct sockaddr_un *addr_un = (struct sockaddr_un *)addr;
269
270 (void)unlink(addr_un->sun_path);
271 }
272 #endif
273 /* Inform parent we're all done */
274 (void)kill(getppid(), SIGALRM);
275 _exit(EXIT_SUCCESS);
276 } else {
277 /* Parent, server */
278
279 char buf[UDP_BUF];
280 int fd, status;
281 #if !defined(__minix__)
282 int so_reuseaddr = 1;
283 #endif
284 socklen_t addr_len = 0;
285 struct sockaddr *addr = NULL;
286
287 (void)setpgid(pid, g_pgrp);
288
289 if (stress_sig_stop_stressing(args->name, SIGALRM) < 0) {
290 rc = EXIT_FAILURE;
291 goto die;
292 }
293 if ((fd = socket(udp_domain, SOCK_DGRAM, proto)) < 0) {
294 pr_fail("%s: socket failed, errno=%d (%s)\n",
295 args->name, errno, strerror(errno));
296 rc = EXIT_FAILURE;
297 goto die;
298 }
299 stress_set_sockaddr(args->name, args->instance, ppid,
300 udp_domain, udp_port,
301 &addr, &addr_len, NET_ADDR_ANY);
302 #if defined(IPPROTO_UDPLITE)
303 if (proto == IPPROTO_UDPLITE) {
304 int val = 8; /* Just the 8 byte header */
305
306 if (setsockopt(fd, SOL_UDPLITE, UDPLITE_RECV_CSCOV, &val, sizeof(val)) < 0) {
307 pr_fail("%s: setsockopt failed, errno=%d (%s)\n",
308 args->name, errno, strerror(errno));
309 rc = EXIT_FAILURE;
310 goto die_close;
311 }
312 }
313 #endif
314 if (bind(fd, addr, addr_len) < 0) {
315 pr_fail("%s: bind failed, errno=%d (%s)\n",
316 args->name, errno, strerror(errno));
317 rc = EXIT_FAILURE;
318 goto die_close;
319 }
320 #if !defined(__minix__)
321 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddr, sizeof(so_reuseaddr)) < 0) {
322 /*
323 * Some systems don't support SO_REUSEADDR
324 */
325 if (errno != EINVAL) {
326 pr_fail("%s: setsockopt failed, errno=%d (%s)\n",
327 args->name, errno, strerror(errno));
328 rc = EXIT_FAILURE;
329 goto die_close;
330 }
331 }
332 #endif
333
334 do {
335 socklen_t len = addr_len;
336 ssize_t n;
337 #if defined(SIOCOUTQ)
338 {
339 int pending;
340
341 (void)ioctl(fd, SIOCINQ, &pending);
342 }
343 #endif
344
345 n = recvfrom(fd, buf, sizeof(buf), 0, addr, &len);
346 if (n == 0)
347 break;
348 if (n < 0) {
349 if (errno != EINTR)
350 pr_fail("%s: recvfrom failed, errno=%d (%s)\n",
351 args->name, errno, strerror(errno));
352 break;
353 }
354 inc_counter(args);
355 } while (keep_stressing(args));
356
357 die_close:
358 stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
359 (void)close(fd);
360 die:
361 stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
362 #if defined(AF_UNIX) && \
363 defined(HAVE_SOCKADDR_UN)
364 if ((udp_domain == AF_UNIX) && addr) {
365 struct sockaddr_un *addr_un = (struct sockaddr_un *)addr;
366
367 (void)unlink(addr_un->sun_path);
368 }
369 #endif
370 if (pid) {
371 (void)kill(pid, SIGKILL);
372 (void)shim_waitpid(pid, &status, 0);
373 }
374 }
375 return rc;
376 }
377
378 static const stress_opt_set_func_t opt_set_funcs[] = {
379 { OPT_udp_domain, stress_set_udp_domain },
380 { OPT_udp_port, stress_set_udp_port },
381 { OPT_udp_lite, stress_set_udp_lite },
382 { 0, NULL }
383 };
384
385 stressor_info_t stress_udp_info = {
386 .stressor = stress_udp,
387 .class = CLASS_NETWORK | CLASS_OS,
388 .opt_set_funcs = opt_set_funcs,
389 .help = help
390 };
391