This is xnu-11215.1.10. See this file in:
/*
 * 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@
 */

#ifndef _SKYWALK_NEXUS_NETIF_H_
#define _SKYWALK_NEXUS_NETIF_H_

#include <skywalk/os_skywalk_private.h>
#include <skywalk/nexus/nexus_pktq.h>

#if CONFIG_NEXUS_NETIF

#define NEXUS_PROVIDER_NET_IF           "com.apple.nexus.netif"

#define NX_NETIF_MAXPORTS       128
#define NX_NETIF_EVENT_RING_NUM      1     /* number of event rings */
#define NX_NETIF_EVENT_RING_SIZE     32    /* default event ring size */

struct netif_filter {
	STAILQ_ENTRY(netif_filter) nf_link;
	nexus_port_t            nf_port;
	uint32_t                nf_refcnt;
	void                    *nf_cb_arg;
	errno_t                 (*nf_cb_func)(void *,
	    struct __kern_packet *, uint32_t);
};
STAILQ_HEAD(netif_filter_head, netif_filter);

struct netif_flow_desc {
	uint16_t        fd_ethertype;
	struct in6_addr fd_laddr;
	struct in6_addr fd_raddr;
};

struct netif_port_info {
	struct nx_port_info_header npi_hdr;
	struct netif_flow_desc  npi_fd;
};

struct netif_flow {
	SLIST_ENTRY(netif_flow) nf_link;
	SLIST_ENTRY(netif_flow) nf_table_link;
	nexus_port_t            nf_port;
	uint32_t                nf_refcnt;
	struct netif_flow_desc  nf_desc;
	void                    *nf_cb_arg;
	errno_t                 (*nf_cb_func)(void *,
	    void *, uint32_t);
};

typedef enum {
	FT_TYPE_ETHERTYPE,
	FT_TYPE_IPV6_ULA
} netif_flowtable_type_t;

struct netif_flowtable {
	struct netif_flowtable_ops      *ft_ops;
	void                            *ft_internal;
};

typedef int netif_flow_lookup_t(struct netif_flowtable *,
    struct __kern_packet *, uint32_t, struct netif_flow **);
typedef boolean_t netif_flow_match_t(struct netif_flow_desc *,
    struct netif_flow_desc *);
typedef int netif_flow_info_t(struct __kern_packet *,
    struct netif_flow_desc *, uint32_t);
typedef int netif_flow_insert_t(struct netif_flowtable *,
    struct netif_flow *);
typedef void netif_flow_remove_t(struct netif_flowtable *,
    struct netif_flow *);
typedef struct netif_flowtable *netif_flow_table_alloc_t(
	struct netif_flowtable_ops *);
typedef void netif_flow_table_free_t(struct netif_flowtable *);

struct netif_flowtable_ops {
	netif_flow_lookup_t           *nfo_lookup;
	netif_flow_match_t            *nfo_match;
	netif_flow_info_t             *nfo_info;
	netif_flow_insert_t           *nfo_insert;
	netif_flow_remove_t           *nfo_remove;
	netif_flow_table_alloc_t      *nfo_table_alloc;
	netif_flow_table_free_t       *nfo_table_free;
};

SLIST_HEAD(netif_flow_head, netif_flow);

struct netif_queue {
	decl_lck_mtx_data(, nq_lock);
	struct netif_qset               *nq_qset; /* backpointer to parent netif qset */
	struct pktq                     nq_pktq;
	struct netif_qstats             nq_stats;
	uint64_t                        nq_accumulated_bytes;
	uint64_t                        nq_accumulated_pkts;
	uint64_t                        nq_accumulate_start; /* in seconds */
	void                            *nq_ctx;
	kern_packet_svc_class_t         nq_svc; /* service class of TX queue */
	uint16_t                        nq_flags;
}__attribute__((aligned(sizeof(uint64_t))));

/* values for nq_flags */
#define NETIF_QUEUE_EXT_INITED   0x0001 /* nxnpi_queue_init() succeeded */
#define NETIF_QUEUE_IS_RX        0x0002 /* RX queue, else TX */

#define _NETIF_QSET_QUEUE(_p, _n)    \
    (struct netif_queue *)(void *)((uint8_t *)((_p)->nqs_driver_queues) + \
    ((_n) * sizeof(struct netif_queue)))
#define NETIF_QSET_RX_QUEUE(_p, _n)    _NETIF_QSET_QUEUE(_p, _n)
#define NETIF_QSET_TX_QUEUE(_p, _n)    \
    _NETIF_QSET_QUEUE(_p, (_p)->nqs_num_rx_queues + (_n))

