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) { 12175f4f3edSVincenzo Maffione nm_prerr("freeing not empty pipe array for %s (%d dangling pipes)!", 12275f4f3edSVincenzo 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 19375f4f3edSVincenzo Maffione nm_prdis("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name); 19475f4f3edSVincenzo 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]; 214*a6d768d8SVincenzo Maffione uint64_t off = nm_get_offset(rxkring, rs); 215f0ea3689SLuigi Rizzo 2162a7db7a6SVincenzo Maffione *rs = *ts; 217*a6d768d8SVincenzo Maffione if (nm_get_offset(rxkring, rs) < off) { 218*a6d768d8SVincenzo Maffione nm_write_offset(rxkring, rs, off); 219*a6d768d8SVincenzo Maffione } 2202ff91c17SVincenzo Maffione if (ts->flags & NS_BUF_CHANGED) { 2212ff91c17SVincenzo Maffione ts->flags &= ~NS_BUF_CHANGED; 2222ff91c17SVincenzo Maffione } 2232a7db7a6SVincenzo Maffione complete = !(ts->flags & NS_MOREFRAG); 224f0ea3689SLuigi Rizzo } 225f0ea3689SLuigi Rizzo 226f0ea3689SLuigi Rizzo txkring->nr_hwcur = k; 227f0ea3689SLuigi Rizzo 22875f4f3edSVincenzo Maffione nm_prdis(20, "TX after : hwcur %d hwtail %d cur %d head %d tail %d k %d", 2292ff91c17SVincenzo Maffione txkring->nr_hwcur, txkring->nr_hwtail, 2302ff91c17SVincenzo Maffione txkring->rcur, txkring->rhead, txkring->rtail, k); 231f0ea3689SLuigi Rizzo 2322a7db7a6SVincenzo Maffione if (likely(nk <= lim)) { 2332a7db7a6SVincenzo Maffione mb(); /* make sure the slots are updated before publishing them */ 2342a7db7a6SVincenzo Maffione rxkring->pipe_tail = nk; /* only publish complete packets */ 235847bf383SLuigi Rizzo rxkring->nm_notify(rxkring, 0); 2362a7db7a6SVincenzo Maffione } 237f0ea3689SLuigi Rizzo 238f0ea3689SLuigi Rizzo return 0; 239f0ea3689SLuigi Rizzo } 240f0ea3689SLuigi Rizzo 241c3e9b4dbSLuiz Otavio O Souza int 2424bf50f18SLuigi Rizzo netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags) 243f0ea3689SLuigi Rizzo { 2444bf50f18SLuigi Rizzo struct netmap_kring *txkring = rxkring->pipe; 2452ff91c17SVincenzo Maffione u_int k, lim = rxkring->nkr_num_slots - 1; 2462ff91c17SVincenzo Maffione int m; /* slots to release */ 2472ff91c17SVincenzo Maffione struct netmap_ring *txring = txkring->ring, *rxring = rxkring->ring; 248f0ea3689SLuigi Rizzo 24975f4f3edSVincenzo Maffione nm_prdis("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name); 25075f4f3edSVincenzo Maffione nm_prdis(20, "RX before: hwcur %d hwtail %d cur %d head %d tail %d", 2512ff91c17SVincenzo Maffione rxkring->nr_hwcur, rxkring->nr_hwtail, 252f0ea3689SLuigi Rizzo rxkring->rcur, rxkring->rhead, rxkring->rtail); 253f0ea3689SLuigi Rizzo 2542a7db7a6SVincenzo Maffione /* update the hwtail */ 2552a7db7a6SVincenzo Maffione rxkring->nr_hwtail = rxkring->pipe_tail; 2562a7db7a6SVincenzo Maffione 2572ff91c17SVincenzo Maffione m = rxkring->rhead - rxkring->nr_hwcur; /* released slots */ 2582ff91c17SVincenzo Maffione if (m < 0) 2592ff91c17SVincenzo Maffione m += rxkring->nkr_num_slots; 2602ff91c17SVincenzo Maffione 2612ff91c17SVincenzo Maffione if (m == 0) { 2622ff91c17SVincenzo Maffione /* nothing to release */ 2632ff91c17SVincenzo Maffione return 0; 264f0ea3689SLuigi Rizzo } 2652ff91c17SVincenzo Maffione 2662ff91c17SVincenzo Maffione for (k = rxkring->nr_hwcur; m; m--, k = nm_next(k, lim)) { 2672ff91c17SVincenzo Maffione struct netmap_slot *rs = &rxring->slot[k]; 2682ff91c17SVincenzo Maffione struct netmap_slot *ts = &txring->slot[k]; 2692ff91c17SVincenzo Maffione 270*a6d768d8SVincenzo Maffione /* copy the slot. This also propagates any offset */ 2712ff91c17SVincenzo Maffione *ts = *rs; 272*a6d768d8SVincenzo Maffione if (rs->flags & NS_BUF_CHANGED) { 2732ff91c17SVincenzo Maffione rs->flags &= ~NS_BUF_CHANGED; 2742ff91c17SVincenzo Maffione } 2752ff91c17SVincenzo Maffione } 2762ff91c17SVincenzo Maffione 2772ff91c17SVincenzo Maffione mb(); /* make sure the slots are updated before publishing them */ 2782a7db7a6SVincenzo Maffione txkring->pipe_tail = nm_prev(k, lim); 2792ff91c17SVincenzo Maffione rxkring->nr_hwcur = k; 2802ff91c17SVincenzo Maffione 28175f4f3edSVincenzo Maffione nm_prdis(20, "RX after : hwcur %d hwtail %d cur %d head %d tail %d k %d", 2822ff91c17SVincenzo Maffione rxkring->nr_hwcur, rxkring->nr_hwtail, 2832ff91c17SVincenzo Maffione rxkring->rcur, rxkring->rhead, rxkring->rtail, k); 2842ff91c17SVincenzo Maffione 2852ff91c17SVincenzo Maffione txkring->nm_notify(txkring, 0); 2862ff91c17SVincenzo Maffione 287f0ea3689SLuigi Rizzo return 0; 288f0ea3689SLuigi Rizzo } 289f0ea3689SLuigi Rizzo 290f0ea3689SLuigi Rizzo /* Pipe endpoints are created and destroyed together, so that endopoints do not 291f0ea3689SLuigi Rizzo * have to check for the existence of their peer at each ?xsync. 292f0ea3689SLuigi Rizzo * 293f0ea3689SLuigi Rizzo * To play well with the existing netmap infrastructure (refcounts etc.), we 294f0ea3689SLuigi Rizzo * adopt the following strategy: 295f0ea3689SLuigi Rizzo * 296f0ea3689SLuigi Rizzo * 1) The first endpoint that is created also creates the other endpoint and 297f0ea3689SLuigi Rizzo * grabs a reference to it. 298f0ea3689SLuigi Rizzo * 299f0ea3689SLuigi Rizzo * state A) user1 --> endpoint1 --> endpoint2 300f0ea3689SLuigi Rizzo * 301f0ea3689SLuigi Rizzo * 2) If, starting from state A, endpoint2 is then registered, endpoint1 gives 302f0ea3689SLuigi Rizzo * its reference to the user: 303f0ea3689SLuigi Rizzo * 304f0ea3689SLuigi Rizzo * state B) user1 --> endpoint1 endpoint2 <--- user2 305f0ea3689SLuigi Rizzo * 306f0ea3689SLuigi Rizzo * 3) Assume that, starting from state B endpoint2 is closed. In the unregister 307f0ea3689SLuigi Rizzo * callback endpoint2 notes that endpoint1 is still active and adds a reference 308f0ea3689SLuigi Rizzo * from endpoint1 to itself. When user2 then releases her own reference, 309f0ea3689SLuigi Rizzo * endpoint2 is not destroyed and we are back to state A. A symmetrical state 310f0ea3689SLuigi Rizzo * would be reached if endpoint1 were released instead. 311f0ea3689SLuigi Rizzo * 312f0ea3689SLuigi Rizzo * 4) If, starting from state A, endpoint1 is closed, the destructor notes that 313f0ea3689SLuigi Rizzo * it owns a reference to endpoint2 and releases it. 314f0ea3689SLuigi Rizzo * 315f0ea3689SLuigi Rizzo * Something similar goes on for the creation and destruction of the krings. 316f0ea3689SLuigi Rizzo */ 317f0ea3689SLuigi Rizzo 318f0ea3689SLuigi Rizzo 31975f4f3edSVincenzo Maffione int netmap_pipe_krings_create_both(struct netmap_adapter *na, 32075f4f3edSVincenzo Maffione struct netmap_adapter *ona) 32175f4f3edSVincenzo Maffione { 32275f4f3edSVincenzo Maffione enum txrx t; 32375f4f3edSVincenzo Maffione int error; 32475f4f3edSVincenzo Maffione int i; 32575f4f3edSVincenzo Maffione 32675f4f3edSVincenzo Maffione /* case 1) below */ 32775f4f3edSVincenzo Maffione nm_prdis("%p: case 1, create both ends", na); 32875f4f3edSVincenzo Maffione error = netmap_krings_create(na, 0); 32975f4f3edSVincenzo Maffione if (error) 33075f4f3edSVincenzo Maffione return error; 33175f4f3edSVincenzo Maffione 33275f4f3edSVincenzo Maffione /* create the krings of the other end */ 33375f4f3edSVincenzo Maffione error = netmap_krings_create(ona, 0); 33475f4f3edSVincenzo Maffione if (error) 33575f4f3edSVincenzo Maffione goto del_krings1; 33675f4f3edSVincenzo Maffione 33775f4f3edSVincenzo Maffione /* cross link the krings and initialize the pipe_tails */ 33875f4f3edSVincenzo Maffione for_rx_tx(t) { 33975f4f3edSVincenzo Maffione enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */ 34075f4f3edSVincenzo Maffione for (i = 0; i < nma_get_nrings(na, t); i++) { 34175f4f3edSVincenzo Maffione struct netmap_kring *k1 = NMR(na, t)[i], 34275f4f3edSVincenzo Maffione *k2 = NMR(ona, r)[i]; 34375f4f3edSVincenzo Maffione k1->pipe = k2; 34475f4f3edSVincenzo Maffione k2->pipe = k1; 34575f4f3edSVincenzo Maffione /* mark all peer-adapter rings as fake */ 34675f4f3edSVincenzo Maffione k2->nr_kflags |= NKR_FAKERING; 34775f4f3edSVincenzo Maffione /* init tails */ 34875f4f3edSVincenzo Maffione k1->pipe_tail = k1->nr_hwtail; 34975f4f3edSVincenzo Maffione k2->pipe_tail = k2->nr_hwtail; 35075f4f3edSVincenzo Maffione } 35175f4f3edSVincenzo Maffione } 35275f4f3edSVincenzo Maffione 35375f4f3edSVincenzo Maffione return 0; 35475f4f3edSVincenzo Maffione 35575f4f3edSVincenzo Maffione del_krings1: 35675f4f3edSVincenzo Maffione netmap_krings_delete(na); 35775f4f3edSVincenzo Maffione return error; 35875f4f3edSVincenzo Maffione } 35975f4f3edSVincenzo Maffione 360c3e9b4dbSLuiz Otavio O Souza /* netmap_pipe_krings_create. 361f0ea3689SLuigi Rizzo * 362f0ea3689SLuigi Rizzo * There are two cases: 363f0ea3689SLuigi Rizzo * 364f0ea3689SLuigi Rizzo * 1) state is 365f0ea3689SLuigi Rizzo * 366f0ea3689SLuigi Rizzo * usr1 --> e1 --> e2 367f0ea3689SLuigi Rizzo * 368f0ea3689SLuigi Rizzo * and we are e1. We have to create both sets 369f0ea3689SLuigi Rizzo * of krings. 370f0ea3689SLuigi Rizzo * 371f0ea3689SLuigi Rizzo * 2) state is 372f0ea3689SLuigi Rizzo * 373f0ea3689SLuigi Rizzo * usr1 --> e1 --> e2 374f0ea3689SLuigi Rizzo * 375f0ea3689SLuigi Rizzo * and we are e2. e1 is certainly registered and our 37637e3a6d3SLuigi Rizzo * krings already exist. Nothing to do. 377f0ea3689SLuigi Rizzo */ 378f0ea3689SLuigi Rizzo static int 379f0ea3689SLuigi Rizzo netmap_pipe_krings_create(struct netmap_adapter *na) 380f0ea3689SLuigi Rizzo { 381f0ea3689SLuigi Rizzo struct netmap_pipe_adapter *pna = 382f0ea3689SLuigi Rizzo (struct netmap_pipe_adapter *)na; 383f0ea3689SLuigi Rizzo struct netmap_adapter *ona = &pna->peer->up; 384847bf383SLuigi Rizzo 38575f4f3edSVincenzo Maffione if (pna->peer_ref) 38675f4f3edSVincenzo Maffione return netmap_pipe_krings_create_both(na, ona); 387f0ea3689SLuigi Rizzo 388f0ea3689SLuigi Rizzo return 0; 389f0ea3689SLuigi Rizzo } 390f0ea3689SLuigi Rizzo 39175f4f3edSVincenzo Maffione int 39275f4f3edSVincenzo Maffione netmap_pipe_reg_both(struct netmap_adapter *na, struct netmap_adapter *ona) 393f0ea3689SLuigi Rizzo { 39437e3a6d3SLuigi Rizzo int i, error = 0; 395847bf383SLuigi Rizzo enum txrx t; 396847bf383SLuigi Rizzo 39737e3a6d3SLuigi Rizzo for_rx_tx(t) { 398c3e9b4dbSLuiz Otavio O Souza for (i = 0; i < nma_get_nrings(na, t); i++) { 3992ff91c17SVincenzo Maffione struct netmap_kring *kring = NMR(na, t)[i]; 40037e3a6d3SLuigi Rizzo 40137e3a6d3SLuigi Rizzo if (nm_kring_pending_on(kring)) { 402c3e9b4dbSLuiz Otavio O Souza /* mark the peer ring as needed */ 40337e3a6d3SLuigi Rizzo kring->pipe->nr_kflags |= NKR_NEEDRING; 40437e3a6d3SLuigi Rizzo } 40537e3a6d3SLuigi Rizzo } 40637e3a6d3SLuigi Rizzo } 40737e3a6d3SLuigi Rizzo 4082ff91c17SVincenzo Maffione /* create all missing needed rings on the other end. 4092ff91c17SVincenzo Maffione * Either our end, or the other, has been marked as 4102ff91c17SVincenzo Maffione * fake, so the allocation will not be done twice. 4112ff91c17SVincenzo Maffione */ 41237e3a6d3SLuigi Rizzo error = netmap_mem_rings_create(ona); 41337e3a6d3SLuigi Rizzo if (error) 41437e3a6d3SLuigi Rizzo return error; 41537e3a6d3SLuigi Rizzo 41637e3a6d3SLuigi Rizzo /* In case of no error we put our rings in netmap mode */ 41737e3a6d3SLuigi Rizzo for_rx_tx(t) { 418b6e66be2SVincenzo Maffione for (i = 0; i < nma_get_nrings(na, t); i++) { 4192ff91c17SVincenzo Maffione struct netmap_kring *kring = NMR(na, t)[i]; 42037e3a6d3SLuigi Rizzo if (nm_kring_pending_on(kring)) { 4212ff91c17SVincenzo Maffione 4222a7db7a6SVincenzo Maffione kring->nr_mode = NKR_NETMAP_ON; 4232a7db7a6SVincenzo Maffione if ((kring->nr_kflags & NKR_FAKERING) && 4242a7db7a6SVincenzo Maffione (kring->pipe->nr_kflags & NKR_FAKERING)) { 4252a7db7a6SVincenzo Maffione /* this is a re-open of a pipe 4262a7db7a6SVincenzo Maffione * end-point kept alive by the other end. 4272a7db7a6SVincenzo Maffione * We need to leave everything as it is 4282a7db7a6SVincenzo Maffione */ 4292a7db7a6SVincenzo Maffione continue; 4302a7db7a6SVincenzo Maffione } 4312a7db7a6SVincenzo Maffione 432*a6d768d8SVincenzo Maffione /* copy the buffers from the non-fake ring 433*a6d768d8SVincenzo Maffione * (this also propagates any initial offset) 434*a6d768d8SVincenzo Maffione */ 435*a6d768d8SVincenzo Maffione memcpy(kring->pipe->ring->slot, 436*a6d768d8SVincenzo Maffione kring->ring->slot, 4372ff91c17SVincenzo Maffione sizeof(struct netmap_slot) * 438*a6d768d8SVincenzo Maffione kring->nkr_num_slots); 439*a6d768d8SVincenzo Maffione /* copy the offset-related fields */ 440*a6d768d8SVincenzo Maffione *(uint64_t *)(uintptr_t)&kring->pipe->ring->offset_mask = 441*a6d768d8SVincenzo Maffione kring->ring->offset_mask; 442*a6d768d8SVincenzo Maffione *(uint64_t *)(uintptr_t)&kring->pipe->ring->buf_align = 443*a6d768d8SVincenzo Maffione kring->ring->buf_align; 4442ff91c17SVincenzo Maffione /* mark both rings as fake and needed, 4452ff91c17SVincenzo Maffione * so that buffers will not be 4462ff91c17SVincenzo Maffione * deleted by the standard machinery 4472ff91c17SVincenzo Maffione * (we will delete them by ourselves in 4482ff91c17SVincenzo Maffione * netmap_pipe_krings_delete) 4492ff91c17SVincenzo Maffione */ 450*a6d768d8SVincenzo Maffione kring->nr_kflags |= 4512ff91c17SVincenzo Maffione (NKR_FAKERING | NKR_NEEDRING); 45237e3a6d3SLuigi Rizzo kring->nr_mode = NKR_NETMAP_ON; 45337e3a6d3SLuigi Rizzo } 45437e3a6d3SLuigi Rizzo } 45537e3a6d3SLuigi Rizzo } 45675f4f3edSVincenzo Maffione 45775f4f3edSVincenzo Maffione return 0; 45875f4f3edSVincenzo Maffione } 45975f4f3edSVincenzo Maffione 46075f4f3edSVincenzo Maffione /* netmap_pipe_reg. 46175f4f3edSVincenzo Maffione * 46275f4f3edSVincenzo Maffione * There are two cases on registration (onoff==1) 46375f4f3edSVincenzo Maffione * 46475f4f3edSVincenzo Maffione * 1.a) state is 46575f4f3edSVincenzo Maffione * 46675f4f3edSVincenzo Maffione * usr1 --> e1 --> e2 46775f4f3edSVincenzo Maffione * 46875f4f3edSVincenzo Maffione * and we are e1. Create the needed rings of the 46975f4f3edSVincenzo Maffione * other end. 47075f4f3edSVincenzo Maffione * 47175f4f3edSVincenzo Maffione * 1.b) state is 47275f4f3edSVincenzo Maffione * 47375f4f3edSVincenzo Maffione * usr1 --> e1 --> e2 <-- usr2 47475f4f3edSVincenzo Maffione * 47575f4f3edSVincenzo Maffione * and we are e2. Drop the ref e1 is holding. 47675f4f3edSVincenzo Maffione * 47775f4f3edSVincenzo Maffione * There are two additional cases on unregister (onoff==0) 47875f4f3edSVincenzo Maffione * 47975f4f3edSVincenzo Maffione * 2.a) state is 48075f4f3edSVincenzo Maffione * 48175f4f3edSVincenzo Maffione * usr1 --> e1 --> e2 48275f4f3edSVincenzo Maffione * 48375f4f3edSVincenzo Maffione * and we are e1. Nothing special to do, e2 will 48475f4f3edSVincenzo Maffione * be cleaned up by the destructor of e1. 48575f4f3edSVincenzo Maffione * 48675f4f3edSVincenzo Maffione * 2.b) state is 48775f4f3edSVincenzo Maffione * 48875f4f3edSVincenzo Maffione * usr1 --> e1 e2 <-- usr2 48975f4f3edSVincenzo Maffione * 49075f4f3edSVincenzo Maffione * and we are either e1 or e2. Add a ref from the 49175f4f3edSVincenzo Maffione * other end. 49275f4f3edSVincenzo Maffione */ 49375f4f3edSVincenzo Maffione static int 49475f4f3edSVincenzo Maffione netmap_pipe_reg(struct netmap_adapter *na, int onoff) 49575f4f3edSVincenzo Maffione { 49675f4f3edSVincenzo Maffione struct netmap_pipe_adapter *pna = 49775f4f3edSVincenzo Maffione (struct netmap_pipe_adapter *)na; 49875f4f3edSVincenzo Maffione struct netmap_adapter *ona = &pna->peer->up; 49975f4f3edSVincenzo Maffione int error = 0; 50075f4f3edSVincenzo Maffione 50175f4f3edSVincenzo Maffione nm_prdis("%p: onoff %d", na, onoff); 50275f4f3edSVincenzo Maffione if (onoff) { 50375f4f3edSVincenzo Maffione error = netmap_pipe_reg_both(na, ona); 50475f4f3edSVincenzo Maffione if (error) { 50575f4f3edSVincenzo Maffione return error; 50675f4f3edSVincenzo Maffione } 50737e3a6d3SLuigi Rizzo if (na->active_fds == 0) 5084bf50f18SLuigi Rizzo na->na_flags |= NAF_NETMAP_ON; 509f0ea3689SLuigi Rizzo } else { 51037e3a6d3SLuigi Rizzo if (na->active_fds == 0) 5114bf50f18SLuigi Rizzo na->na_flags &= ~NAF_NETMAP_ON; 51275f4f3edSVincenzo Maffione netmap_krings_mode_commit(na, onoff); 513c3e9b4dbSLuiz Otavio O Souza } 51437e3a6d3SLuigi Rizzo 51537e3a6d3SLuigi Rizzo if (na->active_fds) { 51675f4f3edSVincenzo Maffione nm_prdis("active_fds %d", na->active_fds); 51737e3a6d3SLuigi Rizzo return 0; 51837e3a6d3SLuigi Rizzo } 51937e3a6d3SLuigi Rizzo 520f0ea3689SLuigi Rizzo if (pna->peer_ref) { 52175f4f3edSVincenzo Maffione nm_prdis("%p: case 1.a or 2.a, nothing to do", na); 522f0ea3689SLuigi Rizzo return 0; 523f0ea3689SLuigi Rizzo } 524f0ea3689SLuigi Rizzo if (onoff) { 52575f4f3edSVincenzo Maffione nm_prdis("%p: case 1.b, drop peer", na); 526f0ea3689SLuigi Rizzo pna->peer->peer_ref = 0; 527f0ea3689SLuigi Rizzo netmap_adapter_put(na); 528f0ea3689SLuigi Rizzo } else { 52975f4f3edSVincenzo Maffione nm_prdis("%p: case 2.b, grab peer", na); 530f0ea3689SLuigi Rizzo netmap_adapter_get(na); 531f0ea3689SLuigi Rizzo pna->peer->peer_ref = 1; 532f0ea3689SLuigi Rizzo } 53337e3a6d3SLuigi Rizzo return error; 534f0ea3689SLuigi Rizzo } 535f0ea3689SLuigi Rizzo 53675f4f3edSVincenzo Maffione void 53775f4f3edSVincenzo Maffione netmap_pipe_krings_delete_both(struct netmap_adapter *na, 53875f4f3edSVincenzo Maffione struct netmap_adapter *ona) 53975f4f3edSVincenzo Maffione { 54075f4f3edSVincenzo Maffione struct netmap_adapter *sna; 54175f4f3edSVincenzo Maffione enum txrx t; 54275f4f3edSVincenzo Maffione int i; 54375f4f3edSVincenzo Maffione 54475f4f3edSVincenzo Maffione /* case 1) below */ 54575f4f3edSVincenzo Maffione nm_prdis("%p: case 1, deleting everything", na); 54675f4f3edSVincenzo Maffione /* To avoid double-frees we zero-out all the buffers in the kernel part 54775f4f3edSVincenzo Maffione * of each ring. The reason is this: If the user is behaving correctly, 54875f4f3edSVincenzo Maffione * all buffers are found in exactly one slot in the userspace part of 54975f4f3edSVincenzo Maffione * some ring. If the user is not behaving correctly, we cannot release 55075f4f3edSVincenzo Maffione * buffers cleanly anyway. In the latter case, the allocator will 55175f4f3edSVincenzo Maffione * return to a clean state only when all its users will close. 55275f4f3edSVincenzo Maffione */ 55375f4f3edSVincenzo Maffione sna = na; 55475f4f3edSVincenzo Maffione cleanup: 55575f4f3edSVincenzo Maffione for_rx_tx(t) { 55675f4f3edSVincenzo Maffione for (i = 0; i < nma_get_nrings(sna, t); i++) { 55775f4f3edSVincenzo Maffione struct netmap_kring *kring = NMR(sna, t)[i]; 55875f4f3edSVincenzo Maffione struct netmap_ring *ring = kring->ring; 55975f4f3edSVincenzo Maffione uint32_t j, lim = kring->nkr_num_slots - 1; 56075f4f3edSVincenzo Maffione 56175f4f3edSVincenzo Maffione nm_prdis("%s ring %p hwtail %u hwcur %u", 56275f4f3edSVincenzo Maffione kring->name, ring, kring->nr_hwtail, kring->nr_hwcur); 56375f4f3edSVincenzo Maffione 56475f4f3edSVincenzo Maffione if (ring == NULL) 56575f4f3edSVincenzo Maffione continue; 56675f4f3edSVincenzo Maffione 56775f4f3edSVincenzo Maffione if (kring->tx == NR_RX) 56875f4f3edSVincenzo Maffione ring->slot[kring->pipe_tail].buf_idx = 0; 56975f4f3edSVincenzo Maffione 57075f4f3edSVincenzo Maffione for (j = nm_next(kring->pipe_tail, lim); 57175f4f3edSVincenzo Maffione j != kring->nr_hwcur; 57275f4f3edSVincenzo Maffione j = nm_next(j, lim)) 57375f4f3edSVincenzo Maffione { 57475f4f3edSVincenzo Maffione nm_prdis("%s[%d] %u", kring->name, j, ring->slot[j].buf_idx); 57575f4f3edSVincenzo Maffione ring->slot[j].buf_idx = 0; 57675f4f3edSVincenzo Maffione } 57775f4f3edSVincenzo Maffione kring->nr_kflags &= ~(NKR_FAKERING | NKR_NEEDRING); 57875f4f3edSVincenzo Maffione } 57975f4f3edSVincenzo Maffione 58075f4f3edSVincenzo Maffione } 58175f4f3edSVincenzo Maffione if (sna != ona && ona->tx_rings) { 58275f4f3edSVincenzo Maffione sna = ona; 58375f4f3edSVincenzo Maffione goto cleanup; 58475f4f3edSVincenzo Maffione } 58575f4f3edSVincenzo Maffione 58675f4f3edSVincenzo Maffione netmap_mem_rings_delete(na); 58775f4f3edSVincenzo Maffione netmap_krings_delete(na); /* also zeroes tx_rings etc. */ 58875f4f3edSVincenzo Maffione 58975f4f3edSVincenzo Maffione if (ona->tx_rings == NULL) { 59075f4f3edSVincenzo Maffione /* already deleted, we must be on an 59175f4f3edSVincenzo Maffione * cleanup-after-error path */ 59275f4f3edSVincenzo Maffione return; 59375f4f3edSVincenzo Maffione } 59475f4f3edSVincenzo Maffione netmap_mem_rings_delete(ona); 59575f4f3edSVincenzo Maffione netmap_krings_delete(ona); 59675f4f3edSVincenzo Maffione } 59775f4f3edSVincenzo Maffione 598f0ea3689SLuigi Rizzo /* netmap_pipe_krings_delete. 599f0ea3689SLuigi Rizzo * 600f0ea3689SLuigi Rizzo * There are two cases: 601f0ea3689SLuigi Rizzo * 602f0ea3689SLuigi Rizzo * 1) state is 603f0ea3689SLuigi Rizzo * 604f0ea3689SLuigi Rizzo * usr1 --> e1 --> e2 605f0ea3689SLuigi Rizzo * 606f0ea3689SLuigi Rizzo * and we are e1 (e2 is not registered, so krings_delete cannot be 607f0ea3689SLuigi Rizzo * called on it); 608f0ea3689SLuigi Rizzo * 609f0ea3689SLuigi Rizzo * 2) state is 610f0ea3689SLuigi Rizzo * 611f0ea3689SLuigi Rizzo * usr1 --> e1 e2 <-- usr2 612f0ea3689SLuigi Rizzo * 613f0ea3689SLuigi Rizzo * and we are either e1 or e2. 614f0ea3689SLuigi Rizzo * 615f0ea3689SLuigi Rizzo * In the former case we have to also delete the krings of e2; 6162ff91c17SVincenzo Maffione * in the latter case we do nothing. 617f0ea3689SLuigi Rizzo */ 618f0ea3689SLuigi Rizzo static void 619f0ea3689SLuigi Rizzo netmap_pipe_krings_delete(struct netmap_adapter *na) 620f0ea3689SLuigi Rizzo { 621f0ea3689SLuigi Rizzo struct netmap_pipe_adapter *pna = 622f0ea3689SLuigi Rizzo (struct netmap_pipe_adapter *)na; 62375f4f3edSVincenzo Maffione struct netmap_adapter *ona; /* na of the other end */ 624f0ea3689SLuigi Rizzo 625f0ea3689SLuigi Rizzo if (!pna->peer_ref) { 62675f4f3edSVincenzo Maffione nm_prdis("%p: case 2, kept alive by peer", na); 627f0ea3689SLuigi Rizzo return; 628f0ea3689SLuigi Rizzo } 6292ff91c17SVincenzo Maffione ona = &pna->peer->up; 63075f4f3edSVincenzo Maffione netmap_pipe_krings_delete_both(na, ona); 631f0ea3689SLuigi Rizzo } 632f0ea3689SLuigi Rizzo 633f0ea3689SLuigi Rizzo 634f0ea3689SLuigi Rizzo static void 635f0ea3689SLuigi Rizzo netmap_pipe_dtor(struct netmap_adapter *na) 636f0ea3689SLuigi Rizzo { 637f0ea3689SLuigi Rizzo struct netmap_pipe_adapter *pna = 638f0ea3689SLuigi Rizzo (struct netmap_pipe_adapter *)na; 63975f4f3edSVincenzo Maffione nm_prdis("%p %p", na, pna->parent_ifp); 640f0ea3689SLuigi Rizzo if (pna->peer_ref) { 64175f4f3edSVincenzo Maffione nm_prdis("%p: clean up peer", na); 642f0ea3689SLuigi Rizzo pna->peer_ref = 0; 643f0ea3689SLuigi Rizzo netmap_adapter_put(&pna->peer->up); 644f0ea3689SLuigi Rizzo } 6452ff91c17SVincenzo Maffione if (pna->role == NM_PIPE_ROLE_MASTER) 646f0ea3689SLuigi Rizzo netmap_pipe_remove(pna->parent, pna); 647c3e9b4dbSLuiz Otavio O Souza if (pna->parent_ifp) 648c3e9b4dbSLuiz Otavio O Souza if_rele(pna->parent_ifp); 649f0ea3689SLuigi Rizzo netmap_adapter_put(pna->parent); 650f0ea3689SLuigi Rizzo pna->parent = NULL; 651f0ea3689SLuigi Rizzo } 652f0ea3689SLuigi Rizzo 653f0ea3689SLuigi Rizzo int 6542ff91c17SVincenzo Maffione netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na, 655c3e9b4dbSLuiz Otavio O Souza struct netmap_mem_d *nmd, int create) 656f0ea3689SLuigi Rizzo { 657cfa866f6SMatt Macy struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body; 658f0ea3689SLuigi Rizzo struct netmap_adapter *pna; /* parent adapter */ 6592ff91c17SVincenzo Maffione struct netmap_pipe_adapter *mna, *sna, *reqna; 66037e3a6d3SLuigi Rizzo struct ifnet *ifp = NULL; 6612ff91c17SVincenzo Maffione const char *pipe_id = NULL; 6622ff91c17SVincenzo Maffione int role = 0; 663c3e9b4dbSLuiz Otavio O Souza int error, retries = 0; 664*a6d768d8SVincenzo Maffione char *cbra, pipe_char; 665f0ea3689SLuigi Rizzo 6662ff91c17SVincenzo Maffione /* Try to parse the pipe syntax 'xx{yy' or 'xx}yy'. */ 6672ff91c17SVincenzo Maffione cbra = strrchr(hdr->nr_name, '{'); 6682ff91c17SVincenzo Maffione if (cbra != NULL) { 6692ff91c17SVincenzo Maffione role = NM_PIPE_ROLE_MASTER; 6702ff91c17SVincenzo Maffione } else { 6712ff91c17SVincenzo Maffione cbra = strrchr(hdr->nr_name, '}'); 6722ff91c17SVincenzo Maffione if (cbra != NULL) { 6732ff91c17SVincenzo Maffione role = NM_PIPE_ROLE_SLAVE; 6742ff91c17SVincenzo Maffione } else { 67575f4f3edSVincenzo Maffione nm_prdis("not a pipe"); 676f0ea3689SLuigi Rizzo return 0; 677f0ea3689SLuigi Rizzo } 6782ff91c17SVincenzo Maffione } 679*a6d768d8SVincenzo Maffione pipe_char = *cbra; 6802ff91c17SVincenzo Maffione pipe_id = cbra + 1; 6812ff91c17SVincenzo Maffione if (*pipe_id == '\0' || cbra == hdr->nr_name) { 6822ff91c17SVincenzo Maffione /* Bracket is the last character, so pipe name is missing; 6832ff91c17SVincenzo Maffione * or bracket is the first character, so base port name 6842ff91c17SVincenzo Maffione * is missing. */ 6852ff91c17SVincenzo Maffione return EINVAL; 6862ff91c17SVincenzo Maffione } 6872ff91c17SVincenzo Maffione 6882ff91c17SVincenzo Maffione if (req->nr_mode != NR_REG_ALL_NIC && req->nr_mode != NR_REG_ONE_NIC) { 6892ff91c17SVincenzo Maffione /* We only accept modes involving hardware rings. */ 6902ff91c17SVincenzo Maffione return EINVAL; 6912ff91c17SVincenzo Maffione } 692f0ea3689SLuigi Rizzo 693f0ea3689SLuigi Rizzo /* first, try to find the parent adapter */ 694c3e9b4dbSLuiz Otavio O Souza for (;;) { 695c3e9b4dbSLuiz Otavio O Souza int create_error; 696c3e9b4dbSLuiz Otavio O Souza 6972ff91c17SVincenzo Maffione /* Temporarily remove the pipe suffix. */ 6982ff91c17SVincenzo Maffione *cbra = '\0'; 6992ff91c17SVincenzo Maffione error = netmap_get_na(hdr, &pna, &ifp, nmd, create); 7002ff91c17SVincenzo Maffione /* Restore the pipe suffix. */ 701*a6d768d8SVincenzo Maffione *cbra = pipe_char; 702c3e9b4dbSLuiz Otavio O Souza if (!error) 703c3e9b4dbSLuiz Otavio O Souza break; 704c3e9b4dbSLuiz Otavio O Souza if (error != ENXIO || retries++) { 70575f4f3edSVincenzo Maffione nm_prdis("parent lookup failed: %d", error); 706f0ea3689SLuigi Rizzo return error; 707f0ea3689SLuigi Rizzo } 70875f4f3edSVincenzo 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(); 714*a6d768d8SVincenzo Maffione *cbra = pipe_char; 715c3e9b4dbSLuiz Otavio O Souza if (create_error && create_error != EEXIST) { 716c3e9b4dbSLuiz Otavio O Souza if (create_error != EOPNOTSUPP) { 71775f4f3edSVincenzo Maffione nm_prerr("failed to create a persistent vale port: %d", 71875f4f3edSVincenzo 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)) { 72575f4f3edSVincenzo 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) { 73575f4f3edSVincenzo Maffione nm_prdis("found %s directly at %d", pipe_id, mna->parent_slot); 7362ff91c17SVincenzo Maffione reqna = mna; 737f0ea3689SLuigi Rizzo } else { 73875f4f3edSVincenzo 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 } 74775f4f3edSVincenzo 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); 774*a6d768d8SVincenzo Maffione mna->up.na_flags |= NAF_MEM_OWNER | NAF_OFFSETS; 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 } 83875f4f3edSVincenzo Maffione nm_prdis("created master %p and slave %p", mna, sna); 839f0ea3689SLuigi Rizzo found: 840f0ea3689SLuigi Rizzo 84175f4f3edSVincenzo 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