]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/netmap/netmap_pipe.c
MFV r323531: 8521 nvlist memory leak in get_clones_stat() and spa_load_best()
[FreeBSD/FreeBSD.git] / sys / dev / netmap / netmap_pipe.c
1 /*
2  * Copyright (C) 2014-2016 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
79 static int netmap_default_pipes = 0; /* ignored, kept for compatibility */
80 SYSBEGIN(vars_pipes);
81 SYSCTL_DECL(_dev_netmap);
82 SYSCTL_INT(_dev_netmap, OID_AUTO, default_pipes, CTLFLAG_RW, &netmap_default_pipes, 0 , "");
83 SYSEND;
84
85 /* allocate the pipe array in the parent adapter */
86 static int
87 nm_pipe_alloc(struct netmap_adapter *na, u_int npipes)
88 {
89         size_t old_len, len;
90         struct netmap_pipe_adapter **npa;
91
92         if (npipes <= na->na_max_pipes)
93                 /* we already have more entries that requested */
94                 return 0;
95
96         if (npipes < na->na_next_pipe || npipes > NM_MAXPIPES)
97                 return EINVAL;
98
99         old_len = sizeof(struct netmap_pipe_adapter *)*na->na_max_pipes;
100         len = sizeof(struct netmap_pipe_adapter *) * npipes;
101         npa = nm_os_realloc(na->na_pipes, len, old_len);
102         if (npa == NULL)
103                 return ENOMEM;
104
105         na->na_pipes = npa;
106         na->na_max_pipes = npipes;
107
108         return 0;
109 }
110
111 /* deallocate the parent array in the parent adapter */
112 void
113 netmap_pipe_dealloc(struct netmap_adapter *na)
114 {
115         if (na->na_pipes) {
116                 if (na->na_next_pipe > 0) {
117                         D("freeing not empty pipe array for %s (%d dangling pipes)!", na->name,
118                                         na->na_next_pipe);
119                 }
120                 nm_os_free(na->na_pipes);
121                 na->na_pipes = NULL;
122                 na->na_max_pipes = 0;
123                 na->na_next_pipe = 0;
124         }
125 }
126
127 /* find a pipe endpoint with the given id among the parent's pipes */
128 static struct netmap_pipe_adapter *
129 netmap_pipe_find(struct netmap_adapter *parent, u_int pipe_id)
130 {
131         int i;
132         struct netmap_pipe_adapter *na;
133
134         for (i = 0; i < parent->na_next_pipe; i++) {
135                 na = parent->na_pipes[i];
136                 if (na->id == pipe_id) {
137                         return na;
138                 }
139         }
140         return NULL;
141 }
142
143 /* add a new pipe endpoint to the parent array */
144 static int
145 netmap_pipe_add(struct netmap_adapter *parent, struct netmap_pipe_adapter *na)
146 {
147         if (parent->na_next_pipe >= parent->na_max_pipes) {
148                 u_int npipes = parent->na_max_pipes ?  2*parent->na_max_pipes : 2;
149                 int error = nm_pipe_alloc(parent, npipes);
150                 if (error)
151                         return error;
152         }
153
154         parent->na_pipes[parent->na_next_pipe] = na;
155         na->parent_slot = parent->na_next_pipe;
156         parent->na_next_pipe++;
157         return 0;
158 }
159
160 /* remove the given pipe endpoint from the parent array */
161 static void
162 netmap_pipe_remove(struct netmap_adapter *parent, struct netmap_pipe_adapter *na)
163 {
164         u_int n;
165         n = --parent->na_next_pipe;
166         if (n != na->parent_slot) {
167                 struct netmap_pipe_adapter **p =
168                         &parent->na_pipes[na->parent_slot];
169                 *p = parent->na_pipes[n];
170                 (*p)->parent_slot = na->parent_slot;
171         }
172         parent->na_pipes[n] = NULL;
173 }
174
175 int
176 netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
177 {
178         struct netmap_kring *rxkring = txkring->pipe;
179         u_int limit; /* slots to transfer */
180         u_int j, k, lim_tx = txkring->nkr_num_slots - 1,
181                 lim_rx = rxkring->nkr_num_slots - 1;
182         int m, busy;
183
184         ND("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name);
185         ND(2, "before: hwcur %d hwtail %d cur %d head %d tail %d", txkring->nr_hwcur, txkring->nr_hwtail,
186                 txkring->rcur, txkring->rhead, txkring->rtail);
187
188         j = rxkring->nr_hwtail; /* RX */
189         k = txkring->nr_hwcur;  /* TX */
190         m = txkring->rhead - txkring->nr_hwcur; /* new slots */
191         if (m < 0)
192                 m += txkring->nkr_num_slots;
193         limit = m;
194         m = lim_rx; /* max avail space on destination */
195         busy = j - rxkring->nr_hwcur; /* busy slots */
196         if (busy < 0)
197                 busy += rxkring->nkr_num_slots;
198         m -= busy; /* subtract busy slots */
199         ND(2, "m %d limit %d", m, limit);
200         if (m < limit)
201                 limit = m;
202
203         if (limit == 0) {
204                 /* either the rxring is full, or nothing to send */
205                 return 0;
206         }
207
208         while (limit-- > 0) {
209                 struct netmap_slot *rs = &rxkring->ring->slot[j];
210                 struct netmap_slot *ts = &txkring->ring->slot[k];
211                 struct netmap_slot tmp;
212
213                 /* swap the slots */
214                 tmp = *rs;
215                 *rs = *ts;
216                 *ts = tmp;
217
218                 /* report the buffer change */
219                 ts->flags |= NS_BUF_CHANGED;
220                 rs->flags |= NS_BUF_CHANGED;
221
222                 j = nm_next(j, lim_rx);
223                 k = nm_next(k, lim_tx);
224         }
225
226         mb(); /* make sure the slots are updated before publishing them */
227         rxkring->nr_hwtail = j;
228         txkring->nr_hwcur = k;
229         txkring->nr_hwtail = nm_prev(k, lim_tx);
230
231         ND(2, "after: hwcur %d hwtail %d cur %d head %d tail %d j %d", txkring->nr_hwcur, txkring->nr_hwtail,
232                 txkring->rcur, txkring->rhead, txkring->rtail, j);
233
234         mb(); /* make sure rxkring->nr_hwtail is updated before notifying */
235         rxkring->nm_notify(rxkring, 0);
236
237         return 0;
238 }
239
240 int
241 netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags)
242 {
243         struct netmap_kring *txkring = rxkring->pipe;
244         uint32_t oldhwcur = rxkring->nr_hwcur;
245
246         ND("%s %x <- %s", rxkring->name, flags, txkring->name);
247         rxkring->nr_hwcur = rxkring->rhead; /* recover user-relased slots */
248         ND(5, "hwcur %d hwtail %d cur %d head %d tail %d", rxkring->nr_hwcur, rxkring->nr_hwtail,
249                 rxkring->rcur, rxkring->rhead, rxkring->rtail);
250         mb(); /* paired with the first mb() in txsync */
251
252         if (oldhwcur != rxkring->nr_hwcur) {
253                 /* we have released some slots, notify the other end */
254                 mb(); /* make sure nr_hwcur is updated before notifying */
255                 txkring->nm_notify(txkring, 0);
256         }
257         return 0;
258 }
259
260 /* Pipe endpoints are created and destroyed together, so that endopoints do not
261  * have to check for the existence of their peer at each ?xsync.
262  *
263  * To play well with the existing netmap infrastructure (refcounts etc.), we
264  * adopt the following strategy:
265  *
266  * 1) The first endpoint that is created also creates the other endpoint and
267  * grabs a reference to it.
268  *
269  *    state A)  user1 --> endpoint1 --> endpoint2
270  *
271  * 2) If, starting from state A, endpoint2 is then registered, endpoint1 gives
272  * its reference to the user:
273  *
274  *    state B)  user1 --> endpoint1     endpoint2 <--- user2
275  *
276  * 3) Assume that, starting from state B endpoint2 is closed. In the unregister
277  * callback endpoint2 notes that endpoint1 is still active and adds a reference
278  * from endpoint1 to itself. When user2 then releases her own reference,
279  * endpoint2 is not destroyed and we are back to state A. A symmetrical state
280  * would be reached if endpoint1 were released instead.
281  *
282  * 4) If, starting from state A, endpoint1 is closed, the destructor notes that
283  * it owns a reference to endpoint2 and releases it.
284  *
285  * Something similar goes on for the creation and destruction of the krings.
286  */
287
288
289 /* netmap_pipe_krings_create.
290  *
291  * There are two cases:
292  *
293  * 1) state is
294  *
295  *        usr1 --> e1 --> e2
296  *
297  *    and we are e1. We have to create both sets
298  *    of krings.
299  *
300  * 2) state is
301  *
302  *        usr1 --> e1 --> e2
303  *
304  *    and we are e2. e1 is certainly registered and our
305  *    krings already exist. Nothing to do.
306  */
307 static int
308 netmap_pipe_krings_create(struct netmap_adapter *na)
309 {
310         struct netmap_pipe_adapter *pna =
311                 (struct netmap_pipe_adapter *)na;
312         struct netmap_adapter *ona = &pna->peer->up;
313         int error = 0;
314         enum txrx t;
315
316         if (pna->peer_ref) {
317                 int i;
318
319                 /* case 1) above */
320                 ND("%p: case 1, create both ends", na);
321                 error = netmap_krings_create(na, 0);
322                 if (error)
323                         goto err;
324
325                 /* create the krings of the other end */
326                 error = netmap_krings_create(ona, 0);
327                 if (error)
328                         goto del_krings1;
329
330                 /* cross link the krings */
331                 for_rx_tx(t) {
332                         enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
333                         for (i = 0; i < nma_get_nrings(na, t); i++) {
334                                 NMR(na, t)[i].pipe = NMR(ona, r) + i;
335                                 NMR(ona, r)[i].pipe = NMR(na, t) + i;
336                         }
337                 }
338
339         }
340         return 0;
341
342 del_krings1:
343         netmap_krings_delete(na);
344 err:
345         return error;
346 }
347
348 /* netmap_pipe_reg.
349  *
350  * There are two cases on registration (onoff==1)
351  *
352  * 1.a) state is
353  *
354  *        usr1 --> e1 --> e2
355  *
356  *      and we are e1. Create the needed rings of the
357  *      other end.
358  *
359  * 1.b) state is
360  *
361  *        usr1 --> e1 --> e2 <-- usr2
362  *
363  *      and we are e2. Drop the ref e1 is holding.
364  *
365  *  There are two additional cases on unregister (onoff==0)
366  *
367  *  2.a) state is
368  *
369  *         usr1 --> e1 --> e2
370  *
371  *       and we are e1. Nothing special to do, e2 will
372  *       be cleaned up by the destructor of e1.
373  *
374  *  2.b) state is
375  *
376  *         usr1 --> e1     e2 <-- usr2
377  *
378  *       and we are either e1 or e2. Add a ref from the
379  *       other end and hide our rings.
380  */
381 static int
382 netmap_pipe_reg(struct netmap_adapter *na, int onoff)
383 {
384         struct netmap_pipe_adapter *pna =
385                 (struct netmap_pipe_adapter *)na;
386         struct netmap_adapter *ona = &pna->peer->up;
387         int i, error = 0;
388         enum txrx t;
389
390         ND("%p: onoff %d", na, onoff);
391         if (onoff) {
392                 for_rx_tx(t) {
393                         for (i = 0; i < nma_get_nrings(na, t); i++) {
394                                 struct netmap_kring *kring = &NMR(na, t)[i];
395
396                                 if (nm_kring_pending_on(kring)) {
397                                         /* mark the peer ring as needed */
398                                         kring->pipe->nr_kflags |= NKR_NEEDRING;
399                                 }
400                         }
401                 }
402
403                 /* create all missing needed rings on the other end */
404                 error = netmap_mem_rings_create(ona);
405                 if (error)
406                         return error;
407
408                 /* In case of no error we put our rings in netmap mode */
409                 for_rx_tx(t) {
410                         for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
411                                 struct netmap_kring *kring = &NMR(na, t)[i];
412
413                                 if (nm_kring_pending_on(kring)) {
414                                         kring->nr_mode = NKR_NETMAP_ON;
415                                 }
416                         }
417                 }
418                 if (na->active_fds == 0)
419                         na->na_flags |= NAF_NETMAP_ON;
420         } else {
421                 if (na->active_fds == 0)
422                         na->na_flags &= ~NAF_NETMAP_ON;
423                 for_rx_tx(t) {
424                         for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
425                                 struct netmap_kring *kring = &NMR(na, t)[i];
426
427                                 if (nm_kring_pending_off(kring)) {
428                                         kring->nr_mode = NKR_NETMAP_OFF;
429                                         /* mark the peer ring as no longer needed by us
430                                          * (it may still be kept if sombody else is using it)
431                                          */
432                                         if (kring->pipe) {
433                                                 kring->pipe->nr_kflags &= ~NKR_NEEDRING;
434                                         }
435                                 }
436                         }
437                 }
438                 /* delete all the peer rings that are no longer needed */
439                 netmap_mem_rings_delete(ona);
440         }
441
442         if (na->active_fds) {
443                 ND("active_fds %d", na->active_fds);
444                 return 0;
445         }
446
447         if (pna->peer_ref) {
448                 ND("%p: case 1.a or 2.a, nothing to do", na);
449                 return 0;
450         }
451         if (onoff) {
452                 ND("%p: case 1.b, drop peer", na);
453                 pna->peer->peer_ref = 0;
454                 netmap_adapter_put(na);
455         } else {
456                 ND("%p: case 2.b, grab peer", na);
457                 netmap_adapter_get(na);
458                 pna->peer->peer_ref = 1;
459         }
460         return error;
461 }
462
463 /* netmap_pipe_krings_delete.
464  *
465  * There are two cases:
466  *
467  * 1) state is
468  *
469  *                usr1 --> e1 --> e2
470  *
471  *    and we are e1 (e2 is not registered, so krings_delete cannot be
472  *    called on it);
473  *
474  * 2) state is
475  *
476  *                usr1 --> e1     e2 <-- usr2
477  *
478  *    and we are either e1 or e2.
479  *
480  * In the former case we have to also delete the krings of e2;
481  * in the latter case we do nothing (note that our krings
482  * have already been hidden in the unregister callback).
483  */
484 static void
485 netmap_pipe_krings_delete(struct netmap_adapter *na)
486 {
487         struct netmap_pipe_adapter *pna =
488                 (struct netmap_pipe_adapter *)na;
489         struct netmap_adapter *ona; /* na of the other end */
490
491         if (!pna->peer_ref) {
492                 ND("%p: case 2, kept alive by peer",  na);
493                 return;
494         }
495         /* case 1) above */
496         ND("%p: case 1, deleting everything", na);
497         netmap_krings_delete(na); /* also zeroes tx_rings etc. */
498         ona = &pna->peer->up;
499         if (ona->tx_rings == NULL) {
500                 /* already deleted, we must be on an
501                  * cleanup-after-error path */
502                 return;
503         }
504         netmap_krings_delete(ona);
505 }
506
507
508 static void
509 netmap_pipe_dtor(struct netmap_adapter *na)
510 {
511         struct netmap_pipe_adapter *pna =
512                 (struct netmap_pipe_adapter *)na;
513         ND("%p %p", na, pna->parent_ifp);
514         if (pna->peer_ref) {
515                 ND("%p: clean up peer", na);
516                 pna->peer_ref = 0;
517                 netmap_adapter_put(&pna->peer->up);
518         }
519         if (pna->role == NR_REG_PIPE_MASTER)
520                 netmap_pipe_remove(pna->parent, pna);
521         if (pna->parent_ifp)
522                 if_rele(pna->parent_ifp);
523         netmap_adapter_put(pna->parent);
524         pna->parent = NULL;
525 }
526
527 int
528 netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
529                 struct netmap_mem_d *nmd, int create)
530 {
531         struct nmreq pnmr;
532         struct netmap_adapter *pna; /* parent adapter */
533         struct netmap_pipe_adapter *mna, *sna, *req;
534         struct ifnet *ifp = NULL;
535         u_int pipe_id;
536         int role = nmr->nr_flags & NR_REG_MASK;
537         int error, retries = 0;
538
539         ND("flags %x", nmr->nr_flags);
540
541         if (role != NR_REG_PIPE_MASTER && role != NR_REG_PIPE_SLAVE) {
542                 ND("not a pipe");
543                 return 0;
544         }
545         role = nmr->nr_flags & NR_REG_MASK;
546
547         /* first, try to find the parent adapter */
548         bzero(&pnmr, sizeof(pnmr));
549         memcpy(&pnmr.nr_name, nmr->nr_name, IFNAMSIZ);
550         /* pass to parent the requested number of pipes */
551         pnmr.nr_arg1 = nmr->nr_arg1;
552         for (;;) {
553                 int create_error;
554
555                 error = netmap_get_na(&pnmr, &pna, &ifp, nmd, create);
556                 if (!error)
557                         break;
558                 if (error != ENXIO || retries++) {
559                         ND("parent lookup failed: %d", error);
560                         return error;
561                 }
562                 ND("try to create a persistent vale port");
563                 /* create a persistent vale port and try again */
564                 NMG_UNLOCK();
565                 create_error = netmap_vi_create(&pnmr, 1 /* autodelete */);
566                 NMG_LOCK();
567                 if (create_error && create_error != EEXIST) {
568                         if (create_error != EOPNOTSUPP) {
569                                 D("failed to create a persistent vale port: %d", create_error);
570                         }
571                         return error;
572                 }
573         }
574
575         if (NETMAP_OWNED_BY_KERN(pna)) {
576                 ND("parent busy");
577                 error = EBUSY;
578                 goto put_out;
579         }
580
581         /* next, lookup the pipe id in the parent list */
582         req = NULL;
583         pipe_id = nmr->nr_ringid & NETMAP_RING_MASK;
584         mna = netmap_pipe_find(pna, pipe_id);
585         if (mna) {
586                 if (mna->role == role) {
587                         ND("found %d directly at %d", pipe_id, mna->parent_slot);
588                         req = mna;
589                 } else {
590                         ND("found %d indirectly at %d", pipe_id, mna->parent_slot);
591                         req = mna->peer;
592                 }
593                 /* the pipe we have found already holds a ref to the parent,
594                  * so we need to drop the one we got from netmap_get_na()
595                  */
596                 netmap_unget_na(pna, ifp);
597                 goto found;
598         }
599         ND("pipe %d not found, create %d", pipe_id, create);
600         if (!create) {
601                 error = ENODEV;
602                 goto put_out;
603         }
604         /* we create both master and slave.
605          * The endpoint we were asked for holds a reference to
606          * the other one.
607          */
608         mna = nm_os_malloc(sizeof(*mna));
609         if (mna == NULL) {
610                 error = ENOMEM;
611                 goto put_out;
612         }
613         snprintf(mna->up.name, sizeof(mna->up.name), "%s{%d", pna->name, pipe_id);
614
615         mna->id = pipe_id;
616         mna->role = NR_REG_PIPE_MASTER;
617         mna->parent = pna;
618         mna->parent_ifp = ifp;
619
620         mna->up.nm_txsync = netmap_pipe_txsync;
621         mna->up.nm_rxsync = netmap_pipe_rxsync;
622         mna->up.nm_register = netmap_pipe_reg;
623         mna->up.nm_dtor = netmap_pipe_dtor;
624         mna->up.nm_krings_create = netmap_pipe_krings_create;
625         mna->up.nm_krings_delete = netmap_pipe_krings_delete;
626         mna->up.nm_mem = netmap_mem_get(pna->nm_mem);
627         mna->up.na_flags |= NAF_MEM_OWNER;
628         mna->up.na_lut = pna->na_lut;
629
630         mna->up.num_tx_rings = 1;
631         mna->up.num_rx_rings = 1;
632         mna->up.num_tx_desc = nmr->nr_tx_slots;
633         nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc,
634                         1, NM_PIPE_MAXSLOTS, NULL);
635         mna->up.num_rx_desc = nmr->nr_rx_slots;
636         nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc,
637                         1, NM_PIPE_MAXSLOTS, NULL);
638         error = netmap_attach_common(&mna->up);
639         if (error)
640                 goto free_mna;
641         /* register the master with the parent */
642         error = netmap_pipe_add(pna, mna);
643         if (error)
644                 goto free_mna;
645
646         /* create the slave */
647         sna = nm_os_malloc(sizeof(*mna));
648         if (sna == NULL) {
649                 error = ENOMEM;
650                 goto unregister_mna;
651         }
652         /* most fields are the same, copy from master and then fix */
653         *sna = *mna;
654         sna->up.nm_mem = netmap_mem_get(mna->up.nm_mem);
655         snprintf(sna->up.name, sizeof(sna->up.name), "%s}%d", pna->name, pipe_id);
656         sna->role = NR_REG_PIPE_SLAVE;
657         error = netmap_attach_common(&sna->up);
658         if (error)
659                 goto free_sna;
660
661         /* join the two endpoints */
662         mna->peer = sna;
663         sna->peer = mna;
664
665         /* we already have a reference to the parent, but we
666          * need another one for the other endpoint we created
667          */
668         netmap_adapter_get(pna);
669         /* likewise for the ifp, if any */
670         if (ifp)
671                 if_ref(ifp);
672
673         if (role == NR_REG_PIPE_MASTER) {
674                 req = mna;
675                 mna->peer_ref = 1;
676                 netmap_adapter_get(&sna->up);
677         } else {
678                 req = sna;
679                 sna->peer_ref = 1;
680                 netmap_adapter_get(&mna->up);
681         }
682         ND("created master %p and slave %p", mna, sna);
683 found:
684
685         ND("pipe %d %s at %p", pipe_id,
686                 (req->role == NR_REG_PIPE_MASTER ? "master" : "slave"), req);
687         *na = &req->up;
688         netmap_adapter_get(*na);
689
690         /* keep the reference to the parent.
691          * It will be released by the req destructor
692          */
693
694         return 0;
695
696 free_sna:
697         nm_os_free(sna);
698 unregister_mna:
699         netmap_pipe_remove(pna, mna);
700 free_mna:
701         nm_os_free(mna);
702 put_out:
703         netmap_unget_na(pna, ifp);
704         return error;
705 }
706
707
708 #endif /* WITH_PIPES */