1718cf2ccSPedro F. Giffuni /*- 2718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3718cf2ccSPedro F. Giffuni * 42a7db7a6SVincenzo Maffione * Copyright (C) 2014-2018 Giuseppe Lettieri 537e3a6d3SLuigi Rizzo * All rights reserved. 6f0ea3689SLuigi Rizzo * 7f0ea3689SLuigi Rizzo * Redistribution and use in source and binary forms, with or without 8f0ea3689SLuigi Rizzo * modification, are permitted provided that the following conditions 9f0ea3689SLuigi Rizzo * are met: 10f0ea3689SLuigi Rizzo * 1. Redistributions of source code must retain the above copyright 11f0ea3689SLuigi Rizzo * notice, this list of conditions and the following disclaimer. 12f0ea3689SLuigi Rizzo * 2. Redistributions in binary form must reproduce the above copyright 13f0ea3689SLuigi Rizzo * notice, this list of conditions and the following disclaimer in the 14f0ea3689SLuigi Rizzo * documentation and/or other materials provided with the distribution. 15f0ea3689SLuigi Rizzo * 16f0ea3689SLuigi Rizzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17f0ea3689SLuigi Rizzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18f0ea3689SLuigi Rizzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19f0ea3689SLuigi Rizzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20f0ea3689SLuigi Rizzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21f0ea3689SLuigi Rizzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22f0ea3689SLuigi Rizzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23f0ea3689SLuigi Rizzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24f0ea3689SLuigi Rizzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25f0ea3689SLuigi Rizzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26f0ea3689SLuigi Rizzo * SUCH DAMAGE. 27f0ea3689SLuigi Rizzo */ 28f0ea3689SLuigi Rizzo 29f0ea3689SLuigi Rizzo /* $FreeBSD$ */ 30f0ea3689SLuigi Rizzo 31f0ea3689SLuigi Rizzo #if defined(__FreeBSD__) 32f0ea3689SLuigi Rizzo #include <sys/cdefs.h> /* prerequisite */ 33f0ea3689SLuigi Rizzo 34f0ea3689SLuigi Rizzo #include <sys/types.h> 35f0ea3689SLuigi Rizzo #include <sys/errno.h> 36f0ea3689SLuigi Rizzo #include <sys/param.h> /* defines used in kernel.h */ 37f0ea3689SLuigi Rizzo #include <sys/kernel.h> /* types used in module initialization */ 38f0ea3689SLuigi Rizzo #include <sys/malloc.h> 39f0ea3689SLuigi Rizzo #include <sys/poll.h> 40f0ea3689SLuigi Rizzo #include <sys/lock.h> 41f0ea3689SLuigi Rizzo #include <sys/rwlock.h> 42f0ea3689SLuigi Rizzo #include <sys/selinfo.h> 43f0ea3689SLuigi Rizzo #include <sys/sysctl.h> 44f0ea3689SLuigi Rizzo #include <sys/socket.h> /* sockaddrs */ 45f0ea3689SLuigi Rizzo #include <net/if.h> 46f0ea3689SLuigi Rizzo #include <net/if_var.h> 47f0ea3689SLuigi Rizzo #include <machine/bus.h> /* bus_dmamap_* */ 48f0ea3689SLuigi Rizzo #include <sys/refcount.h> 49f0ea3689SLuigi Rizzo 50f0ea3689SLuigi Rizzo 51f0ea3689SLuigi Rizzo #elif defined(linux) 52f0ea3689SLuigi Rizzo 53f0ea3689SLuigi Rizzo #include "bsd_glue.h" 54f0ea3689SLuigi Rizzo 55f0ea3689SLuigi Rizzo #elif defined(__APPLE__) 56f0ea3689SLuigi Rizzo 57f0ea3689SLuigi Rizzo #warning OSX support is only partial 58f0ea3689SLuigi Rizzo #include "osx_glue.h" 59f0ea3689SLuigi Rizzo 6037e3a6d3SLuigi Rizzo #elif defined(_WIN32) 6137e3a6d3SLuigi Rizzo #include "win_glue.h" 6237e3a6d3SLuigi Rizzo 63f0ea3689SLuigi Rizzo #else 64f0ea3689SLuigi Rizzo 65f0ea3689SLuigi Rizzo #error Unsupported platform 66f0ea3689SLuigi Rizzo 67f0ea3689SLuigi Rizzo #endif /* unsupported */ 68f0ea3689SLuigi Rizzo 69f0ea3689SLuigi Rizzo /* 70f0ea3689SLuigi Rizzo * common headers 71f0ea3689SLuigi Rizzo */ 72f0ea3689SLuigi Rizzo 73f0ea3689SLuigi Rizzo #include <net/netmap.h> 74f0ea3689SLuigi Rizzo #include <dev/netmap/netmap_kern.h> 75f0ea3689SLuigi Rizzo #include <dev/netmap/netmap_mem2.h> 76f0ea3689SLuigi Rizzo 77f0ea3689SLuigi Rizzo #ifdef WITH_PIPES 78f0ea3689SLuigi Rizzo 79f0ea3689SLuigi Rizzo #define NM_PIPE_MAXSLOTS 4096 802ff91c17SVincenzo Maffione #define NM_PIPE_MAXRINGS 256 81f0ea3689SLuigi Rizzo 8237e3a6d3SLuigi Rizzo static int netmap_default_pipes = 0; /* ignored, kept for compatibility */ 8337e3a6d3SLuigi Rizzo SYSBEGIN(vars_pipes); 84f0ea3689SLuigi Rizzo SYSCTL_DECL(_dev_netmap); 854f80b14cSVincenzo Maffione SYSCTL_INT(_dev_netmap, OID_AUTO, default_pipes, CTLFLAG_RW, 864f80b14cSVincenzo Maffione &netmap_default_pipes, 0, "For compatibility only"); 8737e3a6d3SLuigi Rizzo SYSEND; 88f0ea3689SLuigi Rizzo 89f0ea3689SLuigi Rizzo /* allocate the pipe array in the parent adapter */ 90847bf383SLuigi Rizzo static int 91847bf383SLuigi Rizzo nm_pipe_alloc(struct netmap_adapter *na, u_int npipes) 92f0ea3689SLuigi Rizzo { 93c3e9b4dbSLuiz Otavio O Souza size_t old_len, len; 94847bf383SLuigi Rizzo struct netmap_pipe_adapter **npa; 95f0ea3689SLuigi Rizzo 96847bf383SLuigi Rizzo if (npipes <= na->na_max_pipes) 97847bf383SLuigi Rizzo /* we already have more entries that requested */ 98f0ea3689SLuigi Rizzo return 0; 99f0ea3689SLuigi Rizzo 100847bf383SLuigi Rizzo if (npipes < na->na_next_pipe || npipes > NM_MAXPIPES) 101847bf383SLuigi Rizzo return EINVAL; 102f0ea3689SLuigi Rizzo 103c3e9b4dbSLuiz Otavio O Souza old_len = sizeof(struct netmap_pipe_adapter *)*na->na_max_pipes; 104f0ea3689SLuigi Rizzo len = sizeof(struct netmap_pipe_adapter *) * npipes; 105c3e9b4dbSLuiz Otavio O Souza npa = nm_os_realloc(na->na_pipes, len, old_len); 106847bf383SLuigi Rizzo if (npa == NULL) 107f0ea3689SLuigi Rizzo return ENOMEM; 108f0ea3689SLuigi Rizzo 109847bf383SLuigi Rizzo na->na_pipes = npa; 110f0ea3689SLuigi Rizzo na->na_max_pipes = npipes; 111f0ea3689SLuigi Rizzo 112f0ea3689SLuigi Rizzo return 0; 113f0ea3689SLuigi Rizzo } 114f0ea3689SLuigi Rizzo 115f0ea3689SLuigi Rizzo /* deallocate the parent array in the parent adapter */ 116f0ea3689SLuigi Rizzo void 117f0ea3689SLuigi Rizzo netmap_pipe_dealloc(struct netmap_adapter *na) 118f0ea3689SLuigi Rizzo { 119f0ea3689SLuigi Rizzo if (na->na_pipes) { 120847bf383SLuigi Rizzo if (na->na_next_pipe > 0) { 121847bf383SLuigi Rizzo D("freeing not empty pipe array for %s (%d dangling pipes)!", na->name, 122847bf383SLuigi Rizzo na->na_next_pipe); 123847bf383SLuigi Rizzo } 124c3e9b4dbSLuiz Otavio O Souza nm_os_free(na->na_pipes); 125f0ea3689SLuigi Rizzo na->na_pipes = NULL; 126f0ea3689SLuigi Rizzo na->na_max_pipes = 0; 127f0ea3689SLuigi Rizzo na->na_next_pipe = 0; 128f0ea3689SLuigi Rizzo } 129f0ea3689SLuigi Rizzo } 130f0ea3689SLuigi Rizzo 131f0ea3689SLuigi Rizzo /* find a pipe endpoint with the given id among the parent's pipes */ 132f0ea3689SLuigi Rizzo static struct netmap_pipe_adapter * 1332ff91c17SVincenzo Maffione netmap_pipe_find(struct netmap_adapter *parent, const char *pipe_id) 134f0ea3689SLuigi Rizzo { 135f0ea3689SLuigi Rizzo int i; 136f0ea3689SLuigi Rizzo struct netmap_pipe_adapter *na; 137f0ea3689SLuigi Rizzo 138f0ea3689SLuigi Rizzo for (i = 0; i < parent->na_next_pipe; i++) { 1392ff91c17SVincenzo Maffione const char *na_pipe_id; 140f0ea3689SLuigi Rizzo na = parent->na_pipes[i]; 1412ff91c17SVincenzo Maffione na_pipe_id = strrchr(na->up.name, 1422ff91c17SVincenzo Maffione na->role == NM_PIPE_ROLE_MASTER ? '{' : '}'); 1432ff91c17SVincenzo Maffione KASSERT(na_pipe_id != NULL, ("Invalid pipe name")); 1442ff91c17SVincenzo Maffione ++na_pipe_id; 1452ff91c17SVincenzo Maffione if (!strcmp(na_pipe_id, pipe_id)) { 146f0ea3689SLuigi Rizzo return na; 147f0ea3689SLuigi Rizzo } 148f0ea3689SLuigi Rizzo } 149f0ea3689SLuigi Rizzo return NULL; 150f0ea3689SLuigi Rizzo } 151f0ea3689SLuigi Rizzo 152f0ea3689SLuigi Rizzo /* add a new pipe endpoint to the parent array */ 153f0ea3689SLuigi Rizzo static int 154f0ea3689SLuigi Rizzo netmap_pipe_add(struct netmap_adapter *parent, struct netmap_pipe_adapter *na) 155f0ea3689SLuigi Rizzo { 156f0ea3689SLuigi Rizzo if (parent->na_next_pipe >= parent->na_max_pipes) { 157847bf383SLuigi Rizzo u_int npipes = parent->na_max_pipes ? 2*parent->na_max_pipes : 2; 158847bf383SLuigi Rizzo int error = nm_pipe_alloc(parent, npipes); 159847bf383SLuigi Rizzo if (error) 160847bf383SLuigi Rizzo return error; 161f0ea3689SLuigi Rizzo } 162f0ea3689SLuigi Rizzo 163f0ea3689SLuigi Rizzo parent->na_pipes[parent->na_next_pipe] = na; 164f0ea3689SLuigi Rizzo na->parent_slot = parent->na_next_pipe; 165f0ea3689SLuigi Rizzo parent->na_next_pipe++; 166f0ea3689SLuigi Rizzo return 0; 167f0ea3689SLuigi Rizzo } 168f0ea3689SLuigi Rizzo 169f0ea3689SLuigi Rizzo /* remove the given pipe endpoint from the parent array */ 170f0ea3689SLuigi Rizzo static void 171f0ea3689SLuigi Rizzo netmap_pipe_remove(struct netmap_adapter *parent, struct netmap_pipe_adapter *na) 172f0ea3689SLuigi Rizzo { 173f0ea3689SLuigi Rizzo u_int n; 174f0ea3689SLuigi Rizzo n = --parent->na_next_pipe; 175f0ea3689SLuigi Rizzo if (n != na->parent_slot) { 176847bf383SLuigi Rizzo struct netmap_pipe_adapter **p = 177847bf383SLuigi Rizzo &parent->na_pipes[na->parent_slot]; 178847bf383SLuigi Rizzo *p = parent->na_pipes[n]; 179847bf383SLuigi Rizzo (*p)->parent_slot = na->parent_slot; 180f0ea3689SLuigi Rizzo } 181f0ea3689SLuigi Rizzo parent->na_pipes[n] = NULL; 182f0ea3689SLuigi Rizzo } 183f0ea3689SLuigi Rizzo 184c3e9b4dbSLuiz Otavio O Souza int 1854bf50f18SLuigi Rizzo netmap_pipe_txsync(struct netmap_kring *txkring, int flags) 186f0ea3689SLuigi Rizzo { 1874bf50f18SLuigi Rizzo struct netmap_kring *rxkring = txkring->pipe; 1882a7db7a6SVincenzo Maffione u_int k, lim = txkring->nkr_num_slots - 1, nk; 1892ff91c17SVincenzo Maffione int m; /* slots to transfer */ 1902a7db7a6SVincenzo Maffione int complete; /* did we see a complete packet ? */ 1914f80b14cSVincenzo Maffione struct netmap_ring *txring = txkring->ring, *rxring = rxkring->ring; 192f0ea3689SLuigi Rizzo 193f0ea3689SLuigi Rizzo ND("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name); 1942ff91c17SVincenzo Maffione ND(20, "TX before: hwcur %d hwtail %d cur %d head %d tail %d", 1952ff91c17SVincenzo Maffione txkring->nr_hwcur, txkring->nr_hwtail, 196f0ea3689SLuigi Rizzo txkring->rcur, txkring->rhead, txkring->rtail); 197f0ea3689SLuigi Rizzo 1982a7db7a6SVincenzo Maffione /* update the hwtail */ 1992a7db7a6SVincenzo Maffione txkring->nr_hwtail = txkring->pipe_tail; 2002a7db7a6SVincenzo Maffione 201f0ea3689SLuigi Rizzo m = txkring->rhead - txkring->nr_hwcur; /* new slots */ 202f0ea3689SLuigi Rizzo if (m < 0) 203f0ea3689SLuigi Rizzo m += txkring->nkr_num_slots; 204f0ea3689SLuigi Rizzo 2052ff91c17SVincenzo Maffione if (m == 0) { 2062ff91c17SVincenzo Maffione /* nothing to send */ 207f0ea3689SLuigi Rizzo return 0; 208f0ea3689SLuigi Rizzo } 209f0ea3689SLuigi Rizzo 2102a7db7a6SVincenzo Maffione for (k = txkring->nr_hwcur, nk = lim + 1, complete = 0; m; 2112a7db7a6SVincenzo Maffione m--, k = nm_next(k, lim), nk = (complete ? k : nk)) { 2122ff91c17SVincenzo Maffione struct netmap_slot *rs = &rxring->slot[k]; 2134f80b14cSVincenzo Maffione struct netmap_slot *ts = &txring->slot[k]; 214f0ea3689SLuigi Rizzo 2152a7db7a6SVincenzo Maffione *rs = *ts; 2162ff91c17SVincenzo Maffione if (ts->flags & NS_BUF_CHANGED) { 2172ff91c17SVincenzo Maffione ts->flags &= ~NS_BUF_CHANGED; 2182ff91c17SVincenzo Maffione } 2192a7db7a6SVincenzo Maffione complete = !(ts->flags & NS_MOREFRAG); 220f0ea3689SLuigi Rizzo } 221f0ea3689SLuigi Rizzo 222f0ea3689SLuigi Rizzo txkring->nr_hwcur = k; 223f0ea3689SLuigi Rizzo 2242ff91c17SVincenzo Maffione ND(20, "TX after : hwcur %d hwtail %d cur %d head %d tail %d k %d", 2252ff91c17SVincenzo Maffione txkring->nr_hwcur, txkring->nr_hwtail, 2262ff91c17SVincenzo Maffione txkring->rcur, txkring->rhead, txkring->rtail, k); 227f0ea3689SLuigi Rizzo 2282a7db7a6SVincenzo Maffione if (likely(nk <= lim)) { 2292a7db7a6SVincenzo Maffione mb(); /* make sure the slots are updated before publishing them */ 2302a7db7a6SVincenzo Maffione rxkring->pipe_tail = nk; /* only publish complete packets */ 231847bf383SLuigi Rizzo rxkring->nm_notify(rxkring, 0); 2322a7db7a6SVincenzo Maffione } 233f0ea3689SLuigi Rizzo 234f0ea3689SLuigi Rizzo return 0; 235f0ea3689SLuigi Rizzo } 236f0ea3689SLuigi Rizzo 237c3e9b4dbSLuiz Otavio O Souza int 2384bf50f18SLuigi Rizzo netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags) 239f0ea3689SLuigi Rizzo { 2404bf50f18SLuigi Rizzo struct netmap_kring *txkring = rxkring->pipe; 2412ff91c17SVincenzo Maffione u_int k, lim = rxkring->nkr_num_slots - 1; 2422ff91c17SVincenzo Maffione int m; /* slots to release */ 2432ff91c17SVincenzo Maffione struct netmap_ring *txring = txkring->ring, *rxring = rxkring->ring; 244f0ea3689SLuigi Rizzo 2452ff91c17SVincenzo Maffione ND("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name); 2462ff91c17SVincenzo Maffione ND(20, "RX before: hwcur %d hwtail %d cur %d head %d tail %d", 2472ff91c17SVincenzo Maffione rxkring->nr_hwcur, rxkring->nr_hwtail, 248f0ea3689SLuigi Rizzo rxkring->rcur, rxkring->rhead, rxkring->rtail); 249f0ea3689SLuigi Rizzo 2502a7db7a6SVincenzo Maffione /* update the hwtail */ 2512a7db7a6SVincenzo Maffione rxkring->nr_hwtail = rxkring->pipe_tail; 2522a7db7a6SVincenzo Maffione 2532ff91c17SVincenzo Maffione m = rxkring->rhead - rxkring->nr_hwcur; /* released slots */ 2542ff91c17SVincenzo Maffione if (m < 0) 2552ff91c17SVincenzo Maffione m += rxkring->nkr_num_slots; 2562ff91c17SVincenzo Maffione 2572ff91c17SVincenzo Maffione if (m == 0) { 2582ff91c17SVincenzo Maffione /* nothing to release */ 2592ff91c17SVincenzo Maffione return 0; 260f0ea3689SLuigi Rizzo } 2612ff91c17SVincenzo Maffione 2622ff91c17SVincenzo Maffione for (k = rxkring->nr_hwcur; m; m--, k = nm_next(k, lim)) { 2632ff91c17SVincenzo Maffione struct netmap_slot *rs = &rxring->slot[k]; 2642ff91c17SVincenzo Maffione struct netmap_slot *ts = &txring->slot[k]; 2652ff91c17SVincenzo Maffione 2662ff91c17SVincenzo Maffione if (rs->flags & NS_BUF_CHANGED) { 2672ff91c17SVincenzo Maffione /* copy the slot and report the buffer change */ 2682ff91c17SVincenzo Maffione *ts = *rs; 2692ff91c17SVincenzo Maffione rs->flags &= ~NS_BUF_CHANGED; 2702ff91c17SVincenzo Maffione } 2712ff91c17SVincenzo Maffione } 2722ff91c17SVincenzo Maffione 2732ff91c17SVincenzo Maffione mb(); /* make sure the slots are updated before publishing them */ 2742a7db7a6SVincenzo Maffione txkring->pipe_tail = nm_prev(k, lim); 2752ff91c17SVincenzo Maffione rxkring->nr_hwcur = k; 2762ff91c17SVincenzo Maffione 2772ff91c17SVincenzo Maffione ND(20, "RX after : hwcur %d hwtail %d cur %d head %d tail %d k %d", 2782ff91c17SVincenzo Maffione rxkring->nr_hwcur, rxkring->nr_hwtail, 2792ff91c17SVincenzo Maffione rxkring->rcur, rxkring->rhead, rxkring->rtail, k); 2802ff91c17SVincenzo Maffione 2812ff91c17SVincenzo Maffione txkring->nm_notify(txkring, 0); 2822ff91c17SVincenzo Maffione 283f0ea3689SLuigi Rizzo return 0; 284f0ea3689SLuigi Rizzo } 285f0ea3689SLuigi Rizzo 286f0ea3689SLuigi Rizzo /* Pipe endpoints are created and destroyed together, so that endopoints do not 287f0ea3689SLuigi Rizzo * have to check for the existence of their peer at each ?xsync. 288f0ea3689SLuigi Rizzo * 289f0ea3689SLuigi Rizzo * To play well with the existing netmap infrastructure (refcounts etc.), we 290f0ea3689SLuigi Rizzo * adopt the following strategy: 291f0ea3689SLuigi Rizzo * 292f0ea3689SLuigi Rizzo * 1) The first endpoint that is created also creates the other endpoint and 293f0ea3689SLuigi Rizzo * grabs a reference to it. 294f0ea3689SLuigi Rizzo * 295f0ea3689SLuigi Rizzo * state A) user1 --> endpoint1 --> endpoint2 296f0ea3689SLuigi Rizzo * 297f0ea3689SLuigi Rizzo * 2) If, starting from state A, endpoint2 is then registered, endpoint1 gives 298f0ea3689SLuigi Rizzo * its reference to the user: 299f0ea3689SLuigi Rizzo * 300f0ea3689SLuigi Rizzo * state B) user1 --> endpoint1 endpoint2 <--- user2 301f0ea3689SLuigi Rizzo * 302f0ea3689SLuigi Rizzo * 3) Assume that, starting from state B endpoint2 is closed. In the unregister 303f0ea3689SLuigi Rizzo * callback endpoint2 notes that endpoint1 is still active and adds a reference 304f0ea3689SLuigi Rizzo * from endpoint1 to itself. When user2 then releases her own reference, 305f0ea3689SLuigi Rizzo * endpoint2 is not destroyed and we are back to state A. A symmetrical state 306f0ea3689SLuigi Rizzo * would be reached if endpoint1 were released instead. 307f0ea3689SLuigi Rizzo * 308f0ea3689SLuigi Rizzo * 4) If, starting from state A, endpoint1 is closed, the destructor notes that 309f0ea3689SLuigi Rizzo * it owns a reference to endpoint2 and releases it. 310f0ea3689SLuigi Rizzo * 311f0ea3689SLuigi Rizzo * Something similar goes on for the creation and destruction of the krings. 312f0ea3689SLuigi Rizzo */ 313f0ea3689SLuigi Rizzo 314f0ea3689SLuigi Rizzo 315c3e9b4dbSLuiz Otavio O Souza /* netmap_pipe_krings_create. 316f0ea3689SLuigi Rizzo * 317f0ea3689SLuigi Rizzo * There are two cases: 318f0ea3689SLuigi Rizzo * 319f0ea3689SLuigi Rizzo * 1) state is 320f0ea3689SLuigi Rizzo * 321f0ea3689SLuigi Rizzo * usr1 --> e1 --> e2 322f0ea3689SLuigi Rizzo * 323f0ea3689SLuigi Rizzo * and we are e1. We have to create both sets 324f0ea3689SLuigi Rizzo * of krings. 325f0ea3689SLuigi Rizzo * 326f0ea3689SLuigi Rizzo * 2) state is 327f0ea3689SLuigi Rizzo * 328f0ea3689SLuigi Rizzo * usr1 --> e1 --> e2 329f0ea3689SLuigi Rizzo * 330f0ea3689SLuigi Rizzo * and we are e2. e1 is certainly registered and our 33137e3a6d3SLuigi Rizzo * krings already exist. Nothing to do. 332f0ea3689SLuigi Rizzo */ 333f0ea3689SLuigi Rizzo static int 334f0ea3689SLuigi Rizzo netmap_pipe_krings_create(struct netmap_adapter *na) 335f0ea3689SLuigi Rizzo { 336f0ea3689SLuigi Rizzo struct netmap_pipe_adapter *pna = 337f0ea3689SLuigi Rizzo (struct netmap_pipe_adapter *)na; 338f0ea3689SLuigi Rizzo struct netmap_adapter *ona = &pna->peer->up; 339f0ea3689SLuigi Rizzo int error = 0; 340847bf383SLuigi Rizzo enum txrx t; 341847bf383SLuigi Rizzo 342f0ea3689SLuigi Rizzo if (pna->peer_ref) { 343f0ea3689SLuigi Rizzo int i; 344f0ea3689SLuigi Rizzo 345f0ea3689SLuigi Rizzo /* case 1) above */ 346c3e9b4dbSLuiz Otavio O Souza ND("%p: case 1, create both ends", na); 347f0ea3689SLuigi Rizzo error = netmap_krings_create(na, 0); 348f0ea3689SLuigi Rizzo if (error) 349f0ea3689SLuigi Rizzo goto err; 350f0ea3689SLuigi Rizzo 35137e3a6d3SLuigi Rizzo /* create the krings of the other end */ 352f0ea3689SLuigi Rizzo error = netmap_krings_create(ona, 0); 353f0ea3689SLuigi Rizzo if (error) 35437e3a6d3SLuigi Rizzo goto del_krings1; 355f0ea3689SLuigi Rizzo 3562a7db7a6SVincenzo Maffione /* cross link the krings and initialize the pipe_tails */ 357847bf383SLuigi Rizzo for_rx_tx(t) { 358847bf383SLuigi Rizzo enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */ 359847bf383SLuigi Rizzo for (i = 0; i < nma_get_nrings(na, t); i++) { 3602a7db7a6SVincenzo Maffione struct netmap_kring *k1 = NMR(na, t)[i], 3612a7db7a6SVincenzo Maffione *k2 = NMR(ona, r)[i]; 3622a7db7a6SVincenzo Maffione k1->pipe = k2; 3632a7db7a6SVincenzo Maffione k2->pipe = k1; 3642ff91c17SVincenzo Maffione /* mark all peer-adapter rings as fake */ 3652a7db7a6SVincenzo Maffione k2->nr_kflags |= NKR_FAKERING; 3662a7db7a6SVincenzo Maffione /* init tails */ 3672a7db7a6SVincenzo Maffione k1->pipe_tail = k1->nr_hwtail; 3682a7db7a6SVincenzo Maffione k2->pipe_tail = k2->nr_hwtail; 369847bf383SLuigi Rizzo } 370f0ea3689SLuigi Rizzo } 37137e3a6d3SLuigi Rizzo 372f0ea3689SLuigi Rizzo } 373f0ea3689SLuigi Rizzo return 0; 374f0ea3689SLuigi Rizzo 375f0ea3689SLuigi Rizzo del_krings1: 376f0ea3689SLuigi Rizzo netmap_krings_delete(na); 377f0ea3689SLuigi Rizzo err: 378f0ea3689SLuigi Rizzo return error; 379f0ea3689SLuigi Rizzo } 380f0ea3689SLuigi Rizzo 381f0ea3689SLuigi Rizzo /* netmap_pipe_reg. 382f0ea3689SLuigi Rizzo * 383f0ea3689SLuigi Rizzo * There are two cases on registration (onoff==1) 384f0ea3689SLuigi Rizzo * 385f0ea3689SLuigi Rizzo * 1.a) state is 386f0ea3689SLuigi Rizzo * 387f0ea3689SLuigi Rizzo * usr1 --> e1 --> e2 388f0ea3689SLuigi Rizzo * 38937e3a6d3SLuigi Rizzo * and we are e1. Create the needed rings of the 39037e3a6d3SLuigi Rizzo * other end. 391f0ea3689SLuigi Rizzo * 392f0ea3689SLuigi Rizzo * 1.b) state is 393f0ea3689SLuigi Rizzo * 394f0ea3689SLuigi Rizzo * usr1 --> e1 --> e2 <-- usr2 395f0ea3689SLuigi Rizzo * 396f0ea3689SLuigi Rizzo * and we are e2. Drop the ref e1 is holding. 397f0ea3689SLuigi Rizzo * 398f0ea3689SLuigi Rizzo * There are two additional cases on unregister (onoff==0) 399f0ea3689SLuigi Rizzo * 400f0ea3689SLuigi Rizzo * 2.a) state is 401f0ea3689SLuigi Rizzo * 402f0ea3689SLuigi Rizzo * usr1 --> e1 --> e2 403f0ea3689SLuigi Rizzo * 404f0ea3689SLuigi Rizzo * and we are e1. Nothing special to do, e2 will 405f0ea3689SLuigi Rizzo * be cleaned up by the destructor of e1. 406f0ea3689SLuigi Rizzo * 407f0ea3689SLuigi Rizzo * 2.b) state is 408f0ea3689SLuigi Rizzo * 409f0ea3689SLuigi Rizzo * usr1 --> e1 e2 <-- usr2 410f0ea3689SLuigi Rizzo * 411f0ea3689SLuigi Rizzo * and we are either e1 or e2. Add a ref from the 4122ff91c17SVincenzo Maffione * other end. 413f0ea3689SLuigi Rizzo */ 414f0ea3689SLuigi Rizzo static int 415f0ea3689SLuigi Rizzo netmap_pipe_reg(struct netmap_adapter *na, int onoff) 416f0ea3689SLuigi Rizzo { 417f0ea3689SLuigi Rizzo struct netmap_pipe_adapter *pna = 418f0ea3689SLuigi Rizzo (struct netmap_pipe_adapter *)na; 41937e3a6d3SLuigi Rizzo struct netmap_adapter *ona = &pna->peer->up; 42037e3a6d3SLuigi Rizzo int i, error = 0; 421847bf383SLuigi Rizzo enum txrx t; 422847bf383SLuigi Rizzo 423f0ea3689SLuigi Rizzo ND("%p: onoff %d", na, onoff); 424f0ea3689SLuigi Rizzo if (onoff) { 42537e3a6d3SLuigi Rizzo for_rx_tx(t) { 426c3e9b4dbSLuiz Otavio O Souza for (i = 0; i < nma_get_nrings(na, t); i++) { 4272ff91c17SVincenzo Maffione struct netmap_kring *kring = NMR(na, t)[i]; 42837e3a6d3SLuigi Rizzo 42937e3a6d3SLuigi Rizzo if (nm_kring_pending_on(kring)) { 430c3e9b4dbSLuiz Otavio O Souza /* mark the peer ring as needed */ 43137e3a6d3SLuigi Rizzo kring->pipe->nr_kflags |= NKR_NEEDRING; 43237e3a6d3SLuigi Rizzo } 43337e3a6d3SLuigi Rizzo } 43437e3a6d3SLuigi Rizzo } 43537e3a6d3SLuigi Rizzo 4362ff91c17SVincenzo Maffione /* create all missing needed rings on the other end. 4372ff91c17SVincenzo Maffione * Either our end, or the other, has been marked as 4382ff91c17SVincenzo Maffione * fake, so the allocation will not be done twice. 4392ff91c17SVincenzo Maffione */ 44037e3a6d3SLuigi Rizzo error = netmap_mem_rings_create(ona); 44137e3a6d3SLuigi Rizzo if (error) 44237e3a6d3SLuigi Rizzo return error; 44337e3a6d3SLuigi Rizzo 44437e3a6d3SLuigi Rizzo /* In case of no error we put our rings in netmap mode */ 44537e3a6d3SLuigi Rizzo for_rx_tx(t) { 446*b6e66be2SVincenzo Maffione for (i = 0; i < nma_get_nrings(na, t); i++) { 4472ff91c17SVincenzo Maffione struct netmap_kring *kring = NMR(na, t)[i]; 44837e3a6d3SLuigi Rizzo if (nm_kring_pending_on(kring)) { 4492ff91c17SVincenzo Maffione struct netmap_kring *sring, *dring; 4502ff91c17SVincenzo Maffione 4512a7db7a6SVincenzo Maffione kring->nr_mode = NKR_NETMAP_ON; 4522a7db7a6SVincenzo Maffione if ((kring->nr_kflags & NKR_FAKERING) && 4532a7db7a6SVincenzo Maffione (kring->pipe->nr_kflags & NKR_FAKERING)) { 4542a7db7a6SVincenzo Maffione /* this is a re-open of a pipe 4552a7db7a6SVincenzo Maffione * end-point kept alive by the other end. 4562a7db7a6SVincenzo Maffione * We need to leave everything as it is 4572a7db7a6SVincenzo Maffione */ 4582a7db7a6SVincenzo Maffione continue; 4592a7db7a6SVincenzo Maffione } 4602a7db7a6SVincenzo Maffione 4612ff91c17SVincenzo Maffione /* copy the buffers from the non-fake ring */ 4622ff91c17SVincenzo Maffione if (kring->nr_kflags & NKR_FAKERING) { 4632ff91c17SVincenzo Maffione sring = kring->pipe; 4642ff91c17SVincenzo Maffione dring = kring; 4652ff91c17SVincenzo Maffione } else { 4662ff91c17SVincenzo Maffione sring = kring; 4672ff91c17SVincenzo Maffione dring = kring->pipe; 4682ff91c17SVincenzo Maffione } 4692ff91c17SVincenzo Maffione memcpy(dring->ring->slot, 4702ff91c17SVincenzo Maffione sring->ring->slot, 4712ff91c17SVincenzo Maffione sizeof(struct netmap_slot) * 4722ff91c17SVincenzo Maffione sring->nkr_num_slots); 4732ff91c17SVincenzo Maffione /* mark both rings as fake and needed, 4742ff91c17SVincenzo Maffione * so that buffers will not be 4752ff91c17SVincenzo Maffione * deleted by the standard machinery 4762ff91c17SVincenzo Maffione * (we will delete them by ourselves in 4772ff91c17SVincenzo Maffione * netmap_pipe_krings_delete) 4782ff91c17SVincenzo Maffione */ 4792ff91c17SVincenzo Maffione sring->nr_kflags |= 4802ff91c17SVincenzo Maffione (NKR_FAKERING | NKR_NEEDRING); 4812ff91c17SVincenzo Maffione dring->nr_kflags |= 4822ff91c17SVincenzo Maffione (NKR_FAKERING | NKR_NEEDRING); 48337e3a6d3SLuigi Rizzo kring->nr_mode = NKR_NETMAP_ON; 48437e3a6d3SLuigi Rizzo } 48537e3a6d3SLuigi Rizzo } 48637e3a6d3SLuigi Rizzo } 48737e3a6d3SLuigi Rizzo if (na->active_fds == 0) 4884bf50f18SLuigi Rizzo na->na_flags |= NAF_NETMAP_ON; 489f0ea3689SLuigi Rizzo } else { 49037e3a6d3SLuigi Rizzo if (na->active_fds == 0) 4914bf50f18SLuigi Rizzo na->na_flags &= ~NAF_NETMAP_ON; 49237e3a6d3SLuigi Rizzo for_rx_tx(t) { 493*b6e66be2SVincenzo Maffione for (i = 0; i < nma_get_nrings(na, t); i++) { 4942ff91c17SVincenzo Maffione struct netmap_kring *kring = NMR(na, t)[i]; 49537e3a6d3SLuigi Rizzo 49637e3a6d3SLuigi Rizzo if (nm_kring_pending_off(kring)) { 49737e3a6d3SLuigi Rizzo kring->nr_mode = NKR_NETMAP_OFF; 498f0ea3689SLuigi Rizzo } 49937e3a6d3SLuigi Rizzo } 50037e3a6d3SLuigi Rizzo } 501c3e9b4dbSLuiz Otavio O Souza } 50237e3a6d3SLuigi Rizzo 50337e3a6d3SLuigi Rizzo if (na->active_fds) { 504c3e9b4dbSLuiz Otavio O Souza ND("active_fds %d", na->active_fds); 50537e3a6d3SLuigi Rizzo return 0; 50637e3a6d3SLuigi Rizzo } 50737e3a6d3SLuigi Rizzo 508f0ea3689SLuigi Rizzo if (pna->peer_ref) { 509f0ea3689SLuigi Rizzo ND("%p: case 1.a or 2.a, nothing to do", na); 510f0ea3689SLuigi Rizzo return 0; 511f0ea3689SLuigi Rizzo } 512f0ea3689SLuigi Rizzo if (onoff) { 513f0ea3689SLuigi Rizzo ND("%p: case 1.b, drop peer", na); 514f0ea3689SLuigi Rizzo pna->peer->peer_ref = 0; 515f0ea3689SLuigi Rizzo netmap_adapter_put(na); 516f0ea3689SLuigi Rizzo } else { 517f0ea3689SLuigi Rizzo ND("%p: case 2.b, grab peer", na); 518f0ea3689SLuigi Rizzo netmap_adapter_get(na); 519f0ea3689SLuigi Rizzo pna->peer->peer_ref = 1; 520f0ea3689SLuigi Rizzo } 52137e3a6d3SLuigi Rizzo return error; 522f0ea3689SLuigi Rizzo } 523f0ea3689SLuigi Rizzo 524f0ea3689SLuigi Rizzo /* netmap_pipe_krings_delete. 525f0ea3689SLuigi Rizzo * 526f0ea3689SLuigi Rizzo * There are two cases: 527f0ea3689SLuigi Rizzo * 528f0ea3689SLuigi Rizzo * 1) state is 529f0ea3689SLuigi Rizzo * 530f0ea3689SLuigi Rizzo * usr1 --> e1 --> e2 531f0ea3689SLuigi Rizzo * 532f0ea3689SLuigi Rizzo * and we are e1 (e2 is not registered, so krings_delete cannot be 533f0ea3689SLuigi Rizzo * called on it); 534f0ea3689SLuigi Rizzo * 535f0ea3689SLuigi Rizzo * 2) state is 536f0ea3689SLuigi Rizzo * 537f0ea3689SLuigi Rizzo * usr1 --> e1 e2 <-- usr2 538f0ea3689SLuigi Rizzo * 539f0ea3689SLuigi Rizzo * and we are either e1 or e2. 540f0ea3689SLuigi Rizzo * 541f0ea3689SLuigi Rizzo * In the former case we have to also delete the krings of e2; 5422ff91c17SVincenzo Maffione * in the latter case we do nothing. 543f0ea3689SLuigi Rizzo */ 544f0ea3689SLuigi Rizzo static void 545f0ea3689SLuigi Rizzo netmap_pipe_krings_delete(struct netmap_adapter *na) 546f0ea3689SLuigi Rizzo { 547f0ea3689SLuigi Rizzo struct netmap_pipe_adapter *pna = 548f0ea3689SLuigi Rizzo (struct netmap_pipe_adapter *)na; 5492ff91c17SVincenzo Maffione struct netmap_adapter *sna, *ona; /* na of the other end */ 5502ff91c17SVincenzo Maffione enum txrx t; 5512ff91c17SVincenzo Maffione int i; 552f0ea3689SLuigi Rizzo 553f0ea3689SLuigi Rizzo if (!pna->peer_ref) { 554f0ea3689SLuigi Rizzo ND("%p: case 2, kept alive by peer", na); 555f0ea3689SLuigi Rizzo return; 556f0ea3689SLuigi Rizzo } 5572ff91c17SVincenzo Maffione ona = &pna->peer->up; 558f0ea3689SLuigi Rizzo /* case 1) above */ 559c3e9b4dbSLuiz Otavio O Souza ND("%p: case 1, deleting everything", na); 5602ff91c17SVincenzo Maffione /* To avoid double-frees we zero-out all the buffers in the kernel part 5612ff91c17SVincenzo Maffione * of each ring. The reason is this: If the user is behaving correctly, 5622ff91c17SVincenzo Maffione * all buffers are found in exactly one slot in the userspace part of 5632ff91c17SVincenzo Maffione * some ring. If the user is not behaving correctly, we cannot release 5642ff91c17SVincenzo Maffione * buffers cleanly anyway. In the latter case, the allocator will 5652ff91c17SVincenzo Maffione * return to a clean state only when all its users will close. 5662ff91c17SVincenzo Maffione */ 5672ff91c17SVincenzo Maffione sna = na; 5682ff91c17SVincenzo Maffione cleanup: 5692ff91c17SVincenzo Maffione for_rx_tx(t) { 570*b6e66be2SVincenzo Maffione for (i = 0; i < nma_get_nrings(sna, t); i++) { 5712ff91c17SVincenzo Maffione struct netmap_kring *kring = NMR(sna, t)[i]; 5722ff91c17SVincenzo Maffione struct netmap_ring *ring = kring->ring; 5732ff91c17SVincenzo Maffione uint32_t j, lim = kring->nkr_num_slots - 1; 5742ff91c17SVincenzo Maffione 5752ff91c17SVincenzo Maffione ND("%s ring %p hwtail %u hwcur %u", 5762ff91c17SVincenzo Maffione kring->name, ring, kring->nr_hwtail, kring->nr_hwcur); 5772ff91c17SVincenzo Maffione 5782ff91c17SVincenzo Maffione if (ring == NULL) 5792ff91c17SVincenzo Maffione continue; 5802ff91c17SVincenzo Maffione 5812a7db7a6SVincenzo Maffione if (kring->tx == NR_RX) 5822a7db7a6SVincenzo Maffione ring->slot[kring->pipe_tail].buf_idx = 0; 5832ff91c17SVincenzo Maffione 5842a7db7a6SVincenzo Maffione for (j = nm_next(kring->pipe_tail, lim); 5852ff91c17SVincenzo Maffione j != kring->nr_hwcur; 5862ff91c17SVincenzo Maffione j = nm_next(j, lim)) 5872ff91c17SVincenzo Maffione { 5882ff91c17SVincenzo Maffione ND("%s[%d] %u", kring->name, j, ring->slot[j].buf_idx); 5892ff91c17SVincenzo Maffione ring->slot[j].buf_idx = 0; 5902ff91c17SVincenzo Maffione } 5912ff91c17SVincenzo Maffione kring->nr_kflags &= ~(NKR_FAKERING | NKR_NEEDRING); 5922ff91c17SVincenzo Maffione } 5932ff91c17SVincenzo Maffione 5942ff91c17SVincenzo Maffione } 5952ff91c17SVincenzo Maffione if (sna != ona && ona->tx_rings) { 5962ff91c17SVincenzo Maffione sna = ona; 5972ff91c17SVincenzo Maffione goto cleanup; 5982ff91c17SVincenzo Maffione } 5992ff91c17SVincenzo Maffione 6002ff91c17SVincenzo Maffione netmap_mem_rings_delete(na); 601f0ea3689SLuigi Rizzo netmap_krings_delete(na); /* also zeroes tx_rings etc. */ 6022ff91c17SVincenzo Maffione 603f0ea3689SLuigi Rizzo if (ona->tx_rings == NULL) { 604f0ea3689SLuigi Rizzo /* already deleted, we must be on an 605f0ea3689SLuigi Rizzo * cleanup-after-error path */ 606f0ea3689SLuigi Rizzo return; 607f0ea3689SLuigi Rizzo } 6082ff91c17SVincenzo Maffione netmap_mem_rings_delete(ona); 609f0ea3689SLuigi Rizzo netmap_krings_delete(ona); 610f0ea3689SLuigi Rizzo } 611f0ea3689SLuigi Rizzo 612f0ea3689SLuigi Rizzo 613f0ea3689SLuigi Rizzo static void 614f0ea3689SLuigi Rizzo netmap_pipe_dtor(struct netmap_adapter *na) 615f0ea3689SLuigi Rizzo { 616f0ea3689SLuigi Rizzo struct netmap_pipe_adapter *pna = 617f0ea3689SLuigi Rizzo (struct netmap_pipe_adapter *)na; 618c3e9b4dbSLuiz Otavio O Souza ND("%p %p", na, pna->parent_ifp); 619f0ea3689SLuigi Rizzo if (pna->peer_ref) { 620f0ea3689SLuigi Rizzo ND("%p: clean up peer", na); 621f0ea3689SLuigi Rizzo pna->peer_ref = 0; 622f0ea3689SLuigi Rizzo netmap_adapter_put(&pna->peer->up); 623f0ea3689SLuigi Rizzo } 6242ff91c17SVincenzo Maffione if (pna->role == NM_PIPE_ROLE_MASTER) 625f0ea3689SLuigi Rizzo netmap_pipe_remove(pna->parent, pna); 626c3e9b4dbSLuiz Otavio O Souza if (pna->parent_ifp) 627c3e9b4dbSLuiz Otavio O Souza if_rele(pna->parent_ifp); 628f0ea3689SLuigi Rizzo netmap_adapter_put(pna->parent); 629f0ea3689SLuigi Rizzo pna->parent = NULL; 630f0ea3689SLuigi Rizzo } 631f0ea3689SLuigi Rizzo 632f0ea3689SLuigi Rizzo int 6332ff91c17SVincenzo Maffione netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na, 634c3e9b4dbSLuiz Otavio O Souza struct netmap_mem_d *nmd, int create) 635f0ea3689SLuigi Rizzo { 636cfa866f6SMatt Macy struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body; 637f0ea3689SLuigi Rizzo struct netmap_adapter *pna; /* parent adapter */ 6382ff91c17SVincenzo Maffione struct netmap_pipe_adapter *mna, *sna, *reqna; 63937e3a6d3SLuigi Rizzo struct ifnet *ifp = NULL; 6402ff91c17SVincenzo Maffione const char *pipe_id = NULL; 6412ff91c17SVincenzo Maffione int role = 0; 642c3e9b4dbSLuiz Otavio O Souza int error, retries = 0; 6432ff91c17SVincenzo Maffione char *cbra; 644f0ea3689SLuigi Rizzo 6452ff91c17SVincenzo Maffione /* Try to parse the pipe syntax 'xx{yy' or 'xx}yy'. */ 6462ff91c17SVincenzo Maffione cbra = strrchr(hdr->nr_name, '{'); 6472ff91c17SVincenzo Maffione if (cbra != NULL) { 6482ff91c17SVincenzo Maffione role = NM_PIPE_ROLE_MASTER; 6492ff91c17SVincenzo Maffione } else { 6502ff91c17SVincenzo Maffione cbra = strrchr(hdr->nr_name, '}'); 6512ff91c17SVincenzo Maffione if (cbra != NULL) { 6522ff91c17SVincenzo Maffione role = NM_PIPE_ROLE_SLAVE; 6532ff91c17SVincenzo Maffione } else { 654f0ea3689SLuigi Rizzo ND("not a pipe"); 655f0ea3689SLuigi Rizzo return 0; 656f0ea3689SLuigi Rizzo } 6572ff91c17SVincenzo Maffione } 6582ff91c17SVincenzo Maffione pipe_id = cbra + 1; 6592ff91c17SVincenzo Maffione if (*pipe_id == '\0' || cbra == hdr->nr_name) { 6602ff91c17SVincenzo Maffione /* Bracket is the last character, so pipe name is missing; 6612ff91c17SVincenzo Maffione * or bracket is the first character, so base port name 6622ff91c17SVincenzo Maffione * is missing. */ 6632ff91c17SVincenzo Maffione return EINVAL; 6642ff91c17SVincenzo Maffione } 6652ff91c17SVincenzo Maffione 6662ff91c17SVincenzo Maffione if (req->nr_mode != NR_REG_ALL_NIC && req->nr_mode != NR_REG_ONE_NIC) { 6672ff91c17SVincenzo Maffione /* We only accept modes involving hardware rings. */ 6682ff91c17SVincenzo Maffione return EINVAL; 6692ff91c17SVincenzo Maffione } 670f0ea3689SLuigi Rizzo 671f0ea3689SLuigi Rizzo /* first, try to find the parent adapter */ 672c3e9b4dbSLuiz Otavio O Souza for (;;) { 6732ff91c17SVincenzo Maffione char nr_name_orig[NETMAP_REQ_IFNAMSIZ]; 674c3e9b4dbSLuiz Otavio O Souza int create_error; 675c3e9b4dbSLuiz Otavio O Souza 6762ff91c17SVincenzo Maffione /* Temporarily remove the pipe suffix. */ 677*b6e66be2SVincenzo Maffione strlcpy(nr_name_orig, hdr->nr_name, sizeof(nr_name_orig)); 6782ff91c17SVincenzo Maffione *cbra = '\0'; 6792ff91c17SVincenzo Maffione error = netmap_get_na(hdr, &pna, &ifp, nmd, create); 6802ff91c17SVincenzo Maffione /* Restore the pipe suffix. */ 681*b6e66be2SVincenzo Maffione strlcpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name)); 682c3e9b4dbSLuiz Otavio O Souza if (!error) 683c3e9b4dbSLuiz Otavio O Souza break; 684c3e9b4dbSLuiz Otavio O Souza if (error != ENXIO || retries++) { 685f0ea3689SLuigi Rizzo ND("parent lookup failed: %d", error); 686f0ea3689SLuigi Rizzo return error; 687f0ea3689SLuigi Rizzo } 688c3e9b4dbSLuiz Otavio O Souza ND("try to create a persistent vale port"); 689c3e9b4dbSLuiz Otavio O Souza /* create a persistent vale port and try again */ 6902ff91c17SVincenzo Maffione *cbra = '\0'; 691c3e9b4dbSLuiz Otavio O Souza NMG_UNLOCK(); 6922ff91c17SVincenzo Maffione create_error = netmap_vi_create(hdr, 1 /* autodelete */); 693c3e9b4dbSLuiz Otavio O Souza NMG_LOCK(); 694*b6e66be2SVincenzo Maffione strlcpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name)); 695c3e9b4dbSLuiz Otavio O Souza if (create_error && create_error != EEXIST) { 696c3e9b4dbSLuiz Otavio O Souza if (create_error != EOPNOTSUPP) { 697c3e9b4dbSLuiz Otavio O Souza D("failed to create a persistent vale port: %d", create_error); 698c3e9b4dbSLuiz Otavio O Souza } 699c3e9b4dbSLuiz Otavio O Souza return error; 700c3e9b4dbSLuiz Otavio O Souza } 701c3e9b4dbSLuiz Otavio O Souza } 702f0ea3689SLuigi Rizzo 703f0ea3689SLuigi Rizzo if (NETMAP_OWNED_BY_KERN(pna)) { 704f0ea3689SLuigi Rizzo ND("parent busy"); 705f0ea3689SLuigi Rizzo error = EBUSY; 706f0ea3689SLuigi Rizzo goto put_out; 707f0ea3689SLuigi Rizzo } 708f0ea3689SLuigi Rizzo 709f0ea3689SLuigi Rizzo /* next, lookup the pipe id in the parent list */ 7102ff91c17SVincenzo Maffione reqna = NULL; 711f0ea3689SLuigi Rizzo mna = netmap_pipe_find(pna, pipe_id); 712f0ea3689SLuigi Rizzo if (mna) { 713f0ea3689SLuigi Rizzo if (mna->role == role) { 7142ff91c17SVincenzo Maffione ND("found %s directly at %d", pipe_id, mna->parent_slot); 7152ff91c17SVincenzo Maffione reqna = mna; 716f0ea3689SLuigi Rizzo } else { 7172ff91c17SVincenzo Maffione ND("found %s indirectly at %d", pipe_id, mna->parent_slot); 7182ff91c17SVincenzo Maffione reqna = mna->peer; 719f0ea3689SLuigi Rizzo } 720f0ea3689SLuigi Rizzo /* the pipe we have found already holds a ref to the parent, 721f0ea3689SLuigi Rizzo * so we need to drop the one we got from netmap_get_na() 722f0ea3689SLuigi Rizzo */ 723c3e9b4dbSLuiz Otavio O Souza netmap_unget_na(pna, ifp); 724f0ea3689SLuigi Rizzo goto found; 725f0ea3689SLuigi Rizzo } 7262ff91c17SVincenzo Maffione ND("pipe %s not found, create %d", pipe_id, create); 727f0ea3689SLuigi Rizzo if (!create) { 728f0ea3689SLuigi Rizzo error = ENODEV; 729f0ea3689SLuigi Rizzo goto put_out; 730f0ea3689SLuigi Rizzo } 731f0ea3689SLuigi Rizzo /* we create both master and slave. 732f0ea3689SLuigi Rizzo * The endpoint we were asked for holds a reference to 733f0ea3689SLuigi Rizzo * the other one. 734f0ea3689SLuigi Rizzo */ 735c3e9b4dbSLuiz Otavio O Souza mna = nm_os_malloc(sizeof(*mna)); 736f0ea3689SLuigi Rizzo if (mna == NULL) { 737f0ea3689SLuigi Rizzo error = ENOMEM; 7384bf50f18SLuigi Rizzo goto put_out; 739f0ea3689SLuigi Rizzo } 7402ff91c17SVincenzo Maffione snprintf(mna->up.name, sizeof(mna->up.name), "%s{%s", pna->name, pipe_id); 741f0ea3689SLuigi Rizzo 7422ff91c17SVincenzo Maffione mna->role = NM_PIPE_ROLE_MASTER; 743f0ea3689SLuigi Rizzo mna->parent = pna; 744c3e9b4dbSLuiz Otavio O Souza mna->parent_ifp = ifp; 745f0ea3689SLuigi Rizzo 746f0ea3689SLuigi Rizzo mna->up.nm_txsync = netmap_pipe_txsync; 747f0ea3689SLuigi Rizzo mna->up.nm_rxsync = netmap_pipe_rxsync; 748f0ea3689SLuigi Rizzo mna->up.nm_register = netmap_pipe_reg; 749f0ea3689SLuigi Rizzo mna->up.nm_dtor = netmap_pipe_dtor; 750f0ea3689SLuigi Rizzo mna->up.nm_krings_create = netmap_pipe_krings_create; 751f0ea3689SLuigi Rizzo mna->up.nm_krings_delete = netmap_pipe_krings_delete; 752c3e9b4dbSLuiz Otavio O Souza mna->up.nm_mem = netmap_mem_get(pna->nm_mem); 753c3e9b4dbSLuiz Otavio O Souza mna->up.na_flags |= NAF_MEM_OWNER; 754f0ea3689SLuigi Rizzo mna->up.na_lut = pna->na_lut; 755f0ea3689SLuigi Rizzo 7562ff91c17SVincenzo Maffione mna->up.num_tx_rings = req->nr_tx_rings; 7572ff91c17SVincenzo Maffione nm_bound_var(&mna->up.num_tx_rings, 1, 7582ff91c17SVincenzo Maffione 1, NM_PIPE_MAXRINGS, NULL); 7592ff91c17SVincenzo Maffione mna->up.num_rx_rings = req->nr_rx_rings; 7602ff91c17SVincenzo Maffione nm_bound_var(&mna->up.num_rx_rings, 1, 7612ff91c17SVincenzo Maffione 1, NM_PIPE_MAXRINGS, NULL); 7622ff91c17SVincenzo Maffione mna->up.num_tx_desc = req->nr_tx_slots; 763f0ea3689SLuigi Rizzo nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc, 764f0ea3689SLuigi Rizzo 1, NM_PIPE_MAXSLOTS, NULL); 7652ff91c17SVincenzo Maffione mna->up.num_rx_desc = req->nr_rx_slots; 766f0ea3689SLuigi Rizzo nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc, 767f0ea3689SLuigi Rizzo 1, NM_PIPE_MAXSLOTS, NULL); 768f0ea3689SLuigi Rizzo error = netmap_attach_common(&mna->up); 769f0ea3689SLuigi Rizzo if (error) 7704bf50f18SLuigi Rizzo goto free_mna; 771f0ea3689SLuigi Rizzo /* register the master with the parent */ 772f0ea3689SLuigi Rizzo error = netmap_pipe_add(pna, mna); 773f0ea3689SLuigi Rizzo if (error) 774f0ea3689SLuigi Rizzo goto free_mna; 775f0ea3689SLuigi Rizzo 776f0ea3689SLuigi Rizzo /* create the slave */ 777c3e9b4dbSLuiz Otavio O Souza sna = nm_os_malloc(sizeof(*mna)); 778f0ea3689SLuigi Rizzo if (sna == NULL) { 779f0ea3689SLuigi Rizzo error = ENOMEM; 7809694aad3SLuigi Rizzo goto unregister_mna; 781f0ea3689SLuigi Rizzo } 782f0ea3689SLuigi Rizzo /* most fields are the same, copy from master and then fix */ 783f0ea3689SLuigi Rizzo *sna = *mna; 784c3e9b4dbSLuiz Otavio O Souza sna->up.nm_mem = netmap_mem_get(mna->up.nm_mem); 7852ff91c17SVincenzo Maffione /* swap the number of tx/rx rings */ 7862ff91c17SVincenzo Maffione sna->up.num_tx_rings = mna->up.num_rx_rings; 7872ff91c17SVincenzo Maffione sna->up.num_rx_rings = mna->up.num_tx_rings; 7882ff91c17SVincenzo Maffione snprintf(sna->up.name, sizeof(sna->up.name), "%s}%s", pna->name, pipe_id); 7892ff91c17SVincenzo Maffione sna->role = NM_PIPE_ROLE_SLAVE; 790f0ea3689SLuigi Rizzo error = netmap_attach_common(&sna->up); 791f0ea3689SLuigi Rizzo if (error) 792f0ea3689SLuigi Rizzo goto free_sna; 793f0ea3689SLuigi Rizzo 794f0ea3689SLuigi Rizzo /* join the two endpoints */ 795f0ea3689SLuigi Rizzo mna->peer = sna; 796f0ea3689SLuigi Rizzo sna->peer = mna; 797f0ea3689SLuigi Rizzo 798f0ea3689SLuigi Rizzo /* we already have a reference to the parent, but we 799f0ea3689SLuigi Rizzo * need another one for the other endpoint we created 800f0ea3689SLuigi Rizzo */ 801f0ea3689SLuigi Rizzo netmap_adapter_get(pna); 802c3e9b4dbSLuiz Otavio O Souza /* likewise for the ifp, if any */ 803c3e9b4dbSLuiz Otavio O Souza if (ifp) 804c3e9b4dbSLuiz Otavio O Souza if_ref(ifp); 805f0ea3689SLuigi Rizzo 8062ff91c17SVincenzo Maffione if (role == NM_PIPE_ROLE_MASTER) { 8072ff91c17SVincenzo Maffione reqna = mna; 808f0ea3689SLuigi Rizzo mna->peer_ref = 1; 809f0ea3689SLuigi Rizzo netmap_adapter_get(&sna->up); 810f0ea3689SLuigi Rizzo } else { 8112ff91c17SVincenzo Maffione reqna = sna; 812f0ea3689SLuigi Rizzo sna->peer_ref = 1; 813f0ea3689SLuigi Rizzo netmap_adapter_get(&mna->up); 814f0ea3689SLuigi Rizzo } 815f0ea3689SLuigi Rizzo ND("created master %p and slave %p", mna, sna); 816f0ea3689SLuigi Rizzo found: 817f0ea3689SLuigi Rizzo 8182ff91c17SVincenzo Maffione ND("pipe %s %s at %p", pipe_id, 8192ff91c17SVincenzo Maffione (reqna->role == NM_PIPE_ROLE_MASTER ? "master" : "slave"), reqna); 8202ff91c17SVincenzo Maffione *na = &reqna->up; 821f0ea3689SLuigi Rizzo netmap_adapter_get(*na); 822f0ea3689SLuigi Rizzo 823f0ea3689SLuigi Rizzo /* keep the reference to the parent. 824f0ea3689SLuigi Rizzo * It will be released by the req destructor 825f0ea3689SLuigi Rizzo */ 826f0ea3689SLuigi Rizzo 827f0ea3689SLuigi Rizzo return 0; 828f0ea3689SLuigi Rizzo 829f0ea3689SLuigi Rizzo free_sna: 830c3e9b4dbSLuiz Otavio O Souza nm_os_free(sna); 8319694aad3SLuigi Rizzo unregister_mna: 8329694aad3SLuigi Rizzo netmap_pipe_remove(pna, mna); 833f0ea3689SLuigi Rizzo free_mna: 834c3e9b4dbSLuiz Otavio O Souza nm_os_free(mna); 835f0ea3689SLuigi Rizzo put_out: 83637e3a6d3SLuigi Rizzo netmap_unget_na(pna, ifp); 837f0ea3689SLuigi Rizzo return error; 838f0ea3689SLuigi Rizzo } 839f0ea3689SLuigi Rizzo 840f0ea3689SLuigi Rizzo 841f0ea3689SLuigi Rizzo #endif /* WITH_PIPES */ 842