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
__nexus_attr_set(const nexus_attr_t nxa,const nexus_attr_type_t type,const uint64_t value)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
__nexus_attr_get(const nexus_attr_t nxa,const nexus_attr_type_t type,uint64_t * value)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
__nexus_attr_from_params(nexus_attr_t nxa,const struct nxprov_params * p)262 __nexus_attr_from_params(nexus_attr_t nxa, const struct nxprov_params *p)
263 {
264 bzero(nxa, 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
__nexus_provider_reg_prepare(struct nxprov_reg * reg,const uint8_t * __null_terminated name,const nexus_type_t type,const nexus_attr_t nxa)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(reg, sizeof(*reg));
299 reg->nxpreg_version = NXPROV_REG_CURRENT_VERSION;
300 p->nxp_namelen = (uint32_t)strlcpy((char *)p->nxp_name,
301 (const char *__null_terminated)name, 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
__nexus_bind_req_prepare(struct nx_bind_req * nbr,const uuid_t nx_uuid,const nexus_port_t port,const pid_t pid,const uuid_t exec_uuid,const void * key,const uint32_t key_len,const uint32_t bind_flags)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(nbr, sizeof(*nbr));
413 if (nx_uuid != NULL) {
414 bcopy(nx_uuid, nbr->nb_nx_uuid, sizeof(uuid_t));
415 }
416 if (exec_uuid != NULL) {
417 bcopy(exec_uuid, nbr->nb_exec_uuid, 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
__nexus_unbind_req_prepare(struct nx_unbind_req * nbu,const uuid_t nx_uuid,const nexus_port_t port)436 __nexus_unbind_req_prepare(struct nx_unbind_req *nbu, const uuid_t nx_uuid,
437 const nexus_port_t port)
438 {
439 bzero(nbu, sizeof(*nbu));
440 if (nx_uuid != NULL) {
441 bcopy(nx_uuid, nbu->nu_nx_uuid, sizeof(uuid_t));
442 }
443 nbu->nu_port = port;
444 }
445
446 __attribute__((always_inline))
447 static inline void
__nexus_config_req_prepare(struct nx_cfg_req * ncr,const uuid_t nx_uuid,const nxcfg_cmd_t cmd,const void * arg,const size_t arg_len)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(ncr, sizeof(*ncr));
453 if (nx_uuid != NULL) {
454 bcopy(nx_uuid, ncr->nc_nx_uuid, 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