694 lines
26 KiB
C
694 lines
26 KiB
C
|
/*
|
|||
|
* 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_OS_CHANNEL_H_
|
|||
|
#define _SKYWALK_OS_CHANNEL_H_
|
|||
|
|
|||
|
#ifdef PRIVATE
|
|||
|
|
|||
|
#include <stdint.h>
|
|||
|
#include <sys/types.h>
|
|||
|
#include <sys/cdefs.h>
|
|||
|
#include <uuid/uuid.h>
|
|||
|
#include <mach/vm_types.h>
|
|||
|
#include <skywalk/os_nexus.h>
|
|||
|
#include <skywalk/os_packet.h>
|
|||
|
#ifndef KERNEL
|
|||
|
#include <skywalk/os_channel_event.h>
|
|||
|
#include <net/if_var.h>
|
|||
|
#endif /* !KERNEL */
|
|||
|
|
|||
|
/*
|
|||
|
* Compiler guards used by Libnetcore.
|
|||
|
*/
|
|||
|
#define OS_CHANNEL_HAS_NUM_BUFFERS_ATTR 1 /* CHANNEL_ATTR_NUM_BUFFERS */
|
|||
|
#define OS_CHANNEL_HAS_LARGE_PACKET 1 /* CHANNEL_ATTR_LARGE_BUF_SIZE and */
|
|||
|
/* os_channel_large_packet_alloc() */
|
|||
|
|
|||
|
/* Flow advisory table index */
|
|||
|
typedef uint32_t flowadv_idx_t;
|
|||
|
#define FLOWADV_IDX_NONE ((flowadv_idx_t)-1)
|
|||
|
|
|||
|
/*
|
|||
|
* Channel ring direction.
|
|||
|
*/
|
|||
|
typedef enum {
|
|||
|
CHANNEL_DIR_TX_RX, /* default: TX and RX ring(s) */
|
|||
|
CHANNEL_DIR_TX, /* (monitor) only TX ring(s) */
|
|||
|
CHANNEL_DIR_RX /* (monitor) only RX ring(s) */
|
|||
|
} ring_dir_t;
|
|||
|
|
|||
|
/*
|
|||
|
* Channel ring ID.
|
|||
|
*/
|
|||
|
typedef uint32_t ring_id_t;
|
|||
|
#define CHANNEL_RING_ID_ANY ((ring_id_t)-1)
|
|||
|
|
|||
|
typedef enum {
|
|||
|
CHANNEL_FIRST_TX_RING,
|
|||
|
CHANNEL_LAST_TX_RING,
|
|||
|
CHANNEL_FIRST_RX_RING,
|
|||
|
CHANNEL_LAST_RX_RING
|
|||
|
} ring_id_type_t;
|
|||
|
|
|||
|
/* Sync mode values */
|
|||
|
typedef enum {
|
|||
|
CHANNEL_SYNC_TX, /* synchronize TX ring(s) */
|
|||
|
CHANNEL_SYNC_RX, /* synchronize RX ring(s) */
|
|||
|
#if defined(LIBSYSCALL_INTERFACE) || defined(BSD_KERNEL_PRIVATE)
|
|||
|
CHANNEL_SYNC_UPP /* synchronize packet pool rings only */
|
|||
|
#endif /* LIBSYSCALL_INTERFACE || BSD_KERNEL_PRIVATE */
|
|||
|
} sync_mode_t;
|
|||
|
|
|||
|
/* Sync flags */
|
|||
|
typedef uint32_t sync_flags_t;
|
|||
|
#if defined(LIBSYSCALL_INTERFACE) || defined(BSD_KERNEL_PRIVATE)
|
|||
|
#define CHANNEL_SYNCF_ALLOC 0x1 /* synchronize alloc ring */
|
|||
|
#define CHANNEL_SYNCF_FREE 0x2 /* synchronize free ring */
|
|||
|
#define CHANNEL_SYNCF_PURGE 0x4 /* purge user packet pool */
|
|||
|
#define CHANNEL_SYNCF_ALLOC_BUF 0x8 /* synchronize buflet alloc ring */
|
|||
|
#define CHANNEL_SYNCF_LARGE_ALLOC 0x10 /* synchronize large alloc ring */
|
|||
|
#endif /* LIBSYSCALL_INTERFACE || BSD_KERNEL_PRIVATE */
|
|||
|
|
|||
|
/*
|
|||
|
* Opaque handles.
|
|||
|
*/
|
|||
|
struct channel;
|
|||
|
struct channel_ring_desc;
|
|||
|
struct __slot_desc;
|
|||
|
struct channel_attr;
|
|||
|
|
|||
|
typedef struct channel *channel_t;
|
|||
|
typedef struct channel_ring_desc *channel_ring_t;
|
|||
|
typedef struct __slot_desc *channel_slot_t;
|
|||
|
typedef struct channel_attr *channel_attr_t;
|
|||
|
|
|||
|
/*
|
|||
|
* Channel monitor types.
|
|||
|
*/
|
|||
|
typedef enum {
|
|||
|
CHANNEL_MONITOR_OFF, /* default */
|
|||
|
CHANNEL_MONITOR_NO_COPY, /* zero-copy (delayed) mode */
|
|||
|
CHANNEL_MONITOR_COPY /* copy (immediate) mode */
|
|||
|
} channel_monitor_type_t;
|
|||
|
|
|||
|
/*
|
|||
|
* Channel threshold unit types.
|
|||
|
*/
|
|||
|
typedef enum {
|
|||
|
CHANNEL_THRESHOLD_UNIT_SLOTS, /* unit in slots (default) */
|
|||
|
CHANNEL_THRESHOLD_UNIT_BYTES, /* unit in bytes */
|
|||
|
} channel_threshold_unit_t;
|
|||
|
|
|||
|
/*
|
|||
|
* Channel attribute types gettable/settable via os_channel_attr_{get,set}.
|
|||
|
*
|
|||
|
* g: retrievable at any time
|
|||
|
* s: settable at any time
|
|||
|
* S: settable once, only at creation time
|
|||
|
*/
|
|||
|
typedef enum {
|
|||
|
CHANNEL_ATTR_TX_RINGS, /* (g) # of transmit rings */
|
|||
|
CHANNEL_ATTR_RX_RINGS, /* (g) # of receive rings */
|
|||
|
CHANNEL_ATTR_TX_SLOTS, /* (g) # of slots per transmit ring */
|
|||
|
CHANNEL_ATTR_RX_SLOTS, /* (g) # of slots per receive ring */
|
|||
|
CHANNEL_ATTR_SLOT_BUF_SIZE, /* (g) buffer per slot (bytes) */
|
|||
|
CHANNEL_ATTR_SLOT_META_SIZE, /* (g) metadata per slot (bytes) */
|
|||
|
CHANNEL_ATTR_EXCLUSIVE, /* (g/s) bool: exclusive open */
|
|||
|
CHANNEL_ATTR_NO_AUTO_SYNC, /* (g/s) bool: will do explicit sync */
|
|||
|
CHANNEL_ATTR_MONITOR, /* (g/s) see channel_monitor_type_t */
|
|||
|
CHANNEL_ATTR_TX_LOWAT_UNIT, /* (g/s) see channel_threshold_unit_t */
|
|||
|
CHANNEL_ATTR_TX_LOWAT_VALUE, /* (g/s) transmit low-watermark */
|
|||
|
CHANNEL_ATTR_RX_LOWAT_UNIT, /* (g/s) see channel_threshold_unit_t */
|
|||
|
CHANNEL_ATTR_RX_LOWAT_VALUE, /* (g/s) receive low-watermark */
|
|||
|
CHANNEL_ATTR_NEXUS_TYPE, /* (g) nexus type */
|
|||
|
CHANNEL_ATTR_NEXUS_EXTENSIONS, /* (g) nexus extension(s) */
|
|||
|
CHANNEL_ATTR_NEXUS_MHINTS, /* (g) nexus memory usage hints */
|
|||
|
CHANNEL_ATTR_TX_HOST_RINGS, /* (g) # of transmit host rings */
|
|||
|
CHANNEL_ATTR_RX_HOST_RINGS, /* (g) # of receive host rings */
|
|||
|
CHANNEL_ATTR_NEXUS_IFINDEX, /* (g) nexus network interface index */
|
|||
|
CHANNEL_ATTR_NEXUS_STATS_SIZE, /* (g) nexus statistics region size */
|
|||
|
CHANNEL_ATTR_NEXUS_FLOWADV_MAX, /* (g) # of flow advisory entries */
|
|||
|
CHANNEL_ATTR_NEXUS_META_TYPE, /* (g) nexus metadata type */
|
|||
|
CHANNEL_ATTR_NEXUS_META_SUBTYPE, /* (g) nexus metadata subtype */
|
|||
|
CHANNEL_ATTR_NEXUS_CHECKSUM_OFFLOAD, /* (g) nexus checksum offload */
|
|||
|
CHANNEL_ATTR_USER_PACKET_POOL, /* (g/s) bool: use user packet pool */
|
|||
|
CHANNEL_ATTR_NEXUS_ADV_SIZE, /* (g) nexus advisory region size */
|
|||
|
CHANNEL_ATTR_NEXUS_DEFUNCT_OK, /* (g/s) bool: allow defunct */
|
|||
|
CHANNEL_ATTR_FILTER, /* (g/s) bool: filter mode */
|
|||
|
CHANNEL_ATTR_EVENT_RING, /* (g/s) bool: enable event ring */
|
|||
|
CHANNEL_ATTR_MAX_FRAGS, /* (g) max length of buflet chain */
|
|||
|
CHANNEL_ATTR_NUM_BUFFERS, /* (g) # of buffers in user pool */
|
|||
|
CHANNEL_ATTR_LOW_LATENCY, /* (g/s) bool: low latency channel */
|
|||
|
CHANNEL_ATTR_LARGE_BUF_SIZE, /* (g) large buffer size (bytes) */
|
|||
|
} channel_attr_type_t;
|
|||
|
|
|||
|
/*
|
|||
|
* Channel nexus metadata type.
|
|||
|
*/
|
|||
|
typedef enum {
|
|||
|
CHANNEL_NEXUS_META_TYPE_INVALID = 0,
|
|||
|
CHANNEL_NEXUS_META_TYPE_QUANTUM, /* OK for os_packet quantum APIs */
|
|||
|
CHANNEL_NEXUS_META_TYPE_PACKET, /* OK for all os_packet APIs */
|
|||
|
} channel_nexus_meta_type_t;
|
|||
|
|
|||
|
/*
|
|||
|
* Channel nexus metadata subtype.
|
|||
|
*/
|
|||
|
typedef enum {
|
|||
|
CHANNEL_NEXUS_META_SUBTYPE_INVALID = 0,
|
|||
|
CHANNEL_NEXUS_META_SUBTYPE_PAYLOAD,
|
|||
|
CHANNEL_NEXUS_META_SUBTYPE_RAW,
|
|||
|
} channel_nexus_meta_subtype_t;
|
|||
|
|
|||
|
/*
|
|||
|
* Valid values for CHANNEL_ATTR_NEXUS_CHECKSUM_OFFLOAD
|
|||
|
*/
|
|||
|
#define CHANNEL_NEXUS_CHECKSUM_PARTIAL 0x1 /* partial checksum */
|
|||
|
|
|||
|
/*
|
|||
|
* Channel statistics ID.
|
|||
|
*/
|
|||
|
typedef enum {
|
|||
|
CHANNEL_STATS_ID_IP = 0, /* struct ip_stats */
|
|||
|
CHANNEL_STATS_ID_IP6, /* struct ip6_stats */
|
|||
|
CHANNEL_STATS_ID_TCP, /* struct tcp_stats */
|
|||
|
CHANNEL_STATS_ID_UDP, /* struct udp_stats */
|
|||
|
CHANNEL_STATS_ID_QUIC, /* struct quic_stats */
|
|||
|
} channel_stats_id_t;
|
|||
|
|
|||
|
/*
|
|||
|
* Slot properties. Structure is aligned to allow for efficient copy.
|
|||
|
*
|
|||
|
* Fields except for sp_{flags,len} are immutables (I). The system will
|
|||
|
* verify for correctness during os_channel_put() across the immutable
|
|||
|
* fields, and will abort the process if it detects inconsistencies.
|
|||
|
* This is meant to help with debugging, since it indicates bugs and/or
|
|||
|
* memory corruption.
|
|||
|
*/
|
|||
|
typedef struct slot_prop {
|
|||
|
uint16_t sp_flags; /* private flags */
|
|||
|
uint16_t sp_len; /* length for this slot */
|
|||
|
uint32_t sp_idx; /* (I) slot index */
|
|||
|
mach_vm_address_t sp_ext_ptr; /* (I) pointer for indirect buffer */
|
|||
|
mach_vm_address_t sp_buf_ptr; /* (I) pointer for native buffer */
|
|||
|
mach_vm_address_t sp_mdata_ptr; /* (I) pointer for metadata */
|
|||
|
uint32_t _sp_pad[8]; /* reserved */
|
|||
|
} slot_prop_t __attribute__((aligned(sizeof(uint64_t))));
|
|||
|
|
|||
|
#ifndef KERNEL
|
|||
|
/*
|
|||
|
* User APIs.
|
|||
|
*/
|
|||
|
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
|
|||
|
__BEGIN_DECLS
|
|||
|
/*
|
|||
|
* Creates a Channel attribute object.
|
|||
|
*
|
|||
|
* This must be paired with a os_channel_attr_destroy() on the handle.
|
|||
|
*/
|
|||
|
extern channel_attr_t os_channel_attr_create(void);
|
|||
|
|
|||
|
/*
|
|||
|
* Clones a Channel attribute object. If source attribute is NULL
|
|||
|
* it behaves just like os_channel_attr_create();
|
|||
|
*
|
|||
|
* This must be paired with a os_channel_attr_destroy() on the handle.
|
|||
|
*/
|
|||
|
extern channel_attr_t os_channel_attr_clone(const channel_attr_t);
|
|||
|
|
|||
|
/*
|
|||
|
* Sets a value for a given attribute type on a Channel attribute object.
|
|||
|
*/
|
|||
|
extern int os_channel_attr_set(const channel_attr_t attr,
|
|||
|
const channel_attr_type_t type, const uint64_t value);
|
|||
|
|
|||
|
/*
|
|||
|
* Sets a key blob on a Channel attribute object. Existing key blob
|
|||
|
* information in the attribute object will be removed, if any, and
|
|||
|
* replaced with the new key blob. Specifying 0 for key_len will
|
|||
|
* clear the key stored in the attribute object. The maximum key
|
|||
|
* length is specified by NEXUS_MAX_KEY_LEN.
|
|||
|
*/
|
|||
|
extern int os_channel_attr_set_key(const channel_attr_t attr,
|
|||
|
const void *key, const uint32_t key_len);
|
|||
|
|
|||
|
/*
|
|||
|
* Gets a value for a given attribute type on a Channel attribute object.
|
|||
|
*/
|
|||
|
extern int os_channel_attr_get(const channel_attr_t attr,
|
|||
|
const channel_attr_type_t type, uint64_t *value);
|
|||
|
|
|||
|
/*
|
|||
|
* Gets a key blob on a Channel attribute object. If key is NULL,
|
|||
|
* returns the length of the key blob with key_len, so caller knows
|
|||
|
* how much to allocate space for key blob.
|
|||
|
*/
|
|||
|
extern int os_channel_attr_get_key(const channel_attr_t attr,
|
|||
|
void *key, uint32_t *key_len);
|
|||
|
|
|||
|
/*
|
|||
|
* Destroys a Channel attribute object, along with all resources
|
|||
|
* associated with it (e.g. key blob).
|
|||
|
*/
|
|||
|
extern void os_channel_attr_destroy(const channel_attr_t attr);
|
|||
|
|
|||
|
/*
|
|||
|
* Opens a Channel to a Nexus provider instance. Upon success, maps memory
|
|||
|
* region and allocates resources.
|
|||
|
*
|
|||
|
* This must be paired with a os_channel_destroy() on the handle, in order to
|
|||
|
* unmap the memory region and free resources.
|
|||
|
*/
|
|||
|
extern channel_t os_channel_create(const uuid_t uuid, const nexus_port_t port);
|
|||
|
|
|||
|
/*
|
|||
|
* Extended version of os_channel_create().
|
|||
|
*/
|
|||
|
extern channel_t os_channel_create_extended(const uuid_t uuid,
|
|||
|
const nexus_port_t port, const ring_dir_t dir, const ring_id_t rid,
|
|||
|
const channel_attr_t attr);
|
|||
|
|
|||
|
/*
|
|||
|
* Retrieves the file descriptor associated with the Channel.
|
|||
|
*/
|
|||
|
extern int os_channel_get_fd(const channel_t channel);
|
|||
|
|
|||
|
/*
|
|||
|
* Retrieves current channel attributes into the channel_attr_t handle.
|
|||
|
*/
|
|||
|
extern int os_channel_read_attr(const channel_t channel, channel_attr_t attr);
|
|||
|
|
|||
|
/*
|
|||
|
* Updates channel attributes based on those referred to by the channel_attr_t
|
|||
|
* handle. See comments above on channel_attr_type_t; this routine will only
|
|||
|
* update attributes that are marked with 's' but not 'S'.
|
|||
|
*/
|
|||
|
extern int os_channel_write_attr(const channel_t channel, channel_attr_t attr);
|
|||
|
|
|||
|
/*
|
|||
|
* Retrieves channel's associated nexus type into *nexus_type, and the
|
|||
|
* provider-specific extension attribute into *ext.
|
|||
|
*/
|
|||
|
extern int os_channel_read_nexus_extension_info(const channel_t channel,
|
|||
|
nexus_type_t *nexus_type, uint64_t *ext);
|
|||
|
|
|||
|
/*
|
|||
|
* Non-blocking synchronization. Channel handle may also be used
|
|||
|
* with kqueue(2), select(2) or poll(2) through the file descriptor.
|
|||
|
*/
|
|||
|
extern int os_channel_sync(const channel_t channel, const sync_mode_t mode);
|
|||
|
|
|||
|
/*
|
|||
|
* Destroys a Channel.
|
|||
|
*/
|
|||
|
extern void os_channel_destroy(const channel_t channel);
|
|||
|
|
|||
|
/*
|
|||
|
* Checks if a channel is defunct. Returns non-zero if defunct.
|
|||
|
*/
|
|||
|
extern int os_channel_is_defunct(const channel_t channel);
|
|||
|
|
|||
|
/*
|
|||
|
* Data Movement APIs.
|
|||
|
*
|
|||
|
* Obtain channel_ring_t handle via os_channel_{tx,rx}_ring(). You will
|
|||
|
* need to specify the ring_id_t which identifies the ring — this is true
|
|||
|
* even for a single TX/RX ring case. The Nexus provider can communicate
|
|||
|
* to the client the ID of the TX and RX ring that should be used to
|
|||
|
* communicate to it, through a contract between the two. For instance,
|
|||
|
* it can tell the client to use first TX ring and first RX ring, etc.
|
|||
|
* through some side-channel. It should not assume 0 or any other number
|
|||
|
* as ID, however, as the in-kernel Nexus object is the authoritative source
|
|||
|
* of truth. This is where the os_channel_ring_id() call comes into the
|
|||
|
* picture, as it will return the first and last usable TX and RX ring IDs
|
|||
|
* for the Channel opened to that Nexus object.
|
|||
|
*
|
|||
|
* Once the TX or RX ring handle is obtained above, the client can ask for
|
|||
|
* the first usable slot in the ring through os_channel_get_next_slot()
|
|||
|
* passing NULL for the 'slot' parameter. This returns a channel_slot_t
|
|||
|
* handle that represents the slot, along with the properties of that slot
|
|||
|
* described by the slot_prop_t structure. If no slots are available, this
|
|||
|
* call returns a NULL handle. It’s important to note that this
|
|||
|
* call does NOT advance the ring’s current slot pointer; calling this
|
|||
|
* multiple times in succession will yield the same result.
|
|||
|
*
|
|||
|
* The client proceeds to use the slot by examining the returned
|
|||
|
* slot_prop_t fields including the pointer to the internal buffer
|
|||
|
* associated with that slot. Once the client is finished, it updates
|
|||
|
* the relevant slot_prop_t fields (e.g. length) and calls
|
|||
|
* os_channel_set_slot_properties() to apply them to the slot.
|
|||
|
*
|
|||
|
* To get the next slot, the client provides the non-NULL slot value obtained
|
|||
|
* from the previous call to os_channel_get_next_slot() as the 'slot' parameter
|
|||
|
* in its next invocation of that function.
|
|||
|
*
|
|||
|
* To advance the ring’s current pointer, the client invokes
|
|||
|
* os_channel_advance_slot() specifying the slot to advance past. If the slot
|
|||
|
* is invalid, this function returns a non-zero value.
|
|||
|
*
|
|||
|
* Once the client is ready to commit, call os_channel_sync() in
|
|||
|
* either/all directions.
|
|||
|
*/
|
|||
|
extern ring_id_t os_channel_ring_id(const channel_t channel,
|
|||
|
const ring_id_type_t type);
|
|||
|
extern channel_ring_t os_channel_tx_ring(const channel_t channel,
|
|||
|
const ring_id_t rid);
|
|||
|
extern channel_ring_t os_channel_rx_ring(const channel_t channel,
|
|||
|
const ring_id_t rid);
|
|||
|
extern int os_channel_pending(const channel_ring_t ring);
|
|||
|
|
|||
|
/*
|
|||
|
* This returns a nexus-specific timestamp in nanoseconds taken at the
|
|||
|
* lasttime os_channel_sync() or its equivalent implicit kevent sync
|
|||
|
* was called
|
|||
|
*/
|
|||
|
extern uint64_t os_channel_ring_sync_time(const channel_ring_t ring);
|
|||
|
|
|||
|
/*
|
|||
|
* This returns a nexus-specific timestamp in nanoseconds to indicate
|
|||
|
* the time of last activity on the opposite end of the ring.
|
|||
|
* This is only updated when sync or kevent equivalent is called.
|
|||
|
*/
|
|||
|
extern uint64_t os_channel_ring_notify_time(const channel_ring_t ring);
|
|||
|
|
|||
|
/*
|
|||
|
* For TX ring os_channel_available_slot_count() returns the minimum number
|
|||
|
* of slots available availble for TX, and it is possible that
|
|||
|
* os_channel_get_next_slot() will return more slots than the what was
|
|||
|
* returned by an earlier call to os_channel_available_slot_count()
|
|||
|
*/
|
|||
|
extern uint32_t os_channel_available_slot_count(const channel_ring_t ring);
|
|||
|
extern channel_slot_t os_channel_get_next_slot(const channel_ring_t ring,
|
|||
|
const channel_slot_t slot, slot_prop_t *prop);
|
|||
|
extern int os_channel_advance_slot(channel_ring_t ring,
|
|||
|
const channel_slot_t slot);
|
|||
|
extern void os_channel_set_slot_properties(const channel_ring_t ring,
|
|||
|
const channel_slot_t slot, const slot_prop_t *prop);
|
|||
|
|
|||
|
/*
|
|||
|
* Return the packet handle associated with a given slot of a ring.
|
|||
|
*/
|
|||
|
extern packet_t os_channel_slot_get_packet(const channel_ring_t ring,
|
|||
|
const channel_slot_t slot);
|
|||
|
|
|||
|
/*
|
|||
|
* Each nexus that the channel is connected to determines whether or
|
|||
|
* not there is a shareable statistics region identified by one of
|
|||
|
* the channel_stats_id_t values. This routine returns a pointer to
|
|||
|
* such a region upon success, or NULL if not supported by the nexus.
|
|||
|
*/
|
|||
|
extern void *os_channel_get_stats_region(const channel_t channel,
|
|||
|
const channel_stats_id_t id);
|
|||
|
|
|||
|
/*
|
|||
|
* Each nexus that the channel is connected to determines whether or
|
|||
|
* not there is a nexus-wide advisory region. This routine returns
|
|||
|
* a pointer to such a region upon success, or NULL if not supported
|
|||
|
* by the nexus.
|
|||
|
*/
|
|||
|
extern void *os_channel_get_advisory_region(const channel_t channel);
|
|||
|
|
|||
|
/*
|
|||
|
* Each nexus that supports flow admission control may be queried to
|
|||
|
* advise whether or not the channel is willing to admit more packets
|
|||
|
* for a given flow. A return value of 0 indicates that the packets
|
|||
|
* for the flow are admissible. If ENOBUFS is returned, the flow is
|
|||
|
* currently suspended, and further attempts to send more packets on
|
|||
|
* the ring may result in drops. Any other error values indicate
|
|||
|
* that either the nexus doesn't support admission control, or the
|
|||
|
* arguments aren't valid.
|
|||
|
*/
|
|||
|
extern int os_channel_flow_admissible(const channel_ring_t ring,
|
|||
|
uuid_t flow_id, const flowadv_idx_t flow_index);
|
|||
|
|
|||
|
extern int os_channel_flow_adv_get_ce_count(const channel_ring_t chrd,
|
|||
|
uuid_t flow_id, const flowadv_idx_t flow_index, uint32_t *ce_cnt,
|
|||
|
uint32_t *pkt_cnt);
|
|||
|
/*
|
|||
|
* Allocate a packet from the channel's packet pool.
|
|||
|
* Returns 0 on success with the packet handle in packet arg.
|
|||
|
* Note: os_channel_packet_alloc() & os_channel_packet_free() should be
|
|||
|
* serialized and should not be called from the different thread context.
|
|||
|
*/
|
|||
|
extern int
|
|||
|
os_channel_packet_alloc(const channel_t chd, packet_t *packet);
|
|||
|
|
|||
|
/*
|
|||
|
* Allocate a large packet from the channel's packet pool.
|
|||
|
* Returns 0 on success with the packet handle in packet arg.
|
|||
|
* Note: os_channel_large_packet_alloc() & os_channel_packet_free() should be
|
|||
|
* serialized and should not be called from the different thread context.
|
|||
|
*/
|
|||
|
extern int
|
|||
|
os_channel_large_packet_alloc(const channel_t chd, packet_t *packet);
|
|||
|
|
|||
|
/*
|
|||
|
* Free a packet allocated from the channel's packet pool.
|
|||
|
* Returns 0 on success
|
|||
|
* Note: os_channel_packet_alloc() & os_channel_packet_free() should be
|
|||
|
* serialized and should not be called from the different thread context.
|
|||
|
*/
|
|||
|
extern int
|
|||
|
os_channel_packet_free(const channel_t chd, packet_t packet);
|
|||
|
|
|||
|
/*
|
|||
|
* Attach the given packet to a channel slot
|
|||
|
*/
|
|||
|
extern int
|
|||
|
os_channel_slot_attach_packet(const channel_ring_t chrd,
|
|||
|
const channel_slot_t slot, packet_t packet);
|
|||
|
|
|||
|
/*
|
|||
|
* Detach a given packet from a channel slot
|
|||
|
*/
|
|||
|
extern int
|
|||
|
os_channel_slot_detach_packet(const channel_ring_t chrd,
|
|||
|
const channel_slot_t slot, packet_t packet);
|
|||
|
|
|||
|
/*
|
|||
|
* purge packets from the channel's packet pool.
|
|||
|
* This API should be called at regular intervals by application to purge
|
|||
|
* unused packets from the channel's packet pool. Recommended interval is
|
|||
|
* 11 seconds.
|
|||
|
* Returns 0 on success.
|
|||
|
* Note: This call should be serialized with os_channel_packet_alloc() &
|
|||
|
* os_channel_packet_free() and should not be called from different
|
|||
|
* thread context.
|
|||
|
*/
|
|||
|
extern int
|
|||
|
os_channel_packet_pool_purge(const channel_t chd);
|
|||
|
|
|||
|
/*
|
|||
|
* Retrieve handle to the next available event(s) on the channel.
|
|||
|
* os_event_get_next_event() can then called on the event handle to
|
|||
|
* retrieve the individual events from the handle.
|
|||
|
* Returns 0 on success, ENXIO if the channel is defunct.
|
|||
|
*/
|
|||
|
extern int
|
|||
|
os_channel_get_next_event_handle(const channel_t chd,
|
|||
|
os_channel_event_handle_t *ehandle, os_channel_event_type_t *etype,
|
|||
|
uint32_t *nevents);
|
|||
|
|
|||
|
/*
|
|||
|
* Free an event retrieved from the channel.
|
|||
|
* Returns 0 on success, ENXIO if the channel is defunct.
|
|||
|
*/
|
|||
|
extern int
|
|||
|
os_channel_event_free(const channel_t chd, os_channel_event_handle_t ehandle);
|
|||
|
|
|||
|
/*
|
|||
|
* API to retrieve the latest interface advisory report on the channel.
|
|||
|
* Returns 0 on succcess. If the return value is EAGAIN, caller can attempt
|
|||
|
* to retrieve the information again.
|
|||
|
*/
|
|||
|
extern int
|
|||
|
os_channel_get_interface_advisory(const channel_t chd,
|
|||
|
struct ifnet_interface_advisory *advisory);
|
|||
|
|
|||
|
/*
|
|||
|
* API to configure interface advisory report on the channel.
|
|||
|
* Returns 0 on succcess.
|
|||
|
*/
|
|||
|
extern int
|
|||
|
os_channel_configure_interface_advisory(const channel_t chd, boolean_t enable);
|
|||
|
|
|||
|
extern int
|
|||
|
os_channel_buflet_alloc(const channel_t chd, buflet_t *bft);
|
|||
|
|
|||
|
extern int
|
|||
|
os_channel_buflet_free(const channel_t chd, buflet_t ubft);
|
|||
|
__END_DECLS
|
|||
|
#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
|
|||
|
#else /* KERNEL */
|
|||
|
/*
|
|||
|
* Kernel APIs.
|
|||
|
*/
|
|||
|
|
|||
|
/*
|
|||
|
* Opaque handles.
|
|||
|
*/
|
|||
|
struct kern_channel;
|
|||
|
struct __kern_channel_ring;
|
|||
|
|
|||
|
typedef struct kern_channel *kern_channel_t;
|
|||
|
typedef struct __kern_channel_ring *kern_channel_ring_t;
|
|||
|
typedef struct __slot_desc *kern_channel_slot_t;
|
|||
|
|
|||
|
/*
|
|||
|
* Slot properties (deprecated).
|
|||
|
*/
|
|||
|
struct kern_slot_prop {
|
|||
|
uint32_t _sp_pad[16]; /* reserved */
|
|||
|
} __attribute__((aligned(sizeof(uint64_t))));
|
|||
|
|
|||
|
/*
|
|||
|
* @struct kern_channel_ring_stat_increment
|
|||
|
* @abstract Structure used to increment the per ring statistic counters.
|
|||
|
* @field kcrsi_slots_transferred number of slots transferred
|
|||
|
* @filed kcrsi_bytes_transferred number of bytes transferred
|
|||
|
*/
|
|||
|
struct kern_channel_ring_stat_increment {
|
|||
|
uint32_t kcrsi_slots_transferred;
|
|||
|
uint32_t kcrsi_bytes_transferred;
|
|||
|
};
|
|||
|
|
|||
|
/*
|
|||
|
* Data Movement APIs.
|
|||
|
*
|
|||
|
* See block comment above for userland data movement APIs for general
|
|||
|
* concepts. The main differences here are the kern_channel_notify()
|
|||
|
* and kern_channel_reclaim() calls that aren't available for userland.
|
|||
|
* These calls are typically invoked within the TX and RX sync callbacks
|
|||
|
* implemented by the nexus provider.
|
|||
|
*
|
|||
|
* For TX sync, kern_channel_reclaim() is normally called after the
|
|||
|
* provider has finished reclaiming slots that have been "transmitted".
|
|||
|
* In this case, this call is simply a way to indicate to the system
|
|||
|
* that such condition has happened.
|
|||
|
*
|
|||
|
* For RX sync, kern_channel_reclaim() must be called at the beginning
|
|||
|
* of the callback in order to reclaim user-released slots, and to
|
|||
|
* ensure that subsequent calls to kern_channel_available_slot_count()
|
|||
|
* or kern_channel_get_next_slot() operates on the most recent state.
|
|||
|
*
|
|||
|
* The kern_channel_notify() is used to post notifications to indicate
|
|||
|
* slot availability; this may result in the kernel event subsystem
|
|||
|
* posting readable and writable events.
|
|||
|
*/
|
|||
|
__BEGIN_DECLS
|
|||
|
extern uint32_t kern_channel_notify(const kern_channel_ring_t, uint32_t flags);
|
|||
|
extern uint32_t kern_channel_available_slot_count(
|
|||
|
const kern_channel_ring_t ring);
|
|||
|
/*
|
|||
|
* NOTE: kern_channel_set_slot_properties(), kern_channel_get_next_slot(),
|
|||
|
* kern_channel_reclaim() and kern_channel_advance_slot() require that the
|
|||
|
* caller invokes them from within the sync callback context; they will
|
|||
|
* assert otherwise.
|
|||
|
*/
|
|||
|
extern void kern_channel_set_slot_properties(const kern_channel_ring_t,
|
|||
|
const kern_channel_slot_t slot, const struct kern_slot_prop *prop);
|
|||
|
extern kern_channel_slot_t kern_channel_get_next_slot(
|
|||
|
const kern_channel_ring_t kring, const kern_channel_slot_t slot,
|
|||
|
struct kern_slot_prop *slot_prop);
|
|||
|
extern uint32_t kern_channel_reclaim(const kern_channel_ring_t);
|
|||
|
extern void kern_channel_advance_slot(const kern_channel_ring_t kring,
|
|||
|
kern_channel_slot_t slot);
|
|||
|
|
|||
|
/*
|
|||
|
* Packet.
|
|||
|
*/
|
|||
|
extern kern_packet_t kern_channel_slot_get_packet(
|
|||
|
const kern_channel_ring_t ring, const kern_channel_slot_t slot);
|
|||
|
|
|||
|
/*
|
|||
|
* NOTE: kern_channel_slot_attach_packet(), kern_channel_slot_detach_packet()
|
|||
|
* and kern_channel_ring_get_container() require that the caller invokes them
|
|||
|
* from within the sync callback context; they will assert otherwise.
|
|||
|
*/
|
|||
|
extern errno_t kern_channel_slot_attach_packet(const kern_channel_ring_t ring,
|
|||
|
const kern_channel_slot_t slot, kern_packet_t packet);
|
|||
|
extern errno_t kern_channel_slot_detach_packet(const kern_channel_ring_t ring,
|
|||
|
const kern_channel_slot_t slot, kern_packet_t packet);
|
|||
|
extern errno_t kern_channel_ring_get_container(const kern_channel_ring_t ring,
|
|||
|
kern_packet_t **array, uint32_t *count);
|
|||
|
extern errno_t kern_channel_tx_refill(const kern_channel_ring_t ring,
|
|||
|
uint32_t pkt_limit, uint32_t byte_limit, boolean_t tx_doorbell_ctxt,
|
|||
|
boolean_t *pkts_pending);
|
|||
|
extern errno_t kern_channel_get_service_class(const kern_channel_ring_t ring,
|
|||
|
kern_packet_svc_class_t *svc);
|
|||
|
extern errno_t kern_netif_queue_get_service_class(kern_netif_queue_t,
|
|||
|
kern_packet_svc_class_t *);
|
|||
|
|
|||
|
/*
|
|||
|
* Misc.
|
|||
|
*/
|
|||
|
extern void *kern_channel_get_context(const kern_channel_t channel);
|
|||
|
extern void *kern_channel_ring_get_context(const kern_channel_ring_t ring);
|
|||
|
extern void *kern_channel_slot_get_context(const kern_channel_ring_t ring,
|
|||
|
const kern_channel_slot_t slot);
|
|||
|
|
|||
|
/*
|
|||
|
* NOTE: kern_channel_increment_ring_{net}_stats() requires
|
|||
|
* that the caller invokes it from within the sync callback context;
|
|||
|
* it will assert otherwise.
|
|||
|
*/
|
|||
|
extern void kern_channel_increment_ring_stats(kern_channel_ring_t ring,
|
|||
|
struct kern_channel_ring_stat_increment *stats);
|
|||
|
extern void kern_channel_increment_ring_net_stats(kern_channel_ring_t ring,
|
|||
|
ifnet_t, struct kern_channel_ring_stat_increment *stats);
|
|||
|
|
|||
|
#ifdef BSD_KERNEL_PRIVATE
|
|||
|
/* forward declare */
|
|||
|
struct flowadv_fcentry;
|
|||
|
|
|||
|
/* Flow advisory token */
|
|||
|
typedef uint32_t flowadv_token_t;
|
|||
|
|
|||
|
/*
|
|||
|
* Private, unexported KPIs.
|
|||
|
*/
|
|||
|
__private_extern__ errno_t kern_channel_slot_attach_packet_byidx(
|
|||
|
const kern_channel_ring_t kring, const uint32_t sidx, kern_packet_t ph);
|
|||
|
__private_extern__ errno_t kern_channel_slot_detach_packet_byidx(
|
|||
|
const kern_channel_ring_t kring, const uint32_t sidx, kern_packet_t ph);
|
|||
|
__private_extern__ void kern_channel_flowadv_clear(struct flowadv_fcentry *);
|
|||
|
__private_extern__ void kern_channel_flowadv_report_ce_event(
|
|||
|
struct flowadv_fcentry *, uint32_t, uint32_t);
|
|||
|
__private_extern__ void kern_channel_memstatus(struct proc *, uint32_t,
|
|||
|
struct kern_channel *);
|
|||
|
__private_extern__ void kern_channel_defunct(struct proc *,
|
|||
|
struct kern_channel *);
|
|||
|
__private_extern__ errno_t kern_channel_tx_refill_canblock(
|
|||
|
const kern_channel_ring_t, uint32_t, uint32_t, boolean_t, boolean_t *);
|
|||
|
#endif /* BSD_KERNEL_PRIVATE */
|
|||
|
__END_DECLS
|
|||
|
#endif /* KERNEL */
|
|||
|
#endif /* PRIVATE */
|
|||
|
#endif /* !_SKYWALK_OS_CHANNEL_H_ */
|