Loading...
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
/*
 * Copyright (c) 2015-2023 Apple Inc. All rights reserved.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. The rights granted to you under the License
 * may not be used to create, or enable the creation or redistribution of,
 * unlawful or unlicensed copies of an Apple operating system, or to
 * circumvent, violate, or enable the circumvention or violation of, any
 * terms of an Apple operating system software license agreement.
 *
 * Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this file.
 *
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
 */

/*
 * Copyright (C) 2012-2014 Matteo Landi, Luigi Rizzo, Giuseppe Lettieri.
 * All rights reserved.
 * Copyright (C) 2013-2014 Universita` di Pisa. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef _SKYWALK_NEXUS_NEXUSVAR_H_
#define _SKYWALK_NEXUS_NEXUSVAR_H_

#ifdef BSD_KERNEL_PRIVATE
#include <skywalk/core/skywalk_var.h>
#include <skywalk/os_nexus_private.h>

struct chreq;
struct nxdom;
struct kern_channel;
struct kern_nexus_domain_provider;

/*
 * Nexus controller instance.
 */
struct nxctl {
	decl_lck_mtx_data(, nxctl_lock);
	uint32_t                nxctl_refcnt;
	uint32_t                nxctl_flags;
	uuid_t                  nxctl_uuid;
	uuid_t                  nxctl_proc_uuid;
	uint64_t                nxctl_proc_uniqueid;
	STAILQ_ENTRY(nxctl)     nxctl_link;
	struct fileproc         *nxctl_fp;
	kauth_cred_t            nxctl_cred;
	void                   *nxctl_traffic_rule_storage;
};

#define NEXUSCTLF_ATTACHED      0x1
#define NEXUSCTLF_NOFDREF       0x2
#define NEXUSCTLF_KERNEL        0x4

#define NEXUSCTLF_BITS  \
	"\020\01ATTACHED\02NOFDREF\03KERNEL"

/*
 * Nexus port binding structure.
 */
struct nxbind {
	uint32_t                nxb_flags;
	pid_t                   nxb_pid;
	uint64_t                nxb_uniqueid;
	uuid_t                  nxb_exec_uuid;
	uint32_t                nxb_key_len;
	void                    *nxb_key;
};

#define NXBF_MATCH_UNIQUEID     0x1     /* match against process's unique ID */
#define NXBF_MATCH_EXEC_UUID    0x2     /* match against executable's UUID */
#define NXBF_MATCH_KEY          0x4     /* match against key blob */

#define NXBF_BITS       \
	"\020\01UNIQUEID\02EXEC_UUID\03KEY"

/*
 * Nexus port info structure.
 */
struct nx_port_info {
	/*
	 * We need to store some states on the nexus port info,
	 * e.g. defunct.  The states are encoded in the tagged
	 * pointer handle npi_nah.
	 */
	uintptr_t               npi_nah;
	struct nxbind           *npi_nxb;
	void                    *npi_info;
};

/*
 * Used for indicating what type is attached to npi_info
 * The type enum is defined here. One namespace for all nexus types.
 * The actual structure is defined in nexus specific headers.
 */
typedef enum {
	NX_PORT_INFO_TYPE_NETIF = 0x10000001
} nx_port_info_type_t;

/*
 * Header of nexus specific structure npi_info
 */
struct nx_port_info_header {
	nx_port_info_type_t     ih_type;
	size_t                  ih_size;
};

#define NX_PORT_CHUNK      64
#define NX_PORT_CHUNK_FREE 0xffffffffffffffff /* entire chunk is free */

/*
 * Nexus port state type.
 *
 * Be mindful that due to the use of tagger pointer for nexus adapter in the
 * nexus port info structure, this type gets encoded with the requirement
 * that the object addresses are aligned on 4-bytes boundary at the minimum.
 * That leaves 2 bits for the states, therefore limiting the maximum enum
 * value to 3.
 */
