xref: /freebsd/sys/dev/netmap/netmap_pipe.c (revision f0ea3689a9c1c27067145ed902811149e78cc4fa)
1*f0ea3689SLuigi Rizzo /*
2*f0ea3689SLuigi Rizzo  * Copyright (C) 2014 Giuseppe Lettieri. All rights reserved.
3*f0ea3689SLuigi Rizzo  *
4*f0ea3689SLuigi Rizzo  * Redistribution and use in source and binary forms, with or without
5*f0ea3689SLuigi Rizzo  * modification, are permitted provided that the following conditions
6*f0ea3689SLuigi Rizzo  * are met:
7*f0ea3689SLuigi Rizzo  *   1. Redistributions of source code must retain the above copyright
8*f0ea3689SLuigi Rizzo  *      notice, this list of conditions and the following disclaimer.
9*f0ea3689SLuigi Rizzo  *   2. Redistributions in binary form must reproduce the above copyright
10*f0ea3689SLuigi Rizzo  *      notice, this list of conditions and the following disclaimer in the
11*f0ea3689SLuigi Rizzo  *      documentation and/or other materials provided with the distribution.
12*f0ea3689SLuigi Rizzo  *
13*f0ea3689SLuigi Rizzo  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14*f0ea3689SLuigi Rizzo  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15*f0ea3689SLuigi Rizzo  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16*f0ea3689SLuigi Rizzo  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17*f0ea3689SLuigi Rizzo  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18*f0ea3689SLuigi Rizzo  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19*f0ea3689SLuigi Rizzo  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20*f0ea3689SLuigi Rizzo  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21*f0ea3689SLuigi Rizzo  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22*f0ea3689SLuigi Rizzo  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23*f0ea3689SLuigi Rizzo  * SUCH DAMAGE.
24*f0ea3689SLuigi Rizzo  */
25*f0ea3689SLuigi Rizzo 
26*f0ea3689SLuigi Rizzo /* $FreeBSD$ */
27*f0ea3689SLuigi Rizzo 
28*f0ea3689SLuigi Rizzo #if defined(__FreeBSD__)
29*f0ea3689SLuigi Rizzo #include <sys/cdefs.h> /* prerequisite */
30*f0ea3689SLuigi Rizzo 
31*f0ea3689SLuigi Rizzo #include <sys/types.h>
32*f0ea3689SLuigi Rizzo #include <sys/errno.h>
33*f0ea3689SLuigi Rizzo #include <sys/param.h>	/* defines used in kernel.h */
34*f0ea3689SLuigi Rizzo #include <sys/kernel.h>	/* types used in module initialization */
35*f0ea3689SLuigi Rizzo #include <sys/malloc.h>
36*f0ea3689SLuigi Rizzo #include <sys/poll.h>
37*f0ea3689SLuigi Rizzo #include <sys/lock.h>
38*f0ea3689SLuigi Rizzo #include <sys/rwlock.h>
39*f0ea3689SLuigi Rizzo #include <sys/selinfo.h>
40*f0ea3689SLuigi Rizzo #include <sys/sysctl.h>
41*f0ea3689SLuigi Rizzo #include <sys/socket.h> /* sockaddrs */
42*f0ea3689SLuigi Rizzo #include <net/if.h>
43*f0ea3689SLuigi Rizzo #include <net/if_var.h>
44*f0ea3689SLuigi Rizzo #include <machine/bus.h>	/* bus_dmamap_* */
45*f0ea3689SLuigi Rizzo #include <sys/refcount.h>
46*f0ea3689SLuigi Rizzo 
47*f0ea3689SLuigi Rizzo 
48*f0ea3689SLuigi Rizzo #elif defined(linux)
49*f0ea3689SLuigi Rizzo 
50*f0ea3689SLuigi Rizzo #include "bsd_glue.h"
51*f0ea3689SLuigi Rizzo 
52*f0ea3689SLuigi Rizzo #elif defined(__APPLE__)
53*f0ea3689SLuigi Rizzo 
54*f0ea3689SLuigi Rizzo #warning OSX support is only partial
55*f0ea3689SLuigi Rizzo #include "osx_glue.h"
56*f0ea3689SLuigi Rizzo 
57*f0ea3689SLuigi Rizzo #else
58*f0ea3689SLuigi Rizzo 
59*f0ea3689SLuigi Rizzo #error	Unsupported platform
60*f0ea3689SLuigi Rizzo 
61*f0ea3689SLuigi Rizzo #endif /* unsupported */
62*f0ea3689SLuigi Rizzo 
63*f0ea3689SLuigi Rizzo /*
64*f0ea3689SLuigi Rizzo  * common headers
65*f0ea3689SLuigi Rizzo  */
66*f0ea3689SLuigi Rizzo 
67*f0ea3689SLuigi Rizzo #include <net/netmap.h>
68*f0ea3689SLuigi Rizzo #include <dev/netmap/netmap_kern.h>
69*f0ea3689SLuigi Rizzo #include <dev/netmap/netmap_mem2.h>
70*f0ea3689SLuigi Rizzo 
71*f0ea3689SLuigi Rizzo #ifdef WITH_PIPES
72*f0ea3689SLuigi Rizzo 
73*f0ea3689SLuigi Rizzo #define NM_PIPE_MAXSLOTS	4096
74*f0ea3689SLuigi Rizzo 
75*f0ea3689SLuigi Rizzo int netmap_default_pipes = 0; /* default number of pipes for each nic */
76*f0ea3689SLuigi Rizzo SYSCTL_DECL(_dev_netmap);
77*f0ea3689SLuigi Rizzo SYSCTL_INT(_dev_netmap, OID_AUTO, default_pipes, CTLFLAG_RW, &netmap_default_pipes, 0 , "");
78*f0ea3689SLuigi Rizzo 
79*f0ea3689SLuigi Rizzo /* allocate the pipe array in the parent adapter */
80*f0ea3689SLuigi Rizzo int
81*f0ea3689SLuigi Rizzo netmap_pipe_alloc(struct netmap_adapter *na, struct nmreq *nmr)
82*f0ea3689SLuigi Rizzo {
83*f0ea3689SLuigi Rizzo 	size_t len;
84*f0ea3689SLuigi Rizzo 	int mode = nmr->nr_flags & NR_REG_MASK;
85*f0ea3689SLuigi Rizzo 	u_int npipes;
86*f0ea3689SLuigi Rizzo 
87*f0ea3689SLuigi Rizzo 	if (mode == NR_REG_PIPE_MASTER || mode == NR_REG_PIPE_SLAVE) {
88*f0ea3689SLuigi Rizzo 		/* this is for our parent, not for us */
89*f0ea3689SLuigi Rizzo 		return 0;
90*f0ea3689SLuigi Rizzo 	}
91*f0ea3689SLuigi Rizzo 
92*f0ea3689SLuigi Rizzo 	/* TODO: we can resize the array if the new
93*f0ea3689SLuigi Rizzo          * request can accomodate the already existing pipes
94*f0ea3689SLuigi Rizzo          */
95*f0ea3689SLuigi Rizzo 	if (na->na_pipes) {
96*f0ea3689SLuigi Rizzo 		nmr->nr_arg1 = na->na_max_pipes;
97*f0ea3689SLuigi Rizzo 		return 0;
98*f0ea3689SLuigi Rizzo 	}
99*f0ea3689SLuigi Rizzo 
100*f0ea3689SLuigi Rizzo 	npipes = nmr->nr_arg1;
101*f0ea3689SLuigi Rizzo 	if (npipes == 0)
102*f0ea3689SLuigi Rizzo 		npipes = netmap_default_pipes;
103*f0ea3689SLuigi Rizzo 	nm_bound_var(&npipes, 0, 0, NM_MAXPIPES, NULL);
104*f0ea3689SLuigi Rizzo 
105*f0ea3689SLuigi Rizzo 	if (npipes == 0) {
106*f0ea3689SLuigi Rizzo 		/* really zero, nothing to alloc */
107*f0ea3689SLuigi Rizzo 		goto out;
108*f0ea3689SLuigi Rizzo 	}
109*f0ea3689SLuigi Rizzo 
110*f0ea3689SLuigi Rizzo 	len = sizeof(struct netmap_pipe_adapter *) * npipes;
111*f0ea3689SLuigi Rizzo 	na->na_pipes = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
112*f0ea3689SLuigi Rizzo 	if (na->na_pipes == NULL)
113*f0ea3689SLuigi Rizzo 		return ENOMEM;
114*f0ea3689SLuigi Rizzo 
115*f0ea3689SLuigi Rizzo 	na->na_max_pipes = npipes;
116*f0ea3689SLuigi Rizzo 	na->na_next_pipe = 0;
117*f0ea3689SLuigi Rizzo 
118*f0ea3689SLuigi Rizzo out:
119*f0ea3689SLuigi Rizzo 	nmr->nr_arg1 = npipes;
120*f0ea3689SLuigi Rizzo 
121*f0ea3689SLuigi Rizzo 	return 0;
122*f0ea3689SLuigi Rizzo }
123*f0ea3689SLuigi Rizzo 
124*f0ea3689SLuigi Rizzo /* deallocate the parent array in the parent adapter */
125*f0ea3689SLuigi Rizzo void
126*f0ea3689SLuigi Rizzo netmap_pipe_dealloc(struct netmap_adapter *na)
127*f0ea3689SLuigi Rizzo {
128*f0ea3689SLuigi Rizzo 	if (na->na_pipes) {
129*f0ea3689SLuigi Rizzo 		ND("freeing pipes for %s", NM_IFPNAME(na->ifp));
130*f0ea3689SLuigi Rizzo 		free(na->na_pipes, M_DEVBUF);
131*f0ea3689SLuigi Rizzo 		na->na_pipes = NULL;
132*f0ea3689SLuigi Rizzo 		na->na_max_pipes = 0;
133*f0ea3689SLuigi Rizzo 		na->na_next_pipe = 0;
134*f0ea3689SLuigi Rizzo 	}
135*f0ea3689SLuigi Rizzo }
136*f0ea3689SLuigi Rizzo 
137*f0ea3689SLuigi Rizzo /* find a pipe endpoint with the given id among the parent's pipes */
138*f0ea3689SLuigi Rizzo static struct netmap_pipe_adapter *
139*f0ea3689SLuigi Rizzo netmap_pipe_find(struct netmap_adapter *parent, u_int pipe_id)
140*f0ea3689SLuigi Rizzo {
141*f0ea3689SLuigi Rizzo 	int i;
142*f0ea3689SLuigi Rizzo 	struct netmap_pipe_adapter *na;
143*f0ea3689SLuigi Rizzo 
144*f0ea3689SLuigi Rizzo 	for (i = 0; i < parent->na_next_pipe; i++) {
145*f0ea3689SLuigi Rizzo 		na = parent->na_pipes[i];
146*f0ea3689SLuigi Rizzo 		if (na->id == pipe_id) {
147*f0ea3689SLuigi Rizzo 			return na;
148*f0ea3689SLuigi Rizzo 		}
149*f0ea3689SLuigi Rizzo 	}
150*f0ea3689SLuigi Rizzo 	return NULL;
151*f0ea3689SLuigi Rizzo }
152*f0ea3689SLuigi Rizzo 
153*f0ea3689SLuigi Rizzo /* add a new pipe endpoint to the parent array */
154*f0ea3689SLuigi Rizzo static int
155*f0ea3689SLuigi Rizzo netmap_pipe_add(struct netmap_adapter *parent, struct netmap_pipe_adapter *na)
156*f0ea3689SLuigi Rizzo {
157*f0ea3689SLuigi Rizzo 	if (parent->na_next_pipe >= parent->na_max_pipes) {
158*f0ea3689SLuigi Rizzo 		D("%s: no space left for pipes", NM_IFPNAME(parent->ifp));
159*f0ea3689SLuigi Rizzo 		return ENOMEM;
160*f0ea3689SLuigi Rizzo 	}
161*f0ea3689SLuigi Rizzo 
162*f0ea3689SLuigi Rizzo 	parent->na_pipes[parent->na_next_pipe] = na;
163*f0ea3689SLuigi Rizzo 	na->parent_slot = parent->na_next_pipe;
164*f0ea3689SLuigi Rizzo 	parent->na_next_pipe++;
165*f0ea3689SLuigi Rizzo 	return 0;
166*f0ea3689SLuigi Rizzo }
167*f0ea3689SLuigi Rizzo 
168*f0ea3689SLuigi Rizzo /* remove the given pipe endpoint from the parent array */
169*f0ea3689SLuigi Rizzo static void
170*f0ea3689SLuigi Rizzo netmap_pipe_remove(struct netmap_adapter *parent, struct netmap_pipe_adapter *na)
171*f0ea3689SLuigi Rizzo {
172*f0ea3689SLuigi Rizzo 	u_int n;
173*f0ea3689SLuigi Rizzo 	n = --parent->na_next_pipe;
174*f0ea3689SLuigi Rizzo 	if (n != na->parent_slot) {
175*f0ea3689SLuigi Rizzo 		parent->na_pipes[na->parent_slot] =
176*f0ea3689SLuigi Rizzo 			parent->na_pipes[n];
177*f0ea3689SLuigi Rizzo 	}
178*f0ea3689SLuigi Rizzo 	parent->na_pipes[n] = NULL;
179*f0ea3689SLuigi Rizzo }
180*f0ea3689SLuigi Rizzo 
181*f0ea3689SLuigi Rizzo static int
182*f0ea3689SLuigi Rizzo netmap_pipe_txsync(struct netmap_adapter *na, u_int ring_nr, int flags)
183*f0ea3689SLuigi Rizzo {
184*f0ea3689SLuigi Rizzo         struct netmap_kring *txkring = na->tx_rings + ring_nr,
185*f0ea3689SLuigi Rizzo 		*rxkring = txkring->pipe;
186*f0ea3689SLuigi Rizzo         u_int limit; /* slots to transfer */
187*f0ea3689SLuigi Rizzo         u_int j, k, lim_tx = txkring->nkr_num_slots - 1,
188*f0ea3689SLuigi Rizzo                 lim_rx = rxkring->nkr_num_slots - 1;
189*f0ea3689SLuigi Rizzo         int m, busy;
190*f0ea3689SLuigi Rizzo 
191*f0ea3689SLuigi Rizzo         ND("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name);
192*f0ea3689SLuigi Rizzo         ND(2, "before: hwcur %d hwtail %d cur %d head %d tail %d", txkring->nr_hwcur, txkring->nr_hwtail,
193*f0ea3689SLuigi Rizzo                 txkring->rcur, txkring->rhead, txkring->rtail);
194*f0ea3689SLuigi Rizzo 
195*f0ea3689SLuigi Rizzo         j = rxkring->nr_hwtail; /* RX */
196*f0ea3689SLuigi Rizzo         k = txkring->nr_hwcur;  /* TX */
197*f0ea3689SLuigi Rizzo         m = txkring->rhead - txkring->nr_hwcur; /* new slots */
198*f0ea3689SLuigi Rizzo         if (m < 0)
199*f0ea3689SLuigi Rizzo                 m += txkring->nkr_num_slots;
200*f0ea3689SLuigi Rizzo         limit = m;
201*f0ea3689SLuigi Rizzo         m = rxkring->nkr_num_slots - 1; /* max avail space on destination */
202*f0ea3689SLuigi Rizzo         busy = j - rxkring->nr_hwcur; /* busy slots */
203*f0ea3689SLuigi Rizzo 	if (busy < 0)
204*f0ea3689SLuigi Rizzo 		busy += txkring->nkr_num_slots;
205*f0ea3689SLuigi Rizzo 	m -= busy; /* subtract busy slots */
206*f0ea3689SLuigi Rizzo         ND(2, "m %d limit %d", m, limit);
207*f0ea3689SLuigi Rizzo         if (m < limit)
208*f0ea3689SLuigi Rizzo                 limit = m;
209*f0ea3689SLuigi Rizzo 
210*f0ea3689SLuigi Rizzo 	if (limit == 0) {
211*f0ea3689SLuigi Rizzo 		/* either the rxring is full, or nothing to send */
212*f0ea3689SLuigi Rizzo 		nm_txsync_finalize(txkring); /* actually useless */
213*f0ea3689SLuigi Rizzo 		return 0;
214*f0ea3689SLuigi Rizzo 	}
215*f0ea3689SLuigi Rizzo 
216*f0ea3689SLuigi Rizzo         while (limit-- > 0) {
217*f0ea3689SLuigi Rizzo                 struct netmap_slot *rs = &rxkring->save_ring->slot[j];
218*f0ea3689SLuigi Rizzo                 struct netmap_slot *ts = &txkring->ring->slot[k];
219*f0ea3689SLuigi Rizzo                 struct netmap_slot tmp;
220*f0ea3689SLuigi Rizzo 
221*f0ea3689SLuigi Rizzo                 /* swap the slots */
222*f0ea3689SLuigi Rizzo                 tmp = *rs;
223*f0ea3689SLuigi Rizzo                 *rs = *ts;
224*f0ea3689SLuigi Rizzo                 *ts = tmp;
225*f0ea3689SLuigi Rizzo 
226*f0ea3689SLuigi Rizzo                 /* no need to report the buffer change */
227*f0ea3689SLuigi Rizzo 
228*f0ea3689SLuigi Rizzo                 j = nm_next(j, lim_rx);
229*f0ea3689SLuigi Rizzo                 k = nm_next(k, lim_tx);
230*f0ea3689SLuigi Rizzo         }
231*f0ea3689SLuigi Rizzo 
232*f0ea3689SLuigi Rizzo         wmb(); /* make sure the slots are updated before publishing them */
233*f0ea3689SLuigi Rizzo         rxkring->nr_hwtail = j;
234*f0ea3689SLuigi Rizzo         txkring->nr_hwcur = k;
235*f0ea3689SLuigi Rizzo         txkring->nr_hwtail = nm_prev(k, lim_tx);
236*f0ea3689SLuigi Rizzo 
237*f0ea3689SLuigi Rizzo         nm_txsync_finalize(txkring);
238*f0ea3689SLuigi Rizzo         ND(2, "after: hwcur %d hwtail %d cur %d head %d tail %d j %d", txkring->nr_hwcur, txkring->nr_hwtail,
239*f0ea3689SLuigi Rizzo                 txkring->rcur, txkring->rhead, txkring->rtail, j);
240*f0ea3689SLuigi Rizzo 
241*f0ea3689SLuigi Rizzo         wmb(); /* make sure rxkring->nr_hwtail is updated before notifying */
242*f0ea3689SLuigi Rizzo         rxkring->na->nm_notify(rxkring->na, rxkring->ring_id, NR_RX, 0);
243*f0ea3689SLuigi Rizzo 
244*f0ea3689SLuigi Rizzo 	return 0;
245*f0ea3689SLuigi Rizzo }
246*f0ea3689SLuigi Rizzo 
247*f0ea3689SLuigi Rizzo static int
248*f0ea3689SLuigi Rizzo netmap_pipe_rxsync(struct netmap_adapter *na, u_int ring_nr, int flags)
249*f0ea3689SLuigi Rizzo {
250*f0ea3689SLuigi Rizzo         struct netmap_kring *rxkring = na->rx_rings + ring_nr,
251*f0ea3689SLuigi Rizzo 		*txkring = rxkring->pipe;
252*f0ea3689SLuigi Rizzo 	uint32_t oldhwcur = rxkring->nr_hwcur;
253*f0ea3689SLuigi Rizzo 
254*f0ea3689SLuigi Rizzo         ND("%s %x <- %s", rxkring->name, flags, txkring->name);
255*f0ea3689SLuigi Rizzo         rxkring->nr_hwcur = rxkring->rhead; /* recover user-relased slots */
256*f0ea3689SLuigi Rizzo         ND(5, "hwcur %d hwtail %d cur %d head %d tail %d", rxkring->nr_hwcur, rxkring->nr_hwtail,
257*f0ea3689SLuigi Rizzo                 rxkring->rcur, rxkring->rhead, rxkring->rtail);
258*f0ea3689SLuigi Rizzo         rmb(); /* paired with the first wmb() in txsync */
259*f0ea3689SLuigi Rizzo         nm_rxsync_finalize(rxkring);
260*f0ea3689SLuigi Rizzo 
261*f0ea3689SLuigi Rizzo 	if (oldhwcur != rxkring->nr_hwcur) {
262*f0ea3689SLuigi Rizzo 		/* we have released some slots, notify the other end */
263*f0ea3689SLuigi Rizzo 		wmb(); /* make sure nr_hwcur is updated before notifying */
264*f0ea3689SLuigi Rizzo 		txkring->na->nm_notify(txkring->na, txkring->ring_id, NR_TX, 0);
265*f0ea3689SLuigi Rizzo 	}
266*f0ea3689SLuigi Rizzo         return 0;
267*f0ea3689SLuigi Rizzo }
268*f0ea3689SLuigi Rizzo 
269*f0ea3689SLuigi Rizzo /* Pipe endpoints are created and destroyed together, so that endopoints do not
270*f0ea3689SLuigi Rizzo  * have to check for the existence of their peer at each ?xsync.
271*f0ea3689SLuigi Rizzo  *
272*f0ea3689SLuigi Rizzo  * To play well with the existing netmap infrastructure (refcounts etc.), we
273*f0ea3689SLuigi Rizzo  * adopt the following strategy:
274*f0ea3689SLuigi Rizzo  *
275*f0ea3689SLuigi Rizzo  * 1) The first endpoint that is created also creates the other endpoint and
276*f0ea3689SLuigi Rizzo  * grabs a reference to it.
277*f0ea3689SLuigi Rizzo  *
278*f0ea3689SLuigi Rizzo  *    state A)  user1 --> endpoint1 --> endpoint2
279*f0ea3689SLuigi Rizzo  *
280*f0ea3689SLuigi Rizzo  * 2) If, starting from state A, endpoint2 is then registered, endpoint1 gives
281*f0ea3689SLuigi Rizzo  * its reference to the user:
282*f0ea3689SLuigi Rizzo  *
283*f0ea3689SLuigi Rizzo  *    state B)  user1 --> endpoint1     endpoint2 <--- user2
284*f0ea3689SLuigi Rizzo  *
285*f0ea3689SLuigi Rizzo  * 3) Assume that, starting from state B endpoint2 is closed. In the unregister
286*f0ea3689SLuigi Rizzo  * callback endpoint2 notes that endpoint1 is still active and adds a reference
287*f0ea3689SLuigi Rizzo  * from endpoint1 to itself. When user2 then releases her own reference,
288*f0ea3689SLuigi Rizzo  * endpoint2 is not destroyed and we are back to state A. A symmetrical state
289*f0ea3689SLuigi Rizzo  * would be reached if endpoint1 were released instead.
290*f0ea3689SLuigi Rizzo  *
291*f0ea3689SLuigi Rizzo  * 4) If, starting from state A, endpoint1 is closed, the destructor notes that
292*f0ea3689SLuigi Rizzo  * it owns a reference to endpoint2 and releases it.
293*f0ea3689SLuigi Rizzo  *
294*f0ea3689SLuigi Rizzo  * Something similar goes on for the creation and destruction of the krings.
295*f0ea3689SLuigi Rizzo  */
296*f0ea3689SLuigi Rizzo 
297*f0ea3689SLuigi Rizzo 
298*f0ea3689SLuigi Rizzo /* netmap_pipe_krings_delete.
299*f0ea3689SLuigi Rizzo  *
300*f0ea3689SLuigi Rizzo  * There are two cases:
301*f0ea3689SLuigi Rizzo  *
302*f0ea3689SLuigi Rizzo  * 1) state is
303*f0ea3689SLuigi Rizzo  *
304*f0ea3689SLuigi Rizzo  *        usr1 --> e1 --> e2
305*f0ea3689SLuigi Rizzo  *
306*f0ea3689SLuigi Rizzo  *    and we are e1. We have to create both sets
307*f0ea3689SLuigi Rizzo  *    of krings.
308*f0ea3689SLuigi Rizzo  *
309*f0ea3689SLuigi Rizzo  * 2) state is
310*f0ea3689SLuigi Rizzo  *
311*f0ea3689SLuigi Rizzo  *        usr1 --> e1 --> e2
312*f0ea3689SLuigi Rizzo  *
313*f0ea3689SLuigi Rizzo  *    and we are e2. e1 is certainly registered and our
314*f0ea3689SLuigi Rizzo  *    krings already exist, but they may be hidden.
315*f0ea3689SLuigi Rizzo  */
316*f0ea3689SLuigi Rizzo static int
317*f0ea3689SLuigi Rizzo netmap_pipe_krings_create(struct netmap_adapter *na)
318*f0ea3689SLuigi Rizzo {
319*f0ea3689SLuigi Rizzo 	struct netmap_pipe_adapter *pna =
320*f0ea3689SLuigi Rizzo 		(struct netmap_pipe_adapter *)na;
321*f0ea3689SLuigi Rizzo 	struct netmap_adapter *ona = &pna->peer->up;
322*f0ea3689SLuigi Rizzo 	int error = 0;
323*f0ea3689SLuigi Rizzo 	if (pna->peer_ref) {
324*f0ea3689SLuigi Rizzo 		int i;
325*f0ea3689SLuigi Rizzo 
326*f0ea3689SLuigi Rizzo 		/* case 1) above */
327*f0ea3689SLuigi Rizzo 		D("%p: case 1, create everything", na);
328*f0ea3689SLuigi Rizzo 		error = netmap_krings_create(na, 0);
329*f0ea3689SLuigi Rizzo 		if (error)
330*f0ea3689SLuigi Rizzo 			goto err;
331*f0ea3689SLuigi Rizzo 
332*f0ea3689SLuigi Rizzo 		/* we also create all the rings, since we need to
333*f0ea3689SLuigi Rizzo                  * update the save_ring pointers.
334*f0ea3689SLuigi Rizzo                  * netmap_mem_rings_create (called by our caller)
335*f0ea3689SLuigi Rizzo                  * will not create the rings again
336*f0ea3689SLuigi Rizzo                  */
337*f0ea3689SLuigi Rizzo 
338*f0ea3689SLuigi Rizzo 		error = netmap_mem_rings_create(na);
339*f0ea3689SLuigi Rizzo 		if (error)
340*f0ea3689SLuigi Rizzo 			goto del_krings1;
341*f0ea3689SLuigi Rizzo 
342*f0ea3689SLuigi Rizzo 		/* update our hidden ring pointers */
343*f0ea3689SLuigi Rizzo 		for (i = 0; i < na->num_tx_rings + 1; i++)
344*f0ea3689SLuigi Rizzo 			na->tx_rings[i].save_ring = na->tx_rings[i].ring;
345*f0ea3689SLuigi Rizzo 		for (i = 0; i < na->num_rx_rings + 1; i++)
346*f0ea3689SLuigi Rizzo 			na->rx_rings[i].save_ring = na->rx_rings[i].ring;
347*f0ea3689SLuigi Rizzo 
348*f0ea3689SLuigi Rizzo 		/* now, create krings and rings of the other end */
349*f0ea3689SLuigi Rizzo 		error = netmap_krings_create(ona, 0);
350*f0ea3689SLuigi Rizzo 		if (error)
351*f0ea3689SLuigi Rizzo 			goto del_rings1;
352*f0ea3689SLuigi Rizzo 
353*f0ea3689SLuigi Rizzo 		error = netmap_mem_rings_create(ona);
354*f0ea3689SLuigi Rizzo 		if (error)
355*f0ea3689SLuigi Rizzo 			goto del_krings2;
356*f0ea3689SLuigi Rizzo 
357*f0ea3689SLuigi Rizzo 		for (i = 0; i < ona->num_tx_rings + 1; i++)
358*f0ea3689SLuigi Rizzo 			ona->tx_rings[i].save_ring = ona->tx_rings[i].ring;
359*f0ea3689SLuigi Rizzo 		for (i = 0; i < ona->num_rx_rings + 1; i++)
360*f0ea3689SLuigi Rizzo 			ona->rx_rings[i].save_ring = ona->rx_rings[i].ring;
361*f0ea3689SLuigi Rizzo 
362*f0ea3689SLuigi Rizzo 		/* cross link the krings */
363*f0ea3689SLuigi Rizzo 		for (i = 0; i < na->num_tx_rings; i++) {
364*f0ea3689SLuigi Rizzo 			na->tx_rings[i].pipe = pna->peer->up.rx_rings + i;
365*f0ea3689SLuigi Rizzo 			na->rx_rings[i].pipe = pna->peer->up.tx_rings + i;
366*f0ea3689SLuigi Rizzo 			pna->peer->up.tx_rings[i].pipe = na->rx_rings + i;
367*f0ea3689SLuigi Rizzo 			pna->peer->up.rx_rings[i].pipe = na->tx_rings + i;
368*f0ea3689SLuigi Rizzo 		}
369*f0ea3689SLuigi Rizzo 	} else {
370*f0ea3689SLuigi Rizzo 		int i;
371*f0ea3689SLuigi Rizzo 		/* case 2) above */
372*f0ea3689SLuigi Rizzo 		/* recover the hidden rings */
373*f0ea3689SLuigi Rizzo 		ND("%p: case 2, hidden rings", na);
374*f0ea3689SLuigi Rizzo 		for (i = 0; i < na->num_tx_rings + 1; i++)
375*f0ea3689SLuigi Rizzo 			na->tx_rings[i].ring = na->tx_rings[i].save_ring;
376*f0ea3689SLuigi Rizzo 		for (i = 0; i < na->num_rx_rings + 1; i++)
377*f0ea3689SLuigi Rizzo 			na->rx_rings[i].ring = na->rx_rings[i].save_ring;
378*f0ea3689SLuigi Rizzo 	}
379*f0ea3689SLuigi Rizzo 	return 0;
380*f0ea3689SLuigi Rizzo 
381*f0ea3689SLuigi Rizzo del_krings2:
382*f0ea3689SLuigi Rizzo 	netmap_krings_delete(ona);
383*f0ea3689SLuigi Rizzo del_rings1:
384*f0ea3689SLuigi Rizzo 	netmap_mem_rings_delete(na);
385*f0ea3689SLuigi Rizzo del_krings1:
386*f0ea3689SLuigi Rizzo 	netmap_krings_delete(na);
387*f0ea3689SLuigi Rizzo err:
388*f0ea3689SLuigi Rizzo 	return error;
389*f0ea3689SLuigi Rizzo }
390*f0ea3689SLuigi Rizzo 
391*f0ea3689SLuigi Rizzo /* netmap_pipe_reg.
392*f0ea3689SLuigi Rizzo  *
393*f0ea3689SLuigi Rizzo  * There are two cases on registration (onoff==1)
394*f0ea3689SLuigi Rizzo  *
395*f0ea3689SLuigi Rizzo  * 1.a) state is
396*f0ea3689SLuigi Rizzo  *
397*f0ea3689SLuigi Rizzo  *        usr1 --> e1 --> e2
398*f0ea3689SLuigi Rizzo  *
399*f0ea3689SLuigi Rizzo  *      and we are e1. Nothing special to do.
400*f0ea3689SLuigi Rizzo  *
401*f0ea3689SLuigi Rizzo  * 1.b) state is
402*f0ea3689SLuigi Rizzo  *
403*f0ea3689SLuigi Rizzo  *        usr1 --> e1 --> e2 <-- usr2
404*f0ea3689SLuigi Rizzo  *
405*f0ea3689SLuigi Rizzo  *      and we are e2. Drop the ref e1 is holding.
406*f0ea3689SLuigi Rizzo  *
407*f0ea3689SLuigi Rizzo  *  There are two additional cases on unregister (onoff==0)
408*f0ea3689SLuigi Rizzo  *
409*f0ea3689SLuigi Rizzo  *  2.a) state is
410*f0ea3689SLuigi Rizzo  *
411*f0ea3689SLuigi Rizzo  *         usr1 --> e1 --> e2
412*f0ea3689SLuigi Rizzo  *
413*f0ea3689SLuigi Rizzo  *       and we are e1. Nothing special to do, e2 will
414*f0ea3689SLuigi Rizzo  *       be cleaned up by the destructor of e1.
415*f0ea3689SLuigi Rizzo  *
416*f0ea3689SLuigi Rizzo  *  2.b) state is
417*f0ea3689SLuigi Rizzo  *
418*f0ea3689SLuigi Rizzo  *         usr1 --> e1     e2 <-- usr2
419*f0ea3689SLuigi Rizzo  *
420*f0ea3689SLuigi Rizzo  *       and we are either e1 or e2. Add a ref from the
421*f0ea3689SLuigi Rizzo  *       other end and hide our rings.
422*f0ea3689SLuigi Rizzo  */
423*f0ea3689SLuigi Rizzo static int
424*f0ea3689SLuigi Rizzo netmap_pipe_reg(struct netmap_adapter *na, int onoff)
425*f0ea3689SLuigi Rizzo {
426*f0ea3689SLuigi Rizzo 	struct netmap_pipe_adapter *pna =
427*f0ea3689SLuigi Rizzo 		(struct netmap_pipe_adapter *)na;
428*f0ea3689SLuigi Rizzo 	struct ifnet *ifp = na->ifp;
429*f0ea3689SLuigi Rizzo 	ND("%p: onoff %d", na, onoff);
430*f0ea3689SLuigi Rizzo 	if (onoff) {
431*f0ea3689SLuigi Rizzo 		ifp->if_capenable |= IFCAP_NETMAP;
432*f0ea3689SLuigi Rizzo 	} else {
433*f0ea3689SLuigi Rizzo 		ifp->if_capenable &= ~IFCAP_NETMAP;
434*f0ea3689SLuigi Rizzo 	}
435*f0ea3689SLuigi Rizzo 	if (pna->peer_ref) {
436*f0ea3689SLuigi Rizzo 		ND("%p: case 1.a or 2.a, nothing to do", na);
437*f0ea3689SLuigi Rizzo 		return 0;
438*f0ea3689SLuigi Rizzo 	}
439*f0ea3689SLuigi Rizzo 	if (onoff) {
440*f0ea3689SLuigi Rizzo 		ND("%p: case 1.b, drop peer", na);
441*f0ea3689SLuigi Rizzo 		pna->peer->peer_ref = 0;
442*f0ea3689SLuigi Rizzo 		netmap_adapter_put(na);
443*f0ea3689SLuigi Rizzo 	} else {
444*f0ea3689SLuigi Rizzo 		int i;
445*f0ea3689SLuigi Rizzo 		ND("%p: case 2.b, grab peer", na);
446*f0ea3689SLuigi Rizzo 		netmap_adapter_get(na);
447*f0ea3689SLuigi Rizzo 		pna->peer->peer_ref = 1;
448*f0ea3689SLuigi Rizzo 		/* hide our rings from netmap_mem_rings_delete */
449*f0ea3689SLuigi Rizzo 		for (i = 0; i < na->num_tx_rings + 1; i++) {
450*f0ea3689SLuigi Rizzo 			na->tx_rings[i].ring = NULL;
451*f0ea3689SLuigi Rizzo 		}
452*f0ea3689SLuigi Rizzo 		for (i = 0; i < na->num_rx_rings + 1; i++) {
453*f0ea3689SLuigi Rizzo 			na->rx_rings[i].ring = NULL;
454*f0ea3689SLuigi Rizzo 		}
455*f0ea3689SLuigi Rizzo 	}
456*f0ea3689SLuigi Rizzo 	return 0;
457*f0ea3689SLuigi Rizzo }
458*f0ea3689SLuigi Rizzo 
459*f0ea3689SLuigi Rizzo /* netmap_pipe_krings_delete.
460*f0ea3689SLuigi Rizzo  *
461*f0ea3689SLuigi Rizzo  * There are two cases:
462*f0ea3689SLuigi Rizzo  *
463*f0ea3689SLuigi Rizzo  * 1) state is
464*f0ea3689SLuigi Rizzo  *
465*f0ea3689SLuigi Rizzo  *                usr1 --> e1 --> e2
466*f0ea3689SLuigi Rizzo  *
467*f0ea3689SLuigi Rizzo  *    and we are e1 (e2 is not registered, so krings_delete cannot be
468*f0ea3689SLuigi Rizzo  *    called on it);
469*f0ea3689SLuigi Rizzo  *
470*f0ea3689SLuigi Rizzo  * 2) state is
471*f0ea3689SLuigi Rizzo  *
472*f0ea3689SLuigi Rizzo  *                usr1 --> e1     e2 <-- usr2
473*f0ea3689SLuigi Rizzo  *
474*f0ea3689SLuigi Rizzo  *    and we are either e1 or e2.
475*f0ea3689SLuigi Rizzo  *
476*f0ea3689SLuigi Rizzo  * In the former case we have to also delete the krings of e2;
477*f0ea3689SLuigi Rizzo  * in the latter case we do nothing (note that our krings
478*f0ea3689SLuigi Rizzo  * have already been hidden in the unregister callback).
479*f0ea3689SLuigi Rizzo  */
480*f0ea3689SLuigi Rizzo static void
481*f0ea3689SLuigi Rizzo netmap_pipe_krings_delete(struct netmap_adapter *na)
482*f0ea3689SLuigi Rizzo {
483*f0ea3689SLuigi Rizzo 	struct netmap_pipe_adapter *pna =
484*f0ea3689SLuigi Rizzo 		(struct netmap_pipe_adapter *)na;
485*f0ea3689SLuigi Rizzo 	struct netmap_adapter *ona; /* na of the other end */
486*f0ea3689SLuigi Rizzo 	int i;
487*f0ea3689SLuigi Rizzo 
488*f0ea3689SLuigi Rizzo 	if (!pna->peer_ref) {
489*f0ea3689SLuigi Rizzo 		ND("%p: case 2, kept alive by peer",  na);
490*f0ea3689SLuigi Rizzo 		return;
491*f0ea3689SLuigi Rizzo 	}
492*f0ea3689SLuigi Rizzo 	/* case 1) above */
493*f0ea3689SLuigi Rizzo 	ND("%p: case 1, deleting everyhing", na);
494*f0ea3689SLuigi Rizzo 	netmap_krings_delete(na); /* also zeroes tx_rings etc. */
495*f0ea3689SLuigi Rizzo 	/* restore the ring to be deleted on the peer */
496*f0ea3689SLuigi Rizzo 	ona = &pna->peer->up;
497*f0ea3689SLuigi Rizzo 	if (ona->tx_rings == NULL) {
498*f0ea3689SLuigi Rizzo 		/* already deleted, we must be on an
499*f0ea3689SLuigi Rizzo                  * cleanup-after-error path */
500*f0ea3689SLuigi Rizzo 		return;
501*f0ea3689SLuigi Rizzo 	}
502*f0ea3689SLuigi Rizzo 	for (i = 0; i < ona->num_tx_rings + 1; i++)
503*f0ea3689SLuigi Rizzo 		ona->tx_rings[i].ring = ona->tx_rings[i].save_ring;
504*f0ea3689SLuigi Rizzo 	for (i = 0; i < ona->num_rx_rings + 1; i++)
505*f0ea3689SLuigi Rizzo 		ona->rx_rings[i].ring = ona->rx_rings[i].save_ring;
506*f0ea3689SLuigi Rizzo 	netmap_mem_rings_delete(ona);
507*f0ea3689SLuigi Rizzo 	netmap_krings_delete(ona);
508*f0ea3689SLuigi Rizzo }
509*f0ea3689SLuigi Rizzo 
510*f0ea3689SLuigi Rizzo 
511*f0ea3689SLuigi Rizzo static void
512*f0ea3689SLuigi Rizzo netmap_pipe_dtor(struct netmap_adapter *na)
513*f0ea3689SLuigi Rizzo {
514*f0ea3689SLuigi Rizzo 	struct netmap_pipe_adapter *pna =
515*f0ea3689SLuigi Rizzo 		(struct netmap_pipe_adapter *)na;
516*f0ea3689SLuigi Rizzo 	ND("%p", na);
517*f0ea3689SLuigi Rizzo 	if (pna->peer_ref) {
518*f0ea3689SLuigi Rizzo 		ND("%p: clean up peer", na);
519*f0ea3689SLuigi Rizzo 		pna->peer_ref = 0;
520*f0ea3689SLuigi Rizzo 		netmap_adapter_put(&pna->peer->up);
521*f0ea3689SLuigi Rizzo 	}
522*f0ea3689SLuigi Rizzo 	if (pna->role == NR_REG_PIPE_MASTER)
523*f0ea3689SLuigi Rizzo 		netmap_pipe_remove(pna->parent, pna);
524*f0ea3689SLuigi Rizzo 	netmap_adapter_put(pna->parent);
525*f0ea3689SLuigi Rizzo 	free(na->ifp, M_DEVBUF);
526*f0ea3689SLuigi Rizzo 	na->ifp = NULL;
527*f0ea3689SLuigi Rizzo 	pna->parent = NULL;
528*f0ea3689SLuigi Rizzo }
529*f0ea3689SLuigi Rizzo 
530*f0ea3689SLuigi Rizzo int
531*f0ea3689SLuigi Rizzo netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na, int create)
532*f0ea3689SLuigi Rizzo {
533*f0ea3689SLuigi Rizzo 	struct nmreq pnmr;
534*f0ea3689SLuigi Rizzo 	struct netmap_adapter *pna; /* parent adapter */
535*f0ea3689SLuigi Rizzo 	struct netmap_pipe_adapter *mna, *sna, *req;
536*f0ea3689SLuigi Rizzo 	struct ifnet *ifp, *ifp2;
537*f0ea3689SLuigi Rizzo 	u_int pipe_id;
538*f0ea3689SLuigi Rizzo 	int role = nmr->nr_flags & NR_REG_MASK;
539*f0ea3689SLuigi Rizzo 	int error;
540*f0ea3689SLuigi Rizzo 
541*f0ea3689SLuigi Rizzo 	ND("flags %x", nmr->nr_flags);
542*f0ea3689SLuigi Rizzo 
543*f0ea3689SLuigi Rizzo 	if (role != NR_REG_PIPE_MASTER && role != NR_REG_PIPE_SLAVE) {
544*f0ea3689SLuigi Rizzo 		ND("not a pipe");
545*f0ea3689SLuigi Rizzo 		return 0;
546*f0ea3689SLuigi Rizzo 	}
547*f0ea3689SLuigi Rizzo 	role = nmr->nr_flags & NR_REG_MASK;
548*f0ea3689SLuigi Rizzo 
549*f0ea3689SLuigi Rizzo 	/* first, try to find the parent adapter */
550*f0ea3689SLuigi Rizzo 	bzero(&pnmr, sizeof(pnmr));
551*f0ea3689SLuigi Rizzo 	memcpy(&pnmr.nr_name, nmr->nr_name, IFNAMSIZ);
552*f0ea3689SLuigi Rizzo 	/* pass to parent the requested number of pipes */
553*f0ea3689SLuigi Rizzo 	pnmr.nr_arg1 = nmr->nr_arg1;
554*f0ea3689SLuigi Rizzo 	error = netmap_get_na(&pnmr, &pna, create);
555*f0ea3689SLuigi Rizzo 	if (error) {
556*f0ea3689SLuigi Rizzo 		ND("parent lookup failed: %d", error);
557*f0ea3689SLuigi Rizzo 		return error;
558*f0ea3689SLuigi Rizzo 	}
559*f0ea3689SLuigi Rizzo 	ND("found parent: %s", NM_IFPNAME(pna->ifp));
560*f0ea3689SLuigi Rizzo 
561*f0ea3689SLuigi Rizzo 	if (NETMAP_OWNED_BY_KERN(pna)) {
562*f0ea3689SLuigi Rizzo 		ND("parent busy");
563*f0ea3689SLuigi Rizzo 		error = EBUSY;
564*f0ea3689SLuigi Rizzo 		goto put_out;
565*f0ea3689SLuigi Rizzo 	}
566*f0ea3689SLuigi Rizzo 
567*f0ea3689SLuigi Rizzo 	/* next, lookup the pipe id in the parent list */
568*f0ea3689SLuigi Rizzo 	req = NULL;
569*f0ea3689SLuigi Rizzo 	pipe_id = nmr->nr_ringid & NETMAP_RING_MASK;
570*f0ea3689SLuigi Rizzo 	mna = netmap_pipe_find(pna, pipe_id);
571*f0ea3689SLuigi Rizzo 	if (mna) {
572*f0ea3689SLuigi Rizzo 		if (mna->role == role) {
573*f0ea3689SLuigi Rizzo 			ND("found %d directly at %d", pipe_id, mna->parent_slot);
574*f0ea3689SLuigi Rizzo 			req = mna;
575*f0ea3689SLuigi Rizzo 		} else {
576*f0ea3689SLuigi Rizzo 			ND("found %d indirectly at %d", pipe_id, mna->parent_slot);
577*f0ea3689SLuigi Rizzo 			req = mna->peer;
578*f0ea3689SLuigi Rizzo 		}
579*f0ea3689SLuigi Rizzo 		/* the pipe we have found already holds a ref to the parent,
580*f0ea3689SLuigi Rizzo                  * so we need to drop the one we got from netmap_get_na()
581*f0ea3689SLuigi Rizzo                  */
582*f0ea3689SLuigi Rizzo 		netmap_adapter_put(pna);
583*f0ea3689SLuigi Rizzo 		goto found;
584*f0ea3689SLuigi Rizzo 	}
585*f0ea3689SLuigi Rizzo 	ND("pipe %d not found, create %d", pipe_id, create);
586*f0ea3689SLuigi Rizzo 	if (!create) {
587*f0ea3689SLuigi Rizzo 		error = ENODEV;
588*f0ea3689SLuigi Rizzo 		goto put_out;
589*f0ea3689SLuigi Rizzo 	}
590*f0ea3689SLuigi Rizzo 	/* we create both master and slave.
591*f0ea3689SLuigi Rizzo          * The endpoint we were asked for holds a reference to
592*f0ea3689SLuigi Rizzo          * the other one.
593*f0ea3689SLuigi Rizzo          */
594*f0ea3689SLuigi Rizzo 	ifp = malloc(sizeof(*ifp), M_DEVBUF, M_NOWAIT | M_ZERO);
595*f0ea3689SLuigi Rizzo 	if (!ifp) {
596*f0ea3689SLuigi Rizzo 		error = ENOMEM;
597*f0ea3689SLuigi Rizzo 		goto put_out;
598*f0ea3689SLuigi Rizzo 	}
599*f0ea3689SLuigi Rizzo 	strcpy(ifp->if_xname, NM_IFPNAME(pna->ifp));
600*f0ea3689SLuigi Rizzo 
601*f0ea3689SLuigi Rizzo 	mna = malloc(sizeof(*mna), M_DEVBUF, M_NOWAIT | M_ZERO);
602*f0ea3689SLuigi Rizzo 	if (mna == NULL) {
603*f0ea3689SLuigi Rizzo 		error = ENOMEM;
604*f0ea3689SLuigi Rizzo 		goto free_ifp;
605*f0ea3689SLuigi Rizzo 	}
606*f0ea3689SLuigi Rizzo 	mna->up.ifp = ifp;
607*f0ea3689SLuigi Rizzo 
608*f0ea3689SLuigi Rizzo 	mna->id = pipe_id;
609*f0ea3689SLuigi Rizzo 	mna->role = NR_REG_PIPE_MASTER;
610*f0ea3689SLuigi Rizzo 	mna->parent = pna;
611*f0ea3689SLuigi Rizzo 
612*f0ea3689SLuigi Rizzo 	mna->up.nm_txsync = netmap_pipe_txsync;
613*f0ea3689SLuigi Rizzo 	mna->up.nm_rxsync = netmap_pipe_rxsync;
614*f0ea3689SLuigi Rizzo 	mna->up.nm_register = netmap_pipe_reg;
615*f0ea3689SLuigi Rizzo 	mna->up.nm_dtor = netmap_pipe_dtor;
616*f0ea3689SLuigi Rizzo 	mna->up.nm_krings_create = netmap_pipe_krings_create;
617*f0ea3689SLuigi Rizzo 	mna->up.nm_krings_delete = netmap_pipe_krings_delete;
618*f0ea3689SLuigi Rizzo 	mna->up.nm_mem = pna->nm_mem;
619*f0ea3689SLuigi Rizzo 	mna->up.na_lut = pna->na_lut;
620*f0ea3689SLuigi Rizzo 	mna->up.na_lut_objtotal = pna->na_lut_objtotal;
621*f0ea3689SLuigi Rizzo 
622*f0ea3689SLuigi Rizzo 	mna->up.num_tx_rings = 1;
623*f0ea3689SLuigi Rizzo 	mna->up.num_rx_rings = 1;
624*f0ea3689SLuigi Rizzo 	mna->up.num_tx_desc = nmr->nr_tx_slots;
625*f0ea3689SLuigi Rizzo 	nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc,
626*f0ea3689SLuigi Rizzo 			1, NM_PIPE_MAXSLOTS, NULL);
627*f0ea3689SLuigi Rizzo 	mna->up.num_rx_desc = nmr->nr_rx_slots;
628*f0ea3689SLuigi Rizzo 	nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc,
629*f0ea3689SLuigi Rizzo 			1, NM_PIPE_MAXSLOTS, NULL);
630*f0ea3689SLuigi Rizzo 	error = netmap_attach_common(&mna->up);
631*f0ea3689SLuigi Rizzo 	if (error)
632*f0ea3689SLuigi Rizzo 		goto free_ifp;
633*f0ea3689SLuigi Rizzo 	/* register the master with the parent */
634*f0ea3689SLuigi Rizzo 	error = netmap_pipe_add(pna, mna);
635*f0ea3689SLuigi Rizzo 	if (error)
636*f0ea3689SLuigi Rizzo 		goto free_mna;
637*f0ea3689SLuigi Rizzo 
638*f0ea3689SLuigi Rizzo 	/* create the slave */
639*f0ea3689SLuigi Rizzo 	ifp2 = malloc(sizeof(*ifp), M_DEVBUF, M_NOWAIT | M_ZERO);
640*f0ea3689SLuigi Rizzo 	if (!ifp) {
641*f0ea3689SLuigi Rizzo 		error = ENOMEM;
642*f0ea3689SLuigi Rizzo 		goto free_mna;
643*f0ea3689SLuigi Rizzo 	}
644*f0ea3689SLuigi Rizzo 	strcpy(ifp2->if_xname, NM_IFPNAME(pna->ifp));
645*f0ea3689SLuigi Rizzo 
646*f0ea3689SLuigi Rizzo 	sna = malloc(sizeof(*mna), M_DEVBUF, M_NOWAIT | M_ZERO);
647*f0ea3689SLuigi Rizzo 	if (sna == NULL) {
648*f0ea3689SLuigi Rizzo 		error = ENOMEM;
649*f0ea3689SLuigi Rizzo 		goto free_ifp2;
650*f0ea3689SLuigi Rizzo 	}
651*f0ea3689SLuigi Rizzo 	/* most fields are the same, copy from master and then fix */
652*f0ea3689SLuigi Rizzo 	*sna = *mna;
653*f0ea3689SLuigi Rizzo 	sna->up.ifp = ifp2;
654*f0ea3689SLuigi Rizzo 	sna->role = NR_REG_PIPE_SLAVE;
655*f0ea3689SLuigi Rizzo 	error = netmap_attach_common(&sna->up);
656*f0ea3689SLuigi Rizzo 	if (error)
657*f0ea3689SLuigi Rizzo 		goto free_sna;
658*f0ea3689SLuigi Rizzo 
659*f0ea3689SLuigi Rizzo 	/* join the two endpoints */
660*f0ea3689SLuigi Rizzo 	mna->peer = sna;
661*f0ea3689SLuigi Rizzo 	sna->peer = mna;
662*f0ea3689SLuigi Rizzo 
663*f0ea3689SLuigi Rizzo 	/* we already have a reference to the parent, but we
664*f0ea3689SLuigi Rizzo          * need another one for the other endpoint we created
665*f0ea3689SLuigi Rizzo          */
666*f0ea3689SLuigi Rizzo 	netmap_adapter_get(pna);
667*f0ea3689SLuigi Rizzo 
668*f0ea3689SLuigi Rizzo 	if (role == NR_REG_PIPE_MASTER) {
669*f0ea3689SLuigi Rizzo 		req = mna;
670*f0ea3689SLuigi Rizzo 		mna->peer_ref = 1;
671*f0ea3689SLuigi Rizzo 		netmap_adapter_get(&sna->up);
672*f0ea3689SLuigi Rizzo 	} else {
673*f0ea3689SLuigi Rizzo 		req = sna;
674*f0ea3689SLuigi Rizzo 		sna->peer_ref = 1;
675*f0ea3689SLuigi Rizzo 		netmap_adapter_get(&mna->up);
676*f0ea3689SLuigi Rizzo 	}
677*f0ea3689SLuigi Rizzo 	ND("created master %p and slave %p", mna, sna);
678*f0ea3689SLuigi Rizzo found:
679*f0ea3689SLuigi Rizzo 
680*f0ea3689SLuigi Rizzo 	ND("pipe %d %s at %p", pipe_id,
681*f0ea3689SLuigi Rizzo 		(req->role == NR_REG_PIPE_MASTER ? "master" : "slave"), req);
682*f0ea3689SLuigi Rizzo 	*na = &req->up;
683*f0ea3689SLuigi Rizzo 	netmap_adapter_get(*na);
684*f0ea3689SLuigi Rizzo 
685*f0ea3689SLuigi Rizzo 	/* write the configuration back */
686*f0ea3689SLuigi Rizzo 	nmr->nr_tx_rings = req->up.num_tx_rings;
687*f0ea3689SLuigi Rizzo 	nmr->nr_rx_rings = req->up.num_rx_rings;
688*f0ea3689SLuigi Rizzo 	nmr->nr_tx_slots = req->up.num_tx_desc;
689*f0ea3689SLuigi Rizzo 	nmr->nr_rx_slots = req->up.num_rx_desc;
690*f0ea3689SLuigi Rizzo 
691*f0ea3689SLuigi Rizzo 	/* keep the reference to the parent.
692*f0ea3689SLuigi Rizzo          * It will be released by the req destructor
693*f0ea3689SLuigi Rizzo          */
694*f0ea3689SLuigi Rizzo 
695*f0ea3689SLuigi Rizzo 	return 0;
696*f0ea3689SLuigi Rizzo 
697*f0ea3689SLuigi Rizzo free_sna:
698*f0ea3689SLuigi Rizzo 	free(sna, M_DEVBUF);
699*f0ea3689SLuigi Rizzo free_ifp2:
700*f0ea3689SLuigi Rizzo 	free(ifp2, M_DEVBUF);
701*f0ea3689SLuigi Rizzo free_mna:
702*f0ea3689SLuigi Rizzo 	free(mna, M_DEVBUF);
703*f0ea3689SLuigi Rizzo free_ifp:
704*f0ea3689SLuigi Rizzo 	free(ifp, M_DEVBUF);
705*f0ea3689SLuigi Rizzo put_out:
706*f0ea3689SLuigi Rizzo 	netmap_adapter_put(pna);
707*f0ea3689SLuigi Rizzo 	return error;
708*f0ea3689SLuigi Rizzo }
709*f0ea3689SLuigi Rizzo 
710*f0ea3689SLuigi Rizzo 
711*f0ea3689SLuigi Rizzo #endif /* WITH_PIPES */
712