xref: /xnu-11215.41.3/tests/skywalk/skt_utunloop.c (revision 33de042d024d46de5ff4e89f2471de6608e37fa4)
1 /*
2  * Copyright (c) 2017-2024 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 /*
30  * <rdar://problem/31245751> User space forwarding for testing utun/ipsec
31  *
32  * A process that opens 2 channels, each one to a separate utun/ipsec interface
33  * The process would then shuttle packets from one to another.
34  *
35  */
36 
37 #include <assert.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <stdlib.h>
42 #include <errno.h>
43 #include <pthread.h>
44 #include <fcntl.h>
45 #include <mach/mach.h>
46 #include <mach/host_reboot.h>
47 
48 #include <uuid/uuid.h>
49 #include <sys/types.h>
50 #include <sys/event.h>
51 #include <net/if_utun.h>
52 #include <sys/ioctl.h>
53 #include <sys/socket.h>
54 #include <sys/kern_control.h>
55 #include <sys/reboot.h>
56 #include <sys/sys_domain.h>
57 #include <sys/sysctl.h>
58 
59 #include <arpa/inet.h> // for inet_ntop
60 
61 #include <skywalk/os_skywalk.h>
62 #include <darwintest.h>
63 
64 #include "skywalk_test_driver.h"
65 #include "skywalk_test_utils.h"
66 #include "skywalk_test_common.h"
67 
68 static volatile bool g_die;
69 
70 static volatile bool g_verbose;
71 
72 char debugcmd[1024];
73 
74 FILE *g_dumpfile;
75 
76 #define VLOG(_fmt, ...)            \
77 	do {                                               \
78 	        if (g_verbose) {                                   \
79 	                struct timeval _stamp, _delta;                  \
80 	                if (!g_dumpfile) g_dumpfile = stderr;                   \
81 	                gettimeofday(&_stamp, NULL);                            \
82 	                timersub(&_stamp, &prevtime, &_delta);                                    \
83 	                fprintf(g_dumpfile, "% 10ld.%06d % 10ld.%06d %s: " _fmt "\n", \
84 	                        _stamp.tv_sec, _stamp.tv_usec,                                                  \
85 	                        _delta.tv_sec, _delta.tv_usec, threadname, ##__VA_ARGS__); \
86 	                fflush(g_dumpfile); \
87 	                prevtime = _stamp;                                                                                      \
88 	        }                                                                                                                               \
89 	} while (0)
90 
91 static bool g_assert_stalls12;
92 static bool g_assert_stalls21;
93 
94 static void
skt_utunloop_xfer_slots(int kq,channel_t rxchannel,int rxindex,channel_t txchannel,int txindex,const char * threadname,bool xfer12)95 skt_utunloop_xfer_slots(int kq,
96     channel_t rxchannel, int rxindex,
97     channel_t txchannel, int txindex,
98     const char *threadname, bool xfer12)
99 {
100 	int error;
101 	channel_ring_t rxring, txring;
102 	struct kevent kev;
103 	int rxfd, txfd;
104 	bool rxenable, txenable;
105 	time_t start, then, now;
106 	uint64_t slotcount, bytecount;
107 	uint64_t prevslotcount, prevbytecount;
108 	struct timeval prevtime;
109 
110 	gettimeofday(&prevtime, NULL);
111 
112 	rxring = os_channel_rx_ring(rxchannel, rxindex +
113 	    os_channel_ring_id(rxchannel, CHANNEL_FIRST_RX_RING));
114 	assert(rxring);
115 	txring = os_channel_tx_ring(txchannel, txindex +
116 	    os_channel_ring_id(txchannel, CHANNEL_FIRST_TX_RING));
117 	assert(txring);
118 
119 	rxfd = os_channel_get_fd(rxchannel);
120 	EV_SET(&kev, rxfd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL);
121 	error = kevent(kq, &kev, 1, NULL, 0, NULL);
122 	SKTC_ASSERT_ERR(!error);
123 	rxenable = true;
124 
125 	txfd = os_channel_get_fd(txchannel);
126 	EV_SET(&kev, txfd, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, NULL);
127 	error = kevent(kq, &kev, 1, NULL, 0, NULL);
128 	SKTC_ASSERT_ERR(!error);
129 	txenable = true;
130 
131 	T_LOG("thread %s has kq %d rxfd %d txfd %d\n",
132 	    threadname, kq, rxfd, txfd);
133 
134 	prevslotcount = slotcount = 0;
135 	prevbytecount = bytecount = 0;
136 	int stallcount = 0;
137 	start = time(NULL);
138 
139 	while (!g_die) {
140 		uint32_t rxavail, txavail, xfer;
141 
142 		do {
143 			rxavail = os_channel_available_slot_count(rxring);
144 			txavail = os_channel_available_slot_count(txring);
145 			VLOG("rxavail %u txavail %u", rxavail, txavail);
146 
147 			/* If there's no data to receive stop asking for output notifications
148 			 * but make sure that if both rx and tx are not available, that
149 			 * the tx remains enabled to we can wake up to reenable rx when tx
150 			 * eventually becomes available
151 			 */
152 			if (txenable && !rxavail && txavail) {
153 				EV_SET(&kev, txfd, EVFILT_WRITE, EV_DISABLE, 0, 0, NULL);
154 				error = kevent(kq, &kev, 1, NULL, 0, NULL);
155 				SKTC_ASSERT_ERR(!error);
156 				txenable = false;
157 				VLOG("txenable = false");
158 			} else if (!txenable && (rxavail || (!rxavail && !txavail))) {
159 				EV_SET(&kev, txfd, EVFILT_WRITE, EV_ENABLE, 0, 0, NULL);
160 				error = kevent(kq, &kev, 1, NULL, 0, NULL);
161 				SKTC_ASSERT_ERR(!error);
162 				txenable = true;
163 				VLOG("txenable = true");
164 			}
165 
166 			/* If there's no place to put data, stop asking for input notifications */
167 			if (rxenable && !txavail) {
168 				EV_SET(&kev, rxfd, EVFILT_READ, EV_DISABLE, 0, 0, NULL);
169 				error = kevent(kq, &kev, 1, NULL, 0, NULL);
170 				SKTC_ASSERT_ERR(!error);
171 				rxenable = false;
172 				VLOG("rxenable = false");
173 			} else if (!rxenable && txavail) {
174 				EV_SET(&kev, rxfd, EVFILT_READ, EV_ENABLE, 0, 0, NULL);
175 				error = kevent(kq, &kev, 1, NULL, 0, NULL);
176 				SKTC_ASSERT_ERR(!error);
177 				rxenable = true;
178 				VLOG("rxenable = true");
179 			}
180 
181 			if (!rxavail || !txavail) {
182 				struct timespec timeout = {.tv_sec = 1, .tv_nsec = 0};  // 1 second
183 				VLOG("waiting rxen %d rx %u txen %d tx %u",
184 				    rxenable, rxavail, txenable, txavail);
185 
186 				assert(txenable || rxenable);
187 
188 				error = kevent(kq, NULL, 0, &kev, 1, &timeout);
189 				if (error == 0) {
190 					//T_LOG("%s: kevent tick\n", threadname);
191 					if (g_die) {
192 						T_LOG("%s: die set, exiting\n", threadname);
193 						goto out;
194 					}
195 				} else {
196 					SKTC_ASSERT_ERR(error != -1);
197 					SKTC_ASSERT_ERR(error == 1);
198 					if (kev.filter == EVFILT_USER) {
199 						T_LOG("%s: user event, exiting\n",
200 						    threadname);
201 						goto out;
202 					} else if (kev.filter == EVFILT_WRITE) {
203 						VLOG("write event");
204 					} else if (kev.filter == EVFILT_READ) {
205 						VLOG("read event");
206 					} else {
207 						assert(false);
208 					}
209 				}
210 			}
211 
212 			now = time(NULL);
213 			if (now > then) {
214 				T_LOG("%s: time %ld slotcount %llu "
215 				    "(total %llu) bytecount %llu (total %llu)\n",
216 				    threadname, now - start,
217 				    slotcount - prevslotcount, slotcount,
218 				    bytecount - prevbytecount, bytecount);
219 
220 				if ((now - start) > 0 && (slotcount - prevslotcount) == 0) {
221 					stallcount++;
222 					VLOG("STALLING");
223 					if ((xfer12 && g_assert_stalls12) || (!xfer12 && g_assert_stalls21)) {
224 						if (stallcount > 2) {
225 							T_LOG("%s: STALLING count %d rxavail %u txavail %u\n",
226 							    threadname, stallcount, rxavail, txavail);
227 						}
228 						assert(stallcount < 10);
229 						if (stallcount == 5) {
230 #if 0
231 							reboot_np(RB_PANIC | RB_QUICK, "skt_utunloop stalled");
232 							host_reboot(mach_host_self(), HOST_REBOOT_DEBUGGER);
233 #elif 0
234 							if (!strcmp(threadname, "sktc_channel_worker_xfer21")) {
235 								T_LOG("%s: Running %s\n", threadname, debugcmd);
236 								pclose(popen(debugcmd, "r"));
237 								//system(debugcmd);
238 							}
239 //						T_LOG("%s: Sleeping\n", threadname);
240 //						sleep(3600000);
241 							T_LOG("%s: exiting because of stall\n", threadname);
242 							exit(252);
243 #elif 0
244 							T_LOG("%s: enabling verbose\n", threadname);
245 							uint64_t verbose = (1ULL << 50);
246 							error = sysctlbyname("kern.skywalk.verbose", NULL, NULL, &verbose, sizeof(verbose));
247 							SKTC_ASSERT_ERR(!error);
248 #endif
249 						}
250 					}
251 				} else {
252 					stallcount = 0;
253 				}
254 
255 				then = now;
256 				prevslotcount = slotcount;
257 				prevbytecount = bytecount;
258 			}
259 		} while (!rxavail || !txavail);
260 
261 #if 0
262 		/*
263 		 * Yes this distribution includes syncs with 0 slots,
264 		 * but that should be handled ok, so lets include it.
265 		 */
266 		xfer = arc4random_uniform(1 + MIN(txavail, rxavail));
267 #else
268 		/* IDS only transfers one slot i think */
269 		xfer = 1;
270 		//xfer = MIN(txavail,rxavail);
271 #endif
272 
273 		VLOG("rx %u tx %u xfer %u", rxavail, txavail, xfer);
274 
275 		channel_slot_t rxprev = NULL, txprev = NULL;
276 
277 		for (uint32_t i = 0; i < xfer; i++) {
278 			slot_prop_t rxprop, txprop;
279 			channel_slot_t rxslot, txslot;
280 
281 			rxslot = os_channel_get_next_slot(rxring, rxprev, &rxprop);
282 			assert(rxslot);
283 			txslot = os_channel_get_next_slot(txring, txprev, &txprop);
284 			assert(txslot);
285 
286 			assert(txprop.sp_len >= rxprop.sp_len);
287 			memcpy((void *)txprop.sp_buf_ptr,
288 			    (void *)rxprop.sp_buf_ptr, rxprop.sp_len);
289 			txprop.sp_len = rxprop.sp_len;
290 			os_channel_set_slot_properties(txring, txslot, &txprop);
291 
292 			slotcount += 1;
293 			bytecount += txprop.sp_len;
294 
295 			rxprev = rxslot;
296 			txprev = txslot;
297 
298 #if 1 // this tries to be like IDS which syncs every outgoing packet
299 			error = os_channel_advance_slot(txring, txprev);
300 			SKTC_ASSERT_ERR(!error);
301 			error = os_channel_sync(txchannel, CHANNEL_SYNC_TX);
302 			SKTC_ASSERT_ERR(!error);
303 			txprev = NULL;
304 #endif
305 		}
306 
307 		if (txprev) {
308 			// If we don't sync every slot above we would do this
309 			error = os_channel_advance_slot(txring, txprev);
310 			SKTC_ASSERT_ERR(!error);
311 			error = os_channel_sync(txchannel, CHANNEL_SYNC_TX);
312 			SKTC_ASSERT_ERR(!error);
313 		}
314 
315 		// IDS calls rx sync, so we do it here.
316 		error = os_channel_advance_slot(rxring, rxprev);
317 		SKTC_ASSERT_ERR(!error);
318 		error = os_channel_sync(rxchannel, CHANNEL_SYNC_RX);
319 		SKTC_ASSERT_ERR(!error);
320 	}
321 
322 out:
323 	return;
324 }
325 
326 static channel_t g_channel1, g_channel2;
327 static int g_kq1, g_kq2;
328 
329 static void *
sktc_channel_worker_xfer12(void * ignored)330 sktc_channel_worker_xfer12(void *ignored)
331 {
332 	pthread_setname_np(__func__);
333 	skt_utunloop_xfer_slots(g_kq1, g_channel1, 0, g_channel2, 0, __func__, true);
334 	return NULL;
335 }
336 
337 static void *
sktc_channel_worker_xfer21(void * ignored)338 sktc_channel_worker_xfer21(void *ignored)
339 {
340 	pthread_setname_np(__func__);
341 	skt_utunloop_xfer_slots(g_kq2, g_channel2, 0, g_channel1, 0, __func__, false);
342 	return NULL;
343 }
344 
345 static bool
setblocking(int s,bool blocking)346 setblocking(int s, bool blocking)
347 {
348 	int error, flags;
349 	bool ret;
350 	error = fcntl(s, F_GETFL, 0);
351 	SKTC_ASSERT_ERR(error >= 0);
352 	flags = error;
353 
354 	ret = !(flags & O_NONBLOCK);
355 
356 	if (blocking) {
357 		flags &= ~O_NONBLOCK;
358 	} else {
359 		flags |= O_NONBLOCK;
360 	}
361 
362 	T_LOG("Setting fd %d from %s to %s\n",
363 	    s, ret ? "blocking" : "nonblocking",
364 	    blocking ? "blocking" : "nonblocking");
365 
366 	error = fcntl(s, F_SETFL, flags);
367 	SKTC_ASSERT_ERR(!error);
368 
369 	return ret;
370 }
371 
372 
373 static int
makesocket(int type,in_addr_t addr)374 makesocket(int type, in_addr_t addr)
375 {
376 	int error;
377 	int s;
378 	char sbuf[INET6_ADDRSTRLEN];
379 	struct sockaddr_in sin;
380 
381 	s = socket(PF_INET, type, 0);
382 	assert(s != -1);
383 
384 #if 0
385 	unsigned int ifidx;
386 	ifidx = if_nametoindex(ifname1); // xxx
387 	assert(ifidx != 0);
388 	error = setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifidx, sizeof(ifidx));
389 	SKTC_ASSERT_ERR(!error);
390 #endif
391 
392 	memset(&sin, 0, sizeof(sin));
393 	sin.sin_len = sizeof(sin);
394 	sin.sin_family = AF_INET;
395 	sin.sin_addr.s_addr = htonl(addr);
396 
397 	error = bind(s, (struct sockaddr *)&sin, sizeof(sin));
398 	SKTC_ASSERT_ERR(!error);
399 
400 	inet_ntop(sin.sin_family, &sin.sin_addr.s_addr, sbuf, sizeof(sbuf));
401 	T_LOG("%s socket %d bound to %s port %d\n",
402 	    type == SOCK_DGRAM ? "udp" : "tcp",
403 	    s, sbuf, ntohs(sin.sin_port));
404 
405 	return s;
406 }
407 
408 static void
connectsocks(int s1,int s2,bool block)409 connectsocks(int s1, int s2, bool block)
410 {
411 	int error;
412 	struct sockaddr_in sin;
413 	socklen_t slen;
414 	char sbuf[INET6_ADDRSTRLEN];
415 	bool oblock;
416 
417 	slen = sizeof(sin);
418 	error = getsockname(s2, (struct sockaddr *)&sin, &slen);
419 	SKTC_ASSERT_ERR(!error);
420 	assert(slen <= sizeof(sin));
421 
422 	oblock = setblocking(s1, block);
423 
424 	inet_ntop(sin.sin_family, &sin.sin_addr.s_addr, sbuf, sizeof(sbuf));
425 	T_LOG("socket %d attempting to connect to %s port %d\n", s1, sbuf, ntohs(sin.sin_port));
426 
427 	error = connect(s1, (struct sockaddr *)&sin, slen);
428 	if (block) {
429 		SKTC_ASSERT_ERR(!error);
430 	} else {
431 		if (error == -1 && (errno == ENETDOWN || errno == EHOSTUNREACH)) {
432 			SKT_LOG("socket %d waiting 1 second for net to come up (errno %d)\n",
433 			    s1, errno);
434 			sleep(1);
435 			error = connect(s1, (struct sockaddr *)&sin, slen);
436 		}
437 		SKTC_ASSERT_ERR(error == -1);
438 		SKTC_ASSERT_ERR(errno == EINPROGRESS);
439 	}
440 
441 	setblocking(s1, oblock);
442 
443 	inet_ntop(AF_INET, &sin.sin_addr.s_addr, sbuf, sizeof(sbuf));
444 	T_LOG("socket %d connect%s to %s port %d\n", s1,
445 	    block ? "ed" : "ing", sbuf, ntohs(sin.sin_port));
446 }
447 
448 static int
acceptsock(int s)449 acceptsock(int s)
450 {
451 	int error;
452 	struct sockaddr_in sin;
453 	socklen_t slen;
454 	char sbuf[INET6_ADDRSTRLEN];
455 
456 	slen = sizeof(sin);
457 	error = accept(s, (struct sockaddr *)&sin, &slen);
458 	SKTC_ASSERT_ERR(error >= 0);
459 
460 	inet_ntop(AF_INET, &sin.sin_addr.s_addr, sbuf, sizeof(sbuf));
461 	T_LOG("tcp socket %d accepted connection from %s port %d\n", error, sbuf, ntohs(sin.sin_port));
462 
463 	return error;
464 }
465 
466 #if __LP64__
467 #define UDPXFER                 100000 /* 100k */
468 #define UDPLOSSOK               3000   /* 3% */
469 #define UDPXFER_MEMFAIL         30000  /* 30k */
470 #define UDPLOSSOK_MEMFAIL       9000   /* 30% */
471 #define UDPPACE                 100003 /* 100us (prime) */
472 #else
473 /* On 32 bit platforms, only try to xfer 10k slots */
474 #define UDPXFER                 10000  /* 10k */
475 #define UDPLOSSOK               300    /* 3% */
476 #define UDPXFER_MEMFAIL         3000   /* 30k */
477 #define UDPLOSSOK_MEMFAIL       900    /* 30% */
478 #define UDPPACE                 150001 /* 150us (prime) */
479 #endif
480 #define UDPSIZE 1000
481 
482 static uint32_t udpxfer;
483 static uint32_t udplossok;
484 
485 static void *
sinkudp(void * sockfd)486 sinkudp(void *sockfd)
487 {
488 	int s = *(int *)sockfd;
489 	ssize_t len;
490 	char buf[UDPSIZE];
491 	char threadname[20];
492 	int missed = 0;
493 	int readcount = 0;
494 	int i;
495 	struct timeval prevtime;
496 
497 	gettimeofday(&prevtime, NULL);
498 
499 	snprintf(threadname, sizeof(threadname), "%s%d", __func__, s);
500 	pthread_setname_np(threadname);
501 
502 	assert(udpxfer != 0);
503 
504 	for (i = 0; i < udpxfer; i++) {
505 		len = read(s, buf, sizeof(buf));
506 		VLOG("read %zd/%zd", len, sizeof(buf));
507 		if (len != sizeof(buf)) {
508 			SKT_LOG("%s read returned %zd errno %d count %d/%d\n",
509 			    threadname, len, errno, i, udpxfer);
510 			if (len == -1 && errno == EBADF) {
511 				goto out;
512 			}
513 		}
514 		readcount++;
515 		if (memcmp(buf, &i, sizeof(i))) {
516 			int tmp;
517 			memcpy(&tmp, buf, sizeof(tmp));
518 			if (tmp < i) {
519 				T_LOG("%s out of order expecting %d got %d\n",
520 				    threadname, i, tmp);
521 			}
522 			assert(tmp > i); // out of order will crash
523 			missed += tmp - i;
524 			i = tmp; // skip missing packets
525 		}
526 		assert(len == sizeof(buf));
527 	}
528 
529 out:
530 	T_LOG("%s received %d packets, missed %d, i = %d\n",
531 	    threadname, readcount, missed, i);
532 	assert(missed <= udplossok);
533 	assert(readcount >= udpxfer - udplossok);
534 
535 	return NULL;
536 }
537 
538 static void *
sourceudp(void * sockfd)539 sourceudp(void *sockfd)
540 {
541 	int s = *(int *)sockfd;
542 	ssize_t len;
543 	char buf[UDPSIZE];
544 	char threadname[20];
545 	int error;
546 	int kq;
547 	struct kevent kev;
548 	struct timeval prevtime;
549 
550 	gettimeofday(&prevtime, NULL);
551 
552 	snprintf(threadname, sizeof(threadname), "%s%d", __func__, s);
553 	pthread_setname_np(threadname);
554 
555 	kq = kqueue();
556 	EV_SET(&kev, s, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, NULL);
557 	error = kevent(kq, &kev, 1, NULL, 0, NULL);
558 	SKTC_ASSERT_ERR(!error);
559 
560 	assert(udpxfer != 0);
561 
562 	uint64_t totalloop = 0;
563 	uint32_t loops = 0;
564 	for (int i = 0; i < udpxfer; i++) {
565 		uint32_t loopcnt = 0;
566 		struct timespec ts;
567 
568 		memcpy(buf, &i, sizeof(i));
569 
570 		do {
571 			len = write(s, buf, sizeof(buf));
572 			VLOG("wrote %zd/%zd", len, sizeof(buf));
573 
574 			/* If the very first write gets ENETDOWN, wait 1 second */
575 			if (i == 0 && loopcnt == 0 &&
576 			    len == -1 && (errno == ENETDOWN || errno == EHOSTUNREACH)) {
577 				SKT_LOG("%s waiting 1 second for net to come up (errno %d)\n",
578 				    threadname, errno);
579 				sleep(1);
580 				len = write(s, buf, sizeof(buf));
581 				VLOG("wrote %zd/%zd", len, sizeof(buf));
582 			}
583 
584 			/* Wait for buffers to be available */
585 			if (len == -1 && errno == ENOBUFS) {
586 				loopcnt++;
587 				//T_LOG("%s waiting in kevent for buffers\n", threadname);
588 				error = kevent(kq, NULL, 0, &kev, 1, NULL);
589 				SKTC_ASSERT_ERR(error == 1);
590 				assert(kev.filter == EVFILT_WRITE);
591 				assert(kev.ident == s);
592 				assert(kev.udata == NULL);
593 				assert((kev.flags & EV_ERROR) == 0);
594 			} else {
595 				if (len != sizeof(buf)) {
596 					SKT_LOG("%s write returned %zd errno %d count %d/%d\n",
597 					    threadname, len, errno, i, udpxfer);
598 				}
599 				assert(len == sizeof(buf));
600 			}
601 
602 			if (loopcnt > 1) {
603 				/* if we got ENOBUFS more than once, then sleep
604 				 * to avoid tight looping on write
605 				 */
606 				ts.tv_sec = 0;
607 				ts.tv_nsec = 1000003; // 1ms (prime)
608 				nanosleep(&ts, NULL);
609 			} else {
610 				ts.tv_sec = 0;
611 				ts.tv_nsec = UDPPACE;
612 				nanosleep(&ts, NULL);
613 			}
614 
615 			/* If we're starved for a full five seconds, crash */
616 			if (loopcnt >= 5000) {
617 				T_LOG("loopcount %d\n", loopcnt);
618 			}
619 			assert(loopcnt < 5000);
620 		} while (len != sizeof(buf));
621 
622 		/* Ideally we wouldn't get ENOBUFS immediately after getting
623 		 * a writable kevent.  However, these are coming from nx_netif_host
624 		 * when ms_classq_mbuf_to_kpkt can't allocate a packet.  In this
625 		 * case, flow control doesn't apply, so just tally the occurances.
626 		 */
627 		if (loopcnt > 1) {
628 			loops++;
629 			totalloop += loopcnt - 1;
630 			//T_LOG("%s spun in kevent %d times\n", threadname, loopcnt);
631 		}
632 	}
633 
634 	error = close(kq);
635 	SKTC_ASSERT_ERR(!error);
636 
637 	T_LOG("%s wrote %d packets, looped %u times (avg %f) exiting\n",
638 	    threadname, udpxfer, loops, (double)totalloop / loops);
639 
640 	return NULL;
641 }
642 
643 #if __LP64__
644 #define TCPXFER         100000000 /* 100mb */
645 #define TCPXFER_MEMFAIL 5000000   /* 5mb */
646 #else
647 #define TCPXFER         10000000  /* 10mb */
648 #define TCPXFER_MEMFAIL 500000    /* 0.5mb */
649 #endif
650 
651 static uint32_t tcpxfer;
652 
653 static void *
sinktcp(void * sockfd)654 sinktcp(void *sockfd)
655 {
656 	int s = *(int *)sockfd;
657 	ssize_t len;
658 	char *buf;
659 	int buflen;
660 	socklen_t optlen;
661 	char threadname[20];
662 	int error;
663 	size_t nxfer;
664 	struct timeval prevtime;
665 
666 	gettimeofday(&prevtime, NULL);
667 
668 	snprintf(threadname, sizeof(threadname), "%s%d", __func__, s);
669 	pthread_setname_np(threadname);
670 
671 	optlen = sizeof(buflen);
672 	error = getsockopt(s, SOL_SOCKET, SO_RCVBUF, &buflen, &optlen);
673 	SKTC_ASSERT_ERR(!error);
674 
675 	T_LOG("%s fd %d rcvbuf size %d\n", threadname, s, buflen);
676 
677 	buf = calloc(buflen, 1);
678 	assert(buf);
679 
680 	assert(tcpxfer != 0);
681 
682 	nxfer = 0;
683 	while (nxfer < tcpxfer) {
684 		size_t thisxfer = MIN(tcpxfer - nxfer, buflen);
685 		len = read(s, buf, thisxfer);
686 		VLOG("read %zd/%zd", len, thisxfer);
687 		//T_LOG("%s fd %d read of %zu returned %zd\n", threadname, s, thisxfer, len);
688 		error = len;
689 		SKTC_ASSERT_ERR(error != -1);
690 		SKTC_ASSERT_ERR(error > 0);
691 		SKTC_ASSERT_ERR(error <= thisxfer);
692 		nxfer += len;
693 	}
694 
695 	assert(nxfer == tcpxfer);
696 
697 	free(buf);
698 
699 	T_LOG("%s read %zu bytes exiting\n",
700 	    threadname, nxfer);
701 
702 	return NULL;
703 }
704 
705 
706 static void *
sourcetcp(void * sockfd)707 sourcetcp(void *sockfd)
708 {
709 	int s = *(int *)sockfd;
710 	ssize_t len;
711 	char *buf;
712 	int buflen;
713 	socklen_t optlen;
714 	char threadname[20];
715 	int error;
716 	size_t nxfer;
717 	struct timeval prevtime;
718 
719 	gettimeofday(&prevtime, NULL);
720 
721 	snprintf(threadname, sizeof(threadname), "%s%d", __func__, s);
722 	pthread_setname_np(threadname);
723 
724 	optlen = sizeof(buflen);
725 	error = getsockopt(s, SOL_SOCKET, SO_SNDBUF, &buflen, &optlen);
726 	SKTC_ASSERT_ERR(!error);
727 
728 	T_LOG("%s fd %d sndbuf size %d\n", threadname, s, buflen);
729 
730 	buf = calloc(buflen, 1);
731 	assert(buf);
732 
733 	assert(tcpxfer != 0);
734 
735 	nxfer = 0;
736 	while (nxfer < tcpxfer) {
737 		size_t thisxfer = MIN(tcpxfer - nxfer, buflen);
738 		len = write(s, buf, thisxfer);
739 		VLOG("wrote %zd/%zd", len, thisxfer);
740 
741 		/* If the very first write gets ENETDOWN, wait 1 second */
742 		if (nxfer == 0 && len == -1 &&
743 		    (errno == ENETDOWN || errno == EHOSTUNREACH)) {
744 			SKT_LOG("%s waiting 1 second for net to come up (errno %d)\n",
745 			    threadname, errno);
746 			sleep(1);
747 			len = write(s, buf, thisxfer);
748 			VLOG("wrote %zd/%zd", len, thisxfer);
749 		}
750 
751 		//T_LOG("%s fd %d write of %zu returned %zd\n", threadname, s, thisxfer, len);
752 		error = len;
753 		SKTC_ASSERT_ERR(error == thisxfer);
754 		nxfer += len;
755 	}
756 
757 	assert(nxfer == tcpxfer);
758 
759 	free(buf);
760 
761 	T_LOG("%s wrote %zu bytes exiting\n",
762 	    threadname, nxfer);
763 
764 	return NULL;
765 }
766 
767 static void
dotraffic(void * (* sourcefunc)(void *),void * (* sinkfunc)(void *),int sourcesock1,int sinksock2,int sourcesock2,int sinksock1)768 dotraffic(void *(*sourcefunc)(void *), void *(*sinkfunc)(void *),
769     int sourcesock1, int sinksock2, int sourcesock2, int sinksock1)
770 {
771 	int error;
772 	pthread_t sinkthread1, sinkthread2;
773 	pthread_t sourcethread1, sourcethread2;
774 
775 	assert(sourcesock1 != -1);
776 	assert(sinksock2 != -1);
777 	assert((sourcesock2 == -1) == (sinksock1 == -1));
778 
779 	if (sinksock1 != -1) {
780 		error = pthread_create(&sinkthread1, NULL, sinkfunc, &sinksock1);
781 		SKTC_ASSERT_ERR(!error);
782 	}
783 	error = pthread_create(&sinkthread2, NULL, sinkfunc, &sinksock2);
784 	SKTC_ASSERT_ERR(!error);
785 	error = pthread_create(&sourcethread1, NULL, sourcefunc, &sourcesock1);
786 	SKTC_ASSERT_ERR(!error);
787 	if (sourcesock2 != -1) {
788 		T_LOG("waiting 1 second before starting reverse traffic\n");
789 		sleep(1);
790 		error = pthread_create(&sourcethread2, NULL, sourcefunc, &sourcesock2);
791 		SKTC_ASSERT_ERR(!error);
792 	}
793 
794 	/* Wait for all data to be sent */
795 	error = pthread_join(sourcethread1, NULL);
796 	SKTC_ASSERT_ERR(!error);
797 	if (sourcesock2 != -1) {
798 		error = pthread_join(sourcethread2, NULL);
799 		SKTC_ASSERT_ERR(!error);
800 	}
801 
802 	/* Give it 1 second to drain */
803 	T_LOG("waiting 1 second for reads to drain\n");
804 	sleep(1);
805 
806 	/* Force the reads to exit by closing sockets */
807 	if (sinksock1 != -1) {
808 		T_LOG("closing sinksock1 %d\n", sinksock1);
809 		error = close(sinksock1);
810 		SKTC_ASSERT_ERR(!error);
811 	}
812 	T_LOG("closing sinksock2 %d\n", sinksock2);
813 	error = close(sinksock2);
814 	SKTC_ASSERT_ERR(!error);
815 
816 	if (sinksock1 != -1) {
817 		error = pthread_join(sinkthread1, NULL);
818 		SKTC_ASSERT_ERR(!error);
819 	}
820 	error = pthread_join(sinkthread2, NULL);
821 	SKTC_ASSERT_ERR(!error);
822 
823 	if (sourcesock1 != sinksock1) {
824 		T_LOG("closing sourcesock1 %d\n", sourcesock1);
825 		error = close(sourcesock1);
826 		SKTC_ASSERT_ERR(!error);
827 	}
828 	if (sourcesock2 != sinksock2 && sourcesock2 != -1) {
829 		T_LOG("closing sourcesock2 %d\n", sourcesock2);
830 		error = close(sourcesock2);
831 		SKTC_ASSERT_ERR(!error);
832 	}
833 }
834 
835 
836 static void
skt_tunloop_common(bool doutun,bool enable_netif,bool udp,bool udpduplex,bool tcp,bool tcpduplex,bool dualstream)837 skt_tunloop_common(bool doutun, bool enable_netif, bool udp, bool udpduplex, bool tcp, bool tcpduplex, bool dualstream)
838 {
839 	int error;
840 	int utun1, utun2;
841 	char ifname1[IFNAMSIZ];
842 	char ifname2[IFNAMSIZ];
843 	pthread_t thread1, thread2;
844 	struct kevent kev;
845 	uint32_t memfail = 0;
846 	size_t len;
847 	int keysock;
848 
849 	len = sizeof(memfail);
850 	if (sysctlbyname("kern.skywalk.mem.region_mtbf", &memfail, &len,
851 	    NULL, 0) != 0) {
852 		SKT_LOG("warning got errno %d getting "
853 		    "kern.skywalk.mem.region_mtbf: %s\n", errno,
854 		    strerror(errno));
855 	}
856 
857 	if (memfail) {
858 		udpxfer = UDPXFER_MEMFAIL;
859 		udplossok = UDPLOSSOK_MEMFAIL;
860 		tcpxfer = TCPXFER_MEMFAIL;
861 	} else {
862 		udpxfer = UDPXFER;
863 		udplossok = UDPLOSSOK;
864 		tcpxfer = TCPXFER;
865 	}
866 
867 	g_dumpfile = fopen(getenv("SKT_UTUNLOOP_DUMPFILE"), "w");
868 	if (g_dumpfile) {
869 		g_verbose = 1;
870 	}
871 
872 	sktu_if_type_t type = doutun ? SKTU_IFT_UTUN : SKTU_IFT_IPSEC;
873 	sktu_if_flag_t flags = enable_netif ? SKTU_IFF_ENABLE_NETIF : 0;
874 	utun1 = sktu_create_interface(type, flags);
875 	utun2 = sktu_create_interface(type, flags);
876 
877 	sktu_get_interface_name(type, utun1, ifname1);
878 	sktu_get_interface_name(type, utun2, ifname2);
879 	snprintf(debugcmd, sizeof(debugcmd), "netstat -qq -I %s > netstatqq.%s.txt; netstat -qq -I %s > netstatqq.%s.txt; skywalkctl netstat --flowswitch --netif > skywalkctl.txt",
880 	    ifname1, ifname1, ifname2, ifname2);
881 
882 	uint32_t utun1addr = (10 << 24) | (getpid() & 0xffff) << 8 | 150;
883 	uint32_t utun2addr = utun1addr + 1;
884 
885 	struct in_addr addr1, addr2, mask;
886 	mask  = sktc_make_in_addr(0xffffffff);
887 	addr1 = sktc_make_in_addr(utun1addr);
888 	addr2 = sktc_make_in_addr(utun2addr);
889 
890 	error = sktc_ifnet_add_addr(ifname1, &addr1, &mask, &addr2);
891 	SKTC_ASSERT_ERR(!error);
892 	error = sktc_ifnet_add_addr(ifname2, &addr2, &mask, &addr1);
893 	SKTC_ASSERT_ERR(!error);
894 
895 	if (!doutun) {
896 		keysock = sktu_create_pfkeysock();
897 		sktu_create_sa(keysock, ifname1, 12345, &addr1, &addr2);
898 		sktu_create_sa(keysock, ifname1, 12346, &addr2, &addr1);
899 		sktu_create_sa(keysock, ifname2, 12345, &addr2, &addr1);
900 		sktu_create_sa(keysock, ifname2, 12346, &addr1, &addr2);
901 	}
902 
903 	g_channel1 = sktu_create_interface_channel(type, utun1);
904 	g_channel2 = sktu_create_interface_channel(type, utun2);
905 
906 	T_LOG("Created %s and %s\n", ifname1, ifname2);
907 
908 	g_kq1 = kqueue();
909 	EV_SET(&kev, (uintptr_t)&g_die, EVFILT_USER,
910 	    EV_ADD | EV_ENABLE, 0, 0, NULL);
911 	error = kevent(g_kq1, &kev, 1, NULL, 0, NULL);
912 	SKTC_ASSERT_ERR(!error);
913 
914 	g_kq2 = kqueue();
915 	EV_SET(&kev, (uintptr_t)&g_die, EVFILT_USER,
916 	    EV_ADD | EV_ENABLE, 0, 0, NULL);
917 	error = kevent(g_kq2, &kev, 1, NULL, 0, NULL);
918 	SKTC_ASSERT_ERR(!error);
919 
920 //	T_LOG("Sleeping 10 seconds at startup\n");
921 //	sleep(10);
922 
923 	error = pthread_create(&thread1, NULL, sktc_channel_worker_xfer12, NULL);
924 	SKTC_ASSERT_ERR(!error);
925 	error = pthread_create(&thread2, NULL, sktc_channel_worker_xfer21, NULL);
926 	SKTC_ASSERT_ERR(!error);
927 
928 	if (udp) {
929 		int usock1, usock2;
930 		usock1 = makesocket(SOCK_DGRAM, utun1addr);
931 		usock2 = makesocket(SOCK_DGRAM, utun2addr);
932 		connectsocks(usock1, usock2, true);
933 		connectsocks(usock2, usock1, true);
934 		if (udpduplex) {
935 			if (dualstream) {
936 				int usock3, usock4;
937 				usock3 = makesocket(SOCK_DGRAM, utun2addr);
938 				usock4 = makesocket(SOCK_DGRAM, utun1addr);
939 				connectsocks(usock3, usock4, true);
940 				connectsocks(usock4, usock3, true);
941 				dotraffic(sourceudp, sinkudp, usock1, usock2, usock3, usock4);
942 			} else {
943 				dotraffic(sourceudp, sinkudp, usock1, usock2, usock2, usock1);
944 			}
945 		} else {
946 			dotraffic(sourceudp, sinkudp, usock1, usock2, -1, -1);
947 		}
948 	}
949 
950 	if (tcp) {
951 		int tsock1, tsock2, lsock; // listening socket
952 		tsock1 = makesocket(SOCK_STREAM, utun1addr);
953 		lsock = makesocket(SOCK_STREAM, utun2addr);
954 		error = listen(lsock, 1);
955 		SKTC_ASSERT_ERR(!error);
956 		connectsocks(tsock1, lsock, false);
957 		tsock2 = acceptsock(lsock);
958 		error = close(lsock);
959 		SKTC_ASSERT_ERR(!error);
960 		if (tcpduplex) {
961 			if (dualstream) {
962 				int tsock3, tsock4;
963 				tsock3 = makesocket(SOCK_STREAM, utun2addr);
964 				lsock = makesocket(SOCK_STREAM, utun1addr);
965 				error = listen(lsock, 1);
966 				SKTC_ASSERT_ERR(!error);
967 				connectsocks(tsock3, lsock, false);
968 				tsock4 = acceptsock(lsock);
969 				error = close(lsock);
970 				SKTC_ASSERT_ERR(!error);
971 				dotraffic(sourcetcp, sinktcp, tsock1, tsock2, tsock3, tsock4);
972 			} else {
973 				dotraffic(sourcetcp, sinktcp, tsock1, tsock2, tsock2, tsock1);
974 			}
975 		} else {
976 			dotraffic(sourcetcp, sinktcp, tsock1, tsock2, -1, -1);
977 		}
978 	}
979 
980 	/* This can be useful for just setting up two utuns */
981 	if (!udp && !tcp) {
982 		sleep(1000);
983 	}
984 
985 	/* Tell utun threads to exit */
986 	g_die = true;
987 	EV_SET(&kev, (uintptr_t)&g_die, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
988 	error = kevent(g_kq1, &kev, 1, NULL, 0, NULL);
989 	SKTC_ASSERT_ERR(!error);
990 	EV_SET(&kev, (uintptr_t)&g_die, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
991 	error = kevent(g_kq2, &kev, 1, NULL, 0, NULL);
992 	SKTC_ASSERT_ERR(!error);
993 
994 	error = pthread_join(thread1, NULL);
995 	SKTC_ASSERT_ERR(!error);
996 	error = pthread_join(thread2, NULL);
997 	SKTC_ASSERT_ERR(!error);
998 
999 	os_channel_destroy(g_channel1);
1000 	os_channel_destroy(g_channel2);
1001 
1002 	if (!doutun) {
1003 		error = close(keysock);
1004 		SKTC_ASSERT_ERR(!error);
1005 	}
1006 	error = close(utun1);
1007 	SKTC_ASSERT_ERR(!error);
1008 	error = close(utun2);
1009 	SKTC_ASSERT_ERR(!error);
1010 }
1011 
1012 /****************************************************************/
1013 
1014 static int
skt_utunloopn4u1_main(int argc,char * argv[])1015 skt_utunloopn4u1_main(int argc, char *argv[])
1016 {
1017 	g_assert_stalls12 = true;
1018 	skt_tunloop_common(true, false, true, false, false, false, false);
1019 	return 0;
1020 }
1021 
1022 static int
skt_utunloopn4u2_main(int argc,char * argv[])1023 skt_utunloopn4u2_main(int argc, char *argv[])
1024 {
1025 	g_assert_stalls12 = true;
1026 	g_assert_stalls21 = true;
1027 	skt_tunloop_common(true, false, true, true, false, false, false);
1028 	return 0;
1029 }
1030 
1031 static int
skt_utunloopn4t1_main(int argc,char * argv[])1032 skt_utunloopn4t1_main(int argc, char *argv[])
1033 {
1034 	g_assert_stalls12 = true;
1035 	skt_tunloop_common(true, false, false, false, true, false, false);
1036 	return 0;
1037 }
1038 
1039 static int
skt_utunloopn4t2_main(int argc,char * argv[])1040 skt_utunloopn4t2_main(int argc, char *argv[])
1041 {
1042 	g_assert_stalls12 = true;
1043 	g_assert_stalls21 = true;
1044 	skt_tunloop_common(true, false, false, false, true, true, false);
1045 	return 0;
1046 }
1047 
1048 static int
skt_utunloopy4u1_main(int argc,char * argv[])1049 skt_utunloopy4u1_main(int argc, char *argv[])
1050 {
1051 	g_assert_stalls12 = true;
1052 	skt_tunloop_common(true, true, true, false, false, false, false);
1053 	return 0;
1054 }
1055 
1056 static int
skt_utunloopy4u2_main(int argc,char * argv[])1057 skt_utunloopy4u2_main(int argc, char *argv[])
1058 {
1059 	g_assert_stalls12 = true;
1060 	g_assert_stalls21 = true;
1061 	skt_tunloop_common(true, true, true, true, false, false, false);
1062 	return 0;
1063 }
1064 
1065 static int
skt_utunloopy4t1_main(int argc,char * argv[])1066 skt_utunloopy4t1_main(int argc, char *argv[])
1067 {
1068 	g_assert_stalls12 = true;
1069 	skt_tunloop_common(true, true, false, false, true, false, false);
1070 	return 0;
1071 }
1072 
1073 static int
skt_utunloopy4t2_main(int argc,char * argv[])1074 skt_utunloopy4t2_main(int argc, char *argv[])
1075 {
1076 	g_assert_stalls12 = true;
1077 	g_assert_stalls21 = true;
1078 	skt_tunloop_common(true, true, false, false, true, true, false);
1079 	return 0;
1080 }
1081 
1082 static int
skt_utunloopn1000_main(int argc,char * argv[])1083 skt_utunloopn1000_main(int argc, char *argv[])
1084 {
1085 	skt_tunloop_common(true, false, false, false, false, false, false);
1086 	return 0;
1087 }
1088 
1089 static int
skt_utunloopy1000_main(int argc,char * argv[])1090 skt_utunloopy1000_main(int argc, char *argv[])
1091 {
1092 	skt_tunloop_common(true, true, false, false, false, false, false);
1093 	return 0;
1094 }
1095 
1096 struct skywalk_test skt_utunloopn4u1 = {
1097 	"utunloopn4u1", "open 2 utuns without netif and floods ipv4 udp packets in one direction",
1098 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE,
1099 	skt_utunloopn4u1_main,
1100 };
1101 
1102 struct skywalk_test skt_utunloopn4u2 = {
1103 	"utunloopn4u2", "open 2 utuns without netif and floods ipv4 udp packets in two directions",
1104 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE,
1105 	skt_utunloopn4u2_main,
1106 };
1107 
1108 struct skywalk_test skt_utunloopn4t1 = {
1109 	"utunloopn4t1", "open 2 utuns without netif and floods ipv4 tcp packets in one direction",
1110 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE,
1111 	skt_utunloopn4t1_main,
1112 };
1113 
1114 struct skywalk_test skt_utunloopn4t2 = {
1115 	"utunloopn4t2", "open 2 utuns without netif and floods ipv4 tcp packets in two directions",
1116 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE,
1117 	skt_utunloopn4t2_main,
1118 };
1119 
1120 struct skywalk_test skt_utunloopy4u1 = {
1121 	"utunloopy4u1", "open 2 utuns with netif and floods ipv4 udp packets in one direction",
1122 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE,
1123 	skt_utunloopy4u1_main,
1124 };
1125 
1126 struct skywalk_test skt_utunloopy4u2 = {
1127 	"utunloopy4u2", "open 2 utuns with netif and floods ipv4 udp packets in two directions",
1128 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE,
1129 	skt_utunloopy4u2_main,
1130 };
1131 
1132 struct skywalk_test skt_utunloopy4t1 = {
1133 	"utunloopy4t1", "open 2 utuns with netif and floods ipv4 tcp packets in one direction",
1134 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE,
1135 	skt_utunloopy4t1_main,
1136 };
1137 
1138 struct skywalk_test skt_utunloopy4t2 = {
1139 	"utunloopy4t2", "open 2 utuns with netif and floods ipv4 tcp packets in two directions",
1140 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE,
1141 	skt_utunloopy4t2_main,
1142 };
1143 
1144 struct skywalk_test skt_utunloopn1000 = {
1145 	"utunloopn1000", "open 2 utuns without netif and sleeps for 1000 seconds",
1146 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE,
1147 	skt_utunloopn1000_main,
1148 };
1149 
1150 struct skywalk_test skt_utunloopy1000 = {
1151 	"utunloopy1000", "open 2 utuns with netif and sleeps for 1000 seconds",
1152 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE,
1153 	skt_utunloopy1000_main,
1154 };
1155 
1156 /****************************************************************/
1157 
1158 static int
skt_ipsecloopy4u1_main(int argc,char * argv[])1159 skt_ipsecloopy4u1_main(int argc, char *argv[])
1160 {
1161 	g_assert_stalls12 = true;
1162 	skt_tunloop_common(false, true, true, false, false, false, false);
1163 	return 0;
1164 }
1165 
1166 static int
skt_ipsecloopy4u2_main(int argc,char * argv[])1167 skt_ipsecloopy4u2_main(int argc, char *argv[])
1168 {
1169 	g_assert_stalls12 = true;
1170 	g_assert_stalls21 = true;
1171 	skt_tunloop_common(false, true, true, true, false, false, false);
1172 	return 0;
1173 }
1174 
1175 static int
skt_ipsecloopy4t1_main(int argc,char * argv[])1176 skt_ipsecloopy4t1_main(int argc, char *argv[])
1177 {
1178 	g_assert_stalls12 = true;
1179 	skt_tunloop_common(false, true, false, false, true, false, false);
1180 	return 0;
1181 }
1182 
1183 static int
skt_ipsecloopy4t2_main(int argc,char * argv[])1184 skt_ipsecloopy4t2_main(int argc, char *argv[])
1185 {
1186 	g_assert_stalls12 = true;
1187 	g_assert_stalls21 = true;
1188 	skt_tunloop_common(false, true, false, false, true, true, false);
1189 	return 0;
1190 }
1191 
1192 static int
skt_ipsecloopy1000_main(int argc,char * argv[])1193 skt_ipsecloopy1000_main(int argc, char *argv[])
1194 {
1195 	skt_tunloop_common(false, true, false, false, false, false, false);
1196 	return 0;
1197 }
1198 
1199 struct skywalk_test skt_ipsecloopy4u1 = {
1200 	"ipsecloopy4u1", "open 2 ipsecs with netif and floods ipv4 udp packets in one direction",
1201 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE,
1202 	skt_ipsecloopy4u1_main,
1203 };
1204 
1205 struct skywalk_test skt_ipsecloopy4u2 = {
1206 	"ipsecloopy4u2", "open 2 ipsecs with netif and floods ipv4 udp packets in two directions",
1207 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE,
1208 	skt_ipsecloopy4u2_main,
1209 };
1210 
1211 struct skywalk_test skt_ipsecloopy4t1 = {
1212 	"ipsecloopy4t1", "open 2 ipsecs with netif and floods ipv4 tcp packets in one direction",
1213 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE,
1214 	skt_ipsecloopy4t1_main,
1215 };
1216 
1217 struct skywalk_test skt_ipsecloopy4t2 = {
1218 	"ipsecloopy4t2", "open 2 ipsecs with netif and floods ipv4 tcp packets in two directions",
1219 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE,
1220 	skt_ipsecloopy4t2_main,
1221 };
1222 
1223 struct skywalk_test skt_ipsecloopy1000 = {
1224 	"ipsecloopy1000", "open 2 ipsecs with netif and sleeps for 1000 seconds",
1225 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE,
1226 	skt_ipsecloopy1000_main,
1227 };
1228 
1229 /****************************************************************/
1230