typedef enum {
	NEXUS_PORT_STATE_WORKING = 0,           /* fully operational */
	NEXUS_PORT_STATE_DEFUNCT,               /* no longer in service */
	NEXUS_PORT_STATE_RESERVED_1,            /* for future use */
	NEXUS_PORT_STATE_RESERVED_2,            /* for future use */
	NEXUS_PORT_STATE_MAX = NEXUS_PORT_STATE_RESERVED_2
} nexus_port_state_t;

#define NPI_NA_STATE_MASK       ((uintptr_t)0x3)        /* 11 */
#define NPI_NA_TAG_MASK         ((uintptr_t)0x3)        /* 11 */

#define NPI_NA_TAG(_p)          ((uintptr_t)(_p) & NPI_NA_TAG_MASK)
#define NPI_NA_ADDR_MASK        (~NPI_NA_TAG_MASK)

#define NPI_NA_STATE(_p)        ((uintptr_t)(_p) & NPI_NA_STATE_MASK)
#define NPI_NA_STATE_ENC(_s)    ((uintptr_t)(_s) & NPI_NA_STATE_MASK)

#define NPI_NA_ADDR(_p)         ((uintptr_t)(_p) & NPI_NA_ADDR_MASK)
#define NPI_NA_ADDR_ENC(_p)     ((uintptr_t)(_p) & NPI_NA_ADDR_MASK)

#define NPI_NA_ENCODE(_p, _s)   (NPI_NA_ADDR_ENC(_p) | NPI_NA_STATE_ENC(_s))

#define NPI_NA(_npi)            \
	((struct nexus_adapter *)NPI_NA_ADDR((_npi)->npi_nah))
#define NPI_IS_DEFUNCT(_npi)    \
	(NPI_NA_STATE((_npi)->npi_nah) == NEXUS_PORT_STATE_DEFUNCT)

/*
 * Nexus-wide advisory region and object.
 */
struct kern_nexus_advisory {
	struct skmem_region     *nxv_reg;
	void                    *nxv_adv;
	nexus_advisory_type_t   nxv_adv_type;
	union {
		struct sk_nexusadv             *flowswitch_nxv_adv;
		struct netif_nexus_advisory    *netif_nxv_adv;
	};
};

/*
 * Nexus instance.
 *
 * At present most fields are protected by sk_lock.  The exception is
 * the nx_ch_if_adv_head list which uses nx_ch_if_adv_lock instead.
 *
 * In cases where sk_lock, nx_ch_if_adv_lock and ch_lock must be held,
 * the following ordering needs to be followed:
 *
 *   sk_lock -> nx_ch_if_adv_lock -> ch_lock
 */
struct kern_nexus {
	uint32_t                nx_refcnt;
	volatile uint32_t       nx_flags;
	void                    *nx_ctx;
	nexus_ctx_release_fn_t  nx_ctx_release;
	struct kern_nexus_provider *nx_prov;
	uint64_t                nx_id;
	uuid_t                  nx_uuid;
	STAILQ_ENTRY(kern_nexus) nx_prov_link;
	RB_ENTRY(kern_nexus)    nx_link;
	STAILQ_HEAD(, kern_channel) nx_ch_head;
	uint32_t                nx_ch_count;
	STAILQ_HEAD(, kern_channel) nx_ch_nonxref_head;
	decl_lck_rw_data(, nx_ch_if_adv_lock);
	STAILQ_HEAD(, kern_channel) nx_ch_if_adv_head;
	void                    *nx_arg;
	struct kern_pbufpool    *nx_rx_pp;
	struct kern_pbufpool    *nx_tx_pp;
	struct kern_nexus_advisory nx_adv;

	/* nexus port */
	struct nx_port_info     *nx_ports;
	bitmap_t                *nx_ports_bmap;
	nexus_port_size_t       nx_active_ports;
	nexus_port_size_t       nx_num_ports;
};

