xref: /xnu-12377.61.12/bsd/skywalk/nexus/flowswitch/fsw_netagent.c (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8)
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 * __sized_by (* results_length)* 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 * __sized_by(*results_length) *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 	if (cparams->use_aop_offload) {
146 		req.nfr_flags |= NXFLOWREQF_AOP_OFFLOAD;
147 	}
148 
149 	req.nfr_context = context;
150 	req.nfr_pid = pid;
151 	req.nfr_port_reservation = cparams->port_reservation;
152 
153 	if (cparams->is_demuxable_parent) {
154 		req.nfr_flags |= NXFLOWREQF_PARENT;
155 	} else {
156 		uuid_copy(req.nfr_parent_flow_uuid, cparams->parent_flow_uuid);
157 		if (cparams->demux_pattern_count > 0) {
158 			if (cparams->demux_pattern_count > MAX_FLOW_DEMUX_PATTERN) {
159 				error = EINVAL;
160 				goto done;
161 			}
162 
163 			static_assert(sizeof(struct necp_demux_pattern) == sizeof(struct flow_demux_pattern));
164 			for (int i = 0; i < cparams->demux_pattern_count; i++) {
165 				memcpy(&req.nfr_flow_demux_patterns[i], &cparams->demux_patterns[i],
166 				    sizeof(struct flow_demux_pattern));
167 			}
168 			req.nfr_flow_demux_count = cparams->demux_pattern_count;
169 		}
170 	}
171 
172 	ASSERT(req.nfr_flags & NXFLOWREQF_FLOWADV);
173 	fo = fsw_flow_add(fsw, &req, &error);
174 	if (fo == NULL) {
175 		ASSERT(error != 0);
176 		ASSERT(req.nfr_flow_stats == NULL);
177 		goto done;
178 	}
179 
180 	ASSERT(error == 0);
181 	ASSERT(req.nfr_nx_port != NEXUS_PORT_ANY);
182 	ASSERT(!uuid_is_null(fo->fo_key));
183 	ASSERT(req.nfr_flowadv_idx != FLOWADV_IDX_NONE);
184 	ASSERT(req.nfr_flow_stats != NULL);
185 	ASSERT(flow_stats_refcnt(req.nfr_flow_stats) >= 1);
186 
187 	bzero(&local_endpoint, sizeof(local_endpoint));
188 	bzero(&remote_endpoint, sizeof(remote_endpoint));
189 
190 	bcopy((void *)&req.nfr_saddr, (void *)&local_endpoint.u.sin6,
191 	    sizeof(req.nfr_saddr));
192 	bcopy((void *)&req.nfr_daddr, (void *)&remote_endpoint.u.sin6,
193 	    sizeof(req.nfr_daddr));
194 
195 	assign_message =
196 	    necp_create_nexus_assign_message(fsw->fsw_nx->nx_uuid,
197 	    req.nfr_nx_port, fo->fo_key, sizeof(fo->fo_key),
198 	    &local_endpoint, &remote_endpoint, NULL, req.nfr_flowadv_idx,
199 	    req.nfr_flow_stats, req.nfr_flowid, &assign_message_length);
200 
201 	if (assign_message != NULL) {
202 		req.nfr_flow_stats = NULL;
203 		ASSERT(error == 0);
204 		*results = assign_message;
205 		*results_length = assign_message_length;
206 	} else {
207 		error = ENOMEM;
208 	}
209 
210 done:
211 #if SK_LOG
212 	if (__improbable((sk_verbose & SK_VERB_FLOW) != 0)) {
213 		uuid_string_t uuidstr;
214 		SK_DF(SK_VERB_FLOW, "pid %d connect flow_uuid %s nx_port %d "
215 		    "(err %d)", pid, sk_uuid_unparse(flow_uuid, uuidstr),
216 		    (int)req.nfr_nx_port, error);
217 	}
218 #endif /* SK_LOG */
219 	if (error != 0) {
220 		ASSERT(*results == NULL);
221 		ASSERT(*results_length == 0);
222 		if (assign_message != NULL) {
223 			kfree_data_sized_by(assign_message, assign_message_length);
224 		}
225 		if (fo != NULL) {
226 			req.nfr_pid = pid;
227 			fsw_flow_del(fsw, &req, TRUE, NULL);
228 		}
229 		if (req.nfr_flow_stats != NULL) {
230 			flow_stats_release(req.nfr_flow_stats);
231 			req.nfr_flow_stats = NULL;
232 		}
233 	}
234 
235 	return error;
236 }
237 
238 static int
fsw_netagent_flow_del(struct nx_flowswitch * fsw,uuid_t flow_uuid,pid_t pid,bool nolinger,void * context,void * params)239 fsw_netagent_flow_del(struct nx_flowswitch *fsw, uuid_t flow_uuid, pid_t pid,
240     bool nolinger, void *context, void *params)
241 {
242 	struct nx_flow_req req;
243 	int error;
244 
245 	bzero(&req, sizeof(req));
246 	uuid_copy(req.nfr_flow_uuid, flow_uuid);
247 	req.nfr_proc = NULL;
248 	req.nfr_pid = pid;
249 	req.nfr_context = context;
250 
251 	error = fsw_flow_del(fsw, &req, nolinger, params);
252 
253 #if SK_LOG
254 	if (__improbable((sk_verbose & SK_VERB_FLOW) != 0)) {
255 		uuid_string_t uuidstr;
256 		SK_DF(SK_VERB_FLOW, "pid %d flow_uuid %s (err %d)",
257 		    pid, sk_uuid_unparse(flow_uuid, uuidstr), error);
258 	}
259 #endif /* SK_LOG */
260 
261 	return error;
262 }
263 
264 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 * __sized_by (* results_length)* results,size_t * results_length)265 fsw_netagent_event(u_int8_t event, uuid_t flow_uuid, pid_t pid, void *context,
266     void *ctx, struct necp_client_agent_parameters *cparams, void * __sized_by(*results_length) *results,
267     size_t *results_length)
268 {
269 	struct nx_flowswitch *fsw;
270 	int error = 0;
271 
272 	ASSERT(!uuid_is_null(flow_uuid));
273 
274 	fsw = (struct nx_flowswitch *)ctx;
275 	ASSERT(fsw != NULL);
276 
277 	switch (event) {
278 	case NETAGENT_EVENT_NEXUS_FLOW_INSERT:
279 		/* these are required for this event */
280 		ASSERT(cparams != NULL);
281 		ASSERT(results != NULL);
282 		ASSERT(results_length != NULL);
283 		*results = NULL;
284 		*results_length = 0;
285 		error = fsw_netagent_flow_add(fsw, flow_uuid, pid, context,
286 		    &cparams->u.nexus_request, results, results_length);
287 		break;
288 
289 	case NETAGENT_EVENT_NEXUS_FLOW_REMOVE:
290 	case NETAGENT_EVENT_NEXUS_FLOW_ABORT:
291 		/*
292 		 * A flow can be removed gracefully (FLOW_REMOVE) by
293 		 * the client, in which case we don't need to have it
294 		 * linger around to hold the namespace.  If the process
295 		 * crashed or if it's suspended, then we treat that
296 		 * as the abort case (FLOW_ABORT) where we'll hold on
297 		 * to the namespace if needed.
298 		 */
299 		error = fsw_netagent_flow_del(fsw, flow_uuid, pid,
300 		    (event == NETAGENT_EVENT_NEXUS_FLOW_REMOVE), context,
301 		    cparams->u.close_token);
302 		break;
303 
304 	default:
305 		/* events not handled */
306 		return 0;
307 	}
308 
309 	return error;
310 }
311 
312 int
fsw_netagent_register(struct nx_flowswitch * fsw,struct ifnet * ifp)313 fsw_netagent_register(struct nx_flowswitch *fsw, struct ifnet *ifp)
314 {
315 	struct netagent_nexus_agent agent;
316 	int error = 0;
317 
318 	static_assert(FLOWADV_IDX_NONE == UINT32_MAX);
319 	static_assert(NECP_FLOWADV_IDX_INVALID == FLOWADV_IDX_NONE);
320 
321 	if (!fsw_netagent) {
322 		return 0;
323 	}
324 
325 	fsw->fsw_agent_session = netagent_create(fsw_netagent_event, fsw);
326 	if (fsw->fsw_agent_session == NULL) {
327 		return ENOMEM;
328 	}
329 
330 	bzero(&agent, sizeof(agent));
331 	uuid_generate_random(agent.agent.netagent_uuid);
332 	uuid_copy(fsw->fsw_agent_uuid, agent.agent.netagent_uuid);
333 	(void) snprintf(agent.agent.netagent_domain,
334 	    sizeof(agent.agent.netagent_domain), "%s", "Skywalk");
335 	(void) snprintf(agent.agent.netagent_type,
336 	    sizeof(agent.agent.netagent_type), "%s", "FlowSwitch");
337 	(void) snprintf(agent.agent.netagent_desc,
338 	    sizeof(agent.agent.netagent_desc), "%s", "Userspace Networking");
339 	agent.agent.netagent_flags = NETAGENT_FLAG_ACTIVE;
340 	if (ifnet_needs_fsw_transport_netagent(ifp)) {
341 		agent.agent.netagent_flags |= (NETAGENT_FLAG_NEXUS_PROVIDER |
342 		    NETAGENT_FLAG_NEXUS_LISTENER);
343 	}
344 	if (ifnet_needs_fsw_ip_netagent(ifp)) {
345 		ASSERT((sk_features & SK_FEATURE_PROTONS) != 0);
346 		agent.agent.netagent_flags |= (NETAGENT_FLAG_CUSTOM_IP_NEXUS |
347 		    NETAGENT_FLAG_NEXUS_LISTENER);
348 	}
349 	agent.agent.netagent_data_size = sizeof(struct netagent_nexus);
350 	agent.nexus_data.frame_type = NETAGENT_NEXUS_FRAME_TYPE_INTERNET;
351 	agent.nexus_data.endpoint_assignment_type =
352 	    NETAGENT_NEXUS_ENDPOINT_TYPE_ADDRESS;
353 	agent.nexus_data.endpoint_request_types[0] =
354 	    NETAGENT_NEXUS_ENDPOINT_TYPE_ADDRESS;
355 	agent.nexus_data.endpoint_resolution_type_pairs[0] =
356 	    NETAGENT_NEXUS_ENDPOINT_TYPE_HOST;
357 	agent.nexus_data.endpoint_resolution_type_pairs[1] =
358 	    NETAGENT_NEXUS_ENDPOINT_TYPE_ADDRESS;
359 	agent.nexus_data.endpoint_resolution_type_pairs[2] =
360 	    NETAGENT_NEXUS_ENDPOINT_TYPE_BONJOUR;
361 	agent.nexus_data.endpoint_resolution_type_pairs[3] =
362 	    NETAGENT_NEXUS_ENDPOINT_TYPE_HOST;
363 	agent.nexus_data.endpoint_resolution_type_pairs[4] =
364 	    NETAGENT_NEXUS_ENDPOINT_TYPE_SRV;
365 	agent.nexus_data.endpoint_resolution_type_pairs[5] =
366 	    NETAGENT_NEXUS_ENDPOINT_TYPE_HOST;
367 	agent.nexus_data.nexus_max_buf_size =
368 	    fsw->fsw_nx->nx_prov->nxprov_params->nxp_buf_size;
369 	agent.nexus_data.nexus_flags |=
370 	    (NETAGENT_NEXUS_FLAG_SUPPORTS_USER_PACKET_POOL |
371 	    NETAGENT_NEXUS_FLAG_ASSERT_UNSUPPORTED);
372 
373 	error = netagent_register(fsw->fsw_agent_session, &agent.agent);
374 	if (error != 0) {
375 		goto fail_netagent_register;
376 	}
377 
378 	if (ifp->if_bridge != NULL) {
379 		/* see rdar://107076453 */
380 		SK_ERR("%s is bridged, not adding netagent",
381 		    if_name(ifp));
382 		goto done;
383 	}
384 	error = if_add_netagent(ifp, fsw->fsw_agent_uuid);
385 	if (error != 0) {
386 		goto fail_netagent_add;
387 	}
388 	fsw->fsw_state_flags |= FSW_STATEF_NETAGENT_ADDED;
389 	if (if_is_fsw_netagent_enabled()) {
390 		fsw->fsw_state_flags |= FSW_STATEF_NETAGENT_ENABLED;
391 	}
392 done:
393 	return 0;
394 
395 fail_netagent_add:
396 	netagent_unregister(fsw->fsw_agent_session);
397 
398 fail_netagent_register:
399 	netagent_destroy(fsw->fsw_agent_session);
400 	fsw->fsw_agent_session = NULL;
401 	uuid_clear(fsw->fsw_agent_uuid);
402 
403 	return error;
404 }
405 
406 void
fsw_netagent_unregister(struct nx_flowswitch * fsw,struct ifnet * ifp)407 fsw_netagent_unregister(struct nx_flowswitch *fsw, struct ifnet *ifp)
408 {
409 	if (!uuid_is_null(fsw->fsw_agent_uuid)) {
410 		if_delete_netagent(ifp, fsw->fsw_agent_uuid);
411 	}
412 
413 	if (fsw->fsw_agent_session != NULL) {
414 		netagent_destroy(fsw->fsw_agent_session);
415 		fsw->fsw_agent_session = NULL;
416 		uuid_clear(fsw->fsw_agent_uuid);
417 	}
418 }
419