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_FLOWADV_MAX:
135 case NEXUS_ATTR_STATS_SIZE:
136 case NEXUS_ATTR_SLOT_META_SIZE:
137 case NEXUS_ATTR_CHECKSUM_OFFLOAD:
138 case NEXUS_ATTR_USER_PACKET_POOL:
139 case NEXUS_ATTR_ADV_SIZE:
140 err = ENOTSUP;
141 break;
142
143 default:
144 err = EINVAL;
145 break;
146 }
147
148 return err;
149 }
150
151 __attribute__((always_inline))
152 static inline int
__nexus_attr_get(const nexus_attr_t nxa,const nexus_attr_type_t type,uint64_t * value)153 __nexus_attr_get(const nexus_attr_t nxa, const nexus_attr_type_t type,
154 uint64_t *value)
155 {
156 int err = 0;
157
158 if (nxa == NULL || value == NULL) {
159 return EINVAL;
160 }
161
162 switch (type) {
163 case NEXUS_ATTR_TX_RINGS:
164 *value = nxa->nxa_tx_rings;
165 break;
166
167 case NEXUS_ATTR_RX_RINGS:
168 *value = nxa->nxa_rx_rings;
169 break;
170
171 case NEXUS_ATTR_TX_SLOTS:
172 *value = nxa->nxa_tx_slots;
173 break;
174
175 case NEXUS_ATTR_RX_SLOTS:
176 *value = nxa->nxa_rx_slots;
177 break;
178
179 case NEXUS_ATTR_SLOT_BUF_SIZE:
180 *value = nxa->nxa_buf_size;
181 break;
182
183 case NEXUS_ATTR_SLOT_META_SIZE:
184 *value = nxa->nxa_meta_size;
185 break;
186
187 case NEXUS_ATTR_STATS_SIZE:
188 *value = nxa->nxa_stats_size;
189 break;
190
191 case NEXUS_ATTR_FLOWADV_MAX:
192 *value = nxa->nxa_flowadv_max;
193 break;
194
195 case NEXUS_ATTR_ANONYMOUS:
196 *value = nxa->nxa_anonymous;
197 break;
198
199 case NEXUS_ATTR_PIPES:
200 *value = nxa->nxa_pipes;
201 break;
202
203 case NEXUS_ATTR_EXTENSIONS:
204 *value = nxa->nxa_extensions;
205 break;
206
207 case NEXUS_ATTR_MHINTS:
208 *value = nxa->nxa_mhints;
209 break;
210
211 case NEXUS_ATTR_IFINDEX:
212 *value = nxa->nxa_ifindex;
213 break;
214
215 case NEXUS_ATTR_QMAP:
216 *value = nxa->nxa_qmap;
217 break;
218
219 case NEXUS_ATTR_CHECKSUM_OFFLOAD:
220 *value = nxa->nxa_checksum_offload;
221 break;
222
223 case NEXUS_ATTR_USER_PACKET_POOL:
224 *value = nxa->nxa_user_packet_pool;
225 break;
226
227 case NEXUS_ATTR_ADV_SIZE:
228 *value = nxa->nxa_nexusadv_size;
229 break;
230
231 case NEXUS_ATTR_USER_CHANNEL:
232 *value = nxa->nxa_user_channel;
233 break;
234
235 case NEXUS_ATTR_MAX_FRAGS:
236 *value = nxa->nxa_max_frags;
237 break;
238
239 case NEXUS_ATTR_REJECT_ON_CLOSE:
240 *value = nxa->nxa_reject_on_close;
241 break;
242
243 default:
244 err = EINVAL;
245 break;
246 }
247
248 return err;
249 }
250
251 __attribute__((always_inline))
252 static inline void
__nexus_attr_from_params(nexus_attr_t nxa,const struct nxprov_params * p)253 __nexus_attr_from_params(nexus_attr_t nxa, const struct nxprov_params *p)
254 {
255 bzero(nxa, sizeof(*nxa));
256 nxa->nxa_tx_rings = p->nxp_tx_rings;
257 nxa->nxa_rx_rings = p->nxp_rx_rings;
258 nxa->nxa_tx_slots = p->nxp_tx_slots;
259 nxa->nxa_rx_slots = p->nxp_rx_slots;
260 nxa->nxa_buf_size = p->nxp_buf_size;
261 nxa->nxa_meta_size = p->nxp_meta_size;
262 nxa->nxa_stats_size = p->nxp_stats_size;
263 nxa->nxa_flowadv_max = p->nxp_flowadv_max;
264 nxa->nxa_anonymous = !!(p->nxp_flags & NXPF_ANONYMOUS);
265 nxa->nxa_pipes = p->nxp_pipes;
266 nxa->nxa_extensions = p->nxp_extensions;
267 nxa->nxa_mhints = p->nxp_mhints;
268 nxa->nxa_ifindex = p->nxp_ifindex;
269 nxa->nxa_qmap = p->nxp_qmap;
270 nxa->nxa_checksum_offload = (p->nxp_capabilities &
271 NXPCAP_CHECKSUM_PARTIAL) ? 1 : 0;
272 nxa->nxa_user_packet_pool = (p->nxp_capabilities &
273 NXPCAP_USER_PACKET_POOL) ? 1 : 0;
274 nxa->nxa_nexusadv_size = p->nxp_nexusadv_size;
275 nxa->nxa_user_channel = !!(p->nxp_flags & NXPF_USER_CHANNEL);
276 nxa->nxa_max_frags = p->nxp_max_frags;
277 nxa->nxa_reject_on_close = (p->nxp_reject_on_close != 0);
278 }
279
280 __attribute__((always_inline))
281 static inline int
__nexus_provider_reg_prepare(struct nxprov_reg * reg,const nexus_name_t name,const nexus_type_t type,const nexus_attr_t nxa)282 __nexus_provider_reg_prepare(struct nxprov_reg *reg, const nexus_name_t name,
283 const nexus_type_t type, const nexus_attr_t nxa)
284 {
285 struct nxprov_params *p = ®->nxpreg_params;
286 int err = 0;
287
288 bzero(reg, sizeof(*reg));
289 reg->nxpreg_version = NXPROV_REG_CURRENT_VERSION;
290 p->nxp_namelen = (uint32_t)strlcpy((char *)p->nxp_name,
291 (const char *)name, sizeof(nexus_name_t));
292 if (p->nxp_namelen == 0) {
293 err = EINVAL;
294 goto done;
295 }
296 p->nxp_type = type;
297 if (nxa != NULL) {
298 if (nxa->nxa_requested & NXA_REQ_TX_RINGS) {
299 reg->nxpreg_requested |= NXPREQ_TX_RINGS;
300 p->nxp_tx_rings = (uint32_t)nxa->nxa_tx_rings;
301 }
302 if (nxa->nxa_requested & NXA_REQ_RX_RINGS) {
303 reg->nxpreg_requested |= NXPREQ_RX_RINGS;
304 p->nxp_rx_rings = (uint32_t)nxa->nxa_rx_rings;
305 }
306 if (nxa->nxa_requested & NXA_REQ_TX_SLOTS) {
307 reg->nxpreg_requested |= NXPREQ_TX_SLOTS;
308 p->nxp_tx_slots = (uint32_t)nxa->nxa_tx_slots;
309 }
310 if (nxa->nxa_requested & NXA_REQ_RX_SLOTS) {
311 reg->nxpreg_requested |= NXPREQ_RX_SLOTS;
312 p->nxp_rx_slots = (uint32_t)nxa->nxa_rx_slots;
313 }
314 if (nxa->nxa_requested & NXA_REQ_BUF_SIZE) {
315 reg->nxpreg_requested |= NXPREQ_BUF_SIZE;
316 p->nxp_buf_size = (uint32_t)nxa->nxa_buf_size;
317 }
318 if (nxa->nxa_requested & NXA_REQ_ANONYMOUS) {
319 reg->nxpreg_requested |= NXPREQ_ANONYMOUS;
320 if (nxa->nxa_anonymous != 0) {
321 p->nxp_flags |= NXPF_ANONYMOUS;
322 } else {
323 p->nxp_flags &= (uint32_t)~NXPF_ANONYMOUS;
324 }
325 }
326 if (nxa->nxa_requested & NXA_REQ_PIPES) {
327 reg->nxpreg_requested |= NXPREQ_PIPES;
328 p->nxp_pipes = (uint32_t)nxa->nxa_pipes;
329 }
330 if (nxa->nxa_requested & NXA_REQ_EXTENSIONS) {
331 reg->nxpreg_requested |= NXPREQ_EXTENSIONS;
332 p->nxp_extensions = (uint32_t)nxa->nxa_extensions;
333 }
334 if (nxa->nxa_requested & NXA_REQ_MHINTS) {
335 reg->nxpreg_requested |= NXPREQ_MHINTS;
336 p->nxp_mhints = (uint32_t)nxa->nxa_mhints;
337 }
338 if (nxa->nxa_requested & NXA_REQ_QMAP) {
339 if (type != NEXUS_TYPE_NET_IF) {
340 err = EINVAL;
341 goto done;
342 }
343 if ((nxa->nxa_qmap == NEXUS_QMAP_TYPE_WMM) &&
344 (reg->nxpreg_params.nxp_tx_rings !=
345 NEXUS_NUM_WMM_QUEUES)) {
346 err = EINVAL;
347 goto done;
348 }
349 reg->nxpreg_requested |= NXPREQ_QMAP;
350 p->nxp_qmap = (uint32_t)nxa->nxa_qmap;
351 }
352 if (nxa->nxa_requested & NXA_REQ_IFINDEX) {
353 if (type != NEXUS_TYPE_NET_IF) {
354 err = EINVAL;
355 goto done;
356 }
357 reg->nxpreg_requested |= NXPREQ_IFINDEX;
358 p->nxp_ifindex = (uint32_t)nxa->nxa_ifindex;
359 }
360 if (nxa->nxa_requested & NXA_REQ_USER_CHANNEL) {
361 reg->nxpreg_requested |= NXPREQ_USER_CHANNEL;
362 if (nxa->nxa_user_channel != 0) {
363 p->nxp_flags |= NXPF_USER_CHANNEL;
364 } else {
365 p->nxp_flags &= (uint32_t)~NXPF_USER_CHANNEL;
366 }
367 }
368 if (nxa->nxa_requested & NXA_REQ_MAX_FRAGS) {
369 if ((type != NEXUS_TYPE_NET_IF) &&
370 (type != NEXUS_TYPE_FLOW_SWITCH)) {
371 err = EINVAL;
372 goto done;
373 }
374 reg->nxpreg_requested |= NXPREQ_MAX_FRAGS;
375 p->nxp_max_frags = (uint32_t)nxa->nxa_max_frags;
376 }
377 if (nxa->nxa_requested & NXA_REQ_REJECT_ON_CLOSE) {
378 if (type != NEXUS_TYPE_USER_PIPE) {
379 err = EINVAL;
380 goto done;
381 }
382 reg->nxpreg_requested |= NXPREQ_REJECT_ON_CLOSE;
383 p->nxp_reject_on_close =
384 (nxa->nxa_reject_on_close != 0);
385 }
386 }
387 done:
388 return err;
389 }
390
391 __attribute__((always_inline))
392 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)393 __nexus_bind_req_prepare(struct nx_bind_req *nbr, const uuid_t nx_uuid,
394 const nexus_port_t port, const pid_t pid, const uuid_t exec_uuid,
395 const void *key, const uint32_t key_len, const uint32_t bind_flags)
396 {
397 bzero(nbr, sizeof(*nbr));
398 if (nx_uuid != NULL) {
399 bcopy(nx_uuid, nbr->nb_nx_uuid, sizeof(uuid_t));
400 }
401 if (exec_uuid != NULL) {
402 bcopy(exec_uuid, nbr->nb_exec_uuid, sizeof(uuid_t));
403 }
404 nbr->nb_port = port;
405 nbr->nb_pid = pid;
406 if (bind_flags & NEXUS_BIND_PID) {
407 nbr->nb_flags |= NBR_MATCH_PID;
408 }
409 if (bind_flags & NEXUS_BIND_EXEC_UUID) {
410 nbr->nb_flags |= NBR_MATCH_EXEC_UUID;
411 }
412 if (bind_flags & NEXUS_BIND_KEY) {
413 nbr->nb_flags |= NBR_MATCH_KEY;
414 nbr->nb_key = (user_addr_t)key;
415 nbr->nb_key_len = key_len;
416 }
417 }
418
419 __attribute__((always_inline))
420 static inline void
__nexus_unbind_req_prepare(struct nx_unbind_req * nbu,const uuid_t nx_uuid,const nexus_port_t port)421 __nexus_unbind_req_prepare(struct nx_unbind_req *nbu, const uuid_t nx_uuid,
422 const nexus_port_t port)
423 {
424 bzero(nbu, sizeof(*nbu));
425 if (nx_uuid != NULL) {
426 bcopy(nx_uuid, nbu->nu_nx_uuid, sizeof(uuid_t));
427 }
428 nbu->nu_port = port;
429 }
430
431 __attribute__((always_inline))
432 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)433 __nexus_config_req_prepare(struct nx_cfg_req *ncr, const uuid_t nx_uuid,
434 const nxcfg_cmd_t cmd, const void *arg, const size_t arg_len)
435 {
436 VERIFY(arg_len <= UINT32_MAX);
437 bzero(ncr, sizeof(*ncr));
438 if (nx_uuid != NULL) {
439 bcopy(nx_uuid, ncr->nc_nx_uuid, sizeof(uuid_t));
440 }
441 ncr->nc_cmd = cmd;
442 ncr->nc_req_len = (uint32_t)arg_len;
443 ncr->nc_req = (user_addr_t)arg;
444 }
445
446 #endif /* PRIVATE || BSD_KERNEL_PRIVATE */
447 #endif /* !_SKYWALK_NEXUS_COMMON_H_ */
448