/* the top 32 bits are unused for now */
#define NETIF_QSET_ID_ENCODE(llink_id_internal, qset_idx) \
    ((((llink_id_internal) << 16) | (qset_idx)) & 0xffffffff)

struct netif_qset {
	struct netif_llink         *nqs_llink; /* backpointer to parent logical link */
	struct ifclassq            *nqs_ifcq;
	SLIST_ENTRY(netif_qset)    nqs_list;
	void                       *nqs_ctx; /* context provided by driver */
	uint64_t                   nqs_id;  /* queue set identifier */
	uint8_t                    nqs_idx; /* queue set index */
	uint16_t                   nqs_flags;
	uint8_t                    nqs_num_rx_queues;
	uint8_t                    nqs_num_tx_queues;
	uint8_t                    nqs_num_queues;
	/*
	 * nq_queues will be organized as:
	 * nq_queues[0..nq_num_rx_queues-1] will hold RX queues.
	 * nq_queues[nq_num_rx_queues..nq_num_tx_queues-1] will hold TX queues.
	 */
	struct netif_queue         nqs_driver_queues[__counted_by(nqs_num_queues)]
	__attribute__((aligned(sizeof(uint64_t))));
};

/* values for nqs_flags */
#define NETIF_QSET_FLAG_DEFAULT     0x0001 /* default queue set of the logical link */
#define NETIF_QSET_FLAG_AQM         0x0002 /* provides AQM */
#define NETIF_QSET_FLAG_LOW_LATENCY 0x0004 /* provides low latency service */
#define NETIF_QSET_FLAG_EXT_INITED  0x0008 /* nxnpi_qset_init() succeeded */

#define NETIF_DEFAULT_QSET(_qs)    ((_qs)->nqs_flags & NETIF_QSET_FLAG_DEFAULT)

struct netif_llink {
	struct nx_netif             *nll_nif; /* backpointer to parent netif instance */
	STAILQ_ENTRY(netif_llink)   nll_link;
	SLIST_HEAD(, netif_qset)    nll_qset_list;
	struct netif_qset           *nll_default_qset;
	struct ifclassq             *nll_ifcq;
	struct os_refcnt            nll_refcnt;
#define NETIF_LLINK_ID_DEFAULT    0
	kern_nexus_netif_llink_id_t nll_link_id;
	uint16_t                    nll_link_id_internal;
	uint16_t                    nll_qset_cnt;
	uint8_t                     nll_state;
	uint8_t                     nll_flags;
	void                        *nll_ctx; /* context provided by driver */
};
STAILQ_HEAD(netif_llink_head, netif_llink);

/* values for nll_flags */
#define NETIF_LLINK_FLAG_DEFAULT    0x1 /* default logical link */

/* values for nll_state */
#define NETIF_LLINK_STATE_INIT         0x1 /* Intialized and ready for use */
#define NETIF_LLINK_STATE_DESTROYED    0x2 /* not available for use */

#define NETIF_DEFAULT_LLINK(_ll)  ((_ll)->nll_flags & NETIF_LLINK_FLAG_DEFAULT)

SLIST_HEAD(netif_agent_flow_head, netif_agent_flow);
struct netif_agent_flow {
	SLIST_ENTRY(netif_agent_flow) naf_link;
	uuid_t                  naf_flow_uuid;
	uuid_t                  naf_bind_key;
	nexus_port_t            naf_nx_port;
	uint16_t                naf_flags;
	pid_t                   naf_pid;
	union sockaddr_in_4_6   naf_daddr;
	union sockaddr_in_4_6   naf_saddr;
};

#define NIFNA(_na)       (__container_of((_na), struct nexus_netif_adapter, nifna_up))

/* nif_flags */
/*
 * This is named differently from the flow classification rule
 * (IPV6 ULA) because this gives us the flexibility of using
 * different types of classification in the future.
 */
#define NETIF_FLAG_LOW_LATENCY          0x00000001
#define NETIF_FLAG_COMPAT               0x00000002
#define NETIF_FLAG_LLINK_INITIALIZED    0x00000004
#define NETIF_IS_LOW_LATENCY(n) \
    (((n)->nif_flags & NETIF_FLAG_LOW_LATENCY) != 0)
#define NETIF_IS_COMPAT(n) \
    (((n)->nif_flags & NETIF_FLAG_COMPAT) != 0)
#define NETIF_LLINK_ENABLED(n) \
    (((n)->nif_flags & NETIF_FLAG_LLINK_INITIALIZED) != 0)
#define NETIF_DEFAULT_DROP_ENABLED(n) \
    (nx_netif_filter_default_drop != 0 && \
    (((n)->nif_filter_flags & NETIF_FILTER_FLAG_INITIALIZED) != 0))