#define NXF_ATTACHED    0x1
#define NXF_CLOSED      0x2             /* attached but closed */
#define NXF_REJECT      (1U << 31)      /* not accepting channel activities */

#define NXF_BITS        \
	"\020\01ATTACHED\02CLOSED\040REJECT"

#define NX_PROV(_nx)            ((_nx)->nx_prov)
#define NX_PROV_PARAMS(_nx)     (NX_PROV(_nx)->nxprov_params)
#define NX_DOM_PROV(_nx)        (NX_PROV(_nx)->nxprov_dom_prov)
#define NX_DOM(_nx)             (NX_DOM_PROV(_nx)->nxdom_prov_dom)

#define NX_REJECT_ACT(_nx)      (((_nx)->nx_flags & NXF_REJECT) != 0)

/*
 * Nexus provider.
 */
struct kern_nexus_provider {
	uint32_t                        nxprov_refcnt;
	uint32_t                        nxprov_flags;
	STAILQ_ENTRY(kern_nexus_provider) nxprov_link;
	STAILQ_HEAD(, kern_nexus)       nxprov_nx_head;
	uint32_t                        nxprov_nx_count;
	struct nxctl                    *nxprov_ctl;
	uuid_t                          nxprov_uuid;
	struct kern_nexus_domain_provider *nxprov_dom_prov;
	union {
		struct kern_nexus_provider_init nxprov_ext;
		struct kern_nexus_netif_provider_init nxprov_netif_ext;
	};
	struct nxprov_params            *nxprov_params;
	struct skmem_region_params      nxprov_region_params[SKMEM_REGIONS];
};

/* valid flags for nxprov_flags */
#define NXPROVF_ATTACHED        0x1     /* attached to global list */
#define NXPROVF_CLOSED          0x2     /* attached but closed */
#define NXPROVF_EXTERNAL        0x4     /* external nexus provider */
#define NXPROVF_VIRTUAL_DEVICE  0x8     /* device is virtual (no DMA) */

#define NXPROV_LLINK(_nxp) \
	((_nxp)->nxprov_params->nxp_flags & NXPF_NETIF_LLINK)

#define NXPROVF_BITS    \
	"\020\01ATTACHED\02CLOSED\03EXTERNAL\04VIRTUALDEV"

#define NX_ANONYMOUS_PROV(_nx)  \
	(NX_PROV(_nx)->nxprov_params->nxp_flags & NXPF_ANONYMOUS)
#define NX_USER_CHANNEL_PROV(_nx) \
	(NX_PROV(_nx)->nxprov_params->nxp_flags & NXPF_USER_CHANNEL)
#define NX_LLINK_PROV(_nx)    NXPROV_LLINK(NX_PROV(_nx))

/*
 * Nexus domain provider.
 */
