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(®, name, type, nxa)) == 0) {
129 err = __nexus_register(ncd->ncd_fd, ®, 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