1 /*
2 * Copyright (c) 2016-2023 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 <skywalk/os_skywalk_private.h>
30 #include <skywalk/nexus/flowswitch/nx_flowswitch.h>
31 #include <skywalk/nexus/flowswitch/fsw_var.h>
32
33 /* automatically register a netagent at constructor time */
34 static int fsw_netagent = 1;
35
36 #if (DEVELOPMENT || DEBUG)
37 SYSCTL_INT(_kern_skywalk_flowswitch, OID_AUTO, netagent,
38 CTLFLAG_RW | CTLFLAG_LOCKED, &fsw_netagent, 0, "");
39 #endif /* !DEVELOPMENT && !DEBUG */
40
41 static packet_svc_class_t
fsw_netagent_tc2sc(uint32_t tc,uint32_t * scp)42 fsw_netagent_tc2sc(uint32_t tc, uint32_t *scp)
43 {
44 uint32_t sc;
45 int ret = 0;
46
47 switch (tc) {
48 case SO_TC_BK_SYS:
49 sc = PKT_SC_BK_SYS;
50 break;
51 case SO_TC_BK:
52 sc = PKT_SC_BK;
53 break;
54 case SO_TC_BE:
55 sc = PKT_SC_BE;
56 break;
57 case SO_TC_RD:
58 sc = PKT_SC_RD;
59 break;
60 case SO_TC_OAM:
61 sc = PKT_SC_OAM;
62 break;
63 case SO_TC_AV:
64 sc = PKT_SC_AV;
65 break;
66 case SO_TC_RV:
67 sc = PKT_SC_RV;
68 break;
69 case SO_TC_VI:
70 sc = PKT_SC_VI;
71 break;
72 case SO_TC_NETSVC_SIG:
73 sc = PKT_SC_SIG;
74 break;
75 case SO_TC_VO:
76 sc = PKT_SC_VO;
77 break;
78 case SO_TC_CTL:
79 sc = PKT_SC_CTL;
80 break;
81 default:
82 sc = PKT_SC_BE;
83 ret = -1;
84 break;
85 }
86
87 *scp = sc;
88 return ret;
89 }
90
91 static int
fsw_netagent_flow_add(struct nx_flowswitch * fsw,uuid_t flow_uuid,pid_t pid,void * context,struct necp_client_nexus_parameters * cparams,void ** results,size_t * results_length)92 fsw_netagent_flow_add(struct nx_flowswitch *fsw, uuid_t flow_uuid, pid_t pid,
93 void *context, struct necp_client_nexus_parameters *cparams,
94 void **results, size_t *results_length)
95 {
96 struct nx_flow_req req;
97 struct flow_owner *fo = NULL;
98 size_t assign_message_length = 0;
99 void *assign_message = NULL;
100 struct necp_client_endpoint local_endpoint;
101 struct necp_client_endpoint remote_endpoint;
102 int error;
103
104 ASSERT(cparams != NULL);
105 ASSERT(results != NULL && *results == NULL);
106 ASSERT(results_length != NULL && *results_length == 0);
107
108 bzero(&req, sizeof(req));
109 req.nfr_nx_port = NEXUS_PORT_ANY;
110 req.nfr_flowadv_idx = FLOWADV_IDX_NONE;
111 bcopy((void *)&cparams->local_addr, (void *)&req.nfr_saddr,
112 sizeof(cparams->local_addr));
113 bcopy((void *)&cparams->remote_addr, (void *)&req.nfr_daddr,
114 sizeof(cparams->remote_addr));
115 req.nfr_flags = (NXFLOWREQF_TRACK | NXFLOWREQF_FLOWADV);
116 req.nfr_ip_protocol = cparams->ip_protocol;
117 req.nfr_transport_protocol = cparams->transport_protocol;
118 uuid_copy(req.nfr_flow_uuid, flow_uuid);
119 uuid_copy(req.nfr_euuid, cparams->euuid);
120 req.nfr_epid = cparams->epid;
121 req.nfr_policy_id = (uint32_t)cparams->policy_id;
122 req.nfr_skip_policy_id = (uint32_t)cparams->skip_policy_id;
123
124 if (fsw_netagent_tc2sc(cparams->traffic_class,
125 &req.nfr_svc_class) != 0) {
126 error = EINVAL;
127 goto done;
128 }
129
130 if (cparams->allow_qos_marking) {
131 req.nfr_flags |= NXFLOWREQF_QOS_MARKING;
132 }
133 if (cparams->override_address_selection) {
134 req.nfr_flags |= NXFLOWREQF_OVERRIDE_ADDRESS_SELECTION;
135 }
136 if (cparams->use_stable_address) {
137 req.nfr_flags |= NXFLOWREQF_USE_STABLE_ADDRESS;
138 }
139 if (cparams->no_wake_from_sleep) {
140 req.nfr_flags |= NXFLOWREQF_NOWAKEFROMSLEEP;
141 }
142 if (cparams->reuse_port) {
143 req.nfr_flags |= NXFLOWREQF_REUSEPORT;
144 }
145
146 req.nfr_context = context;
147 req.nfr_pid = pid;
148 req.nfr_port_reservation = cparams->port_reservation;
149
150 if (cparams->is_demuxable_parent) {
151 req.nfr_flags |= NXFLOWREQF_PARENT;
152 } else {
153 uuid_copy(req.nfr_parent_flow_uuid, cparams->parent_flow_uuid);
154 if (cparams->demux_pattern_count > 0) {
155 if (cparams->demux_pattern_count > MAX_FLOW_DEMUX_PATTERN) {
156 error = EINVAL;
157 goto done;
158 }
159
160 _CASSERT(sizeof(struct necp_demux_pattern) == sizeof(struct flow_demux_pattern));
161 for (int i = 0; i < cparams->demux_pattern_count; i++) {
162 memcpy(&req.nfr_flow_demux_patterns[i], &cparams->demux_patterns[i],
163 sizeof(struct flow_demux_pattern));
164 }
165 req.nfr_flow_demux_count = cparams->demux_pattern_count;
166 }
167 }
168
169 ASSERT(req.nfr_flags & NXFLOWREQF_FLOWADV);
170 fo = fsw_flow_add(fsw, &req, &error);
171 if (fo == NULL) {
172 ASSERT(error != 0);
173 ASSERT(req.nfr_flow_stats == NULL);
174 goto done;
175 }
176
177 ASSERT(error == 0);
178 ASSERT(req.nfr_nx_port != NEXUS_PORT_ANY);
179 ASSERT(!uuid_is_null(fo->fo_key));
180 ASSERT(req.nfr_flowadv_idx != FLOWADV_IDX_NONE);
181 ASSERT(req.nfr_flow_stats != NULL);
182 ASSERT(flow_stats_refcnt(req.nfr_flow_stats) >= 1);
183
184 bzero(&local_endpoint, sizeof(local_endpoint));
185 bzero(&remote_endpoint, sizeof(remote_endpoint));
186
187 bcopy((void *)&req.nfr_saddr, (void *)&local_endpoint.u.sin6,
188 sizeof(req.nfr_saddr));
189 bcopy((void *)&req.nfr_daddr, (void *)&remote_endpoint.u.sin6,
190 sizeof(req.nfr_daddr));
191
192 assign_message =
193 necp_create_nexus_assign_message(fsw->fsw_nx->nx_uuid,
194 req.nfr_nx_port, fo->fo_key, sizeof(fo->fo_key),
195 &local_endpoint, &remote_endpoint, NULL, req.nfr_flowadv_idx,
196 req.nfr_flow_stats, &assign_message_length);
197
198 if (assign_message != NULL) {
199 req.nfr_flow_stats = NULL;
200 ASSERT(error == 0);
201 *results = assign_message;
202 *results_length = assign_message_length;
203 } else {
204 error = ENOMEM;
205 }
206
207 done:
208 #if SK_LOG
209 if (__improbable((sk_verbose & SK_VERB_FLOW) != 0)) {
210 uuid_string_t uuidstr;
211 SK_DF(SK_VERB_FLOW, "pid %d connect flow_uuid %s nx_port %d "
212 "(err %d)", pid, sk_uuid_unparse(flow_uuid, uuidstr),
213 (int)req.nfr_nx_port, error);
214 }
215 #endif /* SK_LOG */
216 if (error != 0) {
217 ASSERT(*results == NULL);
218 ASSERT(*results_length == 0);
219 if (assign_message != NULL) {
220 kfree_data(assign_message, assign_message_length);
221 assign_message = NULL;
222 }
223 if (fo != NULL) {
224 req.nfr_pid = pid;
225 fsw_flow_del(fsw, &req, TRUE, NULL);
226 }
227 if (req.nfr_flow_stats != NULL) {
228 flow_stats_release(req.nfr_flow_stats);
229 req.nfr_flow_stats = NULL;
230 }
231 }
232
233 return error;
234 }
235
236 static int
fsw_netagent_flow_del(struct nx_flowswitch * fsw,uuid_t flow_uuid,pid_t pid,bool nolinger,void * context,void * params)237 fsw_netagent_flow_del(struct nx_flowswitch *fsw, uuid_t flow_uuid, pid_t pid,
238 bool nolinger, void *context, void *params)
239 {
240 struct nx_flow_req req;
241 int error;
242
243 bzero(&req, sizeof(req));
244 uuid_copy(req.nfr_flow_uuid, flow_uuid);
245 req.nfr_proc = NULL;
246 req.nfr_pid = pid;
247 req.nfr_context = context;
248
249 error = fsw_flow_del(fsw, &req, nolinger, params);
250
251 #if SK_LOG
252 if (__improbable((sk_verbose & SK_VERB_FLOW) != 0)) {
253 uuid_string_t uuidstr;
254 SK_DF(SK_VERB_FLOW, "pid %d flow_uuid %s (err %d)",
255 pid, sk_uuid_unparse(flow_uuid, uuidstr), error);
256 }
257 #endif /* SK_LOG */
258
259 return error;
260 }
261
262 static int
fsw_netagent_event(u_int8_t event,uuid_t flow_uuid,pid_t pid,void * context,void * ctx,struct necp_client_agent_parameters * cparams,void ** results,size_t * results_length)263 fsw_netagent_event(u_int8_t event, uuid_t flow_uuid, pid_t pid, void *context,
264 void *ctx, struct necp_client_agent_parameters *cparams, void **results,
265 size_t *results_length)
266 {
267 struct nx_flowswitch *fsw;
268 int error = 0;
269
270 ASSERT(!uuid_is_null(flow_uuid));
271
272 fsw = (struct nx_flowswitch *)ctx;
273 ASSERT(fsw != NULL);
274
275 switch (event) {
276 case NETAGENT_EVENT_NEXUS_FLOW_INSERT:
277 /* these are required for this event */
278 ASSERT(cparams != NULL);
279 ASSERT(results != NULL);
280 ASSERT(results_length != NULL);
281 *results = NULL;
282 *results_length = 0;
283 error = fsw_netagent_flow_add(fsw, flow_uuid, pid, context,
284 &cparams->u.nexus_request, results, results_length);
285 break;
286
287 case NETAGENT_EVENT_NEXUS_FLOW_REMOVE:
288 case NETAGENT_EVENT_NEXUS_FLOW_ABORT:
289 /*
290 * A flow can be removed gracefully (FLOW_REMOVE) by
291 * the client, in which case we don't need to have it
292 * linger around to hold the namespace. If the process
293 * crashed or if it's suspended, then we treat that
294 * as the abort case (FLOW_ABORT) where we'll hold on
295 * to the namespace if needed.
296 */
297 error = fsw_netagent_flow_del(fsw, flow_uuid, pid,
298 (event == NETAGENT_EVENT_NEXUS_FLOW_REMOVE), context,
299 cparams);
300 break;
301
302 default:
303 /* events not handled */
304 return 0;
305 }
306
307 return error;
308 }
309
310 int
fsw_netagent_register(struct nx_flowswitch * fsw,struct ifnet * ifp)311 fsw_netagent_register(struct nx_flowswitch *fsw, struct ifnet *ifp)
312 {
313 struct netagent_nexus_agent agent;
314 int error = 0;
315
316 _CASSERT(FLOWADV_IDX_NONE == UINT32_MAX);
317 _CASSERT(NECP_FLOWADV_IDX_INVALID == FLOWADV_IDX_NONE);
318
319 if (!fsw_netagent) {
320 return 0;
321 }
322
323 fsw->fsw_agent_session = netagent_create(fsw_netagent_event, fsw);
324 if (fsw->fsw_agent_session == NULL) {
325 return ENOMEM;
326 }
327
328 bzero(&agent, sizeof(agent));
329 uuid_generate_random(agent.agent.netagent_uuid);
330 uuid_copy(fsw->fsw_agent_uuid, agent.agent.netagent_uuid);
331 (void) snprintf(agent.agent.netagent_domain,
332 sizeof(agent.agent.netagent_domain), "%s", "Skywalk");
333 (void) snprintf(agent.agent.netagent_type,
334 sizeof(agent.agent.netagent_type), "%s", "FlowSwitch");
335 (void) snprintf(agent.agent.netagent_desc,
336 sizeof(agent.agent.netagent_desc), "%s", "Userspace Networking");
337 agent.agent.netagent_flags = NETAGENT_FLAG_ACTIVE;
338 if (ifnet_needs_fsw_transport_netagent(ifp)) {
339 agent.agent.netagent_flags |= (NETAGENT_FLAG_NEXUS_PROVIDER |
340 NETAGENT_FLAG_NEXUS_LISTENER);
341 }
342 if (ifnet_needs_fsw_ip_netagent(ifp)) {
343 ASSERT((sk_features & SK_FEATURE_PROTONS) != 0);
344 agent.agent.netagent_flags |= (NETAGENT_FLAG_CUSTOM_IP_NEXUS |
345 NETAGENT_FLAG_NEXUS_LISTENER);
346 }
347 agent.agent.netagent_data_size = sizeof(struct netagent_nexus);
348 agent.nexus_data.frame_type = NETAGENT_NEXUS_FRAME_TYPE_INTERNET;
349 agent.nexus_data.endpoint_assignment_type =
350 NETAGENT_NEXUS_ENDPOINT_TYPE_ADDRESS;
351 agent.nexus_data.endpoint_request_types[0] =
352 NETAGENT_NEXUS_ENDPOINT_TYPE_ADDRESS;
353 agent.nexus_data.endpoint_resolution_type_pairs[0] =
354 NETAGENT_NEXUS_ENDPOINT_TYPE_HOST;
355 agent.nexus_data.endpoint_resolution_type_pairs[1] =
356 NETAGENT_NEXUS_ENDPOINT_TYPE_ADDRESS;
357 agent.nexus_data.endpoint_resolution_type_pairs[2] =
358 NETAGENT_NEXUS_ENDPOINT_TYPE_BONJOUR;
359 agent.nexus_data.endpoint_resolution_type_pairs[3] =
360 NETAGENT_NEXUS_ENDPOINT_TYPE_HOST;
361 agent.nexus_data.endpoint_resolution_type_pairs[4] =
362 NETAGENT_NEXUS_ENDPOINT_TYPE_SRV;
363 agent.nexus_data.endpoint_resolution_type_pairs[5] =
364 NETAGENT_NEXUS_ENDPOINT_TYPE_HOST;
365 agent.nexus_data.nexus_max_buf_size =
366 fsw->fsw_nx->nx_prov->nxprov_params->nxp_buf_size;
367 agent.nexus_data.nexus_flags |=
368 (NETAGENT_NEXUS_FLAG_SUPPORTS_USER_PACKET_POOL |
369 NETAGENT_NEXUS_FLAG_ASSERT_UNSUPPORTED);
370
371 error = netagent_register(fsw->fsw_agent_session, &agent.agent);
372 if (error != 0) {
373 goto fail_netagent_register;
374 }
375
376 if (ifp->if_bridge != NULL) {
377 /* see rdar://107076453 */
378 SK_ERR("%s is bridged, not adding netagent",
379 if_name(ifp));
380 goto done;
381 }
382 error = if_add_netagent(ifp, fsw->fsw_agent_uuid);
383 if (error != 0) {
384 goto fail_netagent_add;
385 }
386 fsw->fsw_state_flags |= FSW_STATEF_NETAGENT_ADDED;
387 if (if_is_fsw_netagent_enabled()) {
388 fsw->fsw_state_flags |= FSW_STATEF_NETAGENT_ENABLED;
389 }
390 done:
391 return 0;
392
393 fail_netagent_add:
394 netagent_unregister(fsw->fsw_agent_session);
395
396 fail_netagent_register:
397 netagent_destroy(fsw->fsw_agent_session);
398 fsw->fsw_agent_session = NULL;
399 uuid_clear(fsw->fsw_agent_uuid);
400
401 return error;
402 }
403
404 void
fsw_netagent_unregister(struct nx_flowswitch * fsw,struct ifnet * ifp)405 fsw_netagent_unregister(struct nx_flowswitch *fsw, struct ifnet *ifp)
406 {
407 if (!uuid_is_null(fsw->fsw_agent_uuid)) {
408 if_delete_netagent(ifp, fsw->fsw_agent_uuid);
409 }
410
411 if (fsw->fsw_agent_session != NULL) {
412 netagent_destroy(fsw->fsw_agent_session);
413 fsw->fsw_agent_session = NULL;
414 uuid_clear(fsw->fsw_agent_uuid);
415 }
416 }
417