struct kern_nexus_domain_provider {
	STAILQ_ENTRY(kern_nexus_domain_provider) nxdom_prov_link;
	STAILQ_ENTRY(kern_nexus_domain_provider) nxdom_prov_detaching_link;
	char                    nxdom_prov_name[64];
	uuid_t                  nxdom_prov_uuid;
	uint64_t                nxdom_prov_gencnt;
	uint32_t                nxdom_prov_refcnt;
	uint32_t                nxdom_prov_flags;
	struct nxdom            *nxdom_prov_dom;
	struct kern_nexus_domain_provider_init nxdom_prov_ext;
	/*
	 * The callbacks are grouped together to simplify the
	 * initialization of external domain providers; see
	 * kern_nexus_register_domain_provider() for details.
	 */
	struct nxdom_prov_cb {
		int (*dp_cb_init)(struct kern_nexus_domain_provider *);
		void (*dp_cb_fini)(struct kern_nexus_domain_provider *);
		int (*dp_cb_params)(struct kern_nexus_domain_provider *,
		    const uint32_t, const struct nxprov_params *,
		    struct nxprov_params *,
		    struct skmem_region_params[SKMEM_REGIONS], uint32_t);
		int (*dp_cb_mem_new)(struct kern_nexus_domain_provider *,
		    struct kern_nexus *, struct nexus_adapter *);
		int (*dp_cb_config)(struct kern_nexus_domain_provider *,
		    struct kern_nexus *, struct nx_cfg_req *, int,
		    struct proc *, kauth_cred_t);
		int (*dp_cb_nx_ctor)(struct kern_nexus *);
		void (*dp_cb_nx_dtor)(struct kern_nexus *);
		int (*dp_cb_nx_mem_info)(struct kern_nexus *,
		    struct kern_pbufpool **, struct kern_pbufpool **);
		size_t (*dp_cb_nx_mib_get)(struct kern_nexus *,
		    struct nexus_mib_filter *, void *, size_t, struct proc *);
		int (*dp_cb_nx_stop)(struct kern_nexus *);
	} nxdom_prov_cb;
#define nxdom_prov_init         nxdom_prov_cb.dp_cb_init
#define nxdom_prov_fini         nxdom_prov_cb.dp_cb_fini
#define nxdom_prov_params       nxdom_prov_cb.dp_cb_params
#define nxdom_prov_mem_new      nxdom_prov_cb.dp_cb_mem_new
#define nxdom_prov_config       nxdom_prov_cb.dp_cb_config
#define nxdom_prov_nx_ctor      nxdom_prov_cb.dp_cb_nx_ctor
#define nxdom_prov_nx_dtor      nxdom_prov_cb.dp_cb_nx_dtor
#define nxdom_prov_nx_mem_info  nxdom_prov_cb.dp_cb_nx_mem_info
#define nxdom_prov_nx_mib_get   nxdom_prov_cb.dp_cb_nx_mib_get
#define nxdom_prov_nx_stop      nxdom_prov_cb.dp_cb_nx_stop
};

#define NXDOMPROVF_INITIALIZED  0x1     /* provider has been initialized */
#define NXDOMPROVF_ATTACHED     0x2     /* provider is attached to a domain */
#define NXDOMPROVF_DETACHING    0x4     /* provider is being detached */
#define NXDOMPROVF_EXT          0x8     /* external provider */
#define NXDOMPROVF_EXT_INITED   0x10    /* nxpi_init() succeeded */
#define NXDOMPROVF_DEFAULT      0x20    /* default provider for domain */

struct nxp_bounds {
	uint32_t        nb_def;
	uint32_t        nb_min;
	uint32_t        nb_max;
};

/*
 * Nexus domain.
 *
 * Each Nexus type is represented by a Nexus domain; there can
 * be more than one providers for a given domain.
 */
struct nxdom {
	STAILQ_ENTRY(nxdom) nxdom_link;
	STAILQ_HEAD(, kern_nexus_domain_provider) nxdom_prov_head;
	nexus_type_t    nxdom_type;
	nexus_meta_type_t nxdom_md_type;
	nexus_meta_subtype_t nxdom_md_subtype;
	uint32_t        nxdom_flags;
	struct nxp_bounds nxdom_ports;
	struct nxp_bounds nxdom_tx_rings;
	struct nxp_bounds nxdom_rx_rings;
	struct nxp_bounds nxdom_tx_slots;
	struct nxp_bounds nxdom_rx_slots;
	struct nxp_bounds nxdom_buf_size;
	struct nxp_bounds nxdom_large_buf_size;
	struct nxp_bounds nxdom_meta_size;
	struct nxp_bounds nxdom_stats_size;
	struct nxp_bounds nxdom_pipes;
	struct nxp_bounds nxdom_extensions;
	struct nxp_bounds nxdom_mhints;
	struct nxp_bounds nxdom_flowadv_max;
	struct nxp_bounds nxdom_nexusadv_size;
	struct nxp_bounds nxdom_capabilities;
	struct nxp_bounds nxdom_qmap;
	struct nxp_bounds nxdom_max_frags;
	struct skmem_region_params nxdom_region_params[SKMEM_REGIONS];
	const char      *nxdom_name;

