xref: /xnu-11215.61.5/bsd/skywalk/namespace/netns.h (revision 4f1223e81cd707a65cc109d0b8ad6653699da3c4)
1 /*
2  * Copyright (c) 2016-2018 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 #ifndef _SKYWALK_NAMESPACE_NETNS_H_
29 #define _SKYWALK_NAMESPACE_NETNS_H_
30 
31 #include <sys/param.h>
32 #include <net/if_var.h>
33 
34 /*
35  * The netns module arbitrates local L4 port number usage across Skywalk
36  * and the BSD networking stack. Its aim is to be lightweight and keep as
37  * little state as possible; as such, it can't tell you WHO is using port X
38  * so much as that port X is being used.
39  *
40  * NOTE: This API expects port numbers and IP addresses to be passed in
41  *	 network byte order.
42  */
43 
44 
45 /*
46  * netns_token is a structure passed back to port registrants used to keep
47  * track of what they registered and what flags they passed at the time.
48  *
49  * These tokens are intended to be opaque to users and should never be
50  * modified by external code.
51  *
52  * Token memory is managed by netns; they are created as the result of a call
53  * to netns_reserve(), and remain valid until passed into netns_release().
54  */
55 typedef struct ns_token *netns_token;
56 
57 extern int netns_init(void);
58 extern void netns_uninit(void);
59 extern void netns_reap_caches(boolean_t);
60 extern boolean_t netns_is_enabled(void);
61 
62 /*
63  * Metadata about a flow
64  */
65 struct ns_flow_info {
66 	/* rule (flow) UUID */
67 	uuid_t                  nfi_flow_uuid
68 	__attribute((aligned(sizeof(uint64_t))));
69 
70 	struct ifnet            *nfi_ifp;       /* interface index */
71 	union sockaddr_in_4_6   nfi_laddr;      /* local IP address */
72 	union sockaddr_in_4_6   nfi_faddr;      /* foreign IP address */
73 	uint8_t                 nfi_protocol;   /* protocol */
74 	uint8_t                 nfi_pad[3];     /* for future */
75 	pid_t                   nfi_owner_pid;
76 	pid_t                   nfi_effective_pid;
77 	char                    nfi_owner_name[MAXCOMLEN + 1];
78 	char                    nfi_effective_name[MAXCOMLEN + 1];
79 };
80 
81 /*
82  * Reserve a port in the namespace of the provided <addr, proto> tuple. The
83  * return code indicates whether the reservation succeeded or failed (if the
84  * port was already reserved by another protocol stack).
85  *
86  * The function will create a new netns_token and set the token argument to
87  * point to it. This token should be held for the lifetime of the port
88  * reservation and passed to future netns calls to modify or release
89  * the reservation.
90  *
91  * If a preexisting token is passed in, the call will either panic (if the
92  * NETNS_PRERESERVED flag is not set) or assert that the function arguments
93  * match the reservation pointed to by the token, returning with no further
94  * action (if NETNS_PRERESERVED is set).
95  *
96  * Either NETNS_SKYWALK, NETNS_LISTENER, NETNS_BSD or NETNS_PF must be passed
97  * in through the flags parameter depending on the caller as this is what the
98  * reservation logic uses to determine if a given port is already in use:
99  *    - BSD and PF can reserve a port only if it has no Skywalk or Listener
100  *      reservations
101  *    - Listeners can reserve a port only if it has no Listener, BSD or PF
102  *      reservations
103  *    - Skywalk can reserve a port only if it has no Skywalk, BSD or PF
104  *      reservations, UNLESS there is also a Listener reservation, in which
105  *      case the presence of prexisting Skywalk reservations are ignored
106  */
107 extern int netns_reserve(netns_token * token, uint32_t *__sized_by(addr_len) addr,
108     uint8_t addr_len, uint8_t proto, in_port_t port, uint32_t flags,
109     struct ns_flow_info *nfi);
110 
111 /*
112  * Reserve a port in the namespace of the provided <addr, proto> tuple, letting
113  * netns pick the port for the caller and saving its value into the port
114  * argument. Aside from this behavior, this function behaves identically to
115  * netns_reserve().
116  */
117 extern int netns_reserve_ephemeral(netns_token * token,
118     uint32_t *__sized_by(addr_len) addr, uint8_t addr_len, uint8_t proto,
119     in_port_t *port, uint32_t flags, struct ns_flow_info *nfi);
120 
121 /*
122  * Release a port reservation recorded by the provided token.
123  *
124  * After calling, the token passed into the function becomes valid and the
125  * pointer to it will be set to NULL.
126  */
127 extern void netns_release(netns_token *token);
128 
129 /*
130  * Mark a port reservation recorded by the provided token as half closed.
131  * The half closed port will not be included in the list of ports returned
132  * by netns_get_local_ports() when IFNET_GET_LOCAL_PORTS_ACTIVEONLY flag is set.
133  */
134 extern void netns_half_close(netns_token *token);
135 
136 /*
137  * Mark a port reservation recorded by the provided token as withdrawn.
138  * The withdrawn port will not be included in the list of ports returned
139  * by netns_get_local_ports().
140  */
141 extern void netns_withdraw(netns_token *token);
142 
143 /*
144  * Access the flow info associated with a token, by filling out the local struct.
145  * Returns 0 on success, or an error otherwise.
146  */
147 extern int netns_get_flow_info(netns_token *token, struct ns_flow_info *nfi);
148 
149 /*
150  * Update the IP address a port reservation is assigned to - mostly used by
151  * the TCP subsystem of the BSD stack, but technically whenever a pcb element
152  * gets rehashed.
153  *
154  * This operation is atomic - it may fail if the port is already reserved on
155  * the new address and the appropriate reuse flags aren't present, but in this
156  * case the old reservation is kept.
157  *
158  * The passed in token will be updated to reflect this new reservation.
159  */
160 extern int netns_change_addr(netns_token * token,
161     uint32_t *__sized_by(new_addr_len) new_addr, uint8_t new_addr_len);
162 
163 /*
164  * Update which network interface a given port reservation corresponds to.
165  * Passing NULL for the ifp argument clears the reservation from all
166  * interfaces.
167  *
168  * Note that a port reservation holds across ALL interfaces in the system,
169  * not just the one set by this function - the ifnet here is primarily used
170  * by netns_get_local_ports() to identify which L4 ports are active on a given
171  * interface.
172  */
173 extern void netns_set_ifnet(netns_token *token, ifnet_t ifp);
174 
175 /*
176  * Unrelate all port reservations to the specified interface (effectively
177  * iterates over all tokens pointed to ifp with netns_set_ifnet, and sets their
178  * ifp to null)
179  */
180 extern void netns_ifnet_detach(ifnet_t ifp);
181 
182 /*
183  * Change flags related to the port reservation, primarily to provide
184  * information about connection state to drivers looking for port offload
185  * lists.
186  *
187  * Cannot be used to change flags related to the initial reservation, like
188  * NETNS_SKYWALK/NETNS_BSD/etc.
189  */
190 extern void netns_change_flags(netns_token *token, uint32_t set_flags,
191     uint32_t clear_flags);
192 
193 /*
194  * Fill in the provided bitfield with the active ports corresponding to the
195  * ifnet specified by ifp. Additional filters can be applied to this bitmap
196  * with the protocol and flags arguments, which behave identically to their
197  * corresponding arguments in ifnet_get_local_ports_extended().
198  */
199 extern errno_t
200 netns_get_local_ports(ifnet_t ifp, protocol_family_t protocol,
201     u_int32_t flags, u_int8_t bitfield[IP_PORTRANGE_BITFIELD_LEN]);
202 
203 /*
204  * Return 1 if the parent ifnet of the specified ifaddr has any reservations
205  * for the specified protocol, 0 otherwise.
206  */
207 extern uint32_t
208 netns_find_anyres_byaddr(struct ifaddr *ifa, uint8_t proto);
209 
210 /*
211  * Return count of existing port reservations in the coresponding namespace, IPv4.
212  */
213 extern uint32_t
214 netns_lookup_reservations_count_in(struct in_addr addr, uint8_t proto);
215 
216 /*
217  * Return count of existing port reservations in the coresponding namespace, IPv6.
218  */
219 extern uint32_t
220 netns_lookup_reservations_count_in6(struct in6_addr addr, uint8_t proto);
221 
222 /*
223  * Address-family-specific versions of netns_reserve and netns_change_addr.
224  */
225 __attribute__((always_inline))
226 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)227 netns_reserve_in(netns_token *token, struct in_addr addr, uint8_t proto,
228     in_port_t port, uint32_t flags, struct ns_flow_info *nfi)
229 {
230 	return netns_reserve(token, &addr.s_addr, sizeof(struct in_addr),
231 	           proto, port, flags, nfi);
232 }
233 
234 __attribute__((always_inline))
235 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)236 netns_reserve_in6(netns_token *token, struct in6_addr addr, uint8_t proto,
237     in_port_t port, uint32_t flags, struct ns_flow_info *nfi)
238 {
239 	if (IN6_IS_SCOPE_EMBED(&addr)) {
240 		addr.s6_addr16[1] = 0;
241 	}
242 	return netns_reserve(token, &addr.s6_addr32[0],
243 	           sizeof(struct in6_addr), proto, port, flags, nfi);
244 }
245 
246 __attribute__((always_inline))
247 static inline int
netns_change_addr_in(netns_token * token,struct in_addr addr)248 netns_change_addr_in(netns_token *token, struct in_addr addr)
249 {
250 	return netns_change_addr(token, &addr.s_addr,
251 	           sizeof(struct in_addr));
252 }
253 
254 __attribute__((always_inline))
255 static inline int
netns_change_addr_in6(netns_token * token,struct in6_addr addr)256 netns_change_addr_in6(netns_token *token, struct in6_addr addr)
257 {
258 	if (IN6_IS_SCOPE_EMBED(&addr)) {
259 		addr.s6_addr16[1] = 0;
260 	}
261 	return netns_change_addr(token, &addr.s6_addr32[0],
262 	           sizeof(struct in6_addr));
263 }
264 
265 #define NETNS_TOKEN_VALID(token_ptr) ((*token_ptr) != NULL)
266 #define NETNS_AF_SIZE(af)       \
267 	(((af) == AF_INET) ? sizeof (struct in_addr) : sizeof (struct in6_addr))
268 
269 /* Flags for reserve */
270 
271 /* The caller is reserving a port on behalf of skywalk, but for a listener */
272 #define NETNS_LISTENER          0x00
273 /* The caller is reserving a port on behalf of skywalk. */
274 #define NETNS_SKYWALK           0x01
275 /* The caller is reserving a port on behalf of the BSD stack. */
276 #define NETNS_BSD               0x02
277 /* The caller is reserving a port on behalf of the Packet Filter (PF). */
278 #define NETNS_PF                0x03
279 
280 #define NETNS_OWNER_MAX         NETNS_PF
281 #define NETNS_OWNER_MASK        0x07
282 /* Danger Will Robinson: This uses the above as a bitmap. */
283 #define NETNS_IS_SKYWALK(flags) ((flags & NETNS_BSD) == 0)
284 
285 /* 0x08 is reserved */
286 
287 /*
288  * When passing an already-valid token to netns_reserve, behave as a no-op.
289  * Used by the BSD stack which may speculatively create reservations and then
290  * "finalize" them later by calling netns_reserve again.
291  */
292 #define NETNS_PRERESERVED       0x10
293 
294 #define NETNS_RESERVATION_FLAGS (NETNS_PRERESERVED | NETNS_OWNER_MASK)
295 
296 /* Flags for change_flags */
297 
298 /*
299  * Set when the reservation backs a socket with the SO_NOWAKEFROMSLEEP option
300  * set
301  */
302 #define NETNS_NOWAKEFROMSLEEP   0x20
303 
304 /* Set when the reservation backs a socket with the SO_RECV_ANYIF option set */
305 #define NETNS_RECVANYIF         0x40
306 
307 /*
308  * Set when the reservation backs a socket with the SO_EXTENDED_BK_IDLE option
309  * set
310  */
311 #define NETNS_EXTBGIDLE         0x80
312 
313 /*
314  * Set when the reservation allows reusing the port for new listener
315  */
316 #define NETNS_REUSEPORT         0x100
317 
318 #define NETNS_CONFIGURATION_FLAGS (NETNS_NOWAKEFROMSLEEP | NETNS_RECVANYIF | \
319 	                        NETNS_EXTBGIDLE | NETNS_REUSEPORT)
320 
321 #endif /* !_SKYWALK_NAMESPACE_NETNS_H_ */
322