/* nif_agent_flags */
#define NETIF_AGENT_FLAG_REGISTERED     0x00000001
#define NETIF_AGENT_FLAG_ADDED          0x00000002

/* nif_filter_flags */
#define NETIF_FILTER_FLAG_INITIALIZED   0x00000001
#define NETIF_FILTER_FLAG_ENABLED       0x00000002

/* nif_flow_flags */
#define NETIF_FLOW_FLAG_INITIALIZED     0x00000001
#define NETIF_FLOW_FLAG_ENABLED         0x00000002

/* nif_llink_flags */
#define NETIF_LLINK_FLAG_INITIALIZED    0x00000001

/* Used by netif_hwna_set_mode() */
typedef enum {
	NETIF_MODE_NONE,
	NETIF_MODE_FSW,
	NETIF_MODE_LLW
} netif_mode_t;

/* nif capabilities */
#define NETIF_CAPAB_INTERFACE_ADVISORY 0x00000001
#define NETIF_CAPAB_QSET_EXTENSIONS    0x00000002

struct netif_qset_extensions {
	kern_nexus_capab_qsext_notify_steering_info_fn_t qe_notify_steering_info;
	void *qe_prov_ctx;
};

/*
 * nx_netif is a descriptor for a netif nexus instance.
 */
struct nx_netif {
	decl_lck_rw_data(, nif_lock);
	struct kern_nexus       *nif_nx;

	struct nxbind           *nif_dev_nxb;
	struct nxbind           *nif_host_nxb;
	uuid_t                  nif_uuid;       /* attachment UUID */
	struct netif_stats      nif_stats;
	uint32_t                nif_flags;
	struct os_refcnt        nif_refcnt;

	decl_lck_mtx_data(, nif_agent_lock);
	struct netif_agent_flow_head nif_agent_flow_list;
	uint32_t                nif_agent_flow_cnt;
	uint32_t                nif_agent_flags;
	netagent_session_t      nif_agent_session;
	uuid_t                  nif_agent_uuid;

	uint32_t                nif_hwassist;
	uint32_t                nif_capabilities;
	uint32_t                nif_capenable;
	uint64_t                nif_input_rate; /* device input rate limit */

	struct ifnet            *nif_ifp;
	struct nx_flowswitch    *nif_fsw;       /* attached flowswitch nexus */
	struct sk_nexusadv      *nif_fsw_nxadv; /* flowswitch nexus advisory */
	struct netif_nexus_advisory *nif_netif_nxadv; /* netif nexus advisory */

	/* packet-mbuf copy routines */
	pkt_copy_from_mbuf_t    *nif_pkt_copy_from_mbuf;
	pkt_copy_to_mbuf_t      *nif_pkt_copy_to_mbuf;
	pkt_copy_from_pkt_t     *nif_pkt_copy_from_pkt;

	/* packet filtering */
	decl_lck_mtx_data(, nif_filter_lock);
	uint32_t                nif_filter_flags;
	uint32_t                nif_filter_vp_cnt;
	uint32_t                nif_filter_cnt;
	struct kern_pbufpool    *nif_filter_pp;
	struct netif_filter_head nif_filter_list;
	union {
		struct nx_mbq   nif_tx_processed_mbq[MBUF_TC_MAX];
		struct nx_pktq  nif_tx_processed_pktq[KPKT_TC_MAX];
	};

	/* virtual port */
	decl_lck_mtx_data(, nif_flow_lock);
	uint32_t                nif_vp_cnt;
	uint32_t                nif_flow_flags;
	uint32_t                nif_flow_cnt;
	struct netif_flow_head  nif_flow_list;
	struct netif_flowtable  *nif_flow_table;
	struct kern_channel     *nif_hw_ch;
	uint32_t                nif_hw_ch_refcnt;

	/* logical link */
	decl_lck_rw_data(, nif_llink_lock);
	struct kern_nexus_netif_llink_init *nif_default_llink_params;
	struct netif_llink         *nif_default_llink;
	STAILQ_HEAD(, netif_llink) nif_llink_list;
	uint16_t                   nif_llink_cnt;

	/* capability configuration callback function and context */
	uint32_t                nif_extended_capabilities;
	kern_nexus_capab_interface_advisory_config_fn_t nif_intf_adv_config;
	void *nif_intf_adv_prov_ctx;

	struct netif_qset_extensions nif_qset_extensions;
#if (DEVELOPMENT || DEBUG)
	struct skoid            nif_skoid;
#endif /* !DEVELOPMENT && !DEBUG */
};

#define NX_NETIF_PRIVATE(_nx) ((struct nx_netif *)(_nx)->nx_arg)