	/*
	 * Nexus domain callbacks.
	 */
	void (*nxdom_init)(struct nxdom *);             /* optional */
	void (*nxdom_terminate)(struct nxdom *);        /* optional */
	void (*nxdom_fini)(struct nxdom *);             /* optional */
	int (*nxdom_find_port)                          /* optional */
	(struct kern_nexus *, boolean_t, nexus_port_t *);
	boolean_t (*nxdom_port_is_reserved)             /* optional */
	(struct kern_nexus *, nexus_port_t);
	int (*nxdom_bind_port)                          /* required */
	(struct kern_nexus *, nexus_port_t *, struct nxbind *, void *);
	int (*nxdom_unbind_port)                        /* required */
	(struct kern_nexus *, nexus_port_t);
	int (*nxdom_connect)                            /* required */
	(struct kern_nexus_domain_provider *, struct kern_nexus *,
	struct kern_channel *, struct chreq *, struct kern_channel *,
	struct nxbind *, struct proc *);
	void (*nxdom_disconnect)                        /* required */
	(struct kern_nexus_domain_provider *, struct kern_nexus *,
	struct kern_channel *);
	void (*nxdom_defunct)                           /* required */
	(struct kern_nexus_domain_provider *, struct kern_nexus *,
	struct kern_channel *, struct proc *);
	void (*nxdom_defunct_finalize)                  /* required */
	(struct kern_nexus_domain_provider *, struct kern_nexus *,
	struct kern_channel *, boolean_t);
};

#define NEXUSDOMF_INITIALIZED   0x1     /* domain has been initialized */
#define NEXUSDOMF_ATTACHED      0x2     /* domain is globally attached */
#define NEXUSDOMF_TERMINATED    0x4     /* domain has been terminated */

#define NXDOM_DEF(_dom, var)    ((_dom)->nxdom_##var.nb_def)
#define NXDOM_MIN(_dom, var)    ((_dom)->nxdom_##var.nb_min)
#define NXDOM_MAX(_dom, var)    ((_dom)->nxdom_##var.nb_max)

extern struct nexus_controller kernnxctl;
extern struct nexus_controller usernxctl;
extern lck_grp_t nexus_lock_group;
extern lck_grp_t nexus_mbq_lock_group;
extern lck_grp_t nexus_pktq_lock_group;
extern lck_attr_t nexus_lock_attr;
extern kern_allocation_name_t skmem_tag_nx_key;
extern kern_allocation_name_t skmem_tag_nx_port_info;

extern struct kern_nexus_domain_provider *nxdom_prov_default[NEXUS_TYPE_MAX];

#define NX_SHARED_NXCTL_INSTANCE(_nxctl)        \
    ((_nxctl) == kernnxctl.ncd_nxctl)

#define NXCTL_LOCK(_nxctl)      do {                    \
	if (!NX_SHARED_NXCTL_INSTANCE((_nxctl))) {      \
	        lck_mtx_lock(&((_nxctl)->nxctl_lock));  \
	} else {                                        \
	        LCK_MTX_ASSERT(&((_nxctl)->nxctl_lock), \
	            LCK_MTX_ASSERT_NOTOWNED);           \
	}                                               \
} while (0)

#define NXCTL_UNLOCK(_nxctl)    do {                    \
	if (!NX_SHARED_NXCTL_INSTANCE((_nxctl))) {      \
	        lck_mtx_unlock(&((_nxctl)->nxctl_lock));\
	}                                               \
	LCK_MTX_ASSERT(&((_nxctl)->nxctl_lock),         \
	    LCK_MTX_ASSERT_NOTOWNED);                   \
} while (0)

