1 /*
2 * Copyright (C) 2014-2018 Giuseppe Lettieri
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 /* $FreeBSD$ */
28
29 #if defined(__FreeBSD__)
30 #include <sys/cdefs.h> /* prerequisite */
31
32 #include <sys/types.h>
33 #include <sys/errno.h>
34 #include <sys/param.h> /* defines used in kernel.h */
35 #include <sys/kernel.h> /* types used in module initialization */
36 #include <sys/malloc.h>
37 #include <sys/poll.h>
38 #include <sys/lock.h>
39 #include <sys/rwlock.h>
40 #include <sys/selinfo.h>
41 #include <sys/sysctl.h>
42 #include <sys/socket.h> /* sockaddrs */
43 #include <net/if.h>
44 #include <net/if_var.h>
45 #include <machine/bus.h> /* bus_dmamap_* */
46 #include <sys/refcount.h>
47
48
49 #elif defined(linux)
50
51 #include "bsd_glue.h"
52
53 #elif defined(__APPLE__)
54
55 #warning OSX support is only partial
56 #include "osx_glue.h"
57
58 #elif defined(_WIN32)
59 #include "win_glue.h"
60
61 #else
62
63 #error Unsupported platform
64
65 #endif /* unsupported */
66
67 /*
68 * common headers
69 */
70
71 #include <net/netmap.h>
72 #include <dev/netmap/netmap_kern.h>
73 #include <dev/netmap/netmap_mem2.h>
74
75 #ifdef WITH_PIPES
76
77 #define NM_PIPE_MAXSLOTS 4096
78 #define NM_PIPE_MAXRINGS 256
79
80 static int netmap_default_pipes = 0; /* ignored, kept for compatibility */
81 SYSBEGIN(vars_pipes);
82 SYSCTL_DECL(_dev_netmap);
83 SYSCTL_INT(_dev_netmap, OID_AUTO, default_pipes, CTLFLAG_RW,
84 &netmap_default_pipes, 0, "For compatibility only");
85 SYSEND;
86
87 /* allocate the pipe array in the parent adapter */
88 static int
nm_pipe_alloc(struct netmap_adapter * na,u_int npipes)89 nm_pipe_alloc(struct netmap_adapter *na, u_int npipes)
90 {
91 size_t old_len, len;
92 struct netmap_pipe_adapter **npa;
93
94 if (npipes <= na->na_max_pipes)
95 /* we already have more entries that requested */
96 return 0;
97
98 if (npipes < na->na_next_pipe || npipes > NM_MAXPIPES)
99 return EINVAL;
100
101 old_len = sizeof(struct netmap_pipe_adapter *)*na->na_max_pipes;
102 len = sizeof(struct netmap_pipe_adapter *) * npipes;
103 npa = nm_os_realloc(na->na_pipes, len, old_len);
104 if (npa == NULL)
105 return ENOMEM;
106
107 na->na_pipes = npa;
108 na->na_max_pipes = npipes;
109
110 return 0;
111 }
112
113 /* deallocate the parent array in the parent adapter */
114 void
netmap_pipe_dealloc(struct netmap_adapter * na)115 netmap_pipe_dealloc(struct netmap_adapter *na)
116 {
117 if (na->na_pipes) {
118 if (na->na_next_pipe > 0) {
119 nm_prerr("freeing not empty pipe array for %s (%d dangling pipes)!",
120 na->name, na->na_next_pipe);
121 }
122 nm_os_free(na->na_pipes);
123 na->na_pipes = NULL;
124 na->na_max_pipes = 0;
125 na->na_next_pipe = 0;
126 }
127 }
128
129 /* find a pipe endpoint with the given id among the parent's pipes */
130 static struct netmap_pipe_adapter *
netmap_pipe_find(struct netmap_adapter * parent,const char * pipe_id)131 netmap_pipe_find(struct netmap_adapter *parent, const char *pipe_id)
132 {
133 int i;
134 struct netmap_pipe_adapter *na;
135
136 for (i = 0; i < parent->na_next_pipe; i++) {
137 const char *na_pipe_id;
138 na = parent->na_pipes[i];
139 na_pipe_id = strrchr(na->up.name,
140 na->role == NM_PIPE_ROLE_MASTER ? '{' : '}');
141 KASSERT(na_pipe_id != NULL, ("Invalid pipe name"));
142 ++na_pipe_id;
143 if (!strcmp(na_pipe_id, pipe_id)) {
144 return na;
145 }
146 }
147 return NULL;
148 }
149
150 /* add a new pipe endpoint to the parent array */
151 static int
netmap_pipe_add(struct netmap_adapter * parent,struct netmap_pipe_adapter * na)152 netmap_pipe_add(struct netmap_adapter *parent, struct netmap_pipe_adapter *na)
153 {
154 if (parent->na_next_pipe >= parent->na_max_pipes) {
155 u_int npipes = parent->na_max_pipes ? 2*parent->na_max_pipes : 2;
156 int error = nm_pipe_alloc(parent, npipes);
157 if (error)
158 return error;
159 }
160
161 parent->na_pipes[parent->na_next_pipe] = na;
162 na->parent_slot = parent->na_next_pipe;
163 parent->na_next_pipe++;
164 return 0;
165 }
166
167 /* remove the given pipe endpoint from the parent array */
168 static void
netmap_pipe_remove(struct netmap_adapter * parent,struct netmap_pipe_adapter * na)169 netmap_pipe_remove(struct netmap_adapter *parent, struct netmap_pipe_adapter *na)
170 {
171 u_int n;
172 n = --parent->na_next_pipe;
173 if (n != na->parent_slot) {
174 struct netmap_pipe_adapter **p =
175 &parent->na_pipes[na->parent_slot];
176 *p = parent->na_pipes[n];
177 (*p)->parent_slot = na->parent_slot;
178 }
179 parent->na_pipes[n] = NULL;
180 }
181
182 int
netmap_pipe_txsync(struct netmap_kring * txkring,int flags)183 netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
184 {
185 struct netmap_kring *rxkring = txkring->pipe;
186 u_int k, lim = txkring->nkr_num_slots - 1, nk;
187 int m; /* slots to transfer */
188 int complete; /* did we see a complete packet ? */
189 struct netmap_ring *txring = txkring->ring, *rxring = rxkring->ring;
190
191 nm_prdis("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name);
192 nm_prdis(20, "TX before: hwcur %d hwtail %d cur %d head %d tail %d",
193 txkring->nr_hwcur, txkring->nr_hwtail,
194 txkring->rcur, txkring->rhead, txkring->rtail);
195
196 /* update the hwtail */
197 txkring->nr_hwtail = txkring->pipe_tail;
198
199 m = txkring->rhead - txkring->nr_hwcur; /* new slots */
200 if (m < 0)
201 m += txkring->nkr_num_slots;
202
203 if (m == 0) {
204 /* nothing to send */
205 return 0;
206 }
207
208 for (k = txkring->nr_hwcur, nk = lim + 1, complete = 0; m;
209 m--, k = nm_next(k, lim), nk = (complete ? k : nk)) {
210 struct netmap_slot *rs = &rxring->slot[k];
211 struct netmap_slot *ts = &txring->slot[k];
212
213 *rs = *ts;
214 if (ts->flags & NS_BUF_CHANGED) {
215 ts->flags &= ~NS_BUF_CHANGED;
216 }
217 complete = !(ts->flags & NS_MOREFRAG);
218 }
219
220 txkring->nr_hwcur = k;
221
222 nm_prdis(20, "TX after : hwcur %d hwtail %d cur %d head %d tail %d k %d",
223 txkring->nr_hwcur, txkring->nr_hwtail,
224 txkring->rcur, txkring->rhead, txkring->rtail, k);
225
226 if (likely(nk <= lim)) {
227 mb(); /* make sure the slots are updated before publishing them */
228 rxkring->pipe_tail = nk; /* only publish complete packets */
229 rxkring->nm_notify(rxkring, 0);
230 }
231
232 return 0;
233 }
234
235 int
netmap_pipe_rxsync(struct netmap_kring * rxkring,int flags)236 netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags)
237 {
238 struct netmap_kring *txkring = rxkring->pipe;
239 u_int k, lim = rxkring->nkr_num_slots - 1;
240 int m; /* slots to release */
241 struct netmap_ring *txring = txkring->ring, *rxring = rxkring->ring;
242
243 nm_prdis("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name);
244 nm_prdis(20, "RX before: hwcur %d hwtail %d cur %d head %d tail %d",
245 rxkring->nr_hwcur, rxkring->nr_hwtail,
246 rxkring->rcur, rxkring->rhead, rxkring->rtail);
247
248 /* update the hwtail */
249 rxkring->nr_hwtail = rxkring->pipe_tail;
250
251 m = rxkring->rhead - rxkring->nr_hwcur; /* released slots */
252 if (m < 0)
253 m += rxkring->nkr_num_slots;
254
255 if (m == 0) {
256 /* nothing to release */
257 return 0;
258 }
259
260 for (k = rxkring->nr_hwcur; m; m--, k = nm_next(k, lim)) {
261 struct netmap_slot *rs = &rxring->slot[k];
262 struct netmap_slot *ts = &txring->slot[k];
263
264 if (rs->flags & NS_BUF_CHANGED) {
265 /* copy the slot and report the buffer change */
266 *ts = *rs;
267 rs->flags &= ~NS_BUF_CHANGED;
268 }
269 }
270
271 mb(); /* make sure the slots are updated before publishing them */
272 txkring->pipe_tail = nm_prev(k, lim);
273 rxkring->nr_hwcur = k;
274
275 nm_prdis(20, "RX after : hwcur %d hwtail %d cur %d head %d tail %d k %d",
276 rxkring->nr_hwcur, rxkring->nr_hwtail,
277 rxkring->rcur, rxkring->rhead, rxkring->rtail, k);
278
279 txkring->nm_notify(txkring, 0);
280
281 return 0;
282 }
283
284 /* Pipe endpoints are created and destroyed together, so that endopoints do not
285 * have to check for the existence of their peer at each ?xsync.
286 *
287 * To play well with the existing netmap infrastructure (refcounts etc.), we
288 * adopt the following strategy:
289 *
290 * 1) The first endpoint that is created also creates the other endpoint and
291 * grabs a reference to it.
292 *
293 * state A) user1 --> endpoint1 --> endpoint2
294 *
295 * 2) If, starting from state A, endpoint2 is then registered, endpoint1 gives
296 * its reference to the user:
297 *
298 * state B) user1 --> endpoint1 endpoint2 <--- user2
299 *
300 * 3) Assume that, starting from state B endpoint2 is closed. In the unregister
301 * callback endpoint2 notes that endpoint1 is still active and adds a reference
302 * from endpoint1 to itself. When user2 then releases her own reference,
303 * endpoint2 is not destroyed and we are back to state A. A symmetrical state
304 * would be reached if endpoint1 were released instead.
305 *
306 * 4) If, starting from state A, endpoint1 is closed, the destructor notes that
307 * it owns a reference to endpoint2 and releases it.
308 *
309 * Something similar goes on for the creation and destruction of the krings.
310 */
311
312
netmap_pipe_krings_create_both(struct netmap_adapter * na,struct netmap_adapter * ona)313 int netmap_pipe_krings_create_both(struct netmap_adapter *na,
314 struct netmap_adapter *ona)
315 {
316 enum txrx t;
317 int error;
318 int i;
319
320 /* case 1) below */
321 nm_prdis("%p: case 1, create both ends", na);
322 error = netmap_krings_create(na, 0);
323 if (error)
324 return error;
325
326 /* create the krings of the other end */
327 error = netmap_krings_create(ona, 0);
328 if (error)
329 goto del_krings1;
330
331 /* cross link the krings and initialize the pipe_tails */
332 for_rx_tx(t) {
333 enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
334 for (i = 0; i < nma_get_nrings(na, t); i++) {
335 struct netmap_kring *k1 = NMR(na, t)[i],
336 *k2 = NMR(ona, r)[i];
337 k1->pipe = k2;
338 k2->pipe = k1;
339 /* mark all peer-adapter rings as fake */
340 k2->nr_kflags |= NKR_FAKERING;
341 /* init tails */
342 k1->pipe_tail = k1->nr_hwtail;
343 k2->pipe_tail = k2->nr_hwtail;
344 }
345 }
346
347 return 0;
348
349 del_krings1:
350 netmap_krings_delete(na);
351 return error;
352 }
353
354 /* netmap_pipe_krings_create.
355 *
356 * There are two cases:
357 *
358 * 1) state is
359 *
360 * usr1 --> e1 --> e2
361 *
362 * and we are e1. We have to create both sets
363 * of krings.
364 *
365 * 2) state is
366 *
367 * usr1 --> e1 --> e2
368 *
369 * and we are e2. e1 is certainly registered and our
370 * krings already exist. Nothing to do.
371 */
372 static int
netmap_pipe_krings_create(struct netmap_adapter * na)373 netmap_pipe_krings_create(struct netmap_adapter *na)
374 {
375 struct netmap_pipe_adapter *pna =
376 (struct netmap_pipe_adapter *)na;
377 struct netmap_adapter *ona = &pna->peer->up;
378
379 if (pna->peer_ref)
380 return netmap_pipe_krings_create_both(na, ona);
381
382 return 0;
383 }
384
385 int
netmap_pipe_reg_both(struct netmap_adapter * na,struct netmap_adapter * ona)386 netmap_pipe_reg_both(struct netmap_adapter *na, struct netmap_adapter *ona)
387 {
388 int i, error = 0;
389 enum txrx t;
390
391 for_rx_tx(t) {
392 for (i = 0; i < nma_get_nrings(na, t); i++) {
393 struct netmap_kring *kring = NMR(na, t)[i];
394
395 if (nm_kring_pending_on(kring)) {
396 /* mark the peer ring as needed */
397 kring->pipe->nr_kflags |= NKR_NEEDRING;
398 }
399 }
400 }
401
402 /* create all missing needed rings on the other end.
403 * Either our end, or the other, has been marked as
404 * fake, so the allocation will not be done twice.
405 */
406 error = netmap_mem_rings_create(ona);
407 if (error)
408 return error;
409
410 /* In case of no error we put our rings in netmap mode */
411 for_rx_tx(t) {
412 for (i = 0; i < nma_get_nrings(na, t); i++) {
413 struct netmap_kring *kring = NMR(na, t)[i];
414 if (nm_kring_pending_on(kring)) {
415 struct netmap_kring *sring, *dring;
416
417 kring->nr_mode = NKR_NETMAP_ON;
418 if ((kring->nr_kflags & NKR_FAKERING) &&
419 (kring->pipe->nr_kflags & NKR_FAKERING)) {
420 /* this is a re-open of a pipe
421 * end-point kept alive by the other end.
422 * We need to leave everything as it is
423 */
424 continue;
425 }
426
427 /* copy the buffers from the non-fake ring */
428 if (kring->nr_kflags & NKR_FAKERING) {
429 sring = kring->pipe;
430 dring = kring;
431 } else {
432 sring = kring;
433 dring = kring->pipe;
434 }
435 memcpy(dring->ring->slot,
436 sring->ring->slot,
437 sizeof(struct netmap_slot) *
438 sring->nkr_num_slots);
439 /* mark both rings as fake and needed,
440 * so that buffers will not be
441 * deleted by the standard machinery
442 * (we will delete them by ourselves in
443 * netmap_pipe_krings_delete)
444 */
445 sring->nr_kflags |=
446 (NKR_FAKERING | NKR_NEEDRING);
447 dring->nr_kflags |=
448 (NKR_FAKERING | NKR_NEEDRING);
449 kring->nr_mode = NKR_NETMAP_ON;
450 }
451 }
452 }
453
454 return 0;
455 }
456
457 /* netmap_pipe_reg.
458 *
459 * There are two cases on registration (onoff==1)
460 *
461 * 1.a) state is
462 *
463 * usr1 --> e1 --> e2
464 *
465 * and we are e1. Create the needed rings of the
466 * other end.
467 *
468 * 1.b) state is
469 *
470 * usr1 --> e1 --> e2 <-- usr2
471 *
472 * and we are e2. Drop the ref e1 is holding.
473 *
474 * There are two additional cases on unregister (onoff==0)
475 *
476 * 2.a) state is
477 *
478 * usr1 --> e1 --> e2
479 *
480 * and we are e1. Nothing special to do, e2 will
481 * be cleaned up by the destructor of e1.
482 *
483 * 2.b) state is
484 *
485 * usr1 --> e1 e2 <-- usr2
486 *
487 * and we are either e1 or e2. Add a ref from the
488 * other end.
489 */
490 static int
netmap_pipe_reg(struct netmap_adapter * na,int onoff)491 netmap_pipe_reg(struct netmap_adapter *na, int onoff)
492 {
493 struct netmap_pipe_adapter *pna =
494 (struct netmap_pipe_adapter *)na;
495 struct netmap_adapter *ona = &pna->peer->up;
496 int error = 0;
497
498 nm_prdis("%p: onoff %d", na, onoff);
499 if (onoff) {
500 error = netmap_pipe_reg_both(na, ona);
501 if (error) {
502 return error;
503 }
504 if (na->active_fds == 0)
505 na->na_flags |= NAF_NETMAP_ON;
506 } else {
507 if (na->active_fds == 0)
508 na->na_flags &= ~NAF_NETMAP_ON;
509 netmap_krings_mode_commit(na, onoff);
510 }
511
512 if (na->active_fds) {
513 nm_prdis("active_fds %d", na->active_fds);
514 return 0;
515 }
516
517 if (pna->peer_ref) {
518 nm_prdis("%p: case 1.a or 2.a, nothing to do", na);
519 return 0;
520 }
521 if (onoff) {
522 nm_prdis("%p: case 1.b, drop peer", na);
523 pna->peer->peer_ref = 0;
524 netmap_adapter_put(na);
525 } else {
526 nm_prdis("%p: case 2.b, grab peer", na);
527 netmap_adapter_get(na);
528 pna->peer->peer_ref = 1;
529 }
530 return error;
531 }
532
533 void
netmap_pipe_krings_delete_both(struct netmap_adapter * na,struct netmap_adapter * ona)534 netmap_pipe_krings_delete_both(struct netmap_adapter *na,
535 struct netmap_adapter *ona)
536 {
537 struct netmap_adapter *sna;
538 enum txrx t;
539 int i;
540
541 /* case 1) below */
542 nm_prdis("%p: case 1, deleting everything", na);
543 /* To avoid double-frees we zero-out all the buffers in the kernel part
544 * of each ring. The reason is this: If the user is behaving correctly,
545 * all buffers are found in exactly one slot in the userspace part of
546 * some ring. If the user is not behaving correctly, we cannot release
547 * buffers cleanly anyway. In the latter case, the allocator will
548 * return to a clean state only when all its users will close.
549 */
550 sna = na;
551 cleanup:
552 for_rx_tx(t) {
553 for (i = 0; i < nma_get_nrings(sna, t); i++) {
554 struct netmap_kring *kring = NMR(sna, t)[i];
555 struct netmap_ring *ring = kring->ring;
556 uint32_t j, lim = kring->nkr_num_slots - 1;
557
558 nm_prdis("%s ring %p hwtail %u hwcur %u",
559 kring->name, ring, kring->nr_hwtail, kring->nr_hwcur);
560
561 if (ring == NULL)
562 continue;
563
564 if (kring->tx == NR_RX)
565 ring->slot[kring->pipe_tail].buf_idx = 0;
566
567 for (j = nm_next(kring->pipe_tail, lim);
568 j != kring->nr_hwcur;
569 j = nm_next(j, lim))
570 {
571 nm_prdis("%s[%d] %u", kring->name, j, ring->slot[j].buf_idx);
572 ring->slot[j].buf_idx = 0;
573 }
574 kring->nr_kflags &= ~(NKR_FAKERING | NKR_NEEDRING);
575 }
576
577 }
578 if (sna != ona && ona->tx_rings) {
579 sna = ona;
580 goto cleanup;
581 }
582
583 netmap_mem_rings_delete(na);
584 netmap_krings_delete(na); /* also zeroes tx_rings etc. */
585
586 if (ona->tx_rings == NULL) {
587 /* already deleted, we must be on an
588 * cleanup-after-error path */
589 return;
590 }
591 netmap_mem_rings_delete(ona);
592 netmap_krings_delete(ona);
593 }
594
595 /* netmap_pipe_krings_delete.
596 *
597 * There are two cases:
598 *
599 * 1) state is
600 *
601 * usr1 --> e1 --> e2
602 *
603 * and we are e1 (e2 is not registered, so krings_delete cannot be
604 * called on it);
605 *
606 * 2) state is
607 *
608 * usr1 --> e1 e2 <-- usr2
609 *
610 * and we are either e1 or e2.
611 *
612 * In the former case we have to also delete the krings of e2;
613 * in the latter case we do nothing.
614 */
615 static void
netmap_pipe_krings_delete(struct netmap_adapter * na)616 netmap_pipe_krings_delete(struct netmap_adapter *na)
617 {
618 struct netmap_pipe_adapter *pna =
619 (struct netmap_pipe_adapter *)na;
620 struct netmap_adapter *ona; /* na of the other end */
621
622 if (!pna->peer_ref) {
623 nm_prdis("%p: case 2, kept alive by peer", na);
624 return;
625 }
626 ona = &pna->peer->up;
627 netmap_pipe_krings_delete_both(na, ona);
628 }
629
630
631 static void
netmap_pipe_dtor(struct netmap_adapter * na)632 netmap_pipe_dtor(struct netmap_adapter *na)
633 {
634 struct netmap_pipe_adapter *pna =
635 (struct netmap_pipe_adapter *)na;
636 nm_prdis("%p %p", na, pna->parent_ifp);
637 if (pna->peer_ref) {
638 nm_prdis("%p: clean up peer", na);
639 pna->peer_ref = 0;
640 netmap_adapter_put(&pna->peer->up);
641 }
642 if (pna->role == NM_PIPE_ROLE_MASTER)
643 netmap_pipe_remove(pna->parent, pna);
644 if (pna->parent_ifp)
645 if_rele(pna->parent_ifp);
646 netmap_adapter_put(pna->parent);
647 pna->parent = NULL;
648 }
649
650 int
netmap_get_pipe_na(struct nmreq_header * hdr,struct netmap_adapter ** na,struct netmap_mem_d * nmd,int create)651 netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
652 struct netmap_mem_d *nmd, int create)
653 {
654 struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body;
655 struct netmap_adapter *pna; /* parent adapter */
656 struct netmap_pipe_adapter *mna, *sna, *reqna;
657 struct ifnet *ifp = NULL;
658 const char *pipe_id = NULL;
659 int role = 0;
660 int error, retries = 0;
661 char *cbra;
662
663 /* Try to parse the pipe syntax 'xx{yy' or 'xx}yy'. */
664 cbra = strrchr(hdr->nr_name, '{');
665 if (cbra != NULL) {
666 role = NM_PIPE_ROLE_MASTER;
667 } else {
668 cbra = strrchr(hdr->nr_name, '}');
669 if (cbra != NULL) {
670 role = NM_PIPE_ROLE_SLAVE;
671 } else {
672 nm_prdis("not a pipe");
673 return 0;
674 }
675 }
676 pipe_id = cbra + 1;
677 if (*pipe_id == '\0' || cbra == hdr->nr_name) {
678 /* Bracket is the last character, so pipe name is missing;
679 * or bracket is the first character, so base port name
680 * is missing. */
681 return EINVAL;
682 }
683
684 if (req->nr_mode != NR_REG_ALL_NIC && req->nr_mode != NR_REG_ONE_NIC) {
685 /* We only accept modes involving hardware rings. */
686 return EINVAL;
687 }
688
689 /* first, try to find the parent adapter */
690 for (;;) {
691 char nr_name_orig[NETMAP_REQ_IFNAMSIZ];
692 int create_error;
693
694 /* Temporarily remove the pipe suffix. */
695 strlcpy(nr_name_orig, hdr->nr_name, sizeof(nr_name_orig));
696 *cbra = '\0';
697 error = netmap_get_na(hdr, &pna, &ifp, nmd, create);
698 /* Restore the pipe suffix. */
699 strlcpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name));
700 if (!error)
701 break;
702 if (error != ENXIO || retries++) {
703 nm_prdis("parent lookup failed: %d", error);
704 return error;
705 }
706 nm_prdis("try to create a persistent vale port");
707 /* create a persistent vale port and try again */
708 *cbra = '\0';
709 NMG_UNLOCK();
710 create_error = netmap_vi_create(hdr, 1 /* autodelete */);
711 NMG_LOCK();
712 strlcpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name));
713 if (create_error && create_error != EEXIST) {
714 if (create_error != EOPNOTSUPP) {
715 nm_prerr("failed to create a persistent vale port: %d",
716 create_error);
717 }
718 return error;
719 }
720 }
721
722 if (NETMAP_OWNED_BY_KERN(pna)) {
723 nm_prdis("parent busy");
724 error = EBUSY;
725 goto put_out;
726 }
727
728 /* next, lookup the pipe id in the parent list */
729 reqna = NULL;
730 mna = netmap_pipe_find(pna, pipe_id);
731 if (mna) {
732 if (mna->role == role) {
733 nm_prdis("found %s directly at %d", pipe_id, mna->parent_slot);
734 reqna = mna;
735 } else {
736 nm_prdis("found %s indirectly at %d", pipe_id, mna->parent_slot);
737 reqna = mna->peer;
738 }
739 /* the pipe we have found already holds a ref to the parent,
740 * so we need to drop the one we got from netmap_get_na()
741 */
742 netmap_unget_na(pna, ifp);
743 goto found;
744 }
745 nm_prdis("pipe %s not found, create %d", pipe_id, create);
746 if (!create) {
747 error = ENODEV;
748 goto put_out;
749 }
750 /* we create both master and slave.
751 * The endpoint we were asked for holds a reference to
752 * the other one.
753 */
754 mna = nm_os_malloc(sizeof(*mna));
755 if (mna == NULL) {
756 error = ENOMEM;
757 goto put_out;
758 }
759 snprintf(mna->up.name, sizeof(mna->up.name), "%s{%s", pna->name, pipe_id);
760
761 mna->role = NM_PIPE_ROLE_MASTER;
762 mna->parent = pna;
763 mna->parent_ifp = ifp;
764
765 mna->up.nm_txsync = netmap_pipe_txsync;
766 mna->up.nm_rxsync = netmap_pipe_rxsync;
767 mna->up.nm_register = netmap_pipe_reg;
768 mna->up.nm_dtor = netmap_pipe_dtor;
769 mna->up.nm_krings_create = netmap_pipe_krings_create;
770 mna->up.nm_krings_delete = netmap_pipe_krings_delete;
771 mna->up.nm_mem = netmap_mem_get(pna->nm_mem);
772 mna->up.na_flags |= NAF_MEM_OWNER;
773 mna->up.na_lut = pna->na_lut;
774
775 mna->up.num_tx_rings = req->nr_tx_rings;
776 nm_bound_var(&mna->up.num_tx_rings, 1,
777 1, NM_PIPE_MAXRINGS, NULL);
778 mna->up.num_rx_rings = req->nr_rx_rings;
779 nm_bound_var(&mna->up.num_rx_rings, 1,
780 1, NM_PIPE_MAXRINGS, NULL);
781 mna->up.num_tx_desc = req->nr_tx_slots;
782 nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc,
783 1, NM_PIPE_MAXSLOTS, NULL);
784 mna->up.num_rx_desc = req->nr_rx_slots;
785 nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc,
786 1, NM_PIPE_MAXSLOTS, NULL);
787 error = netmap_attach_common(&mna->up);
788 if (error)
789 goto free_mna;
790 /* register the master with the parent */
791 error = netmap_pipe_add(pna, mna);
792 if (error)
793 goto free_mna;
794
795 /* create the slave */
796 sna = nm_os_malloc(sizeof(*mna));
797 if (sna == NULL) {
798 error = ENOMEM;
799 goto unregister_mna;
800 }
801 /* most fields are the same, copy from master and then fix */
802 *sna = *mna;
803 sna->up.nm_mem = netmap_mem_get(mna->up.nm_mem);
804 /* swap the number of tx/rx rings and slots */
805 sna->up.num_tx_rings = mna->up.num_rx_rings;
806 sna->up.num_tx_desc = mna->up.num_rx_desc;
807 sna->up.num_rx_rings = mna->up.num_tx_rings;
808 sna->up.num_rx_desc = mna->up.num_tx_desc;
809 snprintf(sna->up.name, sizeof(sna->up.name), "%s}%s", pna->name, pipe_id);
810 sna->role = NM_PIPE_ROLE_SLAVE;
811 error = netmap_attach_common(&sna->up);
812 if (error)
813 goto free_sna;
814
815 /* join the two endpoints */
816 mna->peer = sna;
817 sna->peer = mna;
818
819 /* we already have a reference to the parent, but we
820 * need another one for the other endpoint we created
821 */
822 netmap_adapter_get(pna);
823 /* likewise for the ifp, if any */
824 if (ifp)
825 if_ref(ifp);
826
827 if (role == NM_PIPE_ROLE_MASTER) {
828 reqna = mna;
829 mna->peer_ref = 1;
830 netmap_adapter_get(&sna->up);
831 } else {
832 reqna = sna;
833 sna->peer_ref = 1;
834 netmap_adapter_get(&mna->up);
835 }
836 nm_prdis("created master %p and slave %p", mna, sna);
837 found:
838
839 nm_prdis("pipe %s %s at %p", pipe_id,
840 (reqna->role == NM_PIPE_ROLE_MASTER ? "master" : "slave"), reqna);
841 *na = &reqna->up;
842 netmap_adapter_get(*na);
843
844 /* keep the reference to the parent.
845 * It will be released by the req destructor
846 */
847
848 return 0;
849
850 free_sna:
851 nm_os_free(sna);
852 unregister_mna:
853 netmap_pipe_remove(pna, mna);
854 free_mna:
855 nm_os_free(mna);
856 put_out:
857 netmap_unget_na(pna, ifp);
858 return error;
859 }
860
861
862 #endif /* WITH_PIPES */
863