#define NETIF_RWINIT(_nif)                \
	lck_rw_init(&(_nif)->nif_lock, &nexus_lock_group, &nexus_lock_attr)
#define NETIF_WLOCK(_nif)                 \
	lck_rw_lock_exclusive(&(_nif)->nif_lock)
#define NETIF_WUNLOCK(_nif)               \
	lck_rw_unlock_exclusive(&(_nif)->nif_lock)
#define NETIF_WLOCKTORLOCK(_nif)          \
	lck_rw_lock_exclusive_to_shared(&(_nif)->nif_lock)
#define NETIF_RLOCK(_nif)                 \
	lck_rw_lock_shared(&(_nif)->nif_lock)
#define NETIF_RLOCKTOWLOCK(_nif)          \
	lck_rw_lock_shared_to_exclusive(&(_nif)->nif_lock)
#define NETIF_RTRYLOCK(_nif)              \
	lck_rw_try_lock(&(_nif)->nif_lock, LCK_RW_TYPE_SHARED)
#define NETIF_RUNLOCK(_nif)               \
	lck_rw_unlock_shared(&(_nif)->nif_lock)
#define NETIF_UNLOCK(_nif)                \
	lck_rw_done(&(_nif)->nif_lock)
#define NETIF_RWDESTROY(_nif)             \
	lck_rw_destroy(&(_nif)->nif_lock, &nexus_lock_group)
#define NETIF_WLOCK_ASSERT_HELD(_nif)     \
	LCK_RW_ASSERT(&(_nif)->nif_lock, LCK_RW_ASSERT_EXCLUSIVE)
#define NETIF_RLOCK_ASSERT_HELD(_nif)     \
	LCK_RW_ASSERT(&(_nif)->nif_lock, LCK_RW_ASSERT_SHARED)
#define NETIF_LOCK_ASSERT_HELD(_nif)      \
	LCK_RW_ASSERT(&(_nif)->nif_lock, LCK_RW_ASSERT_HELD)

SYSCTL_DECL(_kern_skywalk_netif);

/*
 * Macros to determine if an interface is skywalk capable or skywalk enabled.
 * See the magic field in struct nexus_adapter.
 */
#define SKYWALK_CAPABLE(ifp)                                            \
	(NA(ifp) != NULL && (ifnet_capabilities_supported(ifp) & IFCAP_SKYWALK))

#define SKYWALK_SET_CAPABLE(ifp) do {                                   \
	ifnet_lock_exclusive(ifp);                                      \
	(ifp)->if_capabilities |= IFCAP_SKYWALK;                        \
	(ifp)->if_capenable |= IFCAP_SKYWALK;                           \
	ifnet_lock_done(ifp);                                           \
} while (0)

#define SKYWALK_CLEAR_CAPABLE(ifp) do {                                 \
	ifnet_lock_exclusive(ifp);                                      \
	(ifp)->if_capabilities &= ~IFCAP_SKYWALK;                       \
	(ifp)->if_capenable &= ~IFCAP_SKYWALK;                          \
	ifnet_lock_done(ifp);                                           \
} while (0)

#define SKYWALK_NATIVE(ifp)                                             \
	((ifp)->if_eflags & IFEF_SKYWALK_NATIVE)

typedef enum {
	MIT_MODE_SIMPLE,
	MIT_MODE_ADVANCED_STATIC,
	MIT_MODE_ADVANCED_DYNAMIC,
} mit_mode_t;

/*
 * Mitigation support.
 */
struct mit_cfg_tbl {
	uint32_t cfg_plowat;            /* packets low watermark */
	uint32_t cfg_phiwat;            /* packets high watermark */
	uint32_t cfg_blowat;            /* bytes low watermark */
	uint32_t cfg_bhiwat;            /* bytes high watermark */
	uint32_t cfg_ival;              /* delay interval (in microsecond) */
};

#define NETIF_MIT_CFG_TBL_MAX_CFG       5

struct nx_netif_mit {
	decl_lck_spin_data(, mit_lock);
	volatile struct __kern_channel_ring *mit_ckr;  /* kring backpointer */
	uint32_t        mit_flags;
	uint32_t        mit_requests;
	uint32_t        mit_interval;

	/*
	 * Adaptive mitigation.
	 */
	uint32_t        mit_cfg_idx_max;        /* highest config selector */
	uint32_t        mit_cfg_idx;            /* current config selector */
	const struct mit_cfg_tbl *mit_cfg;      /* current config mapping */
	mit_mode_t      mit_mode;               /* current mode */
	uint32_t        mit_packets_avg;        /* average # of packets */
	uint32_t        mit_packets_min;        /* smallest # of packets */
	uint32_t        mit_packets_max;        /* largest # of packets */
	uint32_t        mit_bytes_avg;          /* average # of bytes */
	uint32_t        mit_bytes_min;          /* smallest # of bytes */
	uint32_t        mit_bytes_max;          /* largest # of bytes */