#define NXCTL_LOCK_ASSERT_HELD(_nxctl)  do {            \
	if (!NX_SHARED_NXCTL_INSTANCE((_nxctl))) {      \
	        LCK_MTX_ASSERT(&((_nxctl)->nxctl_lock), \
	            LCK_MTX_ASSERT_OWNED);              \
	} else {                                        \
	        LCK_MTX_ASSERT(&((_nxctl)->nxctl_lock), \
	            LCK_MTX_ASSERT_NOTOWNED);           \
	}                                               \
} while (0)

__BEGIN_DECLS
extern int nexus_init(void);
extern void nexus_fini(void);

extern struct kern_nexus *nx_create(struct nxctl *, const uuid_t,
    const nexus_type_t, const void *, nexus_ctx_release_fn_t,
    struct kern_pbufpool *, struct kern_pbufpool *, int *);
extern void nx_retain(struct kern_nexus *);
extern void nx_retain_locked(struct kern_nexus *);
extern int nx_release(struct kern_nexus *);
extern int nx_release_locked(struct kern_nexus *);
extern void nx_detach(struct kern_nexus *);
extern void nx_stop(struct kern_nexus *nx);
extern int nx_close(struct kern_nexus *, boolean_t);
extern int nx_destroy(struct nxctl *, const uuid_t);
extern struct kern_nexus *nx_find(const uuid_t, boolean_t);
extern int nx_advisory_alloc(struct kern_nexus *, const char *,
    struct skmem_region_params *, nexus_advisory_type_t);
extern void nx_advisory_free(struct kern_nexus *);
extern int nx_port_find(struct kern_nexus *, nexus_port_t,
    nexus_port_t, nexus_port_t *);
extern int nx_port_alloc(struct kern_nexus *, nexus_port_t,
    struct nxbind *, struct nexus_adapter **, struct proc *);
extern int nx_port_bind(struct kern_nexus *, nexus_port_t,
    struct nxbind *);
extern int nx_port_bind_info(struct kern_nexus *, nexus_port_t,
    struct nxbind *, void *);
extern int nx_port_unbind(struct kern_nexus *, nexus_port_t);
extern struct nexus_adapter *nx_port_get_na(struct kern_nexus *,
    nexus_port_t);
extern int nx_port_get_info(struct kern_nexus *, nexus_port_t,
    nx_port_info_type_t, void *, uint32_t);
extern void nx_port_defunct(struct kern_nexus *, nexus_port_t);
extern void nx_port_free(struct kern_nexus *, nexus_port_t);
extern void nx_port_free_all(struct kern_nexus *);
extern bool nx_port_is_valid(struct kern_nexus *, nexus_port_t);
extern bool nx_port_is_defunct(struct kern_nexus *, nexus_port_t);
extern void nx_port_foreach(struct kern_nexus *, void (^)(nexus_port_t));
extern void nx_interface_advisory_notify(struct kern_nexus *);

extern struct nxctl *nxctl_create(struct proc *, struct fileproc *,
    const uuid_t, int *);
extern void nxctl_close(struct nxctl *);
extern void nxctl_traffic_rule_clean(struct nxctl *);
extern void nxctl_traffic_rule_init(void);
extern void nxctl_traffic_rule_fini(void);
extern int nxctl_inet_traffic_rule_find_qset_id_with_pkt(const char *,
    struct __kern_packet *, uint64_t *);
extern int nxctl_inet_traffic_rule_find_qset_id(const char *,
    struct ifnet_traffic_descriptor_inet *, uint64_t *);
extern int nxctl_inet_traffic_rule_get_count(const char *, uint32_t *);
extern int nxctl_get_opt(struct nxctl *, struct sockopt *);
extern int nxctl_set_opt(struct nxctl *, struct sockopt *);
extern void nxctl_retain(struct nxctl *);
extern int nxctl_release(struct nxctl *);
extern void nxctl_dtor(void *);

extern int nxprov_advise_connect(struct kern_nexus *, struct kern_channel *,
    struct proc *p);
