1 | /* |
2 | * Copyright (c) 2015-2021 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 | |
29 | #ifndef _SKYWALK_NEXUS_COMMON_H_ |
30 | #define _SKYWALK_NEXUS_COMMON_H_ |
31 | |
32 | #if defined(PRIVATE) || defined(BSD_KERNEL_PRIVATE) |
33 | /* |
34 | * Routines common to kernel and userland. This file is intended to be |
35 | * included by code implementing the nexus controller logic, in particular, |
36 | * the Skywalk kernel and libsyscall code. |
37 | */ |
38 | |
39 | #include <skywalk/os_nexus_private.h> |
40 | #include <sys/errno.h> |
41 | |
42 | #ifndef KERNEL |
43 | #if !defined(LIBSYSCALL_INTERFACE) |
44 | #error "LIBSYSCALL_INTERFACE not defined" |
45 | #endif /* !LIBSYSCALL_INTERFACE */ |
46 | #endif /* !KERNEL */ |
47 | |
48 | __attribute__((always_inline)) |
49 | static inline int |
50 | __nexus_attr_set(const nexus_attr_t nxa, const nexus_attr_type_t type, |
51 | const uint64_t value) |
52 | { |
53 | int err = 0; |
54 | |
55 | if (nxa == NULL) { |
56 | return EINVAL; |
57 | } |
58 | |
59 | switch (type) { |
60 | case NEXUS_ATTR_TX_RINGS: |
61 | nxa->nxa_requested |= NXA_REQ_TX_RINGS; |
62 | nxa->nxa_tx_rings = value; |
63 | break; |
64 | |
65 | case NEXUS_ATTR_RX_RINGS: |
66 | nxa->nxa_requested |= NXA_REQ_RX_RINGS; |
67 | nxa->nxa_rx_rings = value; |
68 | break; |
69 | |
70 | case NEXUS_ATTR_TX_SLOTS: |
71 | nxa->nxa_requested |= NXA_REQ_TX_SLOTS; |
72 | nxa->nxa_tx_slots = value; |
73 | break; |
74 | |
75 | case NEXUS_ATTR_RX_SLOTS: |
76 | nxa->nxa_requested |= NXA_REQ_RX_SLOTS; |
77 | nxa->nxa_rx_slots = value; |
78 | break; |
79 | |
80 | case NEXUS_ATTR_SLOT_BUF_SIZE: |
81 | nxa->nxa_requested |= NXA_REQ_BUF_SIZE; |
82 | nxa->nxa_buf_size = value; |
83 | break; |
84 | |
85 | case NEXUS_ATTR_ANONYMOUS: |
86 | nxa->nxa_requested |= NXA_REQ_ANONYMOUS; |
87 | nxa->nxa_anonymous = value; |
88 | break; |
89 | |
90 | case NEXUS_ATTR_PIPES: |
91 | nxa->nxa_requested |= NXA_REQ_PIPES; |
92 | nxa->nxa_pipes = value; |
93 | break; |
94 | |
95 | case NEXUS_ATTR_EXTENSIONS: |
96 | nxa->nxa_requested |= NXA_REQ_EXTENSIONS; |
97 | nxa->nxa_extensions = value; |
98 | break; |
99 | |
100 | case NEXUS_ATTR_MHINTS: |
101 | nxa->nxa_requested |= NXA_REQ_MHINTS; |
102 | nxa->nxa_mhints = value; |
103 | break; |
104 | |
105 | case NEXUS_ATTR_QMAP: |
106 | nxa->nxa_requested |= NXA_REQ_QMAP; |
107 | nxa->nxa_qmap = value; |
108 | break; |
109 | |
110 | case NEXUS_ATTR_IFINDEX: |
111 | #if !defined(LIBSYSCALL_INTERFACE) |
112 | nxa->nxa_requested |= NXA_REQ_IFINDEX; |
113 | nxa->nxa_ifindex = value; |
114 | #else /* LIBSYSCALL_INTERFACE */ |
115 | err = ENOTSUP; |
116 | #endif /* LIBSYSCALL_INTERFACE */ |
117 | break; |
118 | |
119 | case NEXUS_ATTR_USER_CHANNEL: |
120 | nxa->nxa_requested |= NXA_REQ_USER_CHANNEL; |
121 | nxa->nxa_user_channel = value; |
122 | break; |
123 | |
124 | case NEXUS_ATTR_MAX_FRAGS: |
125 | nxa->nxa_requested |= NXA_REQ_MAX_FRAGS; |
126 | nxa->nxa_max_frags = value; |
127 | break; |
128 | |
129 | case NEXUS_ATTR_REJECT_ON_CLOSE: |
130 | nxa->nxa_requested |= NXA_REQ_REJECT_ON_CLOSE; |
131 | nxa->nxa_reject_on_close = (value != 0); |
132 | break; |
133 | |
134 | case NEXUS_ATTR_LARGE_BUF_SIZE: |
135 | nxa->nxa_requested |= NXA_REQ_LARGE_BUF_SIZE; |
136 | nxa->nxa_large_buf_size = value; |
137 | break; |
138 | |
139 | case NEXUS_ATTR_FLOWADV_MAX: |
140 | case NEXUS_ATTR_STATS_SIZE: |
141 | case NEXUS_ATTR_SLOT_META_SIZE: |
142 | case NEXUS_ATTR_CHECKSUM_OFFLOAD: |
143 | case NEXUS_ATTR_USER_PACKET_POOL: |
144 | case NEXUS_ATTR_ADV_SIZE: |
145 | err = ENOTSUP; |
146 | break; |
147 | |
148 | default: |
149 | err = EINVAL; |
150 | break; |
151 | } |
152 | |
153 | return err; |
154 | } |
155 | |
156 | __attribute__((always_inline)) |
157 | static inline int |
158 | __nexus_attr_get(const nexus_attr_t nxa, const nexus_attr_type_t type, |
159 | uint64_t *value) |
160 | { |
161 | int err = 0; |
162 | |
163 | if (nxa == NULL || value == NULL) { |
164 | return EINVAL; |
165 | } |
166 | |
167 | switch (type) { |
168 | case NEXUS_ATTR_TX_RINGS: |
169 | *value = nxa->nxa_tx_rings; |
170 | break; |
171 | |
172 | case NEXUS_ATTR_RX_RINGS: |
173 | *value = nxa->nxa_rx_rings; |
174 | break; |
175 | |
176 | case NEXUS_ATTR_TX_SLOTS: |
177 | *value = nxa->nxa_tx_slots; |
178 | break; |
179 | |
180 | case NEXUS_ATTR_RX_SLOTS: |
181 | *value = nxa->nxa_rx_slots; |
182 | break; |
183 | |
184 | case NEXUS_ATTR_SLOT_BUF_SIZE: |
185 | *value = nxa->nxa_buf_size; |
186 | break; |
187 | |
188 | case NEXUS_ATTR_SLOT_META_SIZE: |
189 | *value = nxa->nxa_meta_size; |
190 | break; |
191 | |
192 | case NEXUS_ATTR_STATS_SIZE: |
193 | *value = nxa->nxa_stats_size; |
194 | break; |
195 | |
196 | case NEXUS_ATTR_FLOWADV_MAX: |
197 | *value = nxa->nxa_flowadv_max; |
198 | break; |
199 | |
200 | case NEXUS_ATTR_ANONYMOUS: |
201 | *value = nxa->nxa_anonymous; |
202 | break; |
203 | |
204 | case NEXUS_ATTR_PIPES: |
205 | *value = nxa->nxa_pipes; |
206 | break; |
207 | |
208 | case NEXUS_ATTR_EXTENSIONS: |
209 | *value = nxa->nxa_extensions; |
210 | break; |
211 | |
212 | case NEXUS_ATTR_MHINTS: |
213 | *value = nxa->nxa_mhints; |
214 | break; |
215 | |
216 | case NEXUS_ATTR_IFINDEX: |
217 | *value = nxa->nxa_ifindex; |
218 | break; |
219 | |
220 | case NEXUS_ATTR_QMAP: |
221 | *value = nxa->nxa_qmap; |
222 | break; |
223 | |
224 | case NEXUS_ATTR_CHECKSUM_OFFLOAD: |
225 | *value = nxa->nxa_checksum_offload; |
226 | break; |
227 | |
228 | case NEXUS_ATTR_USER_PACKET_POOL: |
229 | *value = nxa->nxa_user_packet_pool; |
230 | break; |
231 | |
232 | case NEXUS_ATTR_ADV_SIZE: |
233 | *value = nxa->nxa_nexusadv_size; |
234 | break; |
235 | |
236 | case NEXUS_ATTR_USER_CHANNEL: |
237 | *value = nxa->nxa_user_channel; |
238 | break; |
239 | |
240 | case NEXUS_ATTR_MAX_FRAGS: |
241 | *value = nxa->nxa_max_frags; |
242 | break; |
243 | |
244 | case NEXUS_ATTR_REJECT_ON_CLOSE: |
245 | *value = nxa->nxa_reject_on_close; |
246 | break; |
247 | |
248 | case NEXUS_ATTR_LARGE_BUF_SIZE: |
249 | *value = nxa->nxa_large_buf_size; |
250 | break; |
251 | |
252 | default: |
253 | err = EINVAL; |
254 | break; |
255 | } |
256 | |
257 | return err; |
258 | } |
259 | |
260 | __attribute__((always_inline)) |
261 | static inline void |
262 | __nexus_attr_from_params(nexus_attr_t nxa, const struct nxprov_params *p) |
263 | { |
264 | bzero(s: nxa, n: sizeof(*nxa)); |
265 | nxa->nxa_tx_rings = p->nxp_tx_rings; |
266 | nxa->nxa_rx_rings = p->nxp_rx_rings; |
267 | nxa->nxa_tx_slots = p->nxp_tx_slots; |
268 | nxa->nxa_rx_slots = p->nxp_rx_slots; |
269 | nxa->nxa_buf_size = p->nxp_buf_size; |
270 | nxa->nxa_meta_size = p->nxp_meta_size; |
271 | nxa->nxa_stats_size = p->nxp_stats_size; |
272 | nxa->nxa_flowadv_max = p->nxp_flowadv_max; |
273 | nxa->nxa_anonymous = !!(p->nxp_flags & NXPF_ANONYMOUS); |
274 | nxa->nxa_pipes = p->nxp_pipes; |
275 | nxa->nxa_extensions = p->nxp_extensions; |
276 | nxa->nxa_mhints = p->nxp_mhints; |
277 | nxa->nxa_ifindex = p->nxp_ifindex; |
278 | nxa->nxa_qmap = p->nxp_qmap; |
279 | nxa->nxa_checksum_offload = (p->nxp_capabilities & |
280 | NXPCAP_CHECKSUM_PARTIAL) ? 1 : 0; |
281 | nxa->nxa_user_packet_pool = (p->nxp_capabilities & |
282 | NXPCAP_USER_PACKET_POOL) ? 1 : 0; |
283 | nxa->nxa_nexusadv_size = p->nxp_nexusadv_size; |
284 | nxa->nxa_user_channel = !!(p->nxp_flags & NXPF_USER_CHANNEL); |
285 | nxa->nxa_max_frags = p->nxp_max_frags; |
286 | nxa->nxa_reject_on_close = (p->nxp_reject_on_close != 0); |
287 | nxa->nxa_large_buf_size = p->nxp_large_buf_size; |
288 | } |
289 | |
290 | __attribute__((always_inline)) |
291 | static inline int |
292 | __nexus_provider_reg_prepare(struct nxprov_reg *reg, const uint8_t *__null_terminated name, |
293 | const nexus_type_t type, const nexus_attr_t nxa) |
294 | { |
295 | struct nxprov_params *p = ®->nxpreg_params; |
296 | int err = 0; |
297 | |
298 | bzero(s: reg, n: sizeof(*reg)); |
299 | reg->nxpreg_version = NXPROV_REG_CURRENT_VERSION; |
300 | p->nxp_namelen = (uint32_t)strlcpy(dst: (char *)p->nxp_name, |
301 | src: (const char *__null_terminated)name, n: sizeof(nexus_name_t)); |
302 | if (p->nxp_namelen == 0) { |
303 | err = EINVAL; |
304 | goto done; |
305 | } |
306 | p->nxp_type = type; |
307 | if (nxa != NULL) { |
308 | if (nxa->nxa_requested & NXA_REQ_TX_RINGS) { |
309 | reg->nxpreg_requested |= NXPREQ_TX_RINGS; |
310 | p->nxp_tx_rings = (uint32_t)nxa->nxa_tx_rings; |
311 | } |
312 | if (nxa->nxa_requested & NXA_REQ_RX_RINGS) { |
313 | reg->nxpreg_requested |= NXPREQ_RX_RINGS; |
314 | p->nxp_rx_rings = (uint32_t)nxa->nxa_rx_rings; |
315 | } |
316 | if (nxa->nxa_requested & NXA_REQ_TX_SLOTS) { |
317 | reg->nxpreg_requested |= NXPREQ_TX_SLOTS; |
318 | p->nxp_tx_slots = (uint32_t)nxa->nxa_tx_slots; |
319 | } |
320 | if (nxa->nxa_requested & NXA_REQ_RX_SLOTS) { |
321 | reg->nxpreg_requested |= NXPREQ_RX_SLOTS; |
322 | p->nxp_rx_slots = (uint32_t)nxa->nxa_rx_slots; |
323 | } |
324 | if (nxa->nxa_requested & NXA_REQ_BUF_SIZE) { |
325 | reg->nxpreg_requested |= NXPREQ_BUF_SIZE; |
326 | p->nxp_buf_size = (uint32_t)nxa->nxa_buf_size; |
327 | } |
328 | if (nxa->nxa_requested & NXA_REQ_ANONYMOUS) { |
329 | reg->nxpreg_requested |= NXPREQ_ANONYMOUS; |
330 | if (nxa->nxa_anonymous != 0) { |
331 | p->nxp_flags |= NXPF_ANONYMOUS; |
332 | } else { |
333 | p->nxp_flags &= (uint32_t)~NXPF_ANONYMOUS; |
334 | } |
335 | } |
336 | if (nxa->nxa_requested & NXA_REQ_PIPES) { |
337 | reg->nxpreg_requested |= NXPREQ_PIPES; |
338 | p->nxp_pipes = (uint32_t)nxa->nxa_pipes; |
339 | } |
340 | if (nxa->nxa_requested & NXA_REQ_EXTENSIONS) { |
341 | reg->nxpreg_requested |= NXPREQ_EXTENSIONS; |
342 | p->nxp_extensions = (uint32_t)nxa->nxa_extensions; |
343 | } |
344 | if (nxa->nxa_requested & NXA_REQ_MHINTS) { |
345 | reg->nxpreg_requested |= NXPREQ_MHINTS; |
346 | p->nxp_mhints = (uint32_t)nxa->nxa_mhints; |
347 | } |
348 | if (nxa->nxa_requested & NXA_REQ_QMAP) { |
349 | if (type != NEXUS_TYPE_NET_IF) { |
350 | err = EINVAL; |
351 | goto done; |
352 | } |
353 | if ((nxa->nxa_qmap == NEXUS_QMAP_TYPE_WMM) && |
354 | (reg->nxpreg_params.nxp_tx_rings != |
355 | NEXUS_NUM_WMM_QUEUES)) { |
356 | err = EINVAL; |
357 | goto done; |
358 | } |
359 | reg->nxpreg_requested |= NXPREQ_QMAP; |
360 | p->nxp_qmap = (uint32_t)nxa->nxa_qmap; |
361 | } |
362 | if (nxa->nxa_requested & NXA_REQ_IFINDEX) { |
363 | if (type != NEXUS_TYPE_NET_IF) { |
364 | err = EINVAL; |
365 | goto done; |
366 | } |
367 | reg->nxpreg_requested |= NXPREQ_IFINDEX; |
368 | p->nxp_ifindex = (uint32_t)nxa->nxa_ifindex; |
369 | } |
370 | if (nxa->nxa_requested & NXA_REQ_USER_CHANNEL) { |
371 | reg->nxpreg_requested |= NXPREQ_USER_CHANNEL; |
372 | if (nxa->nxa_user_channel != 0) { |
373 | p->nxp_flags |= NXPF_USER_CHANNEL; |
374 | } else { |
375 | p->nxp_flags &= (uint32_t)~NXPF_USER_CHANNEL; |
376 | } |
377 | } |
378 | if (nxa->nxa_requested & NXA_REQ_MAX_FRAGS) { |
379 | if ((type != NEXUS_TYPE_NET_IF) && |
380 | (type != NEXUS_TYPE_FLOW_SWITCH)) { |
381 | err = EINVAL; |
382 | goto done; |
383 | } |
384 | reg->nxpreg_requested |= NXPREQ_MAX_FRAGS; |
385 | p->nxp_max_frags = (uint32_t)nxa->nxa_max_frags; |
386 | } |
387 | if (nxa->nxa_requested & NXA_REQ_REJECT_ON_CLOSE) { |
388 | if (type != NEXUS_TYPE_USER_PIPE) { |
389 | err = EINVAL; |
390 | goto done; |
391 | } |
392 | reg->nxpreg_requested |= NXPREQ_REJECT_ON_CLOSE; |
393 | p->nxp_reject_on_close = |
394 | (nxa->nxa_reject_on_close != 0); |
395 | } |
396 | if (nxa->nxa_requested & NXA_REQ_LARGE_BUF_SIZE) { |
397 | reg->nxpreg_requested |= NXPREQ_LARGE_BUF_SIZE; |
398 | p->nxp_large_buf_size = |
399 | (uint32_t)nxa->nxa_large_buf_size; |
400 | } |
401 | } |
402 | done: |
403 | return err; |
404 | } |
405 | |
406 | __attribute__((always_inline)) |
407 | static inline void |
408 | __nexus_bind_req_prepare(struct nx_bind_req *nbr, const uuid_t nx_uuid, |
409 | const nexus_port_t port, const pid_t pid, const uuid_t exec_uuid, |
410 | const void *key, const uint32_t key_len, const uint32_t bind_flags) |
411 | { |
412 | bzero(s: nbr, n: sizeof(*nbr)); |
413 | if (nx_uuid != NULL) { |
414 | bcopy(src: nx_uuid, dst: nbr->nb_nx_uuid, n: sizeof(uuid_t)); |
415 | } |
416 | if (exec_uuid != NULL) { |
417 | bcopy(src: exec_uuid, dst: nbr->nb_exec_uuid, n: sizeof(uuid_t)); |
418 | } |
419 | nbr->nb_port = port; |
420 | nbr->nb_pid = pid; |
421 | if (bind_flags & NEXUS_BIND_PID) { |
422 | nbr->nb_flags |= NBR_MATCH_PID; |
423 | } |
424 | if (bind_flags & NEXUS_BIND_EXEC_UUID) { |
425 | nbr->nb_flags |= NBR_MATCH_EXEC_UUID; |
426 | } |
427 | if (bind_flags & NEXUS_BIND_KEY) { |
428 | nbr->nb_flags |= NBR_MATCH_KEY; |
429 | nbr->nb_key = (user_addr_t)key; |
430 | nbr->nb_key_len = key_len; |
431 | } |
432 | } |
433 | |
434 | __attribute__((always_inline)) |
435 | static inline void |
436 | __nexus_unbind_req_prepare(struct nx_unbind_req *nbu, const uuid_t nx_uuid, |
437 | const nexus_port_t port) |
438 | { |
439 | bzero(s: nbu, n: sizeof(*nbu)); |
440 | if (nx_uuid != NULL) { |
441 | bcopy(src: nx_uuid, dst: nbu->nu_nx_uuid, n: sizeof(uuid_t)); |
442 | } |
443 | nbu->nu_port = port; |
444 | } |
445 | |
446 | __attribute__((always_inline)) |
447 | static inline void |
448 | __nexus_config_req_prepare(struct nx_cfg_req *ncr, const uuid_t nx_uuid, |
449 | const nxcfg_cmd_t cmd, const void *arg, const size_t arg_len) |
450 | { |
451 | VERIFY(arg_len <= UINT32_MAX); |
452 | bzero(s: ncr, n: sizeof(*ncr)); |
453 | if (nx_uuid != NULL) { |
454 | bcopy(src: nx_uuid, dst: ncr->nc_nx_uuid, n: sizeof(uuid_t)); |
455 | } |
456 | ncr->nc_cmd = cmd; |
457 | ncr->nc_req_len = (uint32_t)arg_len; |
458 | ncr->nc_req = (user_addr_t)arg; |
459 | } |
460 | |
461 | #endif /* PRIVATE || BSD_KERNEL_PRIVATE */ |
462 | #endif /* !_SKYWALK_NEXUS_COMMON_H_ */ |
463 | |