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 static int
add_traffic_rule_eth(const nexus_controller_t ncd,const char * ifname,const struct ifnet_traffic_descriptor_eth * td,const struct ifnet_traffic_rule_action_steer * ra,const uint32_t flags,uuid_t * rule_uuid)237 add_traffic_rule_eth(const nexus_controller_t ncd,
238 const char *ifname, const struct ifnet_traffic_descriptor_eth *td,
239 const struct ifnet_traffic_rule_action_steer *ra, const uint32_t flags,
240 uuid_t *rule_uuid)
241 {
242 struct nxctl_add_traffic_rule_eth_iocargs args;
243 int err;
244
245 bzero(&args, sizeof(args));
246 if (ifname != NULL) {
247 (void) strlcpy(args.atre_ifname, ifname, IFNAMSIZ);
248 }
249 bcopy(td, &args.atre_td, sizeof(args.atre_td));
250 bcopy(ra, &args.atre_ra, sizeof(args.atre_ra));
251
252 if ((flags & NXCTL_ADD_TRAFFIC_RULE_FLAG_PERSIST) != 0) {
253 args.atre_flags |= NXIOC_ADD_TRAFFIC_RULE_FLAG_PERSIST;
254 }
255 err = ioctl(ncd->ncd_fd, NXIOC_ADD_TRAFFIC_RULE_ETH, &args);
256 if (err < 0) {
257 return errno;
258 }
259 bcopy(&args.atre_uuid, rule_uuid, sizeof(args.atre_uuid));
260 return 0;
261 }
262
263 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)264 os_nexus_controller_add_traffic_rule(const nexus_controller_t ncd,
265 const char *ifname, const struct ifnet_traffic_descriptor_common *td,
266 const struct ifnet_traffic_rule_action *ra, const uint32_t flags,
267 uuid_t *rule_uuid)
268 {
269 /* only support the steer action for now */
270 if (ra->ra_type != IFNET_TRAFFIC_RULE_ACTION_STEER) {
271 return ENOTSUP;
272 }
273 if (ra->ra_len != sizeof(struct ifnet_traffic_rule_action_steer)) {
274 return EINVAL;
275 }
276 /* only support the inet descriptor type for now */
277 switch (td->itd_type) {
278 case IFNET_TRAFFIC_DESCRIPTOR_TYPE_INET: {
279 if (td->itd_len !=
280 sizeof(struct ifnet_traffic_descriptor_inet)) {
281 return EINVAL;
282 }
283 return add_traffic_rule_inet(ncd, ifname,
284 (const struct ifnet_traffic_descriptor_inet *)td,
285 (const struct ifnet_traffic_rule_action_steer *)ra,
286 flags, rule_uuid);
287 }
288 case IFNET_TRAFFIC_DESCRIPTOR_TYPE_ETH: {
289 if (td->itd_len !=
290 sizeof(struct ifnet_traffic_descriptor_eth)) {
291 return EINVAL;
292 }
293 return add_traffic_rule_eth(ncd, ifname,
294 (const struct ifnet_traffic_descriptor_eth *)td,
295 (const struct ifnet_traffic_rule_action_steer *)ra,
296 flags, rule_uuid);
297 }
298 default:
299 return ENOTSUP;
300 }
301 }
302
303 int
os_nexus_controller_remove_traffic_rule(const nexus_controller_t ncd,const uuid_t rule_uuid)304 os_nexus_controller_remove_traffic_rule(const nexus_controller_t ncd,
305 const uuid_t rule_uuid)
306 {
307 struct nxctl_remove_traffic_rule_iocargs args;
308 int err;
309
310 bzero(&args, sizeof(args));
311 bcopy(rule_uuid, &args.rtr_uuid, sizeof(args.rtr_uuid));
312
313 err = ioctl(ncd->ncd_fd, NXIOC_REMOVE_TRAFFIC_RULE, &args);
314 if (err < 0) {
315 return errno;
316 }
317 return 0;
318 }
319
320 static boolean_t
rule_iterate(struct nxctl_traffic_rule_generic_iocinfo * ginfo,struct ifnet_traffic_descriptor_common * td,struct ifnet_traffic_rule_action * ra,nexus_traffic_rule_iterator_t itr,void * itr_arg)321 rule_iterate(struct nxctl_traffic_rule_generic_iocinfo *ginfo,
322 struct ifnet_traffic_descriptor_common *td,
323 struct ifnet_traffic_rule_action *ra,
324 nexus_traffic_rule_iterator_t itr, void *itr_arg)
325 {
326 struct nexus_traffic_rule_info itr_info;
327
328 bzero(&itr_info, sizeof(itr_info));
329 itr_info.nri_rule_uuid = &ginfo->trg_uuid;
330 itr_info.nri_owner = ginfo->trg_procname;
331 itr_info.nri_ifname = ginfo->trg_ifname;
332 itr_info.nri_td = td;
333 itr_info.nri_ra = ra;
334
335 if (!itr(itr_arg, &itr_info)) {
336 return false;
337 }
338 return true;
339 }
340
341 static void
inet_rule_iterate(void * buf,uint32_t count,nexus_traffic_rule_iterator_t itr,void * itr_arg)342 inet_rule_iterate(void *buf, uint32_t count,
343 nexus_traffic_rule_iterator_t itr, void *itr_arg)
344 {
345 struct nxctl_traffic_rule_inet_iocinfo *info = buf;
346
347 for (uint32_t c = 0; c < count; c++) {
348 if (!rule_iterate(&info->tri_common, &info->tri_td.inet_common,
349 &info->tri_ra.ras_common, itr, itr_arg)) {
350 break;
351 }
352 info++;
353 }
354 }
355
356 static void
eth_rule_iterate(void * buf,uint32_t count,nexus_traffic_rule_iterator_t itr,void * itr_arg)357 eth_rule_iterate(void *buf, uint32_t count,
358 nexus_traffic_rule_iterator_t itr, void *itr_arg)
359 {
360 struct nxctl_traffic_rule_eth_iocinfo *info = buf;
361
362 for (uint32_t c = 0; c < count; c++) {
363 if (!rule_iterate(&info->tre_common, &info->tre_td.eth_common,
364 &info->tre_ra.ras_common, itr, itr_arg)) {
365 break;
366 }
367 info++;
368 }
369 }
370
371 struct traffic_rule_type {
372 uint8_t tr_type;
373 uint32_t tr_size;
374 uint32_t tr_count;
375 void (*tr_iterate)(void *, uint32_t,
376 nexus_traffic_rule_iterator_t, void *);
377 };
378 #define NTRDEFAULTCOUNT 512
379 static struct traffic_rule_type traffic_rule_types[] = {
380 {IFNET_TRAFFIC_DESCRIPTOR_TYPE_INET,
381 sizeof(struct nxctl_traffic_rule_inet_iocinfo),
382 NTRDEFAULTCOUNT, inet_rule_iterate},
383 {IFNET_TRAFFIC_DESCRIPTOR_TYPE_ETH,
384 sizeof(struct nxctl_traffic_rule_eth_iocinfo),
385 NTRDEFAULTCOUNT, eth_rule_iterate},
386 };
387 #define NTRTYPES (sizeof(traffic_rule_types)/sizeof(struct traffic_rule_type))
388
389 int
os_nexus_controller_iterate_traffic_rules(const nexus_controller_t ncd,nexus_traffic_rule_iterator_t itr,void * itr_arg)390 os_nexus_controller_iterate_traffic_rules(const nexus_controller_t ncd,
391 nexus_traffic_rule_iterator_t itr, void *itr_arg)
392 {
393 struct nxctl_get_traffic_rules_iocargs args;
394 struct traffic_rule_type *t;
395 int i, err;
396
397 for (i = 0; i < NTRTYPES; i++) {
398 t = &traffic_rule_types[i];
399 bzero(&args, sizeof(args));
400 args.gtr_type = t->tr_type;
401 args.gtr_size = t->tr_size;
402 args.gtr_count = t->tr_count;
403 args.gtr_buf = malloc(args.gtr_size * args.gtr_count);
404 if (args.gtr_buf == NULL) {
405 return ENOMEM;
406 }
407 err = ioctl(ncd->ncd_fd, NXIOC_GET_TRAFFIC_RULES, &args);
408 if (err < 0) {
409 err = errno;
410 free(args.gtr_buf);
411 return err;
412 }
413 if (args.gtr_count > 0) {
414 t->tr_iterate(args.gtr_buf, args.gtr_count,
415 itr, itr_arg);
416 }
417 free(args.gtr_buf);
418 }
419 return 0;
420 }
421
422 void
os_nexus_controller_destroy(nexus_controller_t ncd)423 os_nexus_controller_destroy(nexus_controller_t ncd)
424 {
425 if (ncd->ncd_fd != -1) {
426 (void) guarded_close_np(ncd->ncd_fd, &ncd->ncd_guard);
427 }
428 free(ncd);
429 }
430
431 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)432 __os_nexus_ifattach(const nexus_controller_t ncd,
433 const uuid_t nx_uuid, const char *ifname, const uuid_t netif_uuid,
434 boolean_t host, uuid_t *nx_if_uuid)
435 {
436 struct nx_cfg_req ncr;
437 struct nx_spec_req nsr;
438 int ret;
439
440 bzero(&nsr, sizeof(nsr));
441 if (ifname != NULL) {
442 (void) strlcpy(nsr.nsr_name, ifname, sizeof(nsr.nsr_name));
443 } else {
444 bcopy(netif_uuid, nsr.nsr_uuid, sizeof(uuid_t));
445 nsr.nsr_flags |= NXSPECREQ_UUID;
446 }
447
448 if (host) {
449 nsr.nsr_flags |= NXSPECREQ_HOST;
450 }
451
452 __nexus_config_req_prepare(&ncr, nx_uuid, NXCFG_CMD_ATTACH,
453 &nsr, sizeof(nsr));
454
455 ret = __nexus_set_opt(ncd->ncd_fd, NXOPT_NEXUS_CONFIG,
456 &ncr, sizeof(ncr));
457
458 if (ret == 0) {
459 bcopy(nsr.nsr_if_uuid, nx_if_uuid, sizeof(uuid_t));
460 }
461
462 return ret;
463 }
464
465 int
__os_nexus_ifdetach(const nexus_controller_t ncd,const uuid_t nx_uuid,const uuid_t nx_if_uuid)466 __os_nexus_ifdetach(const nexus_controller_t ncd, const uuid_t nx_uuid,
467 const uuid_t nx_if_uuid)
468 {
469 struct nx_cfg_req ncr;
470 struct nx_spec_req nsr;
471
472 bzero(&nsr, sizeof(nsr));
473 bcopy(nx_if_uuid, nsr.nsr_if_uuid, sizeof(uuid_t));
474
475 __nexus_config_req_prepare(&ncr, nx_uuid, NXCFG_CMD_DETACH,
476 &nsr, sizeof(nsr));
477
478 return __nexus_set_opt(ncd->ncd_fd, NXOPT_NEXUS_CONFIG,
479 &ncr, sizeof(ncr));
480 }
481
482 int
__os_nexus_flow_add(const nexus_controller_t ncd,const uuid_t nx_uuid,const struct nx_flow_req * nfr)483 __os_nexus_flow_add(const nexus_controller_t ncd, const uuid_t nx_uuid,
484 const struct nx_flow_req *nfr)
485 {
486 struct nx_cfg_req ncr;
487
488 __nexus_config_req_prepare(&ncr, nx_uuid, NXCFG_CMD_FLOW_ADD,
489 nfr, sizeof(*nfr));
490
491 return __nexus_set_opt(ncd->ncd_fd, NXOPT_NEXUS_CONFIG,
492 &ncr, sizeof(ncr));
493 }
494
495 int
__os_nexus_flow_del(const nexus_controller_t ncd,const uuid_t nx_uuid,const struct nx_flow_req * nfr)496 __os_nexus_flow_del(const nexus_controller_t ncd, const uuid_t nx_uuid,
497 const struct nx_flow_req *nfr)
498 {
499 struct nx_cfg_req ncr;
500
501 __nexus_config_req_prepare(&ncr, nx_uuid, NXCFG_CMD_FLOW_DEL,
502 nfr, sizeof(*nfr));
503
504 return __nexus_set_opt(ncd->ncd_fd, NXOPT_NEXUS_CONFIG,
505 &ncr, sizeof(ncr));
506 }
507
508 static int
__os_nexus_config_flow(const uuid_t nx_uuid,struct nx_flow_req * nfr)509 __os_nexus_config_flow(const uuid_t nx_uuid, struct nx_flow_req *nfr)
510 {
511 struct nx_cfg_req ncr;
512
513 __nexus_config_req_prepare(&ncr, nx_uuid, NXCFG_CMD_FLOW_CONFIG,
514 nfr, sizeof(*nfr));
515
516 return __nexus_set_opt(__OS_NEXUS_SHARED_USER_CONTROLLER_FD,
517 NXOPT_NEXUS_CONFIG, &ncr, sizeof(ncr));
518 }
519
520 int
os_nexus_flow_set_wake_from_sleep(const uuid_t nx_uuid,const uuid_t flow_uuid,bool enable)521 os_nexus_flow_set_wake_from_sleep(const uuid_t nx_uuid, const uuid_t flow_uuid,
522 bool enable)
523 {
524 struct nx_flow_req nfr = {0};
525 memcpy(nfr.nfr_flow_uuid, flow_uuid, sizeof(uuid_t));
526 nfr.nfr_flags = enable ? 0 : NXFLOWREQF_NOWAKEFROMSLEEP;
527
528 return __os_nexus_config_flow(nx_uuid, &nfr);
529 }
530
531 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)532 __os_nexus_get_llink_info(const nexus_controller_t ncd, const uuid_t nx_uuid,
533 const struct nx_llink_info_req *nlir, size_t len)
534 {
535 struct nx_cfg_req ncr;
536
537 __nexus_config_req_prepare(&ncr, nx_uuid, NXCFG_CMD_GET_LLINK_INFO,
538 nlir, len);
539
540 return __nexus_set_opt(ncd->ncd_fd, NXOPT_NEXUS_CONFIG,
541 &ncr, sizeof(ncr));
542 }
543
544 int
os_nexus_flow_set_connection_idle(const uuid_t nx_uuid,const uuid_t flow_uuid,bool enable)545 os_nexus_flow_set_connection_idle(const uuid_t nx_uuid, const uuid_t flow_uuid,
546 bool enable)
547 {
548 struct nx_flow_req nfr = {0};
549 memcpy(nfr.nfr_flow_uuid, flow_uuid, sizeof(uuid_t));
550 nfr.nfr_flags = enable ? NXFLOWREQF_CONNECTION_IDLE :
551 NXFLOWREQF_CONNECTION_REUSED;
552
553 return __os_nexus_config_flow(nx_uuid, &nfr);
554 }
555