	struct pktcntr  mit_sstats;             /* pkts & bytes per sampling */
	struct timespec mit_mode_holdtime;      /* mode holdtime in nsec */
	struct timespec mit_mode_lasttime;      /* last mode change time nsec */
	struct timespec mit_sample_time;        /* sampling holdtime in nsec */
	struct timespec mit_sample_lasttime;    /* last sampling time in nsec */
	struct timespec mit_start_time;         /* time of start work in nsec */

	struct thread   *mit_thread;
	char            mit_name[MAXTHREADNAMESIZE];

	const struct ifnet      *mit_netif_ifp;
	/* interface-specific mitigation table */
	struct mit_cfg_tbl mit_tbl[NETIF_MIT_CFG_TBL_MAX_CFG];

#if (DEVELOPMENT || DEBUG)
	struct skoid    mit_skoid;
#endif /* !DEVELOPMENT && !DEBUG */
};

#define NETIF_MITF_INITIALIZED  0x00000001      /* has been initialized */
#define NETIF_MITF_SAMPLING     0x00000002      /* busy sampling stats */
#define NETIF_MITF_SIMPLE       0x00000004      /* no stats, no delay */
#define NETIF_MITF_READY        0x10000000      /* thread is ready */
#define NETIF_MITF_RUNNING      0x20000000      /* thread is running */
#define NETIF_MITF_TERMINATING  0x40000000      /* thread is terminating */
#define NETIF_MITF_TERMINATED   0x80000000      /* thread is terminated */

#define MIT_SPIN_LOCK(_mit)                     \
	lck_spin_lock(&(_mit)->mit_lock)
#define MIT_SPIN_LOCK_ASSERT_HELD(_mit)         \
	LCK_SPIN_ASSERT(&(_mit)->mit_lock, LCK_ASSERT_OWNED)
#define MIT_SPIN_LOCK_ASSERT_NOTHELD(_mit)      \
	LCK_SPIN_ASSERT(&(_mit)->mit_lock, LCK_ASSERT_NOTOWNED)
#define MIT_SPIN_UNLOCK(_mit)                   \
	lck_spin_unlock(&(_mit)->mit_lock)

struct nexus_netif_adapter {
	/*
	 * This is an overlay structure on nexus_adapter;
	 * make sure it contains 'up' as the first member.
	 */
	struct nexus_adapter      nifna_up;
	struct nx_netif           *nifna_netif;

	struct nx_netif_mit       *__counted_by(nifna_tx_mit_count) nifna_tx_mit;
	struct nx_netif_mit       *__counted_by(nifna_rx_mit_count) nifna_rx_mit;

	/*
	 * XXX For filter or vpna only
	 */
	union {
		struct netif_filter     *nifna_filter;
		struct netif_flow       *nifna_flow;
	};
	uint16_t                  nifna_gencnt;
	uint32_t                  nifna_tx_mit_count;
	uint32_t                  nifna_rx_mit_count;
};

extern kern_allocation_name_t skmem_tag_netif_filter;
extern kern_allocation_name_t skmem_tag_netif_flow;
extern kern_allocation_name_t skmem_tag_netif_agent_flow;
extern kern_allocation_name_t skmem_tag_netif_llink;
extern kern_allocation_name_t skmem_tag_netif_qset;

__BEGIN_DECLS
extern struct nxdom nx_netif_dom_s;
extern struct kern_nexus_domain_provider nx_netif_prov_s;

extern struct nx_netif *nx_netif_alloc(zalloc_flags_t);
extern void nx_netif_free(struct nx_netif *);
extern void nx_netif_retain(struct nx_netif *);
extern void nx_netif_release(struct nx_netif *);

extern int nx_netif_dev_krings_create(struct nexus_adapter *,
    struct kern_channel *);
extern void nx_netif_dev_krings_delete(struct nexus_adapter *,
    struct kern_channel *, boolean_t);
extern int nx_netif_na_find(struct kern_nexus *, struct kern_channel *,
    struct chreq *, struct nxbind *, struct proc *, struct nexus_adapter **,
    boolean_t create);
extern int nx_netif_na_special(struct nexus_adapter *,
    struct kern_channel *, struct chreq *, nxspec_cmd_t);
extern int nx_netif_na_special_common(struct nexus_adapter *,
    struct kern_channel *, struct chreq *, nxspec_cmd_t);
extern int nx_netif_common_intr(struct __kern_channel_ring *, struct proc *,
    uint32_t, uint32_t *);

