gems-kernel/source/THIRDPARTY/xnu/bsd/skywalk/namespace/netns.h

321 lines
11 KiB
C
Raw Normal View History

2024-06-03 16:29:39 +00:00
/*
* Copyright (c) 2016-2018 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_NAMESPACE_NETNS_H_
#define _SKYWALK_NAMESPACE_NETNS_H_
#include <sys/param.h>
#include <net/if_var.h>
/*
* The netns module arbitrates local L4 port number usage across Skywalk
* and the BSD networking stack. Its aim is to be lightweight and keep as
* little state as possible; as such, it can't tell you WHO is using port X
* so much as that port X is being used.
*
* NOTE: This API expects port numbers and IP addresses to be passed in
* network byte order.
*/
/*
* netns_token is a structure passed back to port registrants used to keep
* track of what they registered and what flags they passed at the time.
*
* These tokens are intended to be opaque to users and should never be
* modified by external code.
*
* Token memory is managed by netns; they are created as the result of a call
* to netns_reserve(), and remain valid until passed into netns_release().
*/
typedef struct ns_token *netns_token;
extern int netns_init(void);
extern void netns_uninit(void);
extern void netns_reap_caches(boolean_t);
extern boolean_t netns_is_enabled(void);
/*
* Metadata about a flow
*/
struct ns_flow_info {
/* rule (flow) UUID */
uuid_t nfi_flow_uuid
__attribute((aligned(sizeof(uint64_t))));
struct ifnet *nfi_ifp; /* interface index */
union sockaddr_in_4_6 nfi_laddr; /* local IP address */
union sockaddr_in_4_6 nfi_faddr; /* foreign IP address */
uint8_t nfi_protocol; /* protocol */
uint8_t nfi_pad[3]; /* for future */
pid_t nfi_owner_pid;
pid_t nfi_effective_pid;
char nfi_owner_name[MAXCOMLEN + 1];
char nfi_effective_name[MAXCOMLEN + 1];
};
/*
* Reserve a port in the namespace of the provided <addr, proto> tuple. The
* return code indicates whether the reservation succeeded or failed (if the
* port was already reserved by another protocol stack).
*
* The function will create a new netns_token and set the token argument to
* point to it. This token should be held for the lifetime of the port
* reservation and passed to future netns calls to modify or release
* the reservation.
*
* If a preexisting token is passed in, the call will either panic (if the
* NETNS_PRERESERVED flag is not set) or assert that the function arguments
* match the reservation pointed to by the token, returning with no further
* action (if NETNS_PRERESERVED is set).
*
* Either NETNS_SKYWALK, NETNS_LISTENER, NETNS_BSD or NETNS_PF must be passed
* in through the flags parameter depending on the caller as this is what the
* reservation logic uses to determine if a given port is already in use:
* - BSD and PF can reserve a port only if it has no Skywalk or Listener
* reservations
* - Listeners can reserve a port only if it has no Listener, BSD or PF
* reservations
* - Skywalk can reserve a port only if it has no Skywalk, BSD or PF
* reservations, UNLESS there is also a Listener reservation, in which
* case the presence of prexisting Skywalk reservations are ignored
*/
extern int netns_reserve(netns_token *token, uint32_t *addr, uint8_t addr_len,
uint8_t proto, in_port_t port, uint32_t flags, struct ns_flow_info *nfi);
/*
* Reserve a port in the namespace of the provided <addr, proto> tuple, letting
* netns pick the port for the caller and saving its value into the port
* argument. Aside from this behavior, this function behaves identically to
* netns_reserve().
*/
extern int netns_reserve_ephemeral(netns_token *token, uint32_t *addr,
uint8_t addr_len, uint8_t proto, in_port_t *port, uint32_t flags,
struct ns_flow_info *nfi);
/*
* Release a port reservation recorded by the provided token.
*
* After calling, the token passed into the function becomes valid and the
* pointer to it will be set to NULL.
*/
extern void netns_release(netns_token *token);
/*
* Mark a port reservation recorded by the provided token as half closed.
* The half closed port will not be included in the list of ports returned
* by netns_get_local_ports() when IFNET_GET_LOCAL_PORTS_ACTIVEONLY flag is set.
*/
extern void netns_half_close(netns_token *token);
/*
* Mark a port reservation recorded by the provided token as withdrawn.
* The withdrawn port will not be included in the list of ports returned
* by netns_get_local_ports().
*/
extern void netns_withdraw(netns_token *token);
/*
* Access the flow info associated with a token, by filling out the local struct.
* Returns 0 on success, or an error otherwise.
*/
extern int netns_get_flow_info(netns_token *token, struct ns_flow_info *nfi);
/*
* Update the IP address a port reservation is assigned to - mostly used by
* the TCP subsystem of the BSD stack, but technically whenever a pcb element
* gets rehashed.
*
* This operation is atomic - it may fail if the port is already reserved on
* the new address and the appropriate reuse flags aren't present, but in this
* case the old reservation is kept.
*
* The passed in token will be updated to reflect this new reservation.
*/
extern int netns_change_addr(netns_token *token, uint32_t *new_addr,
uint8_t new_addr_len);
/*
* Update which network interface a given port reservation corresponds to.
* Passing NULL for the ifp argument clears the reservation from all
* interfaces.
*
* Note that a port reservation holds across ALL interfaces in the system,
* not just the one set by this function - the ifnet here is primarily used
* by netns_get_local_ports() to identify which L4 ports are active on a given
* interface.
*/
extern void netns_set_ifnet(netns_token *token, ifnet_t ifp);
/*
* Unrelate all port reservations to the specified interface (effectively
* iterates over all tokens pointed to ifp with netns_set_ifnet, and sets their
* ifp to null)
*/
extern void netns_ifnet_detach(ifnet_t ifp);
/*
* Change flags related to the port reservation, primarily to provide
* information about connection state to drivers looking for port offload
* lists.
*
* Cannot be used to change flags related to the initial reservation, like
* NETNS_SKYWALK/NETNS_BSD/etc.
*/
extern void netns_change_flags(netns_token *token, uint32_t set_flags,
uint32_t clear_flags);
/*
* Fill in the provided bitfield with the active ports corresponding to the
* ifnet specified by ifp. Additional filters can be applied to this bitmap
* with the protocol and flags arguments, which behave identically to their
* corresponding arguments in ifnet_get_local_ports_extended().
*/
extern errno_t
netns_get_local_ports(ifnet_t ifp, protocol_family_t protocol,
u_int32_t flags, u_int8_t *bitfield);
/*
* Return 1 if the parent ifnet of the specified ifaddr has any reservations
* for the specified protocol, 0 otherwise.
*/
extern uint32_t
netns_find_anyres_byaddr(struct ifaddr *ifa, uint8_t proto);
/*
* Return count of existing port reservations in the coresponding namespace, IPv4.
*/
extern uint32_t
netns_lookup_reservations_count_in(struct in_addr addr, uint8_t proto);
/*
* Return count of existing port reservations in the coresponding namespace, IPv6.
*/
extern uint32_t
netns_lookup_reservations_count_in6(struct in6_addr addr, uint8_t proto);
/*
* Address-family-specific versions of netns_reserve and netns_change_addr.
*/
__attribute__((always_inline))
static inline int
netns_reserve_in(netns_token *token, struct in_addr addr, uint8_t proto,
in_port_t port, uint32_t flags, struct ns_flow_info *nfi)
{
return netns_reserve(token, &addr.s_addr, sizeof(struct in_addr),
proto, port, flags, nfi);
}
__attribute__((always_inline))
static inline int
netns_reserve_in6(netns_token *token, struct in6_addr addr, uint8_t proto,
in_port_t port, uint32_t flags, struct ns_flow_info *nfi)
{
if (IN6_IS_SCOPE_EMBED(&addr)) {
addr.s6_addr16[1] = 0;
}
return netns_reserve(token, &addr.s6_addr32[0],
sizeof(struct in6_addr), proto, port, flags, nfi);
}
__attribute__((always_inline))
static inline int
netns_change_addr_in(netns_token *token, struct in_addr addr)
{
return netns_change_addr(token, &addr.s_addr,
sizeof(struct in_addr));
}
__attribute__((always_inline))
static inline int
netns_change_addr_in6(netns_token *token, struct in6_addr addr)
{
if (IN6_IS_SCOPE_EMBED(&addr)) {
addr.s6_addr16[1] = 0;
}
return netns_change_addr(token, &addr.s6_addr32[0],
sizeof(struct in6_addr));
}
#define NETNS_TOKEN_VALID(token_ptr) ((*token_ptr) != NULL)
#define NETNS_AF_SIZE(af) \
(((af) == AF_INET) ? sizeof (struct in_addr) : sizeof (struct in6_addr))
/* Flags for reserve */
/* The caller is reserving a port on behalf of skywalk, but for a listener */
#define NETNS_LISTENER 0x00
/* The caller is reserving a port on behalf of skywalk. */
#define NETNS_SKYWALK 0x01
/* The caller is reserving a port on behalf of the BSD stack. */
#define NETNS_BSD 0x02
/* The caller is reserving a port on behalf of the Packet Filter (PF). */
#define NETNS_PF 0x03
#define NETNS_OWNER_MAX NETNS_PF
#define NETNS_OWNER_MASK 0x07
/* Danger Will Robinson: This uses the above as a bitmap. */
#define NETNS_IS_SKYWALK(flags) ((flags & NETNS_BSD) == 0)
/* 0x08 is reserved */
/*
* When passing an already-valid token to netns_reserve, behave as a no-op.
* Used by the BSD stack which may speculatively create reservations and then
* "finalize" them later by calling netns_reserve again.
*/
#define NETNS_PRERESERVED 0x10
#define NETNS_RESERVATION_FLAGS (NETNS_PRERESERVED | NETNS_OWNER_MASK)
/* Flags for change_flags */
/*
* Set when the reservation backs a socket with the SO_NOWAKEFROMSLEEP option
* set
*/
#define NETNS_NOWAKEFROMSLEEP 0x20
/* Set when the reservation backs a socket with the SO_RECV_ANYIF option set */
#define NETNS_RECVANYIF 0x40
/*
* Set when the reservation backs a socket with the SO_EXTENDED_BK_IDLE option
* set
*/
#define NETNS_EXTBGIDLE 0x80
/*
* Set when the reservation allows reusing the port for new listener
*/
#define NETNS_REUSEPORT 0x100
#define NETNS_CONFIGURATION_FLAGS (NETNS_NOWAKEFROMSLEEP | NETNS_RECVANYIF | \
NETNS_EXTBGIDLE | NETNS_REUSEPORT)
#endif /* !_SKYWALK_NAMESPACE_NETNS_H_ */