1 /*
2 * Copyright (c) 2021-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 #include <sys/sysctl.h>
29 #include "skywalk_test_driver.h"
30 #include "skywalk_test_utils.h"
31 #include "skywalk_test_common.h"
32
33 #define TEST_LPORT 12345
34 #define TEST_RPORT 45678
35 #define TEST_QSET_ID 0x0001
36
37 static void
fill_traffic_descriptor_eth(struct ifnet_traffic_descriptor_eth * td,uint8_t mask,bool fill_valid_td)38 fill_traffic_descriptor_eth(struct ifnet_traffic_descriptor_eth *td,
39 uint8_t mask, bool fill_valid_td)
40 {
41 ether_addr_t dst_mac_addr = {0};
42 int err;
43
44 bzero(td, sizeof(*td));
45
46 td->eth_common.itd_type = IFNET_TRAFFIC_DESCRIPTOR_TYPE_ETH;
47 td->eth_common.itd_len = sizeof(*td);
48 td->eth_common.itd_flags = IFNET_TRAFFIC_DESCRIPTOR_FLAG_INBOUND |
49 IFNET_TRAFFIC_DESCRIPTOR_FLAG_OUTBOUND;
50
51 td->eth_mask = mask;
52 if (mask & IFNET_TRAFFIC_DESCRIPTOR_ETH_MASK_ETHER_TYPE) {
53 td->eth_type = (fill_valid_td) ? ETHERTYPE_PAE : ETHERTYPE_IP;
54 }
55 if (mask & IFNET_TRAFFIC_DESCRIPTOR_ETH_MASK_RADDR) {
56 if (fill_valid_td) {
57 err = sktc_get_mac_addr(FETH0_NAME, dst_mac_addr.octet);
58 assert(err == 0);
59 }
60 bcopy(&dst_mac_addr, &td->eth_raddr, ETHER_ADDR_LEN);
61 }
62 }
63
64 static void
fill_traffic_descriptor_v4(struct ifnet_traffic_descriptor_inet * td)65 fill_traffic_descriptor_v4(struct ifnet_traffic_descriptor_inet *td)
66 {
67 struct in_addr feth0_addr, feth1_addr;
68
69 bzero(td, sizeof(*td));
70
71 td->inet_common.itd_type = IFNET_TRAFFIC_DESCRIPTOR_TYPE_INET;
72 td->inet_common.itd_len = sizeof(*td);
73 td->inet_common.itd_flags = IFNET_TRAFFIC_DESCRIPTOR_FLAG_INBOUND |
74 IFNET_TRAFFIC_DESCRIPTOR_FLAG_OUTBOUND;
75
76 td->inet_mask = IFNET_TRAFFIC_DESCRIPTOR_INET_IPVER |
77 IFNET_TRAFFIC_DESCRIPTOR_INET_PROTO |
78 IFNET_TRAFFIC_DESCRIPTOR_INET_LADDR |
79 IFNET_TRAFFIC_DESCRIPTOR_INET_RADDR |
80 IFNET_TRAFFIC_DESCRIPTOR_INET_LPORT |
81 IFNET_TRAFFIC_DESCRIPTOR_INET_RPORT;
82
83 td->inet_ipver = IPVERSION;
84 td->inet_proto = IPPROTO_TCP;
85
86 feth0_addr = sktc_feth0_in_addr();
87 td->inet_laddr.iia_v4addr = feth0_addr.s_addr;
88 feth1_addr = sktc_feth1_in_addr();
89 td->inet_raddr.iia_v4addr = feth1_addr.s_addr;
90
91 td->inet_lport = htons(TEST_LPORT);
92 td->inet_rport = htons(TEST_RPORT);
93 }
94
95 static void
fill_traffic_descriptor_v6(struct ifnet_traffic_descriptor_inet * td)96 fill_traffic_descriptor_v6(struct ifnet_traffic_descriptor_inet *td)
97 {
98 bzero(td, sizeof(*td));
99
100 td->inet_common.itd_type = IFNET_TRAFFIC_DESCRIPTOR_TYPE_INET;
101 td->inet_common.itd_len = sizeof(*td);
102 td->inet_common.itd_flags = IFNET_TRAFFIC_DESCRIPTOR_FLAG_INBOUND |
103 IFNET_TRAFFIC_DESCRIPTOR_FLAG_OUTBOUND;
104
105 td->inet_mask = IFNET_TRAFFIC_DESCRIPTOR_INET_IPVER |
106 IFNET_TRAFFIC_DESCRIPTOR_INET_PROTO |
107 IFNET_TRAFFIC_DESCRIPTOR_INET_LADDR |
108 IFNET_TRAFFIC_DESCRIPTOR_INET_RADDR |
109 IFNET_TRAFFIC_DESCRIPTOR_INET_LPORT |
110 IFNET_TRAFFIC_DESCRIPTOR_INET_RPORT;
111
112 td->inet_ipver = IPV6_VERSION;
113 td->inet_proto = IPPROTO_TCP;
114
115 sktc_feth0_inet6_addr((in6_addr_t *)&td->inet_laddr);
116 sktc_feth1_inet6_addr((in6_addr_t *)&td->inet_raddr);
117 td->inet_lport = htons(TEST_LPORT);
118 td->inet_rport = htons(TEST_RPORT);
119 }
120
121 static void
fill_traffic_rule_action(struct ifnet_traffic_rule_action_steer * ra)122 fill_traffic_rule_action(struct ifnet_traffic_rule_action_steer *ra)
123 {
124 bzero(ra, sizeof(*ra));
125
126 ra->ras_common.ra_type = IFNET_TRAFFIC_RULE_ACTION_STEER;
127 ra->ras_common.ra_len = sizeof(*ra);
128 ra->ras_qset_id = TEST_QSET_ID;
129 }
130
131 static int
skt_steering_main(int argc,char * argv[])132 skt_steering_main(int argc, char *argv[])
133 {
134 nexus_controller_t ctl;
135 struct ifnet_traffic_descriptor_inet td;
136 struct ifnet_traffic_descriptor_eth td_eth;
137 struct ifnet_traffic_rule_action_steer ra;
138 uuid_t v4_rule, v6_rule;
139 uuid_t eth_type_rule, eth_raddr_rule, eth_rule;
140 uint8_t mask;
141 int err;
142
143 ctl = os_nexus_controller_create();
144 assert(ctl != NULL);
145
146 fill_traffic_rule_action(&ra);
147
148 //Adding v4 rule is successful
149 fill_traffic_descriptor_v4(&td);
150 err = os_nexus_controller_add_traffic_rule(ctl, FETH0_NAME,
151 (struct ifnet_traffic_descriptor_common *)&td,
152 (struct ifnet_traffic_rule_action *)&ra, 0, &v4_rule);
153 assert(err == 0);
154
155 //Adding eth & inet rules concurrently is not successful
156 mask = IFNET_TRAFFIC_DESCRIPTOR_ETH_MASK_ETHER_TYPE;
157 fill_traffic_descriptor_eth(&td_eth, mask, true);
158 err = os_nexus_controller_add_traffic_rule(ctl, FETH0_NAME,
159 (struct ifnet_traffic_descriptor_common *)&td_eth,
160 (struct ifnet_traffic_rule_action *)&ra, 0, ð_type_rule);
161 assert(err != 0);
162
163 //Adding v6 rule is successful
164 fill_traffic_descriptor_v6(&td);
165 err = os_nexus_controller_add_traffic_rule(ctl, FETH0_NAME,
166 (struct ifnet_traffic_descriptor_common *)&td,
167 (struct ifnet_traffic_rule_action *)&ra, 0, &v6_rule);
168 assert(err == 0);
169
170 //Removing v4 rule is successful
171 err = os_nexus_controller_remove_traffic_rule(ctl, v4_rule);
172 assert(err == 0);
173
174 //Removing v6 rule is successful
175 err = os_nexus_controller_remove_traffic_rule(ctl, v6_rule);
176 assert(err == 0);
177
178 //Adding eth type rule is successful (All the inet rules are removed)
179 mask = IFNET_TRAFFIC_DESCRIPTOR_ETH_MASK_ETHER_TYPE;
180 fill_traffic_descriptor_eth(&td_eth, mask, true);
181 err = os_nexus_controller_add_traffic_rule(ctl, FETH0_NAME,
182 (struct ifnet_traffic_descriptor_common *)&td_eth,
183 (struct ifnet_traffic_rule_action *)&ra, 0, ð_type_rule);
184 assert(err == 0);
185
186 //Adding duplicate eth type rule is not successful
187 err = os_nexus_controller_add_traffic_rule(ctl, FETH0_NAME,
188 (struct ifnet_traffic_descriptor_common *)&td_eth,
189 (struct ifnet_traffic_rule_action *)&ra, 0, ð_rule);
190 assert(err != 0);
191
192 //Adding eth & inet rules concurrently is not successful
193 fill_traffic_descriptor_v4(&td);
194 err = os_nexus_controller_add_traffic_rule(ctl, FETH0_NAME,
195 (struct ifnet_traffic_descriptor_common *)&td,
196 (struct ifnet_traffic_rule_action *)&ra, 0, &v4_rule);
197 assert(err != 0);
198
199 //Adding eth raddr rule is successful
200 mask = IFNET_TRAFFIC_DESCRIPTOR_ETH_MASK_RADDR;
201 fill_traffic_descriptor_eth(&td_eth, mask, true);
202 err = os_nexus_controller_add_traffic_rule(ctl, FETH0_NAME,
203 (struct ifnet_traffic_descriptor_common *)&td_eth,
204 (struct ifnet_traffic_rule_action *)&ra, 0, ð_raddr_rule);
205 assert(err == 0);
206
207 //Adding duplicate eth raddr rule is not successful
208 err = os_nexus_controller_add_traffic_rule(ctl, FETH0_NAME,
209 (struct ifnet_traffic_descriptor_common *)&td_eth,
210 (struct ifnet_traffic_rule_action *)&ra, 0, ð_raddr_rule);
211 assert(err != 0);
212
213 //Adding a different eth raddr rule is successful
214 bcopy(ether_aton("11:22:33:44:55:66"), &td_eth.eth_raddr, ETHER_ADDR_LEN);
215 err = os_nexus_controller_add_traffic_rule(ctl, FETH0_NAME,
216 (struct ifnet_traffic_descriptor_common *)&td_eth,
217 (struct ifnet_traffic_rule_action *)&ra, 0, ð_rule);
218 assert(err == 0);
219
220 //Removing eth type rule is successful
221 err = os_nexus_controller_remove_traffic_rule(ctl, eth_type_rule);
222 assert(err == 0);
223
224 //Removing eth raddr rule is successful
225 err = os_nexus_controller_remove_traffic_rule(ctl, eth_raddr_rule);
226 assert(err == 0);
227 err = os_nexus_controller_remove_traffic_rule(ctl, eth_rule);
228 assert(err == 0);
229
230 //Adding eth type & raddr rule is not successful
231 mask = IFNET_TRAFFIC_DESCRIPTOR_ETH_MASK_ETHER_TYPE |
232 IFNET_TRAFFIC_DESCRIPTOR_ETH_MASK_RADDR;
233 fill_traffic_descriptor_eth(&td_eth, mask, true);
234 err = os_nexus_controller_add_traffic_rule(ctl, FETH0_NAME,
235 (struct ifnet_traffic_descriptor_common *)&td_eth,
236 (struct ifnet_traffic_rule_action *)&ra, 0, ð_rule);
237 assert(err != 0);
238
239 //Adding invalid eth type rule is not successful
240 mask = IFNET_TRAFFIC_DESCRIPTOR_ETH_MASK_ETHER_TYPE;
241 fill_traffic_descriptor_eth(&td_eth, mask, false);
242 err = os_nexus_controller_add_traffic_rule(ctl, FETH0_NAME,
243 (struct ifnet_traffic_descriptor_common *)&td_eth,
244 (struct ifnet_traffic_rule_action *)&ra, 0, ð_rule);
245 assert(err != 0);
246
247 //Adding invalid eth raddr rule is not successful
248 mask = IFNET_TRAFFIC_DESCRIPTOR_ETH_MASK_RADDR;
249 fill_traffic_descriptor_eth(&td_eth, mask, false);
250 err = os_nexus_controller_add_traffic_rule(ctl, FETH0_NAME,
251 (struct ifnet_traffic_descriptor_common *)&td_eth,
252 (struct ifnet_traffic_rule_action *)&ra, 0, ð_rule);
253 assert(err != 0);
254
255 os_nexus_controller_destroy(ctl);
256 return 0;
257 }
258
259 static uint32_t skt_netif_nxctl_check;
260 static void
skt_steering_init(void)261 skt_steering_init(void)
262 {
263 uint32_t nxctl_check = 1;
264 size_t len = sizeof(skt_netif_nxctl_check);
265
266 assert(sysctlbyname("kern.skywalk.disable_nxctl_check",
267 &skt_netif_nxctl_check, &len, &nxctl_check,
268 sizeof(nxctl_check)) == 0);
269 sktc_ifnet_feth_pair_create(FETH_FLAGS_NATIVE |
270 FETH_FLAGS_NXATTACH);
271 }
272
273 static void
skt_steering_fini(void)274 skt_steering_fini(void)
275 {
276 assert(sysctlbyname("kern.skywalk.disable_nxctl_check",
277 NULL, NULL, &skt_netif_nxctl_check,
278 sizeof(skt_netif_nxctl_check)) == 0);
279 sktc_ifnet_feth_pair_destroy();
280 }
281
282 struct skywalk_test skt_steering = {
283 "steering",
284 "steering rules test",
285 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF | SK_FEATURE_DEV_OR_DEBUG,
286 skt_steering_main,
287 { NULL },
288 skt_steering_init, skt_steering_fini,
289 };
290