extern int nx_netif_prov_init(struct kern_nexus_domain_provider *);
extern int nx_netif_prov_params(struct kern_nexus_domain_provider *,
    const uint32_t, const struct nxprov_params *, struct nxprov_params *,
    struct skmem_region_params[SKMEM_REGIONS], uint32_t);
extern int nx_netif_prov_mem_new(struct kern_nexus_domain_provider *,
    struct kern_nexus *, struct nexus_adapter *);
extern void nx_netif_prov_fini(struct kern_nexus_domain_provider *);
extern int nx_netif_prov_config(struct kern_nexus_domain_provider *,
    struct kern_nexus *, struct nx_cfg_req *, int, struct proc *,
    kauth_cred_t);
extern int nx_netif_prov_nx_ctor(struct kern_nexus *);
extern void nx_netif_prov_nx_dtor(struct kern_nexus *);
extern int nx_netif_prov_nx_mem_info(struct kern_nexus *,
    struct kern_pbufpool **, struct kern_pbufpool **);
extern size_t nx_netif_prov_nx_mib_get(struct kern_nexus *nx,
    struct nexus_mib_filter *, void *__sized_by(len), size_t len, struct proc *);
extern int nx_netif_prov_nx_stop(struct kern_nexus *);

extern void nx_netif_reap(struct nexus_netif_adapter *, struct ifnet *,
    uint32_t, boolean_t);

extern void nx_netif_copy_stats(struct nexus_netif_adapter *,
    struct if_netif_stats *);
extern struct nexus_netif_adapter * na_netif_alloc(zalloc_flags_t);
extern void na_netif_free(struct nexus_adapter *);
extern void na_netif_finalize(struct nexus_netif_adapter *, struct ifnet *);
extern void nx_netif_llw_detach_notify(void *);
extern void nx_netif_config_interface_advisory(struct kern_nexus *, bool);

/*
 * netif netagent API
 */
extern void nx_netif_agent_init(struct nx_netif *);
extern void nx_netif_agent_fini(struct nx_netif *);
extern int nx_netif_netagent_flow_add(struct nx_netif *, struct nx_flow_req *);
extern int nx_netif_netagent_flow_del(struct nx_netif *, struct nx_flow_req *);

/*
 * "Interrupt" mitigation API. This is used by the netif adapter to reduce
 * the number of "interrupt" requests/wakeup to clients on incoming packets.
 */
extern void nx_netif_mit_init(struct nx_netif *, const struct ifnet *,
    struct nx_netif_mit *, struct __kern_channel_ring *, boolean_t);
extern void nx_netif_mit_cleanup(struct nx_netif_mit *);
extern int nx_netif_mit_tx_intr(struct __kern_channel_ring *, struct proc *,
    uint32_t, uint32_t *);
extern int nx_netif_mit_rx_intr(struct __kern_channel_ring *, struct proc *,
    uint32_t, uint32_t *);

/*
 * Interface filter API
 */
#define NETIF_FILTER_RX         0x0001
#define NETIF_FILTER_TX         0x0002
#define NETIF_FILTER_SOURCE     0x0004
#define NETIF_FILTER_INJECT     0x0008
extern errno_t nx_netif_filter_inject(struct nexus_netif_adapter *,
    struct netif_filter *, struct __kern_packet *, uint32_t);
extern errno_t nx_netif_filter_add(struct nx_netif *, nexus_port_t, void *,
    errno_t (*)(void *, struct __kern_packet *, uint32_t),
    struct netif_filter **);
extern errno_t nx_netif_filter_remove(struct nx_netif *, struct netif_filter *);
extern void nx_netif_filter_init(struct nx_netif *);
extern void nx_netif_filter_fini(struct nx_netif *);
extern void nx_netif_filter_enable(struct nx_netif *);
extern void nx_netif_filter_disable(struct nx_netif *);

/*
 * These callbacks are invoked when a packet chain has traversed the full
 * filter chain.
 */
extern errno_t nx_netif_filter_rx_cb(struct nexus_netif_adapter *,
    struct __kern_packet *, uint32_t);
extern errno_t nx_netif_filter_tx_cb(struct nexus_netif_adapter *,
    struct __kern_packet *, uint32_t);

/*
 * These are called by nx_netif_filter_tx_cb() to feed filtered packets
 * back to driver.
 */
extern errno_t
    nx_netif_filter_tx_processed_mbuf_enqueue(struct nexus_netif_adapter *,
    mbuf_svc_class_t, struct mbuf *);
extern errno_t
    nx_netif_filter_tx_processed_pkt_enqueue(struct nexus_netif_adapter *,
    kern_packet_svc_class_t, struct __kern_packet *);

