xref: /xnu-11215.81.4/tests/skywalk/skt_manyflows.c (revision d4514f0bc1d3f944c22d92e68b646ac3fb40d452)
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  * Try to create many flows on many ports, part of:
31  * <rdar://problem/29003665> need to control skywalk behavior at limit of too many flows
32  */
33 
34 #include <assert.h>
35 #include <errno.h>
36 #include <stdio.h>
37 #include <spawn.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <sys/types.h>
42 #include <sys/sysctl.h>
43 #include <darwintest.h>
44 #include "skywalk_test_driver.h"
45 #include "skywalk_test_utils.h"
46 #include "skywalk_test_common.h"
47 
48 static void
do_flows(nexus_controller_t ncd,const uuid_t fsw,nexus_port_t nx_port_start,int nports,int nflows_per_port,uuid_t flows[])49 do_flows(nexus_controller_t ncd, const uuid_t fsw, nexus_port_t nx_port_start, int nports, int nflows_per_port, uuid_t flows[])
50 {
51 	for (int i = 0; i < nports; i++) {
52 		for (int j = 0; j < nflows_per_port; j++) {
53 			int error;
54 			uuid_generate_random(flows[i * nflows_per_port + j]);
55 
56 			error = sktc_bind_tcp4_flow(ncd, fsw, 0, nx_port_start + i, flows[i * nflows_per_port + j]);
57 			SKTC_ASSERT_ERR(!error); // XXX some of these are expected
58 		}
59 	}
60 }
61 
62 static void
undo_flows(nexus_controller_t ncd,const uuid_t fsw,int nflows,const uuid_t flows[])63 undo_flows(nexus_controller_t ncd, const uuid_t fsw, int nflows, const uuid_t flows[])
64 {
65 	for (int i = 0; i < nflows; i++) {
66 		int error;
67 		uuid_string_t uuidstr;
68 		uuid_unparse_upper(flows[i], uuidstr);
69 		//T_LOG("Destroying flow %s\n", uuidstr);
70 		error = sktc_unbind_flow(ncd, fsw, flows[i]);
71 		SKTC_ASSERT_ERR(!error);
72 	}
73 }
74 
75 static int
skt_manyflows_common(int nports,int nflows_per_port)76 skt_manyflows_common(int nports, int nflows_per_port)
77 {
78 	struct sktc_nexus_handles handles;
79 	sktc_create_flowswitch(&handles, 0);
80 
81 	uuid_t flows[nports * nflows_per_port];
82 
83 	do_flows(handles.controller, handles.fsw_nx_uuid, NEXUS_PORT_FLOW_SWITCH_CLIENT, nports, nflows_per_port, flows);
84 	undo_flows(handles.controller, handles.fsw_nx_uuid, sizeof(flows) / sizeof(flows[0]), flows);
85 
86 	sktc_cleanup_flowswitch(&handles);
87 
88 	return 0;
89 }
90 
91 static int
skt_mf10x10_main(int argc,char * argv[])92 skt_mf10x10_main(int argc, char *argv[])
93 {
94 	return skt_manyflows_common(10, 10);
95 }
96 
97 static int
skt_mf10x100_main(int argc,char * argv[])98 skt_mf10x100_main(int argc, char *argv[])
99 {
100 	return skt_manyflows_common(10, 100);
101 }
102 
103 static int
skt_mf100x10_main(int argc,char * argv[])104 skt_mf100x10_main(int argc, char *argv[])
105 {
106 	return skt_manyflows_common(100, 10);
107 }
108 
109 static int
skt_mf100x100_main(int argc,char * argv[])110 skt_mf100x100_main(int argc, char *argv[])
111 {
112 	return skt_manyflows_common(100, 100);
113 }
114 
115 struct skywalk_test skt_mf10x10 = {
116 	"mf10x10", "test binds 10 ports with 10 flows per port",
117 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF | SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
118 	skt_mf10x10_main, { NULL }, sktc_ifnet_feth0_create, sktc_ifnet_feth0_destroy,
119 };
120 
121 struct skywalk_test skt_mf10x100 = {
122 	"mf10x100", "test binds 10 ports with 100 flows per port",
123 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF | SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
124 	skt_mf10x100_main, { NULL }, sktc_ifnet_feth0_create, sktc_ifnet_feth0_destroy,
125 };
126 
127 struct skywalk_test skt_mf100x10 = {
128 	"mf100x10", "test binds 100 ports with 10 flows per port",
129 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF | SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
130 	skt_mf100x10_main, { NULL }, sktc_ifnet_feth0_create, sktc_ifnet_feth0_destroy,
131 };
132 
133 struct skywalk_test skt_mf100x100 = {
134 	"mf100x100", "test binds 100 ports with 100 flows per port",
135 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF | SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
136 	skt_mf100x100_main, { NULL }, sktc_ifnet_feth0_create, sktc_ifnet_feth0_destroy,
137 };
138 
139 /****************************************************************/
140 
141 static int
skt_mf1xall_common(bool stop_on_error)142 skt_mf1xall_common(bool stop_on_error)
143 {
144 	int error;
145 	int first, last;
146 	size_t size;
147 	int i, nports, count;
148 
149 	size = sizeof(first);
150 	error = sysctlbyname("net.inet.ip.portrange.first", &first, &size, NULL, 0);
151 	SKTC_ASSERT_ERR(!error);
152 	assert(size == sizeof(first));
153 
154 	size = sizeof(last);
155 	error = sysctlbyname("net.inet.ip.portrange.last", &last, &size, NULL, 0);
156 	SKTC_ASSERT_ERR(!error);
157 	assert(size == sizeof(last));
158 
159 	if (last < first) {
160 		nports = first - last + 1;
161 	} else {
162 		nports = last - first + 1;
163 	}
164 
165 	/* Check that there are at least 512 ephemeral ports in the range
166 	 * so that we can fill up our flows
167 	 */
168 	assert(nports >= 512);
169 
170 	struct sktc_nexus_handles handles;
171 	sktc_create_flowswitch(&handles, 0);
172 
173 	uuid_t flows[nports];
174 	uuid_t extraflow;
175 
176 	count = 0;
177 	/* Bind all the ephemeral ports */
178 	for (i = 0; i < nports; i++) {
179 		uuid_generate_random(flows[i]);
180 		error = sktc_bind_tcp4_flow(handles.controller, handles.fsw_nx_uuid,
181 		    0, NEXUS_PORT_FLOW_SWITCH_CLIENT, flows[i]);
182 		if (error) {
183 			/* flow_entry_alloc currently returns ENOMEM
184 			 * flow_namespace_create returns EADDRNOTAVAIL
185 			 */
186 			SKTC_ASSERT_ERR(errno == ENOMEM);
187 			uuid_clear(flows[i]);
188 			if (stop_on_error) {
189 				break;
190 			}
191 		} else {
192 			count++;
193 		}
194 	}
195 
196 	T_LOG("bound %d flows out of %d\n", count, nports);
197 
198 	assert(count == 512); /* The default number of flows is currently 512 */
199 
200 	T_LOG("try one more and verify it fails\n");
201 	/* Now try one more and verify it fails */
202 	uuid_generate_random(extraflow);
203 	error = sktc_bind_tcp4_flow(handles.controller, handles.fsw_nx_uuid,
204 	    0, NEXUS_PORT_FLOW_SWITCH_CLIENT, extraflow);
205 	SKTC_ASSERT_ERR(error == -1);
206 	SKTC_ASSERT_ERR(errno == ENOMEM);
207 	uuid_clear(extraflow);
208 
209 	/* Unbind all the flows */
210 	for (i = 0; i < nports; i++) {
211 		if (!uuid_is_null(flows[i])) {
212 			error = sktc_unbind_flow(handles.controller, handles.fsw_nx_uuid, flows[i]);
213 			SKTC_ASSERT_ERR(!error);
214 		}
215 	}
216 
217 	sktc_cleanup_flowswitch(&handles);
218 
219 	return 0;
220 }
221 
222 int
skt_mf1xall_main(int argc,char * argv[])223 skt_mf1xall_main(int argc, char *argv[])
224 {
225 	return skt_mf1xall_common(true);
226 }
227 
228 int
skt_mf1xallslow_main(int argc,char * argv[])229 skt_mf1xallslow_main(int argc, char *argv[])
230 {
231 	return skt_mf1xall_common(false);
232 }
233 
234 
235 struct skywalk_test skt_mf1xall = {
236 	"mf1xall", "test binds all the ephemeral port flows on a single port until it hits failure",
237 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF | SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
238 	skt_mf1xall_main, { NULL }, sktc_ifnet_feth0_create, sktc_ifnet_feth0_destroy,
239 };
240 
241 struct skywalk_test skt_mf1xallslow = {
242 	"mf1xallslow", "test binds all the ephemeral port flows on a single port ",
243 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF | SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
244 	skt_mf1xallslow_main, { NULL }, sktc_ifnet_feth0_create, sktc_ifnet_feth0_destroy,
245 };
246 
247 /****************************************************************/
248 
249 uuid_t mcflows[100 * 100];
250 struct sktc_nexus_handles mchandles;
251 
252 static uuid_string_t fsw_uuid_string;
253 
254 static void
skt_mc10x10_init(void)255 skt_mc10x10_init(void)
256 {
257 	sktc_ifnet_feth0_create();
258 	sktc_create_flowswitch(&mchandles, 0);
259 	do_flows(mchandles.controller, mchandles.fsw_nx_uuid, NEXUS_PORT_FLOW_SWITCH_CLIENT, 10, 10, mcflows);
260 	uuid_unparse(mchandles.fsw_nx_uuid, fsw_uuid_string);
261 }
262 
263 static void
skt_mc10x100_init(void)264 skt_mc10x100_init(void)
265 {
266 	sktc_ifnet_feth0_create();
267 	sktc_create_flowswitch(&mchandles, 0);
268 	do_flows(mchandles.controller, mchandles.fsw_nx_uuid, NEXUS_PORT_FLOW_SWITCH_CLIENT, 10, 100, mcflows);
269 	uuid_unparse(mchandles.fsw_nx_uuid, fsw_uuid_string);
270 }
271 
272 static void
skt_mc100x10_init(void)273 skt_mc100x10_init(void)
274 {
275 	sktc_ifnet_feth0_create();
276 	sktc_create_flowswitch(&mchandles, 0);
277 	do_flows(mchandles.controller, mchandles.fsw_nx_uuid, NEXUS_PORT_FLOW_SWITCH_CLIENT, 100, 10, mcflows);
278 	uuid_unparse(mchandles.fsw_nx_uuid, fsw_uuid_string);
279 }
280 
281 static void
skt_mc100x100_init(void)282 skt_mc100x100_init(void)
283 {
284 	sktc_ifnet_feth0_create();
285 	sktc_create_flowswitch(&mchandles, 0);
286 	do_flows(mchandles.controller, mchandles.fsw_nx_uuid, NEXUS_PORT_FLOW_SWITCH_CLIENT, 100, 100, mcflows);
287 	uuid_unparse(mchandles.fsw_nx_uuid, fsw_uuid_string);
288 }
289 
290 static void
skt_mc100_fini(void)291 skt_mc100_fini(void)
292 {
293 	undo_flows(mchandles.controller, mchandles.fsw_nx_uuid, 100, mcflows);
294 	sktc_cleanup_flowswitch(&mchandles);
295 	sktc_ifnet_feth0_destroy();
296 }
297 
298 static void
skt_mc1000_fini(void)299 skt_mc1000_fini(void)
300 {
301 	undo_flows(mchandles.controller, mchandles.fsw_nx_uuid, 10 * 100, mcflows);
302 	sktc_cleanup_flowswitch(&mchandles);
303 	sktc_ifnet_feth0_destroy();
304 }
305 
306 static void
skt_mc10000_fini(void)307 skt_mc10000_fini(void)
308 {
309 	undo_flows(mchandles.controller, mchandles.fsw_nx_uuid, 100 * 100, mcflows);
310 	sktc_cleanup_flowswitch(&mchandles);
311 	sktc_ifnet_feth0_destroy();
312 }
313 
314 int
skt_mcflows_main(int argc,char * argv[])315 skt_mcflows_main(int argc, char *argv[])
316 {
317 	char buf[1] = { 0 };
318 	ssize_t ret;
319 	int error;
320 	uuid_t fsw_uuid;
321 	channel_t channel;
322 	assert(argc == 6);
323 	assert(!strcmp(argv[3], "--child"));
324 	int child = atoi(argv[4]);
325 	error = uuid_parse(argv[5], fsw_uuid);
326 	SKTC_ASSERT_ERR(!error);
327 
328 	T_LOG("opening channel %d on fsw %s\n",
329 	    NEXUS_PORT_FLOW_SWITCH_CLIENT + child, argv[5]);
330 
331 	channel = sktu_channel_create_extended(fsw_uuid, NEXUS_PORT_FLOW_SWITCH_CLIENT + child,
332 	    CHANNEL_DIR_TX_RX, CHANNEL_RING_ID_ANY, NULL,
333 	    -1, -1, -1, -1, -1, -1, -1, 1, -1, -1);
334 	assert(channel);
335 
336 	if ((ret = write(MPTEST_SEQ_FILENO, buf, sizeof(buf))) == -1) {
337 		SKT_LOG("write fail: %s\n", strerror(errno));
338 		return 1;
339 	}
340 	assert(ret == 1);
341 
342 	/* Wait for go signal */
343 	if ((ret = read(MPTEST_SEQ_FILENO, buf, sizeof(buf))) == -1) {
344 		SKT_LOG("read fail: %s\n", strerror(errno));
345 		return 1;
346 	}
347 	assert(ret == 1);
348 
349 	os_channel_destroy(channel);
350 
351 	return 0;
352 }
353 
354 struct skywalk_mptest skt_mc10x10 = {
355 	"mc10x10", "test forks 10 processes each opening a channel with 10 flows",
356 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF | SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
357 	10, skt_mcflows_main, {NULL, NULL, NULL, NULL, NULL, fsw_uuid_string}, skt_mc10x10_init, skt_mc100_fini,
358 };
359 
360 struct skywalk_mptest skt_mc10x100 = {
361 	"mc10x100", "test forks 10 processes each opening a channel with 100 flows",
362 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF | SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
363 	10, skt_mcflows_main, {NULL, NULL, NULL, NULL, NULL, fsw_uuid_string}, skt_mc10x100_init, skt_mc1000_fini,
364 };
365 
366 struct skywalk_mptest skt_mc100x10 = {
367 	"mc100x10", "test forks 100 processes each opening a channel with 10 flows",
368 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF | SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
369 	100, skt_mcflows_main, {NULL, NULL, NULL, NULL, NULL, fsw_uuid_string}, skt_mc100x10_init, skt_mc1000_fini,
370 };
371 
372 struct skywalk_mptest skt_mc100x100 = {
373 	"mc100x100", "test forks 100 processes each opening a channel with 100 flows",
374 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF | SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
375 	100, skt_mcflows_main, {NULL, NULL, NULL, NULL, NULL, fsw_uuid_string}, skt_mc100x100_init, skt_mc10000_fini,
376 };
377