xref: /freebsd-11-stable/sys/dev/netmap/netmap_pipe.c (revision adf75b88b6bf12a8e23193335dcffd9cab6125a1)
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