xref: /xnu-10002.81.5/bsd/skywalk/namespace/netns.h (revision 5e3eaea39dcf651e66cb99ba7d70e32cc4a99587)
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 *addr, uint8_t addr_len,
108     uint8_t proto, in_port_t port, uint32_t flags, struct ns_flow_info *nfi);
109 
110 /*
111  * Reserve a port in the namespace of the provided <addr, proto> tuple, letting
112  * netns pick the port for the caller and saving its value into the port
113  * argument. Aside from this behavior, this function behaves identically to
114  * netns_reserve().
115  */
116 extern int netns_reserve_ephemeral(netns_token *token, uint32_t *addr,
117     uint8_t addr_len, uint8_t proto, in_port_t *port, uint32_t flags,
118     struct ns_flow_info *nfi);
119 
120 /*
121  * Release a port reservation recorded by the provided token.
122  *
123  * After calling, the token passed into the function becomes valid and the
124  * pointer to it will be set to NULL.
125  */
126 extern void netns_release(netns_token *token);
127 
128 /*
129  * Mark a port reservation recorded by the provided token as half closed.
130  * The half closed port will not be included in the list of ports returned
131  * by netns_get_local_ports() when IFNET_GET_LOCAL_PORTS_ACTIVEONLY flag is set.
132  */
133 extern void netns_half_close(netns_token *token);
134 
135 /*
136  * Mark a port reservation recorded by the provided token as withdrawn.
137  * The withdrawn port will not be included in the list of ports returned
138  * by netns_get_local_ports().
139  */
140 extern void netns_withdraw(netns_token *token);
141 
142 /*
143  * Access the flow info associated with a token, by filling out the local struct.
144  * Returns 0 on success, or an error otherwise.
145  */
146 extern int netns_get_flow_info(netns_token *token, struct ns_flow_info *nfi);
147 
148 /*
149  * Update the IP address a port reservation is assigned to - mostly used by
150  * the TCP subsystem of the BSD stack, but technically whenever a pcb element
151  * gets rehashed.
152  *
153  * This operation is atomic - it may fail if the port is already reserved on
154  * the new address and the appropriate reuse flags aren't present, but in this
155  * case the old reservation is kept.
156  *
157  * The passed in token will be updated to reflect this new reservation.
158  */
159 extern int netns_change_addr(netns_token *token, uint32_t *new_addr,
160     uint8_t new_addr_len);
161 
162 /*
163  * Update which network interface a given port reservation corresponds to.
164  * Passing NULL for the ifp argument clears the reservation from all
165  * interfaces.
166  *
167  * Note that a port reservation holds across ALL interfaces in the system,
168  * not just the one set by this function - the ifnet here is primarily used
169  * by netns_get_local_ports() to identify which L4 ports are active on a given
170  * interface.
171  */
172 extern void netns_set_ifnet(netns_token *token, ifnet_t ifp);
173 
174 /*
175  * Unrelate all port reservations to the specified interface (effectively
176  * iterates over all tokens pointed to ifp with netns_set_ifnet, and sets their
177  * ifp to null)
178  */
179 extern void netns_ifnet_detach(ifnet_t ifp);
180 
181 /*
182  * Change flags related to the port reservation, primarily to provide
183  * information about connection state to drivers looking for port offload
184  * lists.
185  *
186  * Cannot be used to change flags related to the initial reservation, like
187  * NETNS_SKYWALK/NETNS_BSD/etc.
188  */
189 extern void netns_change_flags(netns_token *token, uint32_t set_flags,
190     uint32_t clear_flags);
191 
192 /*
193  * Fill in the provided bitfield with the active ports corresponding to the
194  * ifnet specified by ifp. Additional filters can be applied to this bitmap
195  * with the protocol and flags arguments, which behave identically to their
196  * corresponding arguments in ifnet_get_local_ports_extended().
197  */
198 extern errno_t
199 netns_get_local_ports(ifnet_t ifp, protocol_family_t protocol,
200     u_int32_t flags, u_int8_t *bitfield);
201 
202 /*
203  * Return 1 if the parent ifnet of the specified ifaddr has any reservations
204  * for the specified protocol, 0 otherwise.
205  */
206 extern uint32_t
207 netns_find_anyres_byaddr(struct ifaddr *ifa, uint8_t proto);
208 
209 /*
210  * Return count of existing port reservations in the coresponding namespace, IPv4.
211  */
212 extern uint32_t
213 netns_lookup_reservations_count_in(struct in_addr addr, uint8_t proto);
214 
215 /*
216  * Return count of existing port reservations in the coresponding namespace, IPv6.
217  */
218 extern uint32_t
219 netns_lookup_reservations_count_in6(struct in6_addr addr, uint8_t proto);
220 
221 /*
222  * Address-family-specific versions of netns_reserve and netns_change_addr.
223  */
224 __attribute__((always_inline))
225 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)226 netns_reserve_in(netns_token *token, struct in_addr addr, uint8_t proto,
227     in_port_t port, uint32_t flags, struct ns_flow_info *nfi)
228 {
229 	return netns_reserve(token, &addr.s_addr, sizeof(struct in_addr),
230 	           proto, port, flags, nfi);
231 }
232 
233 __attribute__((always_inline))
234 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)235 netns_reserve_in6(netns_token *token, struct in6_addr addr, uint8_t proto,
236     in_port_t port, uint32_t flags, struct ns_flow_info *nfi)
237 {
238 	if (IN6_IS_SCOPE_EMBED(&addr)) {
239 		addr.s6_addr16[1] = 0;
240 	}
241 	return netns_reserve(token, &addr.s6_addr32[0],
242 	           sizeof(struct in6_addr), proto, port, flags, nfi);
243 }
244 
245 __attribute__((always_inline))
246 static inline int
netns_change_addr_in(netns_token * token,struct in_addr addr)247 netns_change_addr_in(netns_token *token, struct in_addr addr)
248 {
249 	return netns_change_addr(token, &addr.s_addr,
250 	           sizeof(struct in_addr));
251 }
252 
253 __attribute__((always_inline))
254 static inline int
netns_change_addr_in6(netns_token * token,struct in6_addr addr)255 netns_change_addr_in6(netns_token *token, struct in6_addr addr)
256 {
257 	if (IN6_IS_SCOPE_EMBED(&addr)) {
258 		addr.s6_addr16[1] = 0;
259 	}
260 	return netns_change_addr(token, &addr.s6_addr32[0],
261 	           sizeof(struct in6_addr));
262 }
263 
264 #define NETNS_TOKEN_VALID(token_ptr) ((*token_ptr) != NULL)
265 #define NETNS_AF_SIZE(af)       \
266 	(((af) == AF_INET) ? sizeof (struct in_addr) : sizeof (struct in6_addr))
267 
268 /* Flags for reserve */
269 
270 /* The caller is reserving a port on behalf of skywalk, but for a listener */
271 #define NETNS_LISTENER          0x00
272 /* The caller is reserving a port on behalf of skywalk. */
273 #define NETNS_SKYWALK           0x01
274 /* The caller is reserving a port on behalf of the BSD stack. */
275 #define NETNS_BSD               0x02
276 /* The caller is reserving a port on behalf of the Packet Filter (PF). */
277 #define NETNS_PF                0x03
278 
279 #define NETNS_OWNER_MAX         NETNS_PF
280 #define NETNS_OWNER_MASK        0x07
281 /* Danger Will Robinson: This uses the above as a bitmap. */
282 #define NETNS_IS_SKYWALK(flags) ((flags & NETNS_BSD) == 0)
283 
284 /* 0x08 is reserved */
285 
286 /*
287  * When passing an already-valid token to netns_reserve, behave as a no-op.
288  * Used by the BSD stack which may speculatively create reservations and then
289  * "finalize" them later by calling netns_reserve again.
290  */
291 #define NETNS_PRERESERVED       0x10
292 
293 #define NETNS_RESERVATION_FLAGS (NETNS_PRERESERVED | NETNS_OWNER_MASK)
294 
295 /* Flags for change_flags */
296 
297 /*
298  * Set when the reservation backs a socket with the SO_NOWAKEFROMSLEEP option
299  * set
300  */
301 #define NETNS_NOWAKEFROMSLEEP   0x20
302 
303 /* Set when the reservation backs a socket with the SO_RECV_ANYIF option set */
304 #define NETNS_RECVANYIF         0x40
305 
306 /*
307  * Set when the reservation backs a socket with the SO_EXTENDED_BK_IDLE option
308  * set
309  */
310 #define NETNS_EXTBGIDLE         0x80
311 
312 /*
313  * Set when the reservation allows reusing the port for new listener
314  */
315 #define NETNS_REUSEPORT         0x100
316 
317 #define NETNS_CONFIGURATION_FLAGS (NETNS_NOWAKEFROMSLEEP | NETNS_RECVANYIF | \
318 	                        NETNS_EXTBGIDLE | NETNS_REUSEPORT)
319 
320 #endif /* !_SKYWALK_NAMESPACE_NETNS_H_ */
321