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 |
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: &addr.s_addr, addr_len: sizeof(struct in_addr), |
230 | proto, port, flags, nfi); |
231 | } |
232 | |
233 | __attribute__((always_inline)) |
234 | static inline int |
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: &addr.s6_addr32[0], |
242 | addr_len: sizeof(struct in6_addr), proto, port, flags, nfi); |
243 | } |
244 | |
245 | __attribute__((always_inline)) |
246 | static inline int |
247 | netns_change_addr_in(netns_token *token, struct in_addr addr) |
248 | { |
249 | return netns_change_addr(token, new_addr: &addr.s_addr, |
250 | new_addr_len: sizeof(struct in_addr)); |
251 | } |
252 | |
253 | __attribute__((always_inline)) |
254 | static inline int |
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, new_addr: &addr.s6_addr32[0], |
261 | new_addr_len: 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 | |