/*
 * Called by nx_netif_na_find() to create a filter nexus adapter.
 */
extern int netif_filter_na_create(struct kern_nexus *, struct chreq *,
    struct nexus_adapter **);

/*
 * Callbacks from ifnet
 */
extern errno_t nx_netif_native_tx_dequeue(struct nexus_netif_adapter *,
    uint32_t, uint32_t, uint32_t, classq_pkt_t *, classq_pkt_t *,
    uint32_t *, uint32_t *, boolean_t, errno_t);
extern errno_t nx_netif_native_tx_get_len(struct nexus_netif_adapter *,
    uint32_t, uint32_t *, uint32_t *, errno_t);
extern errno_t nx_netif_compat_tx_dequeue(struct nexus_netif_adapter *,
    uint32_t, uint32_t, uint32_t, classq_pkt_t *, classq_pkt_t *,
    uint32_t *, uint32_t *, boolean_t, errno_t);
extern errno_t nx_netif_compat_tx_get_len(struct nexus_netif_adapter *,
    uint32_t, uint32_t *, uint32_t *, errno_t);

/*
 * doorbell dequeue tunable
 */
extern uint32_t nx_netif_doorbell_max_dequeue;

/*
 * Default drop tunable
 */
extern uint32_t nx_netif_filter_default_drop;

/*
 * Flow API
 */
#define NETIF_FLOW_SOURCE       0x0001
#define NETIF_FLOW_INJECT       0x0002
#define NETIF_FLOW_OUTBOUND     0x0004 /* Assumes inbound if flag is missing */

extern errno_t nx_netif_demux(struct nexus_netif_adapter *,
    struct __kern_packet *, struct __kern_packet **, struct nexus_pkt_stats *,
    uint32_t);
extern errno_t nx_netif_flow_add(struct nx_netif *, nexus_port_t,
    struct netif_flow_desc *, void *, errno_t (*)(void *, void *, uint32_t),
    struct netif_flow **);
extern errno_t nx_netif_flow_remove(struct nx_netif *, struct netif_flow *);
extern void nx_netif_flow_init(struct nx_netif *);
extern void nx_netif_flow_fini(struct nx_netif *);
extern void nx_netif_flow_enable(struct nx_netif *);
extern void nx_netif_flow_disable(struct nx_netif *);
extern void nx_netif_snoop(struct nx_netif *, struct __kern_packet *,
    boolean_t);
extern boolean_t nx_netif_validate_macaddr(struct nx_netif *,
    struct __kern_packet *, uint32_t);
extern boolean_t nx_netif_flow_match(struct nx_netif *, struct __kern_packet *,
    struct netif_flow *, uint32_t);
extern struct netif_flow * nx_netif_flow_classify(struct nx_netif *,
    struct __kern_packet *, uint32_t);
extern void nx_netif_flow_release(struct nx_netif *, struct netif_flow *);
extern int netif_vp_na_create(struct kern_nexus *, struct chreq *,
    struct nexus_adapter **);
extern errno_t netif_vp_na_channel_event(struct nx_netif *, uint32_t,
    struct __kern_channel_event *, uint16_t);

/*
 * Disable all checks on inbound/outbound packets on VP adapters
 */
extern uint32_t nx_netif_vp_accept_all;

/*
 * Utility functions
 */
extern struct __kern_packet *nx_netif_alloc_packet(struct kern_pbufpool *,
    uint32_t, kern_packet_t *);
extern void nx_netif_free_packet(struct __kern_packet *);
extern void nx_netif_free_packet_chain(struct __kern_packet *, int *);
extern void netif_ifp_inc_traffic_class_out_pkt(struct ifnet *, uint32_t,
    uint32_t, uint32_t);

#define NETIF_CONVERT_RX        0x0001
#define NETIF_CONVERT_TX        0x0002

extern struct __kern_packet *
    nx_netif_mbuf_to_filter_pkt_chain(struct nexus_netif_adapter *,
    struct mbuf *, uint32_t);
extern struct mbuf *
    nx_netif_filter_pkt_to_mbuf_chain(struct nexus_netif_adapter *,
    struct __kern_packet *, uint32_t);

extern struct __kern_packet *
    nx_netif_pkt_to_filter_pkt(struct nexus_netif_adapter *,
    struct __kern_packet *, uint32_t);
extern struct __kern_packet *
    nx_netif_pkt_to_filter_pkt_chain(struct nexus_netif_adapter *,
    struct __kern_packet *, uint32_t);
extern struct __kern_packet *
    nx_netif_filter_pkt_to_pkt_chain(struct nexus_netif_adapter *,
    struct __kern_packet *, uint32_t);

