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