extern void nxprov_advise_disconnect(struct kern_nexus *,
    struct kern_channel *);
extern struct kern_nexus_provider *nxprov_create(struct proc *,
    struct nxctl *, struct nxprov_reg *, int *);
extern struct kern_nexus_provider *nxprov_create_kern(struct nxctl *,
    struct kern_nexus_domain_provider *, struct nxprov_reg *,
    const struct kern_nexus_provider_init *init, int *err);
extern int nxprov_close(struct kern_nexus_provider *, boolean_t);
extern int nxprov_destroy(struct nxctl *, const uuid_t);
extern void nxprov_retain(struct kern_nexus_provider *);
extern int nxprov_release(struct kern_nexus_provider *);
extern struct nxprov_params *nxprov_params_alloc(zalloc_flags_t);
extern void nxprov_params_free(struct nxprov_params *);

struct nxprov_adjusted_params {
	nexus_meta_subtype_t *adj_md_subtype;
	uint32_t *adj_stats_size;
	uint32_t *adj_flowadv_max;
	uint32_t *adj_nexusadv_size;
	uint32_t *adj_caps;
	uint32_t *adj_tx_rings;
	uint32_t *adj_rx_rings;
	uint32_t *adj_tx_slots;
	uint32_t *adj_rx_slots;
	uint32_t *adj_alloc_rings;
	uint32_t *adj_free_rings;
	uint32_t *adj_alloc_slots;
	uint32_t *adj_free_slots;
	uint32_t *adj_buf_size;
	uint32_t *adj_buf_region_segment_size;
	uint32_t *adj_pp_region_config_flags;
	uint32_t *adj_max_frags;
	uint32_t *adj_event_rings;
	uint32_t *adj_event_slots;
	uint32_t *adj_max_buffers;
	uint32_t *adj_large_buf_size;
};

extern int nxprov_params_adjust(struct kern_nexus_domain_provider *,
    const uint32_t, const struct nxprov_params *, struct nxprov_params *,
    struct skmem_region_params[SKMEM_REGIONS], const struct nxdom *,
    const struct nxdom *, const struct nxdom *, uint32_t,
    int (*adjust_fn)(const struct kern_nexus_domain_provider *,
    const struct nxprov_params *, struct nxprov_adjusted_params *));

extern void nxdom_attach_all(void);
extern void nxdom_detach_all(void);
extern struct nxdom *nxdom_find(nexus_type_t);

extern struct kern_nexus_domain_provider *nxdom_prov_find(
	const struct nxdom *, const char *);
extern struct kern_nexus_domain_provider *nxdom_prov_find_uuid(const uuid_t);
extern int nxdom_prov_add(struct nxdom *, struct kern_nexus_domain_provider *);
extern void nxdom_prov_del(struct kern_nexus_domain_provider *);
extern void nxdom_prov_retain_locked(struct kern_nexus_domain_provider *);
extern void nxdom_prov_retain(struct kern_nexus_domain_provider *);
extern boolean_t nxdom_prov_release_locked(struct kern_nexus_domain_provider *);
extern boolean_t nxdom_prov_release(struct kern_nexus_domain_provider *);
extern int nxdom_prov_validate_params(struct kern_nexus_domain_provider *,
    const struct nxprov_reg *, struct nxprov_params *,
    struct skmem_region_params[SKMEM_REGIONS], const uint32_t, uint32_t);

extern struct nxbind *nxb_alloc(zalloc_flags_t);
extern void nxb_free(struct nxbind *);
extern boolean_t nxb_is_equal(struct nxbind *, struct nxbind *);
extern void nxb_move(struct nxbind *, struct nxbind *);

typedef void kern_nexus_walktree_f_t(struct kern_nexus *, void *);
extern void kern_nexus_walktree(kern_nexus_walktree_f_t *, void *, boolean_t);

