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))
49static 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))
157static 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))
261static 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))
291static 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 = &reg->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 }
402done:
403 return err;
404}
405
406__attribute__((always_inline))
407static 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))
435static 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))
447static 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