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) { 121*75f4f3edSVincenzo Maffione nm_prerr("freeing not empty pipe array for %s (%d dangling pipes)!", 122*75f4f3edSVincenzo Maffione na->name, 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 193*75f4f3edSVincenzo Maffione nm_prdis("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name); 194*75f4f3edSVincenzo Maffione nm_prdis(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 224*75f4f3edSVincenzo Maffione nm_prdis(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 245*75f4f3edSVincenzo Maffione nm_prdis("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name); 246*75f4f3edSVincenzo Maffione nm_prdis(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 277*75f4f3edSVincenzo Maffione nm_prdis(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 315*75f4f3edSVincenzo Maffione int netmap_pipe_krings_create_both(struct netmap_adapter *na, 316*75f4f3edSVincenzo Maffione struct netmap_adapter *ona) 317*75f4f3edSVincenzo Maffione { 318*75f4f3edSVincenzo Maffione enum txrx t; 319*75f4f3edSVincenzo Maffione int error; 320*75f4f3edSVincenzo Maffione int i; 321*75f4f3edSVincenzo Maffione 322*75f4f3edSVincenzo Maffione /* case 1) below */ 323*75f4f3edSVincenzo Maffione nm_prdis("%p: case 1, create both ends", na); 324*75f4f3edSVincenzo Maffione error = netmap_krings_create(na, 0); 325*75f4f3edSVincenzo Maffione if (error) 326*75f4f3edSVincenzo Maffione return error; 327*75f4f3edSVincenzo Maffione 328*75f4f3edSVincenzo Maffione /* create the krings of the other end */ 329*75f4f3edSVincenzo Maffione error = netmap_krings_create(ona, 0); 330*75f4f3edSVincenzo Maffione if (error) 331*75f4f3edSVincenzo Maffione goto del_krings1; 332*75f4f3edSVincenzo Maffione 333*75f4f3edSVincenzo Maffione /* cross link the krings and initialize the pipe_tails */ 334*75f4f3edSVincenzo Maffione for_rx_tx(t) { 335*75f4f3edSVincenzo Maffione enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */ 336*75f4f3edSVincenzo Maffione for (i = 0; i < nma_get_nrings(na, t); i++) { 337*75f4f3edSVincenzo Maffione struct netmap_kring *k1 = NMR(na, t)[i], 338*75f4f3edSVincenzo Maffione *k2 = NMR(ona, r)[i]; 339*75f4f3edSVincenzo Maffione k1->pipe = k2; 340*75f4f3edSVincenzo Maffione k2->pipe = k1; 341*75f4f3edSVincenzo Maffione /* mark all peer-adapter rings as fake */ 342*75f4f3edSVincenzo Maffione k2->nr_kflags |= NKR_FAKERING; 343*75f4f3edSVincenzo Maffione /* init tails */ 344*75f4f3edSVincenzo Maffione k1->pipe_tail = k1->nr_hwtail; 345*75f4f3edSVincenzo Maffione k2->pipe_tail = k2->nr_hwtail; 346*75f4f3edSVincenzo Maffione } 347*75f4f3edSVincenzo Maffione } 348*75f4f3edSVincenzo Maffione 349*75f4f3edSVincenzo Maffione return 0; 350*75f4f3edSVincenzo Maffione 351*75f4f3edSVincenzo Maffione del_krings1: 352*75f4f3edSVincenzo Maffione netmap_krings_delete(na); 353*75f4f3edSVincenzo Maffione return error; 354*75f4f3edSVincenzo Maffione } 355*75f4f3edSVincenzo Maffione 356c3e9b4dbSLuiz Otavio O Souza /* netmap_pipe_krings_create. 357f0ea3689SLuigi Rizzo * 358f0ea3689SLuigi Rizzo * There are two cases: 359f0ea3689SLuigi Rizzo * 360f0ea3689SLuigi Rizzo * 1) state is 361f0ea3689SLuigi Rizzo * 362f0ea3689SLuigi Rizzo * usr1 --> e1 --> e2 363f0ea3689SLuigi Rizzo * 364f0ea3689SLuigi Rizzo * and we are e1. We have to create both sets 365f0ea3689SLuigi Rizzo * of krings. 366f0ea3689SLuigi Rizzo * 367f0ea3689SLuigi Rizzo * 2) state is 368f0ea3689SLuigi Rizzo * 369f0ea3689SLuigi Rizzo * usr1 --> e1 --> e2 370f0ea3689SLuigi Rizzo * 371f0ea3689SLuigi Rizzo * and we are e2. e1 is certainly registered and our 37237e3a6d3SLuigi Rizzo * krings already exist. Nothing to do. 373f0ea3689SLuigi Rizzo */ 374f0ea3689SLuigi Rizzo static int 375f0ea3689SLuigi Rizzo netmap_pipe_krings_create(struct netmap_adapter *na) 376f0ea3689SLuigi Rizzo { 377f0ea3689SLuigi Rizzo struct netmap_pipe_adapter *pna = 378f0ea3689SLuigi Rizzo (struct netmap_pipe_adapter *)na; 379f0ea3689SLuigi Rizzo struct netmap_adapter *ona = &pna->peer->up; 380847bf383SLuigi Rizzo 381*75f4f3edSVincenzo Maffione if (pna->peer_ref) 382*75f4f3edSVincenzo Maffione return netmap_pipe_krings_create_both(na, ona); 383f0ea3689SLuigi Rizzo 384f0ea3689SLuigi Rizzo return 0; 385f0ea3689SLuigi Rizzo } 386f0ea3689SLuigi Rizzo 387*75f4f3edSVincenzo Maffione int 388*75f4f3edSVincenzo Maffione netmap_pipe_reg_both(struct netmap_adapter *na, struct netmap_adapter *ona) 389f0ea3689SLuigi Rizzo { 39037e3a6d3SLuigi Rizzo int i, error = 0; 391847bf383SLuigi Rizzo enum txrx t; 392847bf383SLuigi Rizzo 39337e3a6d3SLuigi Rizzo for_rx_tx(t) { 394c3e9b4dbSLuiz Otavio O Souza for (i = 0; i < nma_get_nrings(na, t); i++) { 3952ff91c17SVincenzo Maffione struct netmap_kring *kring = NMR(na, t)[i]; 39637e3a6d3SLuigi Rizzo 39737e3a6d3SLuigi Rizzo if (nm_kring_pending_on(kring)) { 398c3e9b4dbSLuiz Otavio O Souza /* mark the peer ring as needed */ 39937e3a6d3SLuigi Rizzo kring->pipe->nr_kflags |= NKR_NEEDRING; 40037e3a6d3SLuigi Rizzo } 40137e3a6d3SLuigi Rizzo } 40237e3a6d3SLuigi Rizzo } 40337e3a6d3SLuigi Rizzo 4042ff91c17SVincenzo Maffione /* create all missing needed rings on the other end. 4052ff91c17SVincenzo Maffione * Either our end, or the other, has been marked as 4062ff91c17SVincenzo Maffione * fake, so the allocation will not be done twice. 4072ff91c17SVincenzo Maffione */ 40837e3a6d3SLuigi Rizzo error = netmap_mem_rings_create(ona); 40937e3a6d3SLuigi Rizzo if (error) 41037e3a6d3SLuigi Rizzo return error; 41137e3a6d3SLuigi Rizzo 41237e3a6d3SLuigi Rizzo /* In case of no error we put our rings in netmap mode */ 41337e3a6d3SLuigi Rizzo for_rx_tx(t) { 414b6e66be2SVincenzo Maffione for (i = 0; i < nma_get_nrings(na, t); i++) { 4152ff91c17SVincenzo Maffione struct netmap_kring *kring = NMR(na, t)[i]; 41637e3a6d3SLuigi Rizzo if (nm_kring_pending_on(kring)) { 4172ff91c17SVincenzo Maffione struct netmap_kring *sring, *dring; 4182ff91c17SVincenzo Maffione 4192a7db7a6SVincenzo Maffione kring->nr_mode = NKR_NETMAP_ON; 4202a7db7a6SVincenzo Maffione if ((kring->nr_kflags & NKR_FAKERING) && 4212a7db7a6SVincenzo Maffione (kring->pipe->nr_kflags & NKR_FAKERING)) { 4222a7db7a6SVincenzo Maffione /* this is a re-open of a pipe 4232a7db7a6SVincenzo Maffione * end-point kept alive by the other end. 4242a7db7a6SVincenzo Maffione * We need to leave everything as it is 4252a7db7a6SVincenzo Maffione */ 4262a7db7a6SVincenzo Maffione continue; 4272a7db7a6SVincenzo Maffione } 4282a7db7a6SVincenzo Maffione 4292ff91c17SVincenzo Maffione /* copy the buffers from the non-fake ring */ 4302ff91c17SVincenzo Maffione if (kring->nr_kflags & NKR_FAKERING) { 4312ff91c17SVincenzo Maffione sring = kring->pipe; 4322ff91c17SVincenzo Maffione dring = kring; 4332ff91c17SVincenzo Maffione } else { 4342ff91c17SVincenzo Maffione sring = kring; 4352ff91c17SVincenzo Maffione dring = kring->pipe; 4362ff91c17SVincenzo Maffione } 4372ff91c17SVincenzo Maffione memcpy(dring->ring->slot, 4382ff91c17SVincenzo Maffione sring->ring->slot, 4392ff91c17SVincenzo Maffione sizeof(struct netmap_slot) * 4402ff91c17SVincenzo Maffione sring->nkr_num_slots); 4412ff91c17SVincenzo Maffione /* mark both rings as fake and needed, 4422ff91c17SVincenzo Maffione * so that buffers will not be 4432ff91c17SVincenzo Maffione * deleted by the standard machinery 4442ff91c17SVincenzo Maffione * (we will delete them by ourselves in 4452ff91c17SVincenzo Maffione * netmap_pipe_krings_delete) 4462ff91c17SVincenzo Maffione */ 4472ff91c17SVincenzo Maffione sring->nr_kflags |= 4482ff91c17SVincenzo Maffione (NKR_FAKERING | NKR_NEEDRING); 4492ff91c17SVincenzo Maffione dring->nr_kflags |= 4502ff91c17SVincenzo Maffione (NKR_FAKERING | NKR_NEEDRING); 45137e3a6d3SLuigi Rizzo kring->nr_mode = NKR_NETMAP_ON; 45237e3a6d3SLuigi Rizzo } 45337e3a6d3SLuigi Rizzo } 45437e3a6d3SLuigi Rizzo } 455*75f4f3edSVincenzo Maffione 456*75f4f3edSVincenzo Maffione return 0; 457*75f4f3edSVincenzo Maffione } 458*75f4f3edSVincenzo Maffione 459*75f4f3edSVincenzo Maffione /* netmap_pipe_reg. 460*75f4f3edSVincenzo Maffione * 461*75f4f3edSVincenzo Maffione * There are two cases on registration (onoff==1) 462*75f4f3edSVincenzo Maffione * 463*75f4f3edSVincenzo Maffione * 1.a) state is 464*75f4f3edSVincenzo Maffione * 465*75f4f3edSVincenzo Maffione * usr1 --> e1 --> e2 466*75f4f3edSVincenzo Maffione * 467*75f4f3edSVincenzo Maffione * and we are e1. Create the needed rings of the 468*75f4f3edSVincenzo Maffione * other end. 469*75f4f3edSVincenzo Maffione * 470*75f4f3edSVincenzo Maffione * 1.b) state is 471*75f4f3edSVincenzo Maffione * 472*75f4f3edSVincenzo Maffione * usr1 --> e1 --> e2 <-- usr2 473*75f4f3edSVincenzo Maffione * 474*75f4f3edSVincenzo Maffione * and we are e2. Drop the ref e1 is holding. 475*75f4f3edSVincenzo Maffione * 476*75f4f3edSVincenzo Maffione * There are two additional cases on unregister (onoff==0) 477*75f4f3edSVincenzo Maffione * 478*75f4f3edSVincenzo Maffione * 2.a) state is 479*75f4f3edSVincenzo Maffione * 480*75f4f3edSVincenzo Maffione * usr1 --> e1 --> e2 481*75f4f3edSVincenzo Maffione * 482*75f4f3edSVincenzo Maffione * and we are e1. Nothing special to do, e2 will 483*75f4f3edSVincenzo Maffione * be cleaned up by the destructor of e1. 484*75f4f3edSVincenzo Maffione * 485*75f4f3edSVincenzo Maffione * 2.b) state is 486*75f4f3edSVincenzo Maffione * 487*75f4f3edSVincenzo Maffione * usr1 --> e1 e2 <-- usr2 488*75f4f3edSVincenzo Maffione * 489*75f4f3edSVincenzo Maffione * and we are either e1 or e2. Add a ref from the 490*75f4f3edSVincenzo Maffione * other end. 491*75f4f3edSVincenzo Maffione */ 492*75f4f3edSVincenzo Maffione static int 493*75f4f3edSVincenzo Maffione netmap_pipe_reg(struct netmap_adapter *na, int onoff) 494*75f4f3edSVincenzo Maffione { 495*75f4f3edSVincenzo Maffione struct netmap_pipe_adapter *pna = 496*75f4f3edSVincenzo Maffione (struct netmap_pipe_adapter *)na; 497*75f4f3edSVincenzo Maffione struct netmap_adapter *ona = &pna->peer->up; 498*75f4f3edSVincenzo Maffione int error = 0; 499*75f4f3edSVincenzo Maffione 500*75f4f3edSVincenzo Maffione nm_prdis("%p: onoff %d", na, onoff); 501*75f4f3edSVincenzo Maffione if (onoff) { 502*75f4f3edSVincenzo Maffione error = netmap_pipe_reg_both(na, ona); 503*75f4f3edSVincenzo Maffione if (error) { 504*75f4f3edSVincenzo Maffione return error; 505*75f4f3edSVincenzo Maffione } 50637e3a6d3SLuigi Rizzo if (na->active_fds == 0) 5074bf50f18SLuigi Rizzo na->na_flags |= NAF_NETMAP_ON; 508f0ea3689SLuigi Rizzo } else { 50937e3a6d3SLuigi Rizzo if (na->active_fds == 0) 5104bf50f18SLuigi Rizzo na->na_flags &= ~NAF_NETMAP_ON; 511*75f4f3edSVincenzo Maffione netmap_krings_mode_commit(na, onoff); 512c3e9b4dbSLuiz Otavio O Souza } 51337e3a6d3SLuigi Rizzo 51437e3a6d3SLuigi Rizzo if (na->active_fds) { 515*75f4f3edSVincenzo Maffione nm_prdis("active_fds %d", na->active_fds); 51637e3a6d3SLuigi Rizzo return 0; 51737e3a6d3SLuigi Rizzo } 51837e3a6d3SLuigi Rizzo 519f0ea3689SLuigi Rizzo if (pna->peer_ref) { 520*75f4f3edSVincenzo Maffione nm_prdis("%p: case 1.a or 2.a, nothing to do", na); 521f0ea3689SLuigi Rizzo return 0; 522f0ea3689SLuigi Rizzo } 523f0ea3689SLuigi Rizzo if (onoff) { 524*75f4f3edSVincenzo Maffione nm_prdis("%p: case 1.b, drop peer", na); 525f0ea3689SLuigi Rizzo pna->peer->peer_ref = 0; 526f0ea3689SLuigi Rizzo netmap_adapter_put(na); 527f0ea3689SLuigi Rizzo } else { 528*75f4f3edSVincenzo Maffione nm_prdis("%p: case 2.b, grab peer", na); 529f0ea3689SLuigi Rizzo netmap_adapter_get(na); 530f0ea3689SLuigi Rizzo pna->peer->peer_ref = 1; 531f0ea3689SLuigi Rizzo } 53237e3a6d3SLuigi Rizzo return error; 533f0ea3689SLuigi Rizzo } 534f0ea3689SLuigi Rizzo 535*75f4f3edSVincenzo Maffione void 536*75f4f3edSVincenzo Maffione netmap_pipe_krings_delete_both(struct netmap_adapter *na, 537*75f4f3edSVincenzo Maffione struct netmap_adapter *ona) 538*75f4f3edSVincenzo Maffione { 539*75f4f3edSVincenzo Maffione struct netmap_adapter *sna; 540*75f4f3edSVincenzo Maffione enum txrx t; 541*75f4f3edSVincenzo Maffione int i; 542*75f4f3edSVincenzo Maffione 543*75f4f3edSVincenzo Maffione /* case 1) below */ 544*75f4f3edSVincenzo Maffione nm_prdis("%p: case 1, deleting everything", na); 545*75f4f3edSVincenzo Maffione /* To avoid double-frees we zero-out all the buffers in the kernel part 546*75f4f3edSVincenzo Maffione * of each ring. The reason is this: If the user is behaving correctly, 547*75f4f3edSVincenzo Maffione * all buffers are found in exactly one slot in the userspace part of 548*75f4f3edSVincenzo Maffione * some ring. If the user is not behaving correctly, we cannot release 549*75f4f3edSVincenzo Maffione * buffers cleanly anyway. In the latter case, the allocator will 550*75f4f3edSVincenzo Maffione * return to a clean state only when all its users will close. 551*75f4f3edSVincenzo Maffione */ 552*75f4f3edSVincenzo Maffione sna = na; 553*75f4f3edSVincenzo Maffione cleanup: 554*75f4f3edSVincenzo Maffione for_rx_tx(t) { 555*75f4f3edSVincenzo Maffione for (i = 0; i < nma_get_nrings(sna, t); i++) { 556*75f4f3edSVincenzo Maffione struct netmap_kring *kring = NMR(sna, t)[i]; 557*75f4f3edSVincenzo Maffione struct netmap_ring *ring = kring->ring; 558*75f4f3edSVincenzo Maffione uint32_t j, lim = kring->nkr_num_slots - 1; 559*75f4f3edSVincenzo Maffione 560*75f4f3edSVincenzo Maffione nm_prdis("%s ring %p hwtail %u hwcur %u", 561*75f4f3edSVincenzo Maffione kring->name, ring, kring->nr_hwtail, kring->nr_hwcur); 562*75f4f3edSVincenzo Maffione 563*75f4f3edSVincenzo Maffione if (ring == NULL) 564*75f4f3edSVincenzo Maffione continue; 565*75f4f3edSVincenzo Maffione 566*75f4f3edSVincenzo Maffione if (kring->tx == NR_RX) 567*75f4f3edSVincenzo Maffione ring->slot[kring->pipe_tail].buf_idx = 0; 568*75f4f3edSVincenzo Maffione 569*75f4f3edSVincenzo Maffione for (j = nm_next(kring->pipe_tail, lim); 570*75f4f3edSVincenzo Maffione j != kring->nr_hwcur; 571*75f4f3edSVincenzo Maffione j = nm_next(j, lim)) 572*75f4f3edSVincenzo Maffione { 573*75f4f3edSVincenzo Maffione nm_prdis("%s[%d] %u", kring->name, j, ring->slot[j].buf_idx); 574*75f4f3edSVincenzo Maffione ring->slot[j].buf_idx = 0; 575*75f4f3edSVincenzo Maffione } 576*75f4f3edSVincenzo Maffione kring->nr_kflags &= ~(NKR_FAKERING | NKR_NEEDRING); 577*75f4f3edSVincenzo Maffione } 578*75f4f3edSVincenzo Maffione 579*75f4f3edSVincenzo Maffione } 580*75f4f3edSVincenzo Maffione if (sna != ona && ona->tx_rings) { 581*75f4f3edSVincenzo Maffione sna = ona; 582*75f4f3edSVincenzo Maffione goto cleanup; 583*75f4f3edSVincenzo Maffione } 584*75f4f3edSVincenzo Maffione 585*75f4f3edSVincenzo Maffione netmap_mem_rings_delete(na); 586*75f4f3edSVincenzo Maffione netmap_krings_delete(na); /* also zeroes tx_rings etc. */ 587*75f4f3edSVincenzo Maffione 588*75f4f3edSVincenzo Maffione if (ona->tx_rings == NULL) { 589*75f4f3edSVincenzo Maffione /* already deleted, we must be on an 590*75f4f3edSVincenzo Maffione * cleanup-after-error path */ 591*75f4f3edSVincenzo Maffione return; 592*75f4f3edSVincenzo Maffione } 593*75f4f3edSVincenzo Maffione netmap_mem_rings_delete(ona); 594*75f4f3edSVincenzo Maffione netmap_krings_delete(ona); 595*75f4f3edSVincenzo Maffione } 596*75f4f3edSVincenzo Maffione 597f0ea3689SLuigi Rizzo /* netmap_pipe_krings_delete. 598f0ea3689SLuigi Rizzo * 599f0ea3689SLuigi Rizzo * There are two cases: 600f0ea3689SLuigi Rizzo * 601f0ea3689SLuigi Rizzo * 1) state is 602f0ea3689SLuigi Rizzo * 603f0ea3689SLuigi Rizzo * usr1 --> e1 --> e2 604f0ea3689SLuigi Rizzo * 605f0ea3689SLuigi Rizzo * and we are e1 (e2 is not registered, so krings_delete cannot be 606f0ea3689SLuigi Rizzo * called on it); 607f0ea3689SLuigi Rizzo * 608f0ea3689SLuigi Rizzo * 2) state is 609f0ea3689SLuigi Rizzo * 610f0ea3689SLuigi Rizzo * usr1 --> e1 e2 <-- usr2 611f0ea3689SLuigi Rizzo * 612f0ea3689SLuigi Rizzo * and we are either e1 or e2. 613f0ea3689SLuigi Rizzo * 614f0ea3689SLuigi Rizzo * In the former case we have to also delete the krings of e2; 6152ff91c17SVincenzo Maffione * in the latter case we do nothing. 616f0ea3689SLuigi Rizzo */ 617f0ea3689SLuigi Rizzo static void 618f0ea3689SLuigi Rizzo netmap_pipe_krings_delete(struct netmap_adapter *na) 619f0ea3689SLuigi Rizzo { 620f0ea3689SLuigi Rizzo struct netmap_pipe_adapter *pna = 621f0ea3689SLuigi Rizzo (struct netmap_pipe_adapter *)na; 622*75f4f3edSVincenzo Maffione struct netmap_adapter *ona; /* na of the other end */ 623f0ea3689SLuigi Rizzo 624f0ea3689SLuigi Rizzo if (!pna->peer_ref) { 625*75f4f3edSVincenzo Maffione nm_prdis("%p: case 2, kept alive by peer", na); 626f0ea3689SLuigi Rizzo return; 627f0ea3689SLuigi Rizzo } 6282ff91c17SVincenzo Maffione ona = &pna->peer->up; 629*75f4f3edSVincenzo Maffione netmap_pipe_krings_delete_both(na, ona); 630f0ea3689SLuigi Rizzo } 631f0ea3689SLuigi Rizzo 632f0ea3689SLuigi Rizzo 633f0ea3689SLuigi Rizzo static void 634f0ea3689SLuigi Rizzo netmap_pipe_dtor(struct netmap_adapter *na) 635f0ea3689SLuigi Rizzo { 636f0ea3689SLuigi Rizzo struct netmap_pipe_adapter *pna = 637f0ea3689SLuigi Rizzo (struct netmap_pipe_adapter *)na; 638*75f4f3edSVincenzo Maffione nm_prdis("%p %p", na, pna->parent_ifp); 639f0ea3689SLuigi Rizzo if (pna->peer_ref) { 640*75f4f3edSVincenzo Maffione nm_prdis("%p: clean up peer", na); 641f0ea3689SLuigi Rizzo pna->peer_ref = 0; 642f0ea3689SLuigi Rizzo netmap_adapter_put(&pna->peer->up); 643f0ea3689SLuigi Rizzo } 6442ff91c17SVincenzo Maffione if (pna->role == NM_PIPE_ROLE_MASTER) 645f0ea3689SLuigi Rizzo netmap_pipe_remove(pna->parent, pna); 646c3e9b4dbSLuiz Otavio O Souza if (pna->parent_ifp) 647c3e9b4dbSLuiz Otavio O Souza if_rele(pna->parent_ifp); 648f0ea3689SLuigi Rizzo netmap_adapter_put(pna->parent); 649f0ea3689SLuigi Rizzo pna->parent = NULL; 650f0ea3689SLuigi Rizzo } 651f0ea3689SLuigi Rizzo 652f0ea3689SLuigi Rizzo int 6532ff91c17SVincenzo Maffione netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na, 654c3e9b4dbSLuiz Otavio O Souza struct netmap_mem_d *nmd, int create) 655f0ea3689SLuigi Rizzo { 656cfa866f6SMatt Macy struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body; 657f0ea3689SLuigi Rizzo struct netmap_adapter *pna; /* parent adapter */ 6582ff91c17SVincenzo Maffione struct netmap_pipe_adapter *mna, *sna, *reqna; 65937e3a6d3SLuigi Rizzo struct ifnet *ifp = NULL; 6602ff91c17SVincenzo Maffione const char *pipe_id = NULL; 6612ff91c17SVincenzo Maffione int role = 0; 662c3e9b4dbSLuiz Otavio O Souza int error, retries = 0; 6632ff91c17SVincenzo Maffione char *cbra; 664f0ea3689SLuigi Rizzo 6652ff91c17SVincenzo Maffione /* Try to parse the pipe syntax 'xx{yy' or 'xx}yy'. */ 6662ff91c17SVincenzo Maffione cbra = strrchr(hdr->nr_name, '{'); 6672ff91c17SVincenzo Maffione if (cbra != NULL) { 6682ff91c17SVincenzo Maffione role = NM_PIPE_ROLE_MASTER; 6692ff91c17SVincenzo Maffione } else { 6702ff91c17SVincenzo Maffione cbra = strrchr(hdr->nr_name, '}'); 6712ff91c17SVincenzo Maffione if (cbra != NULL) { 6722ff91c17SVincenzo Maffione role = NM_PIPE_ROLE_SLAVE; 6732ff91c17SVincenzo Maffione } else { 674*75f4f3edSVincenzo Maffione nm_prdis("not a pipe"); 675f0ea3689SLuigi Rizzo return 0; 676f0ea3689SLuigi Rizzo } 6772ff91c17SVincenzo Maffione } 6782ff91c17SVincenzo Maffione pipe_id = cbra + 1; 6792ff91c17SVincenzo Maffione if (*pipe_id == '\0' || cbra == hdr->nr_name) { 6802ff91c17SVincenzo Maffione /* Bracket is the last character, so pipe name is missing; 6812ff91c17SVincenzo Maffione * or bracket is the first character, so base port name 6822ff91c17SVincenzo Maffione * is missing. */ 6832ff91c17SVincenzo Maffione return EINVAL; 6842ff91c17SVincenzo Maffione } 6852ff91c17SVincenzo Maffione 6862ff91c17SVincenzo Maffione if (req->nr_mode != NR_REG_ALL_NIC && req->nr_mode != NR_REG_ONE_NIC) { 6872ff91c17SVincenzo Maffione /* We only accept modes involving hardware rings. */ 6882ff91c17SVincenzo Maffione return EINVAL; 6892ff91c17SVincenzo Maffione } 690f0ea3689SLuigi Rizzo 691f0ea3689SLuigi Rizzo /* first, try to find the parent adapter */ 692c3e9b4dbSLuiz Otavio O Souza for (;;) { 6932ff91c17SVincenzo Maffione char nr_name_orig[NETMAP_REQ_IFNAMSIZ]; 694c3e9b4dbSLuiz Otavio O Souza int create_error; 695c3e9b4dbSLuiz Otavio O Souza 6962ff91c17SVincenzo Maffione /* Temporarily remove the pipe suffix. */ 697b6e66be2SVincenzo Maffione strlcpy(nr_name_orig, hdr->nr_name, sizeof(nr_name_orig)); 6982ff91c17SVincenzo Maffione *cbra = '\0'; 6992ff91c17SVincenzo Maffione error = netmap_get_na(hdr, &pna, &ifp, nmd, create); 7002ff91c17SVincenzo Maffione /* Restore the pipe suffix. */ 701b6e66be2SVincenzo Maffione strlcpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name)); 702c3e9b4dbSLuiz Otavio O Souza if (!error) 703c3e9b4dbSLuiz Otavio O Souza break; 704c3e9b4dbSLuiz Otavio O Souza if (error != ENXIO || retries++) { 705*75f4f3edSVincenzo Maffione nm_prdis("parent lookup failed: %d", error); 706f0ea3689SLuigi Rizzo return error; 707f0ea3689SLuigi Rizzo } 708*75f4f3edSVincenzo Maffione nm_prdis("try to create a persistent vale port"); 709c3e9b4dbSLuiz Otavio O Souza /* create a persistent vale port and try again */ 7102ff91c17SVincenzo Maffione *cbra = '\0'; 711c3e9b4dbSLuiz Otavio O Souza NMG_UNLOCK(); 7122ff91c17SVincenzo Maffione create_error = netmap_vi_create(hdr, 1 /* autodelete */); 713c3e9b4dbSLuiz Otavio O Souza NMG_LOCK(); 714b6e66be2SVincenzo Maffione strlcpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name)); 715c3e9b4dbSLuiz Otavio O Souza if (create_error && create_error != EEXIST) { 716c3e9b4dbSLuiz Otavio O Souza if (create_error != EOPNOTSUPP) { 717*75f4f3edSVincenzo Maffione nm_prerr("failed to create a persistent vale port: %d", 718*75f4f3edSVincenzo Maffione create_error); 719c3e9b4dbSLuiz Otavio O Souza } 720c3e9b4dbSLuiz Otavio O Souza return error; 721c3e9b4dbSLuiz Otavio O Souza } 722c3e9b4dbSLuiz Otavio O Souza } 723f0ea3689SLuigi Rizzo 724f0ea3689SLuigi Rizzo if (NETMAP_OWNED_BY_KERN(pna)) { 725*75f4f3edSVincenzo Maffione nm_prdis("parent busy"); 726f0ea3689SLuigi Rizzo error = EBUSY; 727f0ea3689SLuigi Rizzo goto put_out; 728f0ea3689SLuigi Rizzo } 729f0ea3689SLuigi Rizzo 730f0ea3689SLuigi Rizzo /* next, lookup the pipe id in the parent list */ 7312ff91c17SVincenzo Maffione reqna = NULL; 732f0ea3689SLuigi Rizzo mna = netmap_pipe_find(pna, pipe_id); 733f0ea3689SLuigi Rizzo if (mna) { 734f0ea3689SLuigi Rizzo if (mna->role == role) { 735*75f4f3edSVincenzo Maffione nm_prdis("found %s directly at %d", pipe_id, mna->parent_slot); 7362ff91c17SVincenzo Maffione reqna = mna; 737f0ea3689SLuigi Rizzo } else { 738*75f4f3edSVincenzo Maffione nm_prdis("found %s indirectly at %d", pipe_id, mna->parent_slot); 7392ff91c17SVincenzo Maffione reqna = mna->peer; 740f0ea3689SLuigi Rizzo } 741f0ea3689SLuigi Rizzo /* the pipe we have found already holds a ref to the parent, 742f0ea3689SLuigi Rizzo * so we need to drop the one we got from netmap_get_na() 743f0ea3689SLuigi Rizzo */ 744c3e9b4dbSLuiz Otavio O Souza netmap_unget_na(pna, ifp); 745f0ea3689SLuigi Rizzo goto found; 746f0ea3689SLuigi Rizzo } 747*75f4f3edSVincenzo Maffione nm_prdis("pipe %s not found, create %d", pipe_id, create); 748f0ea3689SLuigi Rizzo if (!create) { 749f0ea3689SLuigi Rizzo error = ENODEV; 750f0ea3689SLuigi Rizzo goto put_out; 751f0ea3689SLuigi Rizzo } 752f0ea3689SLuigi Rizzo /* we create both master and slave. 753f0ea3689SLuigi Rizzo * The endpoint we were asked for holds a reference to 754f0ea3689SLuigi Rizzo * the other one. 755f0ea3689SLuigi Rizzo */ 756c3e9b4dbSLuiz Otavio O Souza mna = nm_os_malloc(sizeof(*mna)); 757f0ea3689SLuigi Rizzo if (mna == NULL) { 758f0ea3689SLuigi Rizzo error = ENOMEM; 7594bf50f18SLuigi Rizzo goto put_out; 760f0ea3689SLuigi Rizzo } 7612ff91c17SVincenzo Maffione snprintf(mna->up.name, sizeof(mna->up.name), "%s{%s", pna->name, pipe_id); 762f0ea3689SLuigi Rizzo 7632ff91c17SVincenzo Maffione mna->role = NM_PIPE_ROLE_MASTER; 764f0ea3689SLuigi Rizzo mna->parent = pna; 765c3e9b4dbSLuiz Otavio O Souza mna->parent_ifp = ifp; 766f0ea3689SLuigi Rizzo 767f0ea3689SLuigi Rizzo mna->up.nm_txsync = netmap_pipe_txsync; 768f0ea3689SLuigi Rizzo mna->up.nm_rxsync = netmap_pipe_rxsync; 769f0ea3689SLuigi Rizzo mna->up.nm_register = netmap_pipe_reg; 770f0ea3689SLuigi Rizzo mna->up.nm_dtor = netmap_pipe_dtor; 771f0ea3689SLuigi Rizzo mna->up.nm_krings_create = netmap_pipe_krings_create; 772f0ea3689SLuigi Rizzo mna->up.nm_krings_delete = netmap_pipe_krings_delete; 773c3e9b4dbSLuiz Otavio O Souza mna->up.nm_mem = netmap_mem_get(pna->nm_mem); 774c3e9b4dbSLuiz Otavio O Souza mna->up.na_flags |= NAF_MEM_OWNER; 775f0ea3689SLuigi Rizzo mna->up.na_lut = pna->na_lut; 776f0ea3689SLuigi Rizzo 7772ff91c17SVincenzo Maffione mna->up.num_tx_rings = req->nr_tx_rings; 7782ff91c17SVincenzo Maffione nm_bound_var(&mna->up.num_tx_rings, 1, 7792ff91c17SVincenzo Maffione 1, NM_PIPE_MAXRINGS, NULL); 7802ff91c17SVincenzo Maffione mna->up.num_rx_rings = req->nr_rx_rings; 7812ff91c17SVincenzo Maffione nm_bound_var(&mna->up.num_rx_rings, 1, 7822ff91c17SVincenzo Maffione 1, NM_PIPE_MAXRINGS, NULL); 7832ff91c17SVincenzo Maffione mna->up.num_tx_desc = req->nr_tx_slots; 784f0ea3689SLuigi Rizzo nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc, 785f0ea3689SLuigi Rizzo 1, NM_PIPE_MAXSLOTS, NULL); 7862ff91c17SVincenzo Maffione mna->up.num_rx_desc = req->nr_rx_slots; 787f0ea3689SLuigi Rizzo nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc, 788f0ea3689SLuigi Rizzo 1, NM_PIPE_MAXSLOTS, NULL); 789f0ea3689SLuigi Rizzo error = netmap_attach_common(&mna->up); 790f0ea3689SLuigi Rizzo if (error) 7914bf50f18SLuigi Rizzo goto free_mna; 792f0ea3689SLuigi Rizzo /* register the master with the parent */ 793f0ea3689SLuigi Rizzo error = netmap_pipe_add(pna, mna); 794f0ea3689SLuigi Rizzo if (error) 795f0ea3689SLuigi Rizzo goto free_mna; 796f0ea3689SLuigi Rizzo 797f0ea3689SLuigi Rizzo /* create the slave */ 798c3e9b4dbSLuiz Otavio O Souza sna = nm_os_malloc(sizeof(*mna)); 799f0ea3689SLuigi Rizzo if (sna == NULL) { 800f0ea3689SLuigi Rizzo error = ENOMEM; 8019694aad3SLuigi Rizzo goto unregister_mna; 802f0ea3689SLuigi Rizzo } 803f0ea3689SLuigi Rizzo /* most fields are the same, copy from master and then fix */ 804f0ea3689SLuigi Rizzo *sna = *mna; 805c3e9b4dbSLuiz Otavio O Souza sna->up.nm_mem = netmap_mem_get(mna->up.nm_mem); 806c52382bdSVincenzo Maffione /* swap the number of tx/rx rings and slots */ 8072ff91c17SVincenzo Maffione sna->up.num_tx_rings = mna->up.num_rx_rings; 808c52382bdSVincenzo Maffione sna->up.num_tx_desc = mna->up.num_rx_desc; 8092ff91c17SVincenzo Maffione sna->up.num_rx_rings = mna->up.num_tx_rings; 810c52382bdSVincenzo Maffione sna->up.num_rx_desc = mna->up.num_tx_desc; 8112ff91c17SVincenzo Maffione snprintf(sna->up.name, sizeof(sna->up.name), "%s}%s", pna->name, pipe_id); 8122ff91c17SVincenzo Maffione sna->role = NM_PIPE_ROLE_SLAVE; 813f0ea3689SLuigi Rizzo error = netmap_attach_common(&sna->up); 814f0ea3689SLuigi Rizzo if (error) 815f0ea3689SLuigi Rizzo goto free_sna; 816f0ea3689SLuigi Rizzo 817f0ea3689SLuigi Rizzo /* join the two endpoints */ 818f0ea3689SLuigi Rizzo mna->peer = sna; 819f0ea3689SLuigi Rizzo sna->peer = mna; 820f0ea3689SLuigi Rizzo 821f0ea3689SLuigi Rizzo /* we already have a reference to the parent, but we 822f0ea3689SLuigi Rizzo * need another one for the other endpoint we created 823f0ea3689SLuigi Rizzo */ 824f0ea3689SLuigi Rizzo netmap_adapter_get(pna); 825c3e9b4dbSLuiz Otavio O Souza /* likewise for the ifp, if any */ 826c3e9b4dbSLuiz Otavio O Souza if (ifp) 827c3e9b4dbSLuiz Otavio O Souza if_ref(ifp); 828f0ea3689SLuigi Rizzo 8292ff91c17SVincenzo Maffione if (role == NM_PIPE_ROLE_MASTER) { 8302ff91c17SVincenzo Maffione reqna = mna; 831f0ea3689SLuigi Rizzo mna->peer_ref = 1; 832f0ea3689SLuigi Rizzo netmap_adapter_get(&sna->up); 833f0ea3689SLuigi Rizzo } else { 8342ff91c17SVincenzo Maffione reqna = sna; 835f0ea3689SLuigi Rizzo sna->peer_ref = 1; 836f0ea3689SLuigi Rizzo netmap_adapter_get(&mna->up); 837f0ea3689SLuigi Rizzo } 838*75f4f3edSVincenzo Maffione nm_prdis("created master %p and slave %p", mna, sna); 839f0ea3689SLuigi Rizzo found: 840f0ea3689SLuigi Rizzo 841*75f4f3edSVincenzo Maffione nm_prdis("pipe %s %s at %p", pipe_id, 8422ff91c17SVincenzo Maffione (reqna->role == NM_PIPE_ROLE_MASTER ? "master" : "slave"), reqna); 8432ff91c17SVincenzo Maffione *na = &reqna->up; 844f0ea3689SLuigi Rizzo netmap_adapter_get(*na); 845f0ea3689SLuigi Rizzo 846f0ea3689SLuigi Rizzo /* keep the reference to the parent. 847f0ea3689SLuigi Rizzo * It will be released by the req destructor 848f0ea3689SLuigi Rizzo */ 849f0ea3689SLuigi Rizzo 850f0ea3689SLuigi Rizzo return 0; 851f0ea3689SLuigi Rizzo 852f0ea3689SLuigi Rizzo free_sna: 853c3e9b4dbSLuiz Otavio O Souza nm_os_free(sna); 8549694aad3SLuigi Rizzo unregister_mna: 8559694aad3SLuigi Rizzo netmap_pipe_remove(pna, mna); 856f0ea3689SLuigi Rizzo free_mna: 857c3e9b4dbSLuiz Otavio O Souza nm_os_free(mna); 858f0ea3689SLuigi Rizzo put_out: 85937e3a6d3SLuigi Rizzo netmap_unget_na(pna, ifp); 860f0ea3689SLuigi Rizzo return error; 861f0ea3689SLuigi Rizzo } 862f0ea3689SLuigi Rizzo 863f0ea3689SLuigi Rizzo 864f0ea3689SLuigi Rizzo #endif /* WITH_PIPES */ 865