extern int kern_nexus_get_pbufpool_info(const uuid_t nx_uuid,
    struct kern_pbufpool_memory_info *rx_pool,
    struct kern_pbufpool_memory_info *tx_pool);
__END_DECLS

#include <skywalk/nexus/nexus_adapter.h>

__attribute__((always_inline))
static inline int
nx_sync_tx(struct __kern_channel_ring *kring, boolean_t commit)
{
	struct kern_nexus_provider *nxprov = NX_PROV(KRNA(kring)->na_nx);

	ASSERT(kring->ckr_tx == NR_TX);
	if (nxprov->nxprov_ext.nxpi_sync_tx != NULL) {
		return nxprov->nxprov_ext.nxpi_sync_tx(nxprov,
		           KRNA(kring)->na_nx, kring,
		           (commit ? KERN_NEXUS_SYNCF_COMMIT : 0));
	} else {
		return 0;
	}
}

__attribute__((always_inline))
static inline int
nx_sync_rx(struct __kern_channel_ring *kring, boolean_t commit)
{
	struct kern_nexus_provider *nxprov = NX_PROV(KRNA(kring)->na_nx);

	ASSERT(kring->ckr_tx == NR_RX);
	if (nxprov->nxprov_ext.nxpi_sync_rx != NULL) {
		return nxprov->nxprov_ext.nxpi_sync_rx(nxprov,
		           KRNA(kring)->na_nx, kring,
		           (commit ? KERN_NEXUS_SYNCF_COMMIT : 0));
	} else {
		return 0;
	}
}

__attribute__((always_inline))
static __inline__ void
nx_tx_doorbell(struct __kern_channel_ring *kring, boolean_t async)
{
	struct kern_nexus_provider *nxprov = NX_PROV(KRNA(kring)->na_nx);

	ASSERT(kring->ckr_tx == NR_TX);
	ASSERT(nxprov->nxprov_ext.nxpi_tx_doorbell != NULL);
	nxprov->nxprov_ext.nxpi_tx_doorbell(nxprov, KRNA(kring)->na_nx,
	    kring, (async ? KERN_NEXUS_TXDOORBELLF_ASYNC_REFILL: 0));
}

__attribute__((always_inline))
static inline int
nx_rx_sync_packets(struct __kern_channel_ring *kring, uint64_t packets[],
    uint32_t *count)
{
	struct kern_nexus_provider *nxprov = NX_PROV(KRNA(kring)->na_nx);

	ASSERT(kring->ckr_tx == NR_RX);
	if (nxprov->nxprov_ext.nxpi_rx_sync_packets != NULL) {
		return nxprov->nxprov_ext.nxpi_rx_sync_packets(nxprov,
		           KRNA(kring)->na_nx, kring, packets, count, 0);
	} else {
		return 0;
	}
}

__attribute__((always_inline))
static inline boolean_t
nx_has_rx_sync_packets(struct __kern_channel_ring *kring)
{
	struct kern_nexus_provider *nxprov = NX_PROV(KRNA(kring)->na_nx);

	ASSERT(kring->ckr_tx == NR_RX);
	return nxprov->nxprov_ext.nxpi_rx_sync_packets != NULL;
}

__attribute__((always_inline))
static __inline__ errno_t
nx_tx_qset_notify(struct kern_nexus *nx, void *qset_ctx)
{
	struct kern_nexus_provider *nxprov = NX_PROV(nx);
	sk_protect_t protect;
	errno_t err;

	ASSERT(nxprov->nxprov_netif_ext.nxnpi_tx_qset_notify != NULL);
	protect = sk_tx_notify_protect();
	err = nxprov->nxprov_netif_ext.nxnpi_tx_qset_notify(nxprov, nx,
	    qset_ctx, 0);
	sk_tx_notify_unprotect(protect);
	return err;
}
#endif /* BSD_KERNEL_PRIVATE */
#endif /* _SKYWALK_NEXUS_NEXUSVAR_H_ */