extern struct mbuf *
    nx_netif_pkt_to_mbuf(struct nexus_netif_adapter *,
    struct __kern_packet *, uint32_t);
extern struct __kern_packet *
    nx_netif_pkt_to_pkt(struct nexus_netif_adapter *,
    struct __kern_packet *, uint32_t);

extern void nx_netif_mbuf_chain_info(struct mbuf *,
    struct mbuf **, uint32_t *, uint32_t *);
extern void nx_netif_pkt_chain_info(struct __kern_packet *,
    struct __kern_packet **, uint32_t *, uint32_t *);
extern int nx_netif_get_max_mtu(ifnet_t, uint32_t *);

extern void nx_netif_mit_config(struct nexus_netif_adapter *,
    boolean_t *, boolean_t *, boolean_t *, boolean_t *);

extern void nx_netif_vp_region_params_adjust(struct nexus_adapter *,
    struct skmem_region_params *);

extern void nx_netif_pktap_output(ifnet_t, int, struct __kern_packet *);

extern int netif_rx_notify_default(struct __kern_channel_ring *,
    struct proc *p, uint32_t);
extern int netif_rx_notify_fast(struct __kern_channel_ring *,
    struct proc *p, uint32_t);
extern int netif_llw_rx_notify_default(struct __kern_channel_ring *,
    struct proc *p, uint32_t);
extern int netif_llw_rx_notify_fast(struct __kern_channel_ring *,
    struct proc *p, uint32_t);
extern void netif_receive(struct nexus_netif_adapter *,
    struct __kern_packet *, struct nexus_pkt_stats *);

#define NETIF_XMIT_FLAG_CHANNEL  0x0001
#define NETIF_XMIT_FLAG_HOST     0x0002
#define NETIF_XMIT_FLAG_REDIRECT 0x0004
#define NETIF_XMIT_FLAG_PACING   0x0008
extern void netif_transmit(struct ifnet *, uint32_t);
extern int netif_ring_tx_refill(const kern_channel_ring_t,
    uint32_t, uint32_t, boolean_t, boolean_t *, boolean_t);
extern void netif_hwna_set_mode(struct nexus_adapter *, netif_mode_t,
    void (*)(struct nexus_adapter *, struct __kern_packet *,
    struct nexus_pkt_stats *));
extern void netif_hwna_clear_mode(struct nexus_adapter *);

/*
 * rxpoll functions
 */
extern errno_t netif_rxpoll_set_params(struct ifnet *,
    struct ifnet_poll_params *, boolean_t locked);
extern void netif_rxpoll_compat_thread_func(void *, wait_result_t);

/*
 * GSO functions
 */
extern int netif_gso_dispatch(struct ifnet *ifp, struct mbuf *m);
extern void netif_gso_init(void);
extern void netif_gso_fini(void);

/*
 * Logical link functions
 */
extern void nx_netif_llink_retain(struct netif_llink *);
extern void nx_netif_llink_release(struct netif_llink **);
extern void nx_netif_qset_retain(struct netif_qset *);
extern void nx_netif_qset_release(struct netif_qset **);
extern void nx_netif_llink_init(struct nx_netif *);
extern void nx_netif_llink_fini(struct nx_netif *);
extern struct netif_qset * nx_netif_find_qset(struct nx_netif *, uint64_t);
extern struct netif_qset * nx_netif_get_default_qset_noref(struct nx_netif *);
extern int netif_qset_enqueue(struct netif_qset *, struct __kern_packet *,
    struct __kern_packet *, uint32_t, uint32_t, uint32_t *, uint32_t *);
extern int nx_netif_default_llink_config(struct nx_netif *,
    struct kern_nexus_netif_llink_init *);
extern void nx_netif_llink_config_free(struct nx_netif *);
extern int nx_netif_llink_ext_init_default_queues(struct kern_nexus *);
extern void nx_netif_llink_ext_fini_default_queues(struct kern_nexus *);
extern int nx_netif_validate_llink_config(struct kern_nexus_netif_llink_init *,
    bool);
extern int nx_netif_llink_add(struct nx_netif *,
    struct kern_nexus_netif_llink_init *, struct netif_llink **);
extern int nx_netif_llink_remove(struct nx_netif *,
    kern_nexus_netif_llink_id_t);
extern int nx_netif_notify_steering_info(struct nx_netif *,
    struct netif_qset *, struct ifnet_traffic_descriptor_common *, bool);
__END_DECLS
#endif /* CONFIG_NEXUS_NETIF */
#include <skywalk/nexus/netif/nx_netif_compat.h>
#include <skywalk/nexus/netif/nx_netif_host.h>
#endif /* _SKYWALK_NEXUS_NETIF_H_ */