1 /*
2 * Copyright (c) 2016-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 #include <assert.h>
30 #include <stdlib.h>
31 #include <fcntl.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include <unistd.h>
35 #include <pthread.h>
36 #include <uuid/uuid.h>
37 #include <sys/sysctl.h>
38 #include <sys/event.h>
39 #include <netinet/in.h>
40 #include <net/if.h>
41 #include <errno.h>
42 #include <arpa/inet.h>
43 #include <skywalk/os_nexus.h>
44 #include <darwintest.h>
45 #include "skywalk_test_driver.h"
46 #include "skywalk_test_common.h"
47 #include "skywalk_test_utils.h"
48
49 #define SKT_TCP_MSL_DELAY 1 /* millisecond */
50 #define INVERT_PROTO(p) (((p) == IPPROTO_TCP) ? IPPROTO_UDP : IPPROTO_TCP)
51
52 #define MESSAGE_STRING "1234567"
53 struct test_message {
54 char tm_string[sizeof(MESSAGE_STRING)];
55 };
56 struct thread_arg {
57 int ta_sock;
58 int ta_proto;
59 };
60
61 typedef enum {
62 kErrorFlagsAssert = 0x1,
63 kErrorFlagsExpectFailure = 0x2,
64 } ErrorFlags;
65
66 #define ERROR_FLAGS_NO_ASSERT 0
67 #define ERROR_FLAGS_ASSERT_SUCCESS kErrorFlagsAssert
68 #define ERROR_FLAGS_ASSERT_FAILURE \
69 (kErrorFlagsAssert | kErrorFlagsExpectFailure)
70
71 static inline boolean_t
ErrorFlagsAreSet(ErrorFlags flags,ErrorFlags check)72 ErrorFlagsAreSet(ErrorFlags flags, ErrorFlags check)
73 {
74 return (flags & check) != 0;
75 }
76
77 const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
78
79 static void *
reader_thread_bsd(void * arg)80 reader_thread_bsd(void *arg)
81 {
82 const struct thread_arg *ta = arg;
83 struct test_message tm;
84 struct sockaddr sa;
85 socklen_t slen;
86 ssize_t rv;
87
88 if (ta->ta_proto == IPPROTO_TCP) {
89 int fd;
90
91 /* Accept the first (and only) connection */
92 fd = accept(ta->ta_sock, &sa, &slen);
93 assert(fd >= 0);
94
95 /* Read the message */
96 rv = read(fd, &tm, sizeof(tm));
97 assert(rv == sizeof(tm));
98 close(fd);
99 } else {
100 /* Wait for a message */
101 rv = recv(ta->ta_sock, &tm, sizeof(tm), MSG_WAITALL);
102 assert(rv == sizeof(tm));
103 }
104
105 if (strncmp(tm.tm_string, MESSAGE_STRING, sizeof(tm.tm_string))) {
106 T_LOG("Unexpected message received");
107 assert(0);
108 }
109
110 return NULL;
111 }
112
113 static void
skt_flowswitch_ns_bsd(struct sktc_nexus_handles * handles,int proto,void * addr)114 skt_flowswitch_ns_bsd(struct sktc_nexus_handles *handles, int proto, void *addr)
115 {
116 union sockaddr_in_4_6 saddr = *(union sockaddr_in_4_6 *)addr;
117 union sockaddr_in_4_6 laddr;
118 struct test_message tm;
119 int error, lsock, wsock;
120 int pf, stype;
121 pthread_t thread;
122 ssize_t rv;
123 char buf0[32], buf1[32];
124 uuid_string_t uuidstr;
125 struct thread_arg ta;
126 struct nx_flow_req nfr;
127 socklen_t len = sizeof(saddr);
128
129 bzero(&laddr, sizeof(laddr));
130 laddr.sa.sa_family = saddr.sa.sa_family;
131 laddr.sa.sa_len = saddr.sa.sa_len;
132 stype = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM;
133 if (saddr.sa.sa_family == AF_INET) {
134 pf = PF_INET;
135 inet_ntop(AF_INET, &saddr.sin.sin_addr, buf1, sizeof(buf1));
136 } else {
137 pf = PF_INET6;
138 inet_ntop(AF_INET6, &saddr.sin6.sin6_addr, buf1, sizeof(buf1));
139 }
140
141 T_LOG("BSD: Testing %s over IPv%u %s\n",
142 (proto == IPPROTO_TCP) ? "TCP" : "UDP",
143 (saddr.sa.sa_family == AF_INET) ? 4 : 6,
144 buf1);
145
146 /* create & bind a BSD socket to the requested port */
147 lsock = socket(pf, stype, proto);
148 assert(lsock >= 0);
149
150 error = bind(lsock, &saddr.sa, saddr.sa.sa_len);
151 SKTC_ASSERT_ERR(error == 0);
152
153 /* retrieve the locally bound name of the socket */
154 error = getsockname(lsock, &saddr.sa, &len);
155 SKTC_ASSERT_ERR(error == 0);
156
157 if (proto == IPPROTO_TCP) {
158 /* Listen for incoming connections */
159 error = listen(lsock, 1);
160 SKTC_ASSERT_ERR(error == 0);
161 }
162
163 /* Create reader thread */
164 ta.ta_sock = lsock;
165 ta.ta_proto = proto;
166 error = pthread_create(&thread, NULL, reader_thread_bsd, &ta);
167 SKTC_ASSERT_ERR(error == 0);
168
169 /* Create another socket for connecting to the first */
170 wsock = socket(pf, stype, proto);
171 assert(wsock >= 0);
172
173 /* Establish the connection */
174 error = connect(wsock, &saddr.sa, saddr.sa.sa_len);
175 SKTC_ASSERT_ERR(error == 0);
176
177 /* Write the message */
178 strncpy(tm.tm_string, MESSAGE_STRING, sizeof(tm.tm_string));
179 if (proto == IPPROTO_TCP) {
180 rv = write(wsock, &tm, sizeof(tm));
181 } else {
182 rv = send(wsock, &tm, sizeof(tm), 0);
183 }
184 assert(rv == sizeof(tm));
185
186 /* Reap the listener thread */
187 error = pthread_join(thread, NULL);
188 SKTC_ASSERT_ERR(error == 0);
189
190 /* Close our end of the connection */
191 close(wsock);
192
193 /* Attempt to bind to the same address/port via Skywalk */
194 memset(&nfr, 0, sizeof(nfr));
195 nfr.nfr_ip_protocol = proto;
196 nfr.nfr_nx_port = NEXUS_PORT_FLOW_SWITCH_CLIENT; /* first usable */
197 memcpy(&nfr.nfr_saddr, &saddr, sizeof(nfr.nfr_saddr));
198 uuid_generate_random(nfr.nfr_flow_uuid);
199
200 /* 3-tuple bind should fail */
201 uuid_unparse_upper(nfr.nfr_flow_uuid, uuidstr);
202
203 if (saddr.sa.sa_family == AF_INET) {
204 (void) inet_ntop(AF_INET, &handles->netif_addr, buf0,
205 sizeof(buf0));
206 } else {
207 #if 0
208 (void) inet_ntop(AF_INET6, &handles->netif_addr6, buf0,
209 sizeof(buf0));
210 #else
211 buf0[0] = '\0';
212 #endif
213 }
214
215 T_LOG("On %s (%s), reserve <%s,%u> through skywalk "
216 "(flow %s)\n", handles->netif_ifname, buf0, buf1,
217 ntohs(nfr.nfr_saddr.sin.sin_port), uuidstr);
218 error = __os_nexus_flow_add(handles->controller,
219 handles->fsw_nx_uuid, &nfr);
220 SKTC_ASSERT_ERR(error != 0);
221
222 /* 2-tuple bind should also fail */
223 T_LOG("On %s (%s), reserve <ANY,%u> through skywalk "
224 "(flow %s)\n", handles->netif_ifname, buf0,
225 ntohs(nfr.nfr_saddr.sin.sin_port), uuidstr);
226 error = __os_nexus_flow_add(handles->controller,
227 handles->fsw_nx_uuid, &nfr);
228 SKTC_ASSERT_ERR(error != 0);
229
230 T_LOG(" %s done\n", __func__);
231 /* Close the BSD listener socket */
232 close(lsock);
233 }
234
235 static void
skt_flowswitch_ns_sky(struct sktc_nexus_handles * handles,int proto,void * addr)236 skt_flowswitch_ns_sky(struct sktc_nexus_handles *handles, int proto, void *addr)
237 {
238 union sockaddr_in_4_6 saddr = *(union sockaddr_in_4_6 *)addr;
239 int error, lsock;
240 int pf, stype, is_wild;
241 char buf1[32];
242 uuid_string_t uuidstr;
243 struct nx_flow_req nfr;
244 nexus_port_t nx_port = 2;
245 uuid_t listener_flow;
246 // uuid_t connected_flow;
247 // char buf0[32];
248
249 stype = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM;
250 if (saddr.sa.sa_family == AF_INET) {
251 pf = PF_INET;
252 is_wild = (saddr.sin.sin_addr.s_addr == INADDR_ANY);
253 (void) inet_ntop(AF_INET, &saddr.sin.sin_addr, buf1,
254 sizeof(buf1));
255 } else {
256 pf = PF_INET6;
257 is_wild = IN6_IS_ADDR_UNSPECIFIED(&saddr.sin6.sin6_addr);
258 (void) inet_ntop(AF_INET6, &saddr.sin6.sin6_addr, buf1,
259 sizeof(buf1));
260 }
261
262 T_LOG("Skywalk: Testing %s over IPv%u %s\n",
263 (proto == IPPROTO_TCP) ? "TCP" : "UDP",
264 (saddr.sa.sa_family == AF_INET) ? 4 : 6,
265 buf1);
266
267 /* Bind to port via Skywalk */
268 uuid_generate_random(listener_flow);
269 memset(&nfr, 0, sizeof(nfr));
270 nfr.nfr_ip_protocol = proto;
271 nfr.nfr_nx_port = nx_port;
272 memcpy(&nfr.nfr_saddr, &saddr, sizeof(nfr.nfr_saddr));
273 uuid_copy(nfr.nfr_flow_uuid, listener_flow);
274 uuid_unparse_upper(nfr.nfr_flow_uuid, uuidstr);
275 T_LOG("On %s, reserve <%s,%u> through skywalk "
276 "(flow %s)\n", handles->netif_ifname, buf1,
277 ntohs(nfr.nfr_saddr.sin.sin_port), uuidstr);
278 error = __os_nexus_flow_add(handles->controller,
279 handles->fsw_nx_uuid, &nfr);
280 SKTC_ASSERT_ERR(error == 0);
281
282 memcpy(&saddr, &nfr.nfr_saddr, sizeof(saddr));
283
284 // Currently doesn't work - No route to host
285 #if 0
286 /* Test connecting a new flow from the listener */
287 uuid_generate_random(connected_flow);
288 memset(&nfr, 0, sizeof(nfr));
289 nfr.nfr_ip_protocol = proto;
290 nfr.nfr_nx_port = nx_port;
291
292 memcpy(&nfr.nfr_saddr, &saddr, sizeof(nfr.nfr_saddr));
293 memcpy(&nfr.nfr_daddr, &saddr, sizeof(nfr.nfr_daddr));
294 if (saddr.sa.sa_family == AF_INET) {
295 nfr.nfr_saddr.sin.sin_addr.s_addr = htonl(INADDR_ANY);
296 nfr.nfr_daddr.sin.sin_port += htons(16);
297 if (is_wild) {
298 nfr.nfr_daddr.sin.sin_addr = handles->netif_addr;
299 }
300 inet_ntop(AF_INET, &nfr.nfr_daddr.sin.sin_addr, buf0,
301 sizeof(buf0));
302 } else {
303 memcpy(&nfr.nfr_saddr.sin6.sin6_addr, &in6addr_any,
304 sizeof(nfr.nfr_saddr.sin6.sin6_addr));
305 nfr.nfr_daddr.sin6.sin6_port += htons(16);
306 #if 0
307 if (is_wild) {
308 nfr.nfr_daddr.sin6.sin6_addr = handles->netif_addr6;
309 }
310 #endif
311 inet_ntop(AF_INET6, &nfr.nfr_daddr.sin6.sin6_addr, buf0,
312 sizeof(buf0));
313 }
314
315 uuid_copy(nfr.nfr_flow_uuid, connected_flow);
316 uuid_unparse_upper(nfr.nfr_flow_uuid, uuidstr);
317 T_LOG("On %s, connect <%s,%u> -> <%s,%u> "
318 "(flow %s)\n", handles->netif_ifname,
319 buf0, ntohs(nfr.nfr_daddr.sin.sin_port),
320 buf1, ntohs(nfr.nfr_saddr.sin.sin_port),
321 uuidstr);
322 error = __os_nexus_flow_add(handles->controller, handles->fsw_nx_uuid, &nfr);
323 SKTC_ASSERT_ERR(error == 0);
324 #endif
325
326 /* create & bind a BSD socket to the requested port */
327 lsock = socket(pf, stype, proto);
328 assert(lsock >= 0);
329
330 /* BSD bind should fail */
331 error = bind(lsock, &saddr.sa, saddr.sa.sa_len);
332 SKTC_ASSERT_ERR(error != 0);
333
334 if (is_wild) {
335 if (saddr.sa.sa_family == AF_INET) {
336 saddr.sin.sin_addr = handles->netif_addr;
337 } else {
338 #if 0
339 saddr.sin6.sin6_addr = handles->netif_addr6;
340 #endif
341 }
342
343 /* BSD bind from non-wildcard should fail */
344 error = bind(lsock, &saddr.sa, saddr.sa.sa_len);
345 SKTC_ASSERT_ERR(error != 0);
346 }
347
348 close(lsock);
349
350 memset(&nfr, 0, sizeof(nfr));
351 uuid_copy(nfr.nfr_flow_uuid, listener_flow);
352
353 error = __os_nexus_flow_del(handles->controller, handles->fsw_nx_uuid,
354 &nfr);
355 SKTC_ASSERT_ERR(!error);
356
357 #if 0
358 memset(&nfr, 0, sizeof(nfr));
359 uuid_copy(nfr.nfr_flow_uuid, connected_flow);
360
361 error = __os_nexus_flow_del(handles->controller, handles->fsw_nx_uuid,
362 &nfr);
363 SKTC_ASSERT_ERR(!error);
364 #endif
365 T_LOG(" %s done\n", __func__);
366 }
367
368 static int
skt_ns_sky_bind(struct sktc_nexus_handles * handles,int proto,void * addr,ErrorFlags error_flags,uuid_t flow,uint16_t * bound_port)369 skt_ns_sky_bind(struct sktc_nexus_handles *handles, int proto, void *addr,
370 ErrorFlags error_flags, uuid_t flow, uint16_t *bound_port)
371 {
372 union sockaddr_in_4_6 sky_saddr = *(union sockaddr_in_4_6 *)addr;
373 int error;
374 int is_wild;
375 char buf[32];
376 uuid_string_t uuidstr;
377 struct nx_flow_req nfr;
378 nexus_port_t nx_port = 2;
379 uint16_t port;
380
381 if (sky_saddr.sa.sa_family == AF_INET) {
382 is_wild = (sky_saddr.sin.sin_addr.s_addr == INADDR_ANY);
383 (void) inet_ntop(AF_INET, &sky_saddr.sin.sin_addr, buf,
384 sizeof(buf));
385 port = sky_saddr.sin.sin_port;
386 } else {
387 is_wild = IN6_IS_ADDR_UNSPECIFIED(&sky_saddr.sin6.sin6_addr);
388 (void) inet_ntop(AF_INET6, &sky_saddr.sin6.sin6_addr, buf,
389 sizeof(buf));
390 port = sky_saddr.sin6.sin6_port;
391 }
392
393 T_LOG("Skywalk: nexus bind %s over IPv%u %s :%d\n",
394 (proto == IPPROTO_TCP) ? "TCP" : "UDP",
395 (sky_saddr.sa.sa_family == AF_INET) ? 4 : 6, buf, ntohs(port));
396
397 /* Bind to port via Skywalk */
398 uuid_generate_random(flow);
399 memset(&nfr, 0, sizeof(nfr));
400 nfr.nfr_ip_protocol = proto;
401 nfr.nfr_nx_port = nx_port;
402 memcpy(&nfr.nfr_saddr, &sky_saddr, sizeof(nfr.nfr_saddr));
403 uuid_copy(nfr.nfr_flow_uuid, flow);
404 uuid_unparse_upper(nfr.nfr_flow_uuid, uuidstr);
405 T_LOG("On %s, reserve <%s,%u> through skywalk "
406 "(flow %s)\n", handles->netif_ifname, buf,
407 ntohs(nfr.nfr_saddr.sin.sin_port), uuidstr);
408 error = __os_nexus_flow_add(handles->controller, handles->fsw_nx_uuid,
409 &nfr);
410 *bound_port = nfr.nfr_saddr.sin.sin_port;
411 if (ErrorFlagsAreSet(error_flags, kErrorFlagsAssert)) {
412 if (ErrorFlagsAreSet(error_flags, kErrorFlagsExpectFailure)) {
413 SKTC_ASSERT_ERR(error != 0);
414 } else {
415 SKTC_ASSERT_ERR(error == 0);
416 }
417 }
418 return error;
419 }
420
421 static int
skt_ns_sock_bind(struct sktc_nexus_handles * handles,int proto,void * addr,ErrorFlags error_flags,int * lsock,boolean_t ipv6_only,uint16_t * bound_port)422 skt_ns_sock_bind(struct sktc_nexus_handles *handles, int proto, void *addr,
423 ErrorFlags error_flags, int *lsock, boolean_t ipv6_only,
424 uint16_t *bound_port)
425 {
426 char buf[32];
427 int error;
428 int on = 0;
429 union sockaddr_in_4_6 bsd_saddr = *(union sockaddr_in_4_6 *)addr;
430 socklen_t len = sizeof(bsd_saddr);
431 uint16_t port;
432
433 if (bsd_saddr.sa.sa_family == AF_INET) {
434 (void) inet_ntop(AF_INET, &bsd_saddr.sin.sin_addr, buf,
435 sizeof(buf));
436 port = bsd_saddr.sin.sin_port;
437 } else {
438 (void) inet_ntop(AF_INET6, &bsd_saddr.sin6.sin6_addr, buf,
439 sizeof(buf));
440 port = bsd_saddr.sin6.sin6_port;
441 }
442 /* create & bind a BSD socket to the requested port */
443 *lsock = socket(bsd_saddr.sa.sa_family,
444 (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM,
445 proto);
446 assert(*lsock >= 0);
447
448 T_LOG("Skywalk: socket bind %s over IPv%u %s :%d\n",
449 (proto == IPPROTO_TCP) ? "TCP" : "UDP",
450 (bsd_saddr.sa.sa_family == AF_INET) ? 4 : 6, buf, ntohs(port));
451
452 if (bsd_saddr.sa.sa_family == AF_INET6) {
453 if (ipv6_only) {
454 on = 1;
455 }
456 error = setsockopt(*lsock, IPPROTO_IPV6, IPV6_V6ONLY, &on,
457 sizeof(on));
458 SKTC_ASSERT_ERR(error == 0);
459 }
460 error = bind(*lsock, &bsd_saddr.sa, bsd_saddr.sa.sa_len);
461 if (ErrorFlagsAreSet(error_flags, kErrorFlagsAssert)) {
462 if (ErrorFlagsAreSet(error_flags, kErrorFlagsExpectFailure)) {
463 SKTC_ASSERT_ERR(error != 0);
464 } else {
465 SKTC_ASSERT_ERR(error == 0);
466 }
467 }
468 *bound_port = 0;
469 if (error == 0) {
470 /* retrieve the locally bound name of the socket */
471 if (getsockname(*lsock, &bsd_saddr.sa, &len) == 0) {
472 *bound_port = bsd_saddr.sin.sin_port;
473 } else {
474 assert(0);
475 }
476 }
477 return error;
478 }
479
480 static void
skt_flowswitch_ns_sky_bsd(struct sktc_nexus_handles * handles,int proto,void * sky_addr,void * bsd_addr,boolean_t sky_bind_first,ErrorFlags sky_err_flags,ErrorFlags bsd_err_flags,boolean_t ipv6_only,boolean_t use_bound_port)481 skt_flowswitch_ns_sky_bsd(struct sktc_nexus_handles *handles, int proto,
482 void *sky_addr, void* bsd_addr, boolean_t sky_bind_first,
483 ErrorFlags sky_err_flags, ErrorFlags bsd_err_flags,
484 boolean_t ipv6_only, boolean_t use_bound_port)
485 {
486 int error;
487 struct nx_flow_req nfr;
488 uint16_t bound_port;
489 uuid_t flow;
490 int lsock;
491
492 if (sky_bind_first) {
493 skt_ns_sky_bind(handles, proto, sky_addr, sky_err_flags,
494 flow, &bound_port);
495 if (use_bound_port) {
496 ((struct sockaddr_in *)bsd_addr)->sin_port = bound_port;
497 }
498 skt_ns_sock_bind(handles, proto, bsd_addr, bsd_err_flags,
499 &lsock, ipv6_only, &bound_port);
500 } else {
501 skt_ns_sock_bind(handles, proto, bsd_addr, bsd_err_flags,
502 &lsock, ipv6_only, &bound_port);
503 /*
504 * sleep to account for inpcb garbage collection delay.
505 */
506 sleep(1);
507 if (use_bound_port) {
508 ((struct sockaddr_in *)sky_addr)->sin_port = bound_port;
509 }
510 skt_ns_sky_bind(handles, proto, sky_addr, sky_err_flags,
511 flow, &bound_port);
512 }
513
514 if (!ErrorFlagsAreSet(sky_err_flags, kErrorFlagsExpectFailure)) {
515 memset(&nfr, 0, sizeof(nfr));
516 uuid_copy(nfr.nfr_flow_uuid, flow);
517 error = __os_nexus_flow_del(handles->controller,
518 handles->fsw_nx_uuid, &nfr);
519 SKTC_ASSERT_ERR(!error);
520 }
521 close(lsock);
522 T_LOG(" %s done\n", __func__);
523 }
524
525 static void
skt_flowswitch_ns_check_v4mappedv6addr(struct sktc_nexus_handles * handles,uint16_t port)526 skt_flowswitch_ns_check_v4mappedv6addr(struct sktc_nexus_handles *handles,
527 uint16_t port)
528 {
529 union sockaddr_in_4_6 saddr, saddr2;
530 struct sockaddr_in *sin;
531 struct sockaddr_in6 *sin6;
532 int sock, error, on = 0;
533 struct nx_flow_req nfr;
534 char ntopbuf[INET6_ADDRSTRLEN];
535 uint16_t bound_port;
536 uuid_t flow;
537
538 memset(&saddr, 0, sizeof(saddr));
539 sin = &saddr.sin;
540 sin->sin_len = sizeof(struct sockaddr_in);
541 sin->sin_family = AF_INET;
542 sin->sin_port = htons(port);
543 sin->sin_addr.s_addr = htonl(INADDR_ANY);
544 /* Bind a skywalk flow */
545 skt_ns_sky_bind(handles, IPPROTO_TCP, sin, FALSE, flow, &bound_port);
546
547 sin6 = &saddr2.sin6;
548 sin6->sin6_len = sizeof(struct sockaddr_in6);
549 sin6->sin6_family = AF_INET6;
550 sin6->sin6_port = bound_port;
551 sin6->sin6_addr = in6addr_any;
552
553 /* create & bind a BSD socket */
554 sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
555 assert(sock >= 0);
556
557 error = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
558 SKTC_ASSERT_ERR(error == 0);
559 /*
560 * BSD bind should fail, if not we will attempt a connect on
561 * IPv4-mapped-IPv6 address which should trip assertion in stack
562 * when it tries to reserve the port in IPv4 domain.
563 */
564 error = bind(sock, (struct sockaddr *)sin6, sin6->sin6_len);
565 if (error == 0) {
566 struct sockaddr_in6 daddr = {
567 .sin6_len = sizeof(daddr),
568 .sin6_family = AF_INET6,
569 .sin6_addr = IN6ADDR_V4MAPPED_INIT,
570 };
571 uint16_t dest_port;
572
573 /* add mapped IPv4 address */
574 daddr.sin6_addr.__u6_addr.__u6_addr32[3]
575 = handles->netif_addr.s_addr;
576 dest_port = ntohs(bound_port);
577 if (dest_port == 65535) {
578 dest_port--;
579 } else {
580 dest_port++;
581 }
582 daddr.sin6_port = htons(dest_port);
583 fcntl(sock, F_SETFL, O_NONBLOCK);
584 T_LOG(
585 "Skywalk: tcp socket connect to %s :%d (mapped)\n",
586 inet_ntop(AF_INET6, &daddr.sin6_addr, ntopbuf,
587 sizeof(ntopbuf)),
588 ntohs(daddr.sin6_port));
589 error = connect(sock, (struct sockaddr *)&daddr, sizeof(daddr));
590 }
591 SKTC_ASSERT_ERR(error != 0);
592 memset(&nfr, 0, sizeof(nfr));
593 uuid_copy(nfr.nfr_flow_uuid, flow);
594 error = __os_nexus_flow_del(handles->controller,
595 handles->fsw_nx_uuid, &nfr);
596 SKTC_ASSERT_ERR(error == 0);
597 close(sock);
598 T_LOG(" %s done\n", __func__);
599 }
600
601 static void
skt_flowswitch_ns_check_v4mappedv6addr2(struct sktc_nexus_handles * handles)602 skt_flowswitch_ns_check_v4mappedv6addr2(struct sktc_nexus_handles *handles)
603 {
604 struct sockaddr_in6 blank_sin6 = {
605 .sin6_len = sizeof(blank_sin6),
606 .sin6_family = AF_INET6,
607 };
608 uint16_t bound_port;
609 struct sockaddr_in6 daddr = {
610 .sin6_len = sizeof(daddr),
611 .sin6_family = AF_INET6,
612 .sin6_addr = IN6ADDR_V4MAPPED_INIT,
613 };
614 int error;
615 uuid_t flow;
616 int lsock;
617 struct sockaddr_in6 nam = { 0 };
618 socklen_t nam_len;
619 char ntopbuf[INET6_ADDRSTRLEN];
620 struct sockaddr_in sin = {
621 .sin_len = sizeof(sin),
622 .sin_family = AF_INET,
623 };
624 int sock;
625
626 /* create and bind an IPv6 TCP socket */
627 sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
628 assert(sock >= 0);
629 error = bind(sock, (struct sockaddr *)&blank_sin6, blank_sin6.sin6_len);
630 assert(error == 0);
631
632 /* get the port */
633 nam_len = sizeof(nam);
634 error = getsockname(sock, (struct sockaddr *)&nam, &nam_len);
635 assert(error == 0);
636
637 /* bind skywalk flow to same port in IPv4 namespace, this should fail */
638 sin.sin_port = nam.sin6_port;
639 error = skt_ns_sky_bind(handles, IPPROTO_TCP, &sin,
640 ERROR_FLAGS_NO_ASSERT, flow, &bound_port);
641 if (error == 0) {
642 /* this shouldn't have worked <rdar://problem/35525592> */
643 T_LOG(
644 "Binding port %d in skywalk should have failed!\n",
645 ntohs(nam.sin6_port));
646 }
647
648 /* create and bind a listener socket and get the listening port */
649 lsock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
650 assert(lsock >= 0);
651 error = bind(lsock, (struct sockaddr *)&blank_sin6,
652 blank_sin6.sin6_len);
653 assert(error == 0);
654 error = listen(lsock, 1);
655 SKTC_ASSERT_ERR(error == 0);
656 nam_len = sizeof(nam);
657 error = getsockname(lsock, (struct sockaddr *)&nam, &nam_len);
658 assert(error == 0);
659
660 /* connect the socket, will panic without <rdar://problem/35525592> */
661 daddr.sin6_addr.__u6_addr.__u6_addr32[3] = handles->netif_addr.s_addr;
662 daddr.sin6_port = nam.sin6_port; /* listener port */
663 T_LOG("Skywalk: tcp socket connect to %s :%d (mapped)\n",
664 inet_ntop(AF_INET6, &daddr.sin6_addr, ntopbuf, sizeof(ntopbuf)),
665 ntohs(daddr.sin6_port));
666 error = connect(sock, (struct sockaddr *)&daddr, sizeof(daddr));
667 SKTC_ASSERT_ERR(error == 0);
668 close(lsock);
669 close(sock);
670 T_LOG(" %s done\n", __func__);
671 }
672
673 static int
skt_flowswitch_ns_reserve_main2(int argc,char * argv[])674 skt_flowswitch_ns_reserve_main2(int argc, char *argv[])
675 {
676 struct sktc_nexus_handles handles;
677 union sockaddr_in_4_6 saddr, saddr2;
678 struct sockaddr_in *sin;
679 struct sockaddr_in6 *sin6;
680
681 srandomdev();
682
683 sktc_create_flowswitch(&handles, 0);
684
685 /* Use ephemeral port for each step to avoid needing SO_REUSEADDR */
686
687 /* Test IPv4 mapped IPv6 address binding */
688 skt_flowswitch_ns_check_v4mappedv6addr(&handles, 0);
689
690 /* Test IPv4-mapped-IPv6 address connect */
691 skt_flowswitch_ns_check_v4mappedv6addr2(&handles);
692
693 /* Test TCP IPv4 wildcard */
694 memset(&saddr, 0, sizeof(saddr));
695 sin = &saddr.sin;
696 sin->sin_len = sizeof(struct sockaddr_in);
697 sin->sin_family = AF_INET;
698 sin->sin_port = 0;
699 sin->sin_addr.s_addr = htonl(INADDR_ANY);
700 skt_flowswitch_ns_bsd(&handles, IPPROTO_TCP, sin);
701 sin->sin_port = 0;
702 skt_flowswitch_ns_sky(&handles, IPPROTO_TCP, sin);
703
704 /* Test TCP IPv4 on feth */
705 sin->sin_port = 0;
706 sin->sin_addr = handles.netif_addr;
707 skt_flowswitch_ns_bsd(&handles, IPPROTO_TCP, sin);
708 sin->sin_port = 0;
709 skt_flowswitch_ns_sky(&handles, IPPROTO_TCP, sin);
710
711 /* Test TCP IPv6 wildcard */
712 memset(&saddr, 0, sizeof(saddr));
713 sin6 = &saddr.sin6;
714 sin6->sin6_len = sizeof(struct sockaddr_in6);
715 sin6->sin6_family = AF_INET6;
716 sin6->sin6_port = 0;
717 memcpy(&sin6->sin6_addr, &in6addr_any, sizeof(sin6->sin6_addr));
718 skt_flowswitch_ns_bsd(&handles, IPPROTO_TCP, sin6);
719
720 /* Test TCP IPv4/IPv6 wildcard */
721 memset(&saddr, 0, sizeof(saddr));
722 sin = &saddr.sin;
723 sin->sin_len = sizeof(struct sockaddr_in);
724 sin->sin_family = AF_INET;
725 sin->sin_port = 0;
726 sin->sin_addr.s_addr = htonl(INADDR_ANY);
727 memset(&saddr2, 0, sizeof(saddr2));
728 sin6 = &saddr2.sin6;
729 sin6->sin6_len = sizeof(struct sockaddr_in6);
730 sin6->sin6_family = AF_INET6;
731 sin6->sin6_port = 0;
732 sin6->sin6_addr = in6addr_any;
733 skt_flowswitch_ns_sky_bsd(&handles, IPPROTO_TCP, sin, sin6, TRUE,
734 ERROR_FLAGS_ASSERT_SUCCESS,
735 ERROR_FLAGS_ASSERT_FAILURE,
736 FALSE, TRUE);
737 sin->sin_port = 0;
738 sin6->sin6_port = 0;
739 skt_flowswitch_ns_sky_bsd(&handles, IPPROTO_TCP, sin, sin6, FALSE,
740 ERROR_FLAGS_ASSERT_FAILURE,
741 ERROR_FLAGS_ASSERT_SUCCESS,
742 FALSE, TRUE);
743 sin->sin_port = 0;
744 sin6->sin6_port = 0;
745 skt_flowswitch_ns_sky_bsd(&handles, IPPROTO_TCP, sin, sin6, TRUE,
746 ERROR_FLAGS_ASSERT_SUCCESS,
747 ERROR_FLAGS_ASSERT_SUCCESS,
748 TRUE, TRUE);
749 sin->sin_port = 0;
750 sin6->sin6_port = 0;
751 skt_flowswitch_ns_sky_bsd(&handles, IPPROTO_TCP, sin, sin6, FALSE,
752 ERROR_FLAGS_ASSERT_FAILURE,
753 ERROR_FLAGS_ASSERT_SUCCESS,
754 TRUE, TRUE);
755
756 // Need IPv6 link-local support on feth
757 #if 0
758 sin6->sin6_port = htons(port);
759 skt_flowswitch_ns_sky(&handles, IPPROTO_TCP, sin6);
760 port += 1;
761
762 /* Test TCP IPv6 on feth */
763 sin6->sin6_port = htons(port);
764 memcpy(&sin6->sin6_addr, &handles->netif_addr6,
765 sizeof(sin6->sin6_addr));
766 skt_flowswitch_ns_bsd(&handles, IPPROTO_TCP, sin6);
767 port += 1;
768 sin6->sin6_port = htons(port);
769 skt_flowswitch_ns_sky(&handles, IPPROTO_TCP, sin6);
770 port += 1;
771 #endif
772
773 /* Test UDP IPv4 wildcard */
774 memset(&saddr, 0, sizeof(saddr));
775 sin = &saddr.sin;
776 sin->sin_len = sizeof(struct sockaddr_in);
777 sin->sin_family = AF_INET;
778 sin->sin_port = 0;
779 sin->sin_addr.s_addr = htonl(INADDR_ANY);
780 skt_flowswitch_ns_bsd(&handles, IPPROTO_UDP, sin);
781 sin->sin_port = 0;
782 skt_flowswitch_ns_sky(&handles, IPPROTO_UDP, sin);
783
784 /* Test UDP IPv4 on feth */
785 sin->sin_port = 0;
786 sin->sin_addr = handles.netif_addr;
787 skt_flowswitch_ns_bsd(&handles, IPPROTO_UDP, sin);
788 sin->sin_port = 0;
789 skt_flowswitch_ns_sky(&handles, IPPROTO_UDP, sin);
790
791 /* Test UDP IPv6 wildcard */
792 memset(&saddr, 0, sizeof(saddr));
793 sin6 = &saddr.sin6;
794 sin6->sin6_len = sizeof(struct sockaddr_in6);
795 sin6->sin6_family = AF_INET6;
796 sin6->sin6_port = 0;
797 memcpy(&sin6->sin6_addr, &in6addr_any, sizeof(sin6->sin6_addr));
798 skt_flowswitch_ns_bsd(&handles, IPPROTO_UDP, sin6);
799
800 /* Test UDP IPv4/IPv6 wildcard */
801 memset(&saddr, 0, sizeof(saddr));
802 sin = &saddr.sin;
803 sin->sin_len = sizeof(struct sockaddr_in);
804 sin->sin_family = AF_INET;
805 sin->sin_port = 0;
806 sin->sin_addr.s_addr = htonl(INADDR_ANY);
807 memset(&saddr2, 0, sizeof(saddr2));
808 sin6 = &saddr2.sin6;
809 sin6->sin6_len = sizeof(struct sockaddr_in6);
810 sin6->sin6_family = AF_INET6;
811 sin6->sin6_port = 0;
812 sin6->sin6_addr = in6addr_any;
813 skt_flowswitch_ns_sky_bsd(&handles, IPPROTO_UDP, sin, sin6, TRUE,
814 ERROR_FLAGS_ASSERT_SUCCESS,
815 ERROR_FLAGS_ASSERT_FAILURE,
816 FALSE, TRUE);
817 sin->sin_port = 0;
818 sin6->sin6_port = 0;
819 skt_flowswitch_ns_sky_bsd(&handles, IPPROTO_UDP, sin, sin6, FALSE,
820 ERROR_FLAGS_ASSERT_FAILURE,
821 ERROR_FLAGS_ASSERT_SUCCESS,
822 FALSE, TRUE);
823 sin->sin_port = 0;
824 sin6->sin6_port = 0;
825 skt_flowswitch_ns_sky_bsd(&handles, IPPROTO_UDP, sin, sin6, TRUE,
826 ERROR_FLAGS_ASSERT_SUCCESS,
827 ERROR_FLAGS_ASSERT_SUCCESS,
828 TRUE, TRUE);
829 sin->sin_port = 0;
830 sin6->sin6_port = 0;
831 skt_flowswitch_ns_sky_bsd(&handles, IPPROTO_UDP, sin, sin6, FALSE,
832 ERROR_FLAGS_ASSERT_FAILURE,
833 ERROR_FLAGS_ASSERT_SUCCESS,
834 TRUE, TRUE);
835 // Need IPv6 link-local support on feth
836 #if 0
837 sin6->sin6_port = htons(port);
838 skt_flowswitch_ns_sky(&handles, IPPROTO_UDP, sin6);
839 port += 1;
840
841 /* Test UDP IPv6 feth */
842 sin6->sin6_port = htons(port);
843 memcpy(&sin6->sin6_addr, &handles.netif_addr6,
844 sizeof(sin6->sin6_addr));
845 skt_flowswitch_ns_bsd(&handles, IPPROTO_UDP, sin6);
846 port += 1;
847 sin6->sin6_port = htons(port);
848 skt_flowswitch_ns_sky(&handles, IPPROTO_UDP, sin6);
849 #endif
850
851 sktc_cleanup_flowswitch(&handles);
852
853 return 0;
854 }
855
856 #define SKTC_ASSERT_ERR_RETRY(_t, _counter, _retry_label) \
857 do { \
858 if (!(_t)) { \
859 T_LOG(\
860 "ERROR: %s:%d " #_t ", retry\n", __FILE__, __LINE__); \
861 _counter++; \
862 goto _retry_label; \
863 } \
864 } while (0);
865
866 #define RETRY_MAX 3
867
868 static int
skt_flowswitch_ns_reserve_main(int argc,char * argv[])869 skt_flowswitch_ns_reserve_main(int argc, char *argv[])
870 {
871 char buf0[32], buf1[32];
872 size_t retries = 0;
873 int error;
874 struct sktc_nexus_handles handles;
875 struct sktc_nexus_handles handles2;
876 uuid_string_t uuidstr;
877 struct nx_flow_req nfr;
878 uuid_t tcp_flow, udp_flow;
879
880 struct sockaddr_in sa;
881 int sock;
882
883 srandomdev();
884
885 start:
886 memset(&nfr, 0, sizeof(nfr));
887 nfr.nfr_ip_protocol = IPPROTO_TCP;
888 nfr.nfr_nx_port = NEXUS_PORT_FLOW_SWITCH_CLIENT; /* first usable */
889 nfr.nfr_saddr.sa.sa_len = sizeof(struct sockaddr_in);
890 nfr.nfr_saddr.sa.sa_family = AF_INET;
891 nfr.nfr_saddr.sin.sin_port = 0; /* pick an ephemeral port */
892 nfr.nfr_saddr.sin.sin_addr.s_addr = htonl(INADDR_ANY);
893
894 T_LOG("--Testing with %s port %d\n",
895 (nfr.nfr_ip_protocol == IPPROTO_TCP) ? "tcp" : "udp",
896 ntohs(nfr.nfr_saddr.sin.sin_port));
897
898 /* bind without flow uuid should fail */
899 sktc_create_flowswitch(&handles, 0);
900 (void) inet_ntop(AF_INET, &handles.netif_addr, buf0, sizeof(buf0));
901 T_LOG("On %s (%s), reserve <ANY,%u> through skywalk "
902 "(no flow ID)\n", handles.netif_ifname, buf0,
903 ntohs(nfr.nfr_saddr.sin.sin_port));
904 error = __os_nexus_flow_add(handles.controller,
905 handles.fsw_nx_uuid, &nfr);
906 SKTC_ASSERT_ERR(error == -1 && errno == EINVAL);
907
908 uuid_generate_random(tcp_flow);
909 uuid_generate_random(udp_flow);
910
911 /* bind correctly called should succeed */
912 uuid_copy(nfr.nfr_flow_uuid, tcp_flow);
913 uuid_unparse_upper(nfr.nfr_flow_uuid, uuidstr);
914 T_LOG("On %s (%s), reserve <ANY,%u> through skywalk "
915 "(flow %s)\n", handles.netif_ifname, buf0,
916 ntohs(nfr.nfr_saddr.sin.sin_port), uuidstr);
917 error = __os_nexus_flow_add(handles.controller,
918 handles.fsw_nx_uuid, &nfr);
919 SKTC_ASSERT_ERR(!error);
920 assert(htonl(INADDR_ANY) == nfr.nfr_saddr.sin.sin_addr.s_addr);
921
922 /* duplicate 2 tuple bind should fail */
923 (void) inet_ntop(AF_INET, &handles.netif_addr, buf0, sizeof(buf0));
924 (void) inet_ntop(AF_INET, &nfr.nfr_saddr.sin.sin_addr,
925 buf1, sizeof(buf1));
926 uuid_generate_random(nfr.nfr_flow_uuid);
927 uuid_unparse_upper(nfr.nfr_flow_uuid, uuidstr);
928 T_LOG("On %s (%s), confirm <%s,%u> re-binding fails "
929 "(flow %s)\n", handles.netif_ifname, buf0, buf1,
930 ntohs(nfr.nfr_saddr.sin.sin_port), uuidstr);
931 error = __os_nexus_flow_add(handles.controller,
932 handles.fsw_nx_uuid, &nfr);
933 SKTC_ASSERT_ERR(error != 0 && (errno == EEXIST || errno == EADDRINUSE));
934
935 /* 3 tuple bind sharing the same port should fail */
936 nfr.nfr_saddr.sin.sin_addr = handles.netif_addr;
937 (void) inet_ntop(AF_INET, &handles.netif_addr, buf0, sizeof(buf0));
938 (void) inet_ntop(AF_INET, &nfr.nfr_saddr.sin.sin_addr,
939 buf1, sizeof(buf1));
940 uuid_generate_random(nfr.nfr_flow_uuid);
941 uuid_unparse_upper(nfr.nfr_flow_uuid, uuidstr);
942 T_LOG("On %s (%s), confirm <%s,%u> re-binding fails "
943 "(flow %s)\n", handles.netif_ifname, buf0, buf1,
944 ntohs(nfr.nfr_saddr.sin.sin_port), uuidstr);
945 error = __os_nexus_flow_add(handles.controller,
946 handles.fsw_nx_uuid, &nfr);
947 SKTC_ASSERT_ERR(error != 0 && (errno == EEXIST || errno == EADDRINUSE));
948
949 /* testing with another fsw */
950 /* bind the same port another fsw is not allowed */
951 sktc_create_flowswitch(&handles2, 1);
952 nfr.nfr_saddr.sin.sin_addr.s_addr = htonl(INADDR_ANY);
953 (void) inet_ntop(AF_INET, &handles2.netif_addr, buf0, sizeof(buf0));
954 (void) inet_ntop(AF_INET, &nfr.nfr_saddr.sin.sin_addr,
955 buf1, sizeof(buf1));
956 uuid_copy(nfr.nfr_flow_uuid, tcp_flow);
957 uuid_unparse_upper(nfr.nfr_flow_uuid, uuidstr);
958 T_LOG("On %s (%s), confirm <%s,%u> binding is not allowed "
959 "(flow %s)\n", handles2.netif_ifname, buf0, buf1,
960 ntohs(nfr.nfr_saddr.sin.sin_port), uuidstr);
961 error = __os_nexus_flow_add(handles2.controller,
962 handles2.fsw_nx_uuid, &nfr);
963 //XXX -- [email protected]
964 // This behavior could change once we add more context(ifnet) into netns
965 // so that netns becomes the single arbitrator of port resource across
966 // all ifnet. Then we can allow binding of tuple <any_addr, a_port, if1>
967 // and <anyaddr, same_port, if2> to go through.
968 SKTC_ASSERT_ERR(error == -1);
969 SKTC_ASSERT_ERR(errno == EEXIST || errno == EADDRINUSE);
970
971 sktc_cleanup_flowswitch(&handles2);
972
973 /* if bound through skywalk, BSD bind should fail */
974 T_LOG("Confirm port is unavailable to BSD stack\n");
975 sock = socket(PF_INET,
976 (nfr.nfr_ip_protocol == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM,
977 nfr.nfr_ip_protocol);
978 assert(sock != -1);
979
980 memset(&sa, 0, sizeof sa);
981 sa.sin_family = AF_INET;
982 sa.sin_port = nfr.nfr_saddr.sin.sin_port;
983 sa.sin_addr.s_addr = htonl(INADDR_ANY);
984 error = bind(sock, (struct sockaddr *)&sa, sizeof sa);
985
986 SKTC_ASSERT_ERR(error == -1);
987 SKTC_ASSERT_ERR(errno == EADDRINUSE);
988
989 /* bind the same port on UDP, should succeed */
990 (void) inet_ntop(AF_INET, &handles.netif_addr, buf0, sizeof(buf0));
991 nfr.nfr_ip_protocol = INVERT_PROTO(nfr.nfr_ip_protocol);
992 nfr.nfr_saddr.sin.sin_addr.s_addr = htonl(INADDR_ANY);
993 uuid_copy(nfr.nfr_flow_uuid, udp_flow);
994 uuid_unparse_upper(nfr.nfr_flow_uuid, uuidstr);
995 T_LOG("On %s (%s) confirm port number %u is available "
996 "on other protocols (flow %s)\n", handles.netif_ifname, buf0,
997 ntohs(nfr.nfr_saddr.sin.sin_port), uuidstr);
998 error = __os_nexus_flow_add(handles.controller,
999 handles.fsw_nx_uuid, &nfr);
1000 SKTC_ASSERT_ERR_RETRY(error == 0, retries, retry);
1001
1002 /* release the UDP port binding, should succeed */
1003 uuid_copy(nfr.nfr_flow_uuid, udp_flow);
1004 uuid_unparse_upper(nfr.nfr_flow_uuid, uuidstr);
1005 T_LOG("On %s (%s) release port %u protocol %d (flow %s)\n",
1006 handles.netif_ifname, buf0, ntohs(nfr.nfr_saddr.sin.sin_port),
1007 nfr.nfr_ip_protocol, uuidstr);
1008 error = __os_nexus_flow_del(handles.controller,
1009 handles.fsw_nx_uuid, &nfr);
1010 SKTC_ASSERT_ERR(error == 0);
1011
1012 /* double release the UDP port binding, should fail */
1013 uuid_copy(nfr.nfr_flow_uuid, udp_flow);
1014 uuid_unparse_upper(nfr.nfr_flow_uuid, uuidstr);
1015 T_LOG("On %s (%s) confirm we can't double-release "
1016 "port %u protocol %d (flow %s)\n", handles.netif_ifname, buf0,
1017 ntohs(nfr.nfr_saddr.sin.sin_port), nfr.nfr_ip_protocol,
1018 uuidstr);
1019 error = __os_nexus_flow_del(handles.controller,
1020 handles.fsw_nx_uuid, &nfr);
1021 //SKTC_ASSERT_ERR(error != 0);
1022
1023 /* Confirm same UDP port is now available on socket */
1024 T_LOG("Confirm port %u protocol %d is now available to "
1025 "BSD stack\n", ntohs(nfr.nfr_saddr.sin.sin_port),
1026 nfr.nfr_ip_protocol);
1027 sock = socket(PF_INET, (nfr.nfr_ip_protocol == IPPROTO_TCP) ?
1028 SOCK_STREAM : SOCK_DGRAM, nfr.nfr_ip_protocol);
1029 SKTC_ASSERT_ERR_RETRY(sock != -1, retries, retry);
1030
1031 memset(&sa, 0, sizeof sa);
1032 sa.sin_family = AF_INET;
1033 sa.sin_port = nfr.nfr_saddr.sin.sin_port;
1034 sa.sin_addr.s_addr = htonl(INADDR_ANY);
1035 error = bind(sock, (struct sockaddr *)&sa, sizeof sa);
1036 SKTC_ASSERT_ERR(error == 0);
1037 close(sock);
1038
1039 /* release the TCP port skywalk binding */
1040 nfr.nfr_ip_protocol = INVERT_PROTO(nfr.nfr_ip_protocol);
1041 uuid_copy(nfr.nfr_flow_uuid, tcp_flow);
1042 uuid_unparse_upper(nfr.nfr_flow_uuid, uuidstr);
1043 T_LOG("On %s (%s) release port %u protocol %d (flow %s)\n",
1044 handles.netif_ifname, buf0, ntohs(nfr.nfr_saddr.sin.sin_port),
1045 nfr.nfr_ip_protocol, uuidstr);
1046 error = __os_nexus_flow_del(handles.controller,
1047 handles.fsw_nx_uuid, &nfr);
1048 SKTC_ASSERT_ERR(error == 0);
1049
1050 /* double release the TCP port binding, should fail */
1051 uuid_copy(nfr.nfr_flow_uuid, tcp_flow);
1052 uuid_unparse_upper(nfr.nfr_flow_uuid, uuidstr);
1053 T_LOG("On %s (%s) confirm we can't double-release "
1054 "port %u protocol %d (flow %s)\n", handles.netif_ifname, buf0,
1055 ntohs(nfr.nfr_saddr.sin.sin_port), nfr.nfr_ip_protocol,
1056 uuidstr);
1057 error = __os_nexus_flow_del(handles.controller,
1058 handles.fsw_nx_uuid, &nfr);
1059 //SKTC_ASSERT_ERR(error != 0);
1060
1061 /* Confirm same TCP port is now available on socket */
1062 T_LOG("Confirm port %u protocol %d is now available to "
1063 "BSD stack\n", ntohs(nfr.nfr_saddr.sin.sin_port),
1064 nfr.nfr_ip_protocol);
1065 sock = socket(PF_INET, (nfr.nfr_ip_protocol == IPPROTO_TCP) ?
1066 SOCK_STREAM : SOCK_DGRAM, nfr.nfr_ip_protocol);
1067 SKTC_ASSERT_ERR_RETRY(sock != -1, retries, retry);
1068
1069 memset(&sa, 0, sizeof sa);
1070 sa.sin_family = AF_INET;
1071 sa.sin_port = nfr.nfr_saddr.sin.sin_port;
1072 sa.sin_addr.s_addr = htonl(INADDR_ANY);
1073
1074 error = bind(sock, (struct sockaddr *)&sa, sizeof sa);
1075 SKTC_ASSERT_ERR(error == 0);
1076
1077 close(sock);
1078 retries = 0;
1079 retry:
1080 sktc_cleanup_flowswitch(&handles);
1081 if (retries > 0) {
1082 if (retries < RETRY_MAX) {
1083 goto start;
1084 }
1085 T_LOG("ERROR: exceeds max %d retries\n", RETRY_MAX);
1086 return -1;
1087 }
1088 return 0;
1089 }
1090
1091 #undef SKTC_ASSERT_ERR_RETRY
1092 #undef RETRY_MAX
1093
1094 static void
skt_flowswitch_ns_reserve_main2_init(void)1095 skt_flowswitch_ns_reserve_main2_init(void)
1096 {
1097 sktc_ifnet_feth0_1_create();
1098 sktc_set_tcp_msl(SKT_TCP_MSL_DELAY);
1099 }
1100
1101 static void
skt_flowswitch_ns_reserve_main2_cleanup(void)1102 skt_flowswitch_ns_reserve_main2_cleanup(void)
1103 {
1104 sktc_ifnet_feth0_1_destroy();
1105 sktc_restore_tcp_msl();
1106 }
1107
1108 struct skywalk_test skt_flowswitch_ns_reserve = {
1109 "flowswitch_ns_reserve", "test confirms that flowswitches can reserve L4 ports",
1110 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
1111 skt_flowswitch_ns_reserve_main, { NULL },
1112 sktc_ifnet_feth0_1_create, sktc_ifnet_feth0_1_destroy,
1113 };
1114
1115 struct skywalk_test skt_flowswitch_ns_reserve2 = {
1116 "flowswitch_ns_reserve2", "throrough test of netns for both BSD & flowswitch, IPv4/v6",
1117 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
1118 skt_flowswitch_ns_reserve_main2, { NULL },
1119 skt_flowswitch_ns_reserve_main2_init,
1120 skt_flowswitch_ns_reserve_main2_cleanup,
1121 };
1122
1123 /****************************************************************/
1124