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