xref: /xnu-8796.101.5/libsyscall/wrappers/skywalk/os_nexus.c (revision aca3beaa3dfbd42498b42c5e5ce20a938e6554e5)
1 /*
2  * Copyright (c) 2015-2022 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 
30 #include <stdlib.h>
31 #include <string.h>
32 #include <strings.h>
33 #include <unistd.h>
34 #include <errno.h>
35 #include <net/if_var.h>
36 #include <skywalk/os_skywalk_private.h>
37 
38 #ifndef LIBSYSCALL_INTERFACE
39 #error "LIBSYSCALL_INTERFACE not defined"
40 #endif /* !LIBSYSCALL_INTERFACE */
41 
42 nexus_attr_t
os_nexus_attr_create(void)43 os_nexus_attr_create(void)
44 {
45 	struct nexus_attr *nxa;
46 
47 	nxa = malloc(sizeof(*nxa));
48 	if (nxa != NULL) {
49 		bzero(nxa, sizeof(*nxa));
50 	}
51 	return nxa;
52 }
53 
54 nexus_attr_t
os_nexus_attr_clone(const nexus_attr_t nxa)55 os_nexus_attr_clone(const nexus_attr_t nxa)
56 {
57 	struct nexus_attr *nnxa = NULL;
58 
59 	nnxa = os_nexus_attr_create();
60 	if (nnxa != NULL && nxa != NULL) {
61 		bcopy(nxa, nnxa, sizeof(*nnxa));
62 	}
63 
64 	return nnxa;
65 }
66 
67 int
os_nexus_attr_set(const nexus_attr_t nxa,const nexus_attr_type_t type,const uint64_t value)68 os_nexus_attr_set(const nexus_attr_t nxa, const nexus_attr_type_t type,
69     const uint64_t value)
70 {
71 	return __nexus_attr_set(nxa, type, value);
72 }
73 
74 int
os_nexus_attr_get(const nexus_attr_t nxa,const nexus_attr_type_t type,uint64_t * value)75 os_nexus_attr_get(const nexus_attr_t nxa, const nexus_attr_type_t type,
76     uint64_t *value)
77 {
78 	return __nexus_attr_get(nxa, type, value);
79 }
80 
81 void
os_nexus_attr_destroy(nexus_attr_t nxa)82 os_nexus_attr_destroy(nexus_attr_t nxa)
83 {
84 	free(nxa);
85 }
86 
87 nexus_controller_t
os_nexus_controller_create(void)88 os_nexus_controller_create(void)
89 {
90 	struct nexus_controller *ncd = NULL;
91 	struct nxctl_init init;
92 	int fd;
93 
94 	bzero(&init, sizeof(init));
95 	init.ni_version = NEXUSCTL_INIT_CURRENT_VERSION;
96 
97 	fd = __nexus_open(&init, sizeof(init));
98 	if (fd == -1) {
99 		goto done;
100 	}
101 
102 	ncd = malloc(sizeof(*ncd));
103 	if (ncd == NULL) {
104 		(void) guarded_close_np(fd, &init.ni_guard);
105 		goto done;
106 	}
107 	bzero(ncd, sizeof(*ncd));
108 	ncd->ncd_fd = fd;
109 	ncd->ncd_guard = init.ni_guard;
110 done:
111 	return ncd;
112 }
113 
114 int
os_nexus_controller_get_fd(const nexus_controller_t ncd)115 os_nexus_controller_get_fd(const nexus_controller_t ncd)
116 {
117 	return ncd->ncd_fd;
118 }
119 
120 int
os_nexus_controller_register_provider(const nexus_controller_t ncd,const nexus_name_t name,const nexus_type_t type,const nexus_attr_t nxa,uuid_t * prov_uuid)121 os_nexus_controller_register_provider(const nexus_controller_t ncd,
122     const nexus_name_t name, const nexus_type_t type,
123     const nexus_attr_t nxa, uuid_t *prov_uuid)
124 {
125 	struct nxprov_reg reg;
126 	int err;
127 
128 	if ((err = __nexus_provider_reg_prepare(&reg, name, type, nxa)) == 0) {
129 		err = __nexus_register(ncd->ncd_fd, &reg, sizeof(reg),
130 		    prov_uuid, sizeof(uuid_t));
131 	}
132 	return err;
133 }
134 
135 int
os_nexus_controller_deregister_provider(const nexus_controller_t ncd,const uuid_t prov_uuid)136 os_nexus_controller_deregister_provider(const nexus_controller_t ncd,
137     const uuid_t prov_uuid)
138 {
139 	return __nexus_deregister(ncd->ncd_fd, prov_uuid, sizeof(uuid_t));
140 }
141 
142 int
os_nexus_controller_alloc_provider_instance(const nexus_controller_t ncd,const uuid_t prov_uuid,uuid_t * nx_uuid)143 os_nexus_controller_alloc_provider_instance(const nexus_controller_t ncd,
144     const uuid_t prov_uuid, uuid_t *nx_uuid)
145 {
146 	return __nexus_create(ncd->ncd_fd, prov_uuid, sizeof(uuid_t),
147 	           nx_uuid, sizeof(uuid_t));
148 }
149 
150 int
os_nexus_controller_free_provider_instance(const nexus_controller_t ncd,const uuid_t nx_uuid)151 os_nexus_controller_free_provider_instance(const nexus_controller_t ncd,
152     const uuid_t nx_uuid)
153 {
154 	return __nexus_destroy(ncd->ncd_fd, nx_uuid, sizeof(uuid_t));
155 }
156 
157 int
os_nexus_controller_bind_provider_instance(const nexus_controller_t ncd,const uuid_t nx_uuid,const nexus_port_t port,const pid_t pid,const uuid_t exec_uuid,const void * key,const uint32_t key_len,uint32_t bind_flags)158 os_nexus_controller_bind_provider_instance(const nexus_controller_t ncd,
159     const uuid_t nx_uuid, const nexus_port_t port, const pid_t pid,
160     const uuid_t exec_uuid, const void *key, const uint32_t key_len,
161     uint32_t bind_flags)
162 {
163 	struct nx_bind_req nbr;
164 
165 	__nexus_bind_req_prepare(&nbr, nx_uuid, port, pid, exec_uuid,
166 	    key, key_len, bind_flags);
167 
168 	return __nexus_set_opt(ncd->ncd_fd, NXOPT_NEXUS_BIND,
169 	           &nbr, sizeof(nbr));
170 }
171 
172 int
os_nexus_controller_unbind_provider_instance(const nexus_controller_t ncd,const uuid_t nx_uuid,const nexus_port_t port)173 os_nexus_controller_unbind_provider_instance(const nexus_controller_t ncd,
174     const uuid_t nx_uuid, const nexus_port_t port)
175 {
176 	struct nx_unbind_req nbu;
177 
178 	__nexus_unbind_req_prepare(&nbu, nx_uuid, port);
179 
180 	return __nexus_set_opt(ncd->ncd_fd, NXOPT_NEXUS_UNBIND,
181 	           &nbu, sizeof(nbu));
182 }
183 
184 int
os_nexus_controller_read_provider_attr(const nexus_controller_t ncd,const uuid_t prov_uuid,nexus_attr_t nxa)185 os_nexus_controller_read_provider_attr(const nexus_controller_t ncd,
186     const uuid_t prov_uuid, nexus_attr_t nxa)
187 {
188 	struct nxprov_reg_ent nre;
189 	uint32_t nre_len = sizeof(nre);
190 	struct nxprov_params *p = &nre.npre_prov_params;
191 	int ret = 0;
192 
193 	if (nxa == NULL) {
194 		return EINVAL;
195 	}
196 
197 	bzero(&nre, sizeof(nre));
198 	bcopy(prov_uuid, nre.npre_prov_uuid, sizeof(uuid_t));
199 	ret = __nexus_get_opt(ncd->ncd_fd, NXOPT_NEXUS_PROV_ENTRY,
200 	    &nre, &nre_len);
201 
202 	if (ret == 0) {
203 		__nexus_attr_from_params(nxa, p);
204 	}
205 
206 	return ret;
207 }
208 
209 static int
add_traffic_rule_inet(const nexus_controller_t ncd,const char * ifname,const struct ifnet_traffic_descriptor_inet * td,const struct ifnet_traffic_rule_action_steer * ra,const uint32_t flags,uuid_t * rule_uuid)210 add_traffic_rule_inet(const nexus_controller_t ncd,
211     const char *ifname, const struct ifnet_traffic_descriptor_inet *td,
212     const struct ifnet_traffic_rule_action_steer *ra, const uint32_t flags,
213     uuid_t *rule_uuid)
214 {
215 	struct nxctl_add_traffic_rule_inet_iocargs args;
216 	int err;
217 
218 	bzero(&args, sizeof(args));
219 	if (ifname != NULL) {
220 		(void) strlcpy(args.atri_ifname, ifname, IFNAMSIZ);
221 	}
222 	bcopy(td, &args.atri_td, sizeof(args.atri_td));
223 	bcopy(ra, &args.atri_ra, sizeof(args.atri_ra));
224 
225 	if ((flags & NXCTL_ADD_TRAFFIC_RULE_FLAG_PERSIST) != 0) {
226 		args.atri_flags |= NXIOC_ADD_TRAFFIC_RULE_FLAG_PERSIST;
227 	}
228 	err = ioctl(ncd->ncd_fd, NXIOC_ADD_TRAFFIC_RULE_INET, &args);
229 	if (err < 0) {
230 		return errno;
231 	}
232 	bcopy(&args.atri_uuid, rule_uuid, sizeof(args.atri_uuid));
233 	return 0;
234 }
235 
236 int
os_nexus_controller_add_traffic_rule(const nexus_controller_t ncd,const char * ifname,const struct ifnet_traffic_descriptor_common * td,const struct ifnet_traffic_rule_action * ra,const uint32_t flags,uuid_t * rule_uuid)237 os_nexus_controller_add_traffic_rule(const nexus_controller_t ncd,
238     const char *ifname, const struct ifnet_traffic_descriptor_common *td,
239     const struct ifnet_traffic_rule_action *ra, const uint32_t flags,
240     uuid_t *rule_uuid)
241 {
242 	/* only support the steer action for now */
243 	if (ra->ra_type != IFNET_TRAFFIC_RULE_ACTION_STEER) {
244 		return ENOTSUP;
245 	}
246 	if (ra->ra_len != sizeof(struct ifnet_traffic_rule_action_steer)) {
247 		return EINVAL;
248 	}
249 	/* only support the inet descriptor type for now */
250 	switch (td->itd_type) {
251 	case IFNET_TRAFFIC_DESCRIPTOR_TYPE_INET: {
252 		if (td->itd_len !=
253 		    sizeof(struct ifnet_traffic_descriptor_inet)) {
254 			return EINVAL;
255 		}
256 		return add_traffic_rule_inet(ncd, ifname,
257 		           (const struct ifnet_traffic_descriptor_inet *)td,
258 		           (const struct ifnet_traffic_rule_action_steer *)ra,
259 		           flags, rule_uuid);
260 	}
261 	default:
262 		return ENOTSUP;
263 	}
264 }
265 
266 int
os_nexus_controller_remove_traffic_rule(const nexus_controller_t ncd,const uuid_t rule_uuid)267 os_nexus_controller_remove_traffic_rule(const nexus_controller_t ncd,
268     const uuid_t rule_uuid)
269 {
270 	struct nxctl_remove_traffic_rule_iocargs args;
271 	int err;
272 
273 	bzero(&args, sizeof(args));
274 	bcopy(rule_uuid, &args.rtr_uuid, sizeof(args.rtr_uuid));
275 
276 	err = ioctl(ncd->ncd_fd, NXIOC_REMOVE_TRAFFIC_RULE, &args);
277 	if (err < 0) {
278 		return errno;
279 	}
280 	return 0;
281 }
282 
283 static void
inet_rule_iterate(void * buf,uint32_t count,nexus_traffic_rule_iterator_t itr,void * itr_arg)284 inet_rule_iterate(void *buf, uint32_t count,
285     nexus_traffic_rule_iterator_t itr, void *itr_arg)
286 {
287 	struct nxctl_traffic_rule_inet_iocinfo *info = buf;
288 	struct nxctl_traffic_rule_generic_iocinfo *ginfo;
289 	struct nexus_traffic_rule_info itr_info;
290 	uint32_t c;
291 
292 	for (c = 0; c < count; c++) {
293 		bzero(&itr_info, sizeof(itr_info));
294 		ginfo = &info->tri_common;
295 		itr_info.nri_rule_uuid = &ginfo->trg_uuid;
296 		itr_info.nri_owner = ginfo->trg_procname;
297 		itr_info.nri_ifname = ginfo->trg_ifname;
298 		itr_info.nri_td =
299 		    (struct ifnet_traffic_descriptor_common *)&info->tri_td;
300 		itr_info.nri_ra =
301 		    (struct ifnet_traffic_rule_action *)&info->tri_ra;
302 
303 		if (!itr(itr_arg, &itr_info)) {
304 			break;
305 		}
306 		info++;
307 	}
308 }
309 
310 struct traffic_rule_type {
311 	uint8_t tr_type;
312 	uint32_t tr_size;
313 	uint32_t tr_count;
314 	void (*tr_iterate)(void *, uint32_t,
315 	    nexus_traffic_rule_iterator_t, void *);
316 };
317 #define NTRDEFAULTCOUNT 512
318 static struct traffic_rule_type traffic_rule_types[] = {
319 	{IFNET_TRAFFIC_DESCRIPTOR_TYPE_INET,
320 	 sizeof(struct nxctl_traffic_rule_inet_iocinfo),
321 	 NTRDEFAULTCOUNT, inet_rule_iterate},
322 };
323 #define NTRTYPES (sizeof(traffic_rule_types)/sizeof(struct traffic_rule_type))
324 
325 int
os_nexus_controller_iterate_traffic_rules(const nexus_controller_t ncd,nexus_traffic_rule_iterator_t itr,void * itr_arg)326 os_nexus_controller_iterate_traffic_rules(const nexus_controller_t ncd,
327     nexus_traffic_rule_iterator_t itr, void *itr_arg)
328 {
329 	struct nxctl_get_traffic_rules_iocargs args;
330 	struct traffic_rule_type *t;
331 	int i, err;
332 
333 	for (i = 0; i < NTRTYPES; i++) {
334 		t = &traffic_rule_types[i];
335 		bzero(&args, sizeof(args));
336 		args.gtr_type = t->tr_type;
337 		args.gtr_size = t->tr_size;
338 		args.gtr_count = t->tr_count;
339 		args.gtr_buf = malloc(args.gtr_size * args.gtr_count);
340 		if (args.gtr_buf == NULL) {
341 			return ENOMEM;
342 		}
343 		err = ioctl(ncd->ncd_fd, NXIOC_GET_TRAFFIC_RULES, &args);
344 		if (err < 0) {
345 			err = errno;
346 			free(args.gtr_buf);
347 			return err;
348 		}
349 		if (args.gtr_count > 0) {
350 			t->tr_iterate(args.gtr_buf, args.gtr_count,
351 			    itr, itr_arg);
352 		}
353 		free(args.gtr_buf);
354 	}
355 	return 0;
356 }
357 
358 void
os_nexus_controller_destroy(nexus_controller_t ncd)359 os_nexus_controller_destroy(nexus_controller_t ncd)
360 {
361 	if (ncd->ncd_fd != -1) {
362 		(void) guarded_close_np(ncd->ncd_fd, &ncd->ncd_guard);
363 	}
364 	free(ncd);
365 }
366 
367 int
__os_nexus_ifattach(const nexus_controller_t ncd,const uuid_t nx_uuid,const char * ifname,const uuid_t netif_uuid,boolean_t host,uuid_t * nx_if_uuid)368 __os_nexus_ifattach(const nexus_controller_t ncd,
369     const uuid_t nx_uuid, const char *ifname, const uuid_t netif_uuid,
370     boolean_t host, uuid_t *nx_if_uuid)
371 {
372 	struct nx_cfg_req ncr;
373 	struct nx_spec_req nsr;
374 	int ret;
375 
376 	bzero(&nsr, sizeof(nsr));
377 	if (ifname != NULL) {
378 		(void) strlcpy(nsr.nsr_name, ifname, sizeof(nsr.nsr_name));
379 	} else {
380 		bcopy(netif_uuid, nsr.nsr_uuid, sizeof(uuid_t));
381 		nsr.nsr_flags |= NXSPECREQ_UUID;
382 	}
383 
384 	if (host) {
385 		nsr.nsr_flags |= NXSPECREQ_HOST;
386 	}
387 
388 	__nexus_config_req_prepare(&ncr, nx_uuid, NXCFG_CMD_ATTACH,
389 	    &nsr, sizeof(nsr));
390 
391 	ret = __nexus_set_opt(ncd->ncd_fd, NXOPT_NEXUS_CONFIG,
392 	    &ncr, sizeof(ncr));
393 
394 	if (ret == 0) {
395 		bcopy(nsr.nsr_if_uuid, nx_if_uuid, sizeof(uuid_t));
396 	}
397 
398 	return ret;
399 }
400 
401 int
__os_nexus_ifdetach(const nexus_controller_t ncd,const uuid_t nx_uuid,const uuid_t nx_if_uuid)402 __os_nexus_ifdetach(const nexus_controller_t ncd, const uuid_t nx_uuid,
403     const uuid_t nx_if_uuid)
404 {
405 	struct nx_cfg_req ncr;
406 	struct nx_spec_req nsr;
407 
408 	bzero(&nsr, sizeof(nsr));
409 	bcopy(nx_if_uuid, nsr.nsr_if_uuid, sizeof(uuid_t));
410 
411 	__nexus_config_req_prepare(&ncr, nx_uuid, NXCFG_CMD_DETACH,
412 	    &nsr, sizeof(nsr));
413 
414 	return __nexus_set_opt(ncd->ncd_fd, NXOPT_NEXUS_CONFIG,
415 	           &ncr, sizeof(ncr));
416 }
417 
418 int
__os_nexus_flow_add(const nexus_controller_t ncd,const uuid_t nx_uuid,const struct nx_flow_req * nfr)419 __os_nexus_flow_add(const nexus_controller_t ncd, const uuid_t nx_uuid,
420     const struct nx_flow_req *nfr)
421 {
422 	struct nx_cfg_req ncr;
423 
424 	__nexus_config_req_prepare(&ncr, nx_uuid, NXCFG_CMD_FLOW_ADD,
425 	    nfr, sizeof(*nfr));
426 
427 	return __nexus_set_opt(ncd->ncd_fd, NXOPT_NEXUS_CONFIG,
428 	           &ncr, sizeof(ncr));
429 }
430 
431 int
__os_nexus_flow_del(const nexus_controller_t ncd,const uuid_t nx_uuid,const struct nx_flow_req * nfr)432 __os_nexus_flow_del(const nexus_controller_t ncd, const uuid_t nx_uuid,
433     const struct nx_flow_req *nfr)
434 {
435 	struct nx_cfg_req ncr;
436 
437 	__nexus_config_req_prepare(&ncr, nx_uuid, NXCFG_CMD_FLOW_DEL,
438 	    nfr, sizeof(*nfr));
439 
440 	return __nexus_set_opt(ncd->ncd_fd, NXOPT_NEXUS_CONFIG,
441 	           &ncr, sizeof(ncr));
442 }
443 
444 int
__os_nexus_get_llink_info(const nexus_controller_t ncd,const uuid_t nx_uuid,const struct nx_llink_info_req * nlir,size_t len)445 __os_nexus_get_llink_info(const nexus_controller_t ncd, const uuid_t nx_uuid,
446     const struct nx_llink_info_req *nlir, size_t len)
447 {
448 	struct nx_cfg_req ncr;
449 
450 	__nexus_config_req_prepare(&ncr, nx_uuid, NXCFG_CMD_GET_LLINK_INFO,
451 	    nlir, len);
452 
453 	return __nexus_set_opt(ncd->ncd_fd, NXOPT_NEXUS_CONFIG,
454 	           &ncr, sizeof(ncr));
455 }
456