1 /*
2 * Copyright (c) 2019-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 <err.h>
30 #include <assert.h>
31 #include <errno.h>
32 #include <semaphore.h>
33 #include <stdio.h>
34 #include <spawn.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sysexits.h>
38 #include <sys/socket.h>
39 #include <uuid/uuid.h>
40 #include <unistd.h>
41 #include <arpa/inet.h>
42 #include <darwintest.h>
43 #include "skywalk_test_driver.h"
44 #include "skywalk_test_utils.h"
45 #include "skywalk_test_common.h"
46
47 static const char * ifname;
48 static struct in_addr our_ip, dst_ip, zero_ip, nowhere_ip;
49 static struct in_addr our_mask;
50 static struct sktc_nexus_handles handles;
51
52 #define SEM_1ST_FLOW_CREATED "/skt_mpprotons_1FC"
53 #define SEM_2ND_FLOW_FAILED "/skt_mpprotons_2FF"
54
55 static void
skt_flow_req_should_succeed(sa_family_t af,void * src,void * dst,uint8_t protocol,uint16_t sport,uint16_t dport)56 skt_flow_req_should_succeed(sa_family_t af, void *src, void *dst,
57 uint8_t protocol, uint16_t sport, uint16_t dport)
58 {
59 struct sktu_flow *flow;
60
61 flow = sktu_create_nexus_flow(&handles, af, src, dst, protocol, sport, dport);
62 assert(flow);
63 }
64
65 static void
skt_flow_req_should_fail(sa_family_t af,void * src,void * dst,uint8_t protocol,uint16_t sport,uint16_t dport)66 skt_flow_req_should_fail(sa_family_t af, void *src, void *dst,
67 uint8_t protocol, uint16_t sport, uint16_t dport)
68 {
69 struct sktu_flow *flow;
70
71 flow = sktu_create_nexus_flow(&handles, af, src, dst, protocol, sport, dport);
72 assert(!flow);
73 }
74
75 static int
skt_protons_main(int argc,char * argv[])76 skt_protons_main(int argc, char *argv[])
77 {
78 ifname = FETH0_NAME;
79 our_mask = sktc_make_in_addr(IN_CLASSC_NET);
80 our_ip = sktc_feth0_in_addr();
81 dst_ip = sktc_feth1_in_addr();
82 zero_ip = (struct in_addr){.s_addr = htonl(INADDR_ANY)};
83 nowhere_ip = sktc_nowhere_in_addr();
84
85 bzero(&handles, sizeof(handles));
86 strlcpy(handles.netif_ifname, ifname, sizeof(handles.netif_ifname));
87 handles.netif_addr = our_ip;
88 handles.netif_mask = our_mask;
89 sktc_create_flowswitch_no_address(&handles, -1, -1, -1, -1, 0);
90
91 skt_flow_req_should_fail(AF_INET, &our_ip, &dst_ip, IPPROTO_TCP, 0, 0);
92 skt_flow_req_should_fail(AF_INET, &our_ip, &dst_ip, IPPROTO_UDP, 0, 0);
93 skt_flow_req_should_fail(AF_INET, &our_ip, &dst_ip, IPPROTO_TTP, 1, 0);
94 skt_flow_req_should_fail(AF_INET, &our_ip, &dst_ip, IPPROTO_TTP, 0, 1);
95 skt_flow_req_should_fail(AF_INET, &our_ip, &dst_ip, IPPROTO_TTP, 1, 1);
96 skt_flow_req_should_fail(AF_INET, &our_ip, &dst_ip, IPPROTO_RAW, 0, 0);
97
98 skt_flow_req_should_succeed(AF_INET, &our_ip, &dst_ip, IPPROTO_TTP, 0, 0);
99 skt_flow_req_should_succeed(AF_INET, &our_ip, &nowhere_ip, IPPROTO_TTP, 0, 0);
100 skt_flow_req_should_fail(AF_INET, &our_ip, &dst_ip, IPPROTO_TTP, 0, 0);
101
102 sktc_cleanup_flowswitch(&handles);
103
104 return 0;
105 }
106
107 static void
skt_protons_net_init(void)108 skt_protons_net_init(void)
109 {
110 sktc_ifnet_feth_pair_create(FETH_FLAGS_TXSTART);
111 }
112
113 static void
skt_protons_net_fini(void)114 skt_protons_net_fini(void)
115 {
116 sktc_ifnet_feth_pair_destroy();
117
118 // cleanup any leftovers
119 sem_unlink(SEM_1ST_FLOW_CREATED);
120 sem_unlink(SEM_2ND_FLOW_FAILED);
121 }
122
123 struct skywalk_test skt_protons = {
124 .skt_testname = "protons",
125 .skt_testdesc = "test skywalk protocol namespace",
126 .skt_required_features = SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
127 .skt_main = skt_protons_main,
128 .skt_argv = { NULL },
129 .skt_init = skt_protons_net_init,
130 .skt_fini = skt_protons_net_fini,
131 };
132
133 /****************************************************************/
134
135 static int
skt_mpprotons_main(int argc,char * argv[])136 skt_mpprotons_main(int argc, char *argv[])
137 {
138 char buf[1] = { 0 };
139 const char * ifname;
140 struct in_addr our_ip, peer_ip;
141 struct in_addr our_mask;
142 ssize_t ret;
143
144 assert(!strcmp(argv[3], "--child"));
145 int child = atoi(argv[4]);
146 T_LOG("in child %d\n", child);
147
148 if (child == 0) {
149 ifname = FETH0_NAME;
150 our_ip = sktc_feth0_in_addr();
151 peer_ip = sktc_feth1_in_addr();
152 } else {
153 child = 1;
154 ifname = FETH1_NAME;
155 our_ip = sktc_feth1_in_addr();
156 peer_ip = sktc_feth0_in_addr();
157 }
158 our_mask = sktc_make_in_addr(IN_CLASSC_NET);
159
160 bzero(&handles, sizeof(handles));
161 strlcpy(handles.netif_ifname, ifname, sizeof(handles.netif_ifname));
162 handles.netif_addr = our_ip;
163 handles.netif_mask = our_mask;
164 sktc_create_flowswitch_no_address(&handles, -1, -1, -1, -1, 0);
165
166 sem_t *sem_flow_created = sem_open(SEM_1ST_FLOW_CREATED, O_CREAT, 0660, 0);
167 sem_t *sem_dup_flow_failed = sem_open(SEM_2ND_FLOW_FAILED, O_CREAT, 0660, 0);
168 if (sem_flow_created == SEM_FAILED || sem_dup_flow_failed == SEM_FAILED) {
169 err(EX_OSERR, "sem open failed");
170 }
171
172 if ((ret = write(MPTEST_SEQ_FILENO, buf, sizeof(buf))) == -1) {
173 SKT_LOG("write fail: %s\n", strerror(errno));
174 return 1;
175 }
176 assert(ret == 1);
177
178 /* Wait for go signal */
179 if ((ret = read(MPTEST_SEQ_FILENO, buf, sizeof(buf))) == -1) {
180 SKT_LOG("read fail: %s\n", strerror(errno));
181 return 1;
182 }
183 assert(ret == 1);
184
185 if (child == 0) {
186 skt_flow_req_should_succeed(AF_INET, &our_ip, &dst_ip, IPPROTO_IPEIP, 0, 0);
187 sem_post(sem_flow_created);
188 sem_wait(sem_dup_flow_failed);
189 sem_post(sem_dup_flow_failed);
190 }
191
192 if (child == 1) {
193 sem_wait(sem_flow_created);
194 skt_flow_req_should_fail(AF_INET, &our_ip, &dst_ip, IPPROTO_IPEIP, 0, 0);
195 sem_post(sem_flow_created);
196 sem_post(sem_dup_flow_failed);
197 }
198
199 sem_close(sem_flow_created);
200 sem_close(sem_dup_flow_failed);
201
202 return 0;
203 }
204
205 struct skywalk_mptest skt_mpprotons = {
206 .skt_testname = "mpprotons",
207 .skt_testdesc = "test skywalk protocol namespace with two process doing conflicting reservation",
208 .skt_required_features = SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF | SK_FEATURE_NEXUS_FLOWSWITCH,
209 .skt_nchildren = 2,
210 .skt_main = skt_mpprotons_main,
211 .skt_init = skt_protons_net_init,
212 .skt_fini = skt_protons_net_fini,
213 };
214