1718cf2ccSPedro F. Giffuni /*- 2718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3718cf2ccSPedro F. Giffuni * 437e3a6d3SLuigi Rizzo * Copyright (C) 2014-2016 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 80*2ff91c17SVincenzo 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 * 133*2ff91c17SVincenzo 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++) { 139*2ff91c17SVincenzo Maffione const char *na_pipe_id; 140f0ea3689SLuigi Rizzo na = parent->na_pipes[i]; 141*2ff91c17SVincenzo Maffione na_pipe_id = strrchr(na->up.name, 142*2ff91c17SVincenzo Maffione na->role == NM_PIPE_ROLE_MASTER ? '{' : '}'); 143*2ff91c17SVincenzo Maffione KASSERT(na_pipe_id != NULL, ("Invalid pipe name")); 144*2ff91c17SVincenzo Maffione ++na_pipe_id; 145*2ff91c17SVincenzo 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; 188*2ff91c17SVincenzo Maffione u_int k, lim = txkring->nkr_num_slots - 1; 189*2ff91c17SVincenzo Maffione int m; /* slots to transfer */ 1904f80b14cSVincenzo Maffione struct netmap_ring *txring = txkring->ring, *rxring = rxkring->ring; 191f0ea3689SLuigi Rizzo 192f0ea3689SLuigi Rizzo ND("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name); 193*2ff91c17SVincenzo Maffione ND(20, "TX before: hwcur %d hwtail %d cur %d head %d tail %d", 194*2ff91c17SVincenzo Maffione txkring->nr_hwcur, txkring->nr_hwtail, 195f0ea3689SLuigi Rizzo txkring->rcur, txkring->rhead, txkring->rtail); 196f0ea3689SLuigi Rizzo 197f0ea3689SLuigi Rizzo m = txkring->rhead - txkring->nr_hwcur; /* new slots */ 198f0ea3689SLuigi Rizzo if (m < 0) 199f0ea3689SLuigi Rizzo m += txkring->nkr_num_slots; 200f0ea3689SLuigi Rizzo 201*2ff91c17SVincenzo Maffione if (m == 0) { 202*2ff91c17SVincenzo Maffione /* nothing to send */ 203f0ea3689SLuigi Rizzo return 0; 204f0ea3689SLuigi Rizzo } 205f0ea3689SLuigi Rizzo 206*2ff91c17SVincenzo Maffione for (k = txkring->nr_hwcur; m; m--, k = nm_next(k, lim)) { 207*2ff91c17SVincenzo Maffione struct netmap_slot *rs = &rxring->slot[k]; 2084f80b14cSVincenzo Maffione struct netmap_slot *ts = &txring->slot[k]; 209f0ea3689SLuigi Rizzo 210*2ff91c17SVincenzo Maffione rs->len = ts->len; 211*2ff91c17SVincenzo Maffione rs->ptr = ts->ptr; 212f0ea3689SLuigi Rizzo 213*2ff91c17SVincenzo Maffione if (ts->flags & NS_BUF_CHANGED) { 214*2ff91c17SVincenzo Maffione rs->buf_idx = ts->buf_idx; 215847bf383SLuigi Rizzo rs->flags |= NS_BUF_CHANGED; 216*2ff91c17SVincenzo Maffione ts->flags &= ~NS_BUF_CHANGED; 217*2ff91c17SVincenzo Maffione } 218f0ea3689SLuigi Rizzo } 219f0ea3689SLuigi Rizzo 220ad15cc59SLuigi Rizzo mb(); /* make sure the slots are updated before publishing them */ 221*2ff91c17SVincenzo Maffione rxkring->nr_hwtail = k; 222f0ea3689SLuigi Rizzo txkring->nr_hwcur = k; 223f0ea3689SLuigi Rizzo 224*2ff91c17SVincenzo Maffione ND(20, "TX after : hwcur %d hwtail %d cur %d head %d tail %d k %d", 225*2ff91c17SVincenzo Maffione txkring->nr_hwcur, txkring->nr_hwtail, 226*2ff91c17SVincenzo Maffione txkring->rcur, txkring->rhead, txkring->rtail, k); 227f0ea3689SLuigi Rizzo 228847bf383SLuigi Rizzo rxkring->nm_notify(rxkring, 0); 229f0ea3689SLuigi Rizzo 230f0ea3689SLuigi Rizzo return 0; 231f0ea3689SLuigi Rizzo } 232f0ea3689SLuigi Rizzo 233c3e9b4dbSLuiz Otavio O Souza int 2344bf50f18SLuigi Rizzo netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags) 235f0ea3689SLuigi Rizzo { 2364bf50f18SLuigi Rizzo struct netmap_kring *txkring = rxkring->pipe; 237*2ff91c17SVincenzo Maffione u_int k, lim = rxkring->nkr_num_slots - 1; 238*2ff91c17SVincenzo Maffione int m; /* slots to release */ 239*2ff91c17SVincenzo Maffione struct netmap_ring *txring = txkring->ring, *rxring = rxkring->ring; 240f0ea3689SLuigi Rizzo 241*2ff91c17SVincenzo Maffione ND("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name); 242*2ff91c17SVincenzo Maffione ND(20, "RX before: hwcur %d hwtail %d cur %d head %d tail %d", 243*2ff91c17SVincenzo Maffione rxkring->nr_hwcur, rxkring->nr_hwtail, 244f0ea3689SLuigi Rizzo rxkring->rcur, rxkring->rhead, rxkring->rtail); 245f0ea3689SLuigi Rizzo 246*2ff91c17SVincenzo Maffione m = rxkring->rhead - rxkring->nr_hwcur; /* released slots */ 247*2ff91c17SVincenzo Maffione if (m < 0) 248*2ff91c17SVincenzo Maffione m += rxkring->nkr_num_slots; 249*2ff91c17SVincenzo Maffione 250*2ff91c17SVincenzo Maffione if (m == 0) { 251*2ff91c17SVincenzo Maffione /* nothing to release */ 252*2ff91c17SVincenzo Maffione return 0; 253f0ea3689SLuigi Rizzo } 254*2ff91c17SVincenzo Maffione 255*2ff91c17SVincenzo Maffione for (k = rxkring->nr_hwcur; m; m--, k = nm_next(k, lim)) { 256*2ff91c17SVincenzo Maffione struct netmap_slot *rs = &rxring->slot[k]; 257*2ff91c17SVincenzo Maffione struct netmap_slot *ts = &txring->slot[k]; 258*2ff91c17SVincenzo Maffione 259*2ff91c17SVincenzo Maffione if (rs->flags & NS_BUF_CHANGED) { 260*2ff91c17SVincenzo Maffione /* copy the slot and report the buffer change */ 261*2ff91c17SVincenzo Maffione *ts = *rs; 262*2ff91c17SVincenzo Maffione rs->flags &= ~NS_BUF_CHANGED; 263*2ff91c17SVincenzo Maffione } 264*2ff91c17SVincenzo Maffione } 265*2ff91c17SVincenzo Maffione 266*2ff91c17SVincenzo Maffione mb(); /* make sure the slots are updated before publishing them */ 267*2ff91c17SVincenzo Maffione txkring->nr_hwtail = nm_prev(k, lim); 268*2ff91c17SVincenzo Maffione rxkring->nr_hwcur = k; 269*2ff91c17SVincenzo Maffione 270*2ff91c17SVincenzo Maffione ND(20, "RX after : hwcur %d hwtail %d cur %d head %d tail %d k %d", 271*2ff91c17SVincenzo Maffione rxkring->nr_hwcur, rxkring->nr_hwtail, 272*2ff91c17SVincenzo Maffione rxkring->rcur, rxkring->rhead, rxkring->rtail, k); 273*2ff91c17SVincenzo Maffione 274*2ff91c17SVincenzo Maffione txkring->nm_notify(txkring, 0); 275*2ff91c17SVincenzo Maffione 276f0ea3689SLuigi Rizzo return 0; 277f0ea3689SLuigi Rizzo } 278f0ea3689SLuigi Rizzo 279f0ea3689SLuigi Rizzo /* Pipe endpoints are created and destroyed together, so that endopoints do not 280f0ea3689SLuigi Rizzo * have to check for the existence of their peer at each ?xsync. 281f0ea3689SLuigi Rizzo * 282f0ea3689SLuigi Rizzo * To play well with the existing netmap infrastructure (refcounts etc.), we 283f0ea3689SLuigi Rizzo * adopt the following strategy: 284f0ea3689SLuigi Rizzo * 285f0ea3689SLuigi Rizzo * 1) The first endpoint that is created also creates the other endpoint and 286f0ea3689SLuigi Rizzo * grabs a reference to it. 287f0ea3689SLuigi Rizzo * 288f0ea3689SLuigi Rizzo * state A) user1 --> endpoint1 --> endpoint2 289f0ea3689SLuigi Rizzo * 290f0ea3689SLuigi Rizzo * 2) If, starting from state A, endpoint2 is then registered, endpoint1 gives 291f0ea3689SLuigi Rizzo * its reference to the user: 292f0ea3689SLuigi Rizzo * 293f0ea3689SLuigi Rizzo * state B) user1 --> endpoint1 endpoint2 <--- user2 294f0ea3689SLuigi Rizzo * 295f0ea3689SLuigi Rizzo * 3) Assume that, starting from state B endpoint2 is closed. In the unregister 296f0ea3689SLuigi Rizzo * callback endpoint2 notes that endpoint1 is still active and adds a reference 297f0ea3689SLuigi Rizzo * from endpoint1 to itself. When user2 then releases her own reference, 298f0ea3689SLuigi Rizzo * endpoint2 is not destroyed and we are back to state A. A symmetrical state 299f0ea3689SLuigi Rizzo * would be reached if endpoint1 were released instead. 300f0ea3689SLuigi Rizzo * 301f0ea3689SLuigi Rizzo * 4) If, starting from state A, endpoint1 is closed, the destructor notes that 302f0ea3689SLuigi Rizzo * it owns a reference to endpoint2 and releases it. 303f0ea3689SLuigi Rizzo * 304f0ea3689SLuigi Rizzo * Something similar goes on for the creation and destruction of the krings. 305f0ea3689SLuigi Rizzo */ 306f0ea3689SLuigi Rizzo 307f0ea3689SLuigi Rizzo 308c3e9b4dbSLuiz Otavio O Souza /* netmap_pipe_krings_create. 309f0ea3689SLuigi Rizzo * 310f0ea3689SLuigi Rizzo * There are two cases: 311f0ea3689SLuigi Rizzo * 312f0ea3689SLuigi Rizzo * 1) state is 313f0ea3689SLuigi Rizzo * 314f0ea3689SLuigi Rizzo * usr1 --> e1 --> e2 315f0ea3689SLuigi Rizzo * 316f0ea3689SLuigi Rizzo * and we are e1. We have to create both sets 317f0ea3689SLuigi Rizzo * of krings. 318f0ea3689SLuigi Rizzo * 319f0ea3689SLuigi Rizzo * 2) state is 320f0ea3689SLuigi Rizzo * 321f0ea3689SLuigi Rizzo * usr1 --> e1 --> e2 322f0ea3689SLuigi Rizzo * 323f0ea3689SLuigi Rizzo * and we are e2. e1 is certainly registered and our 32437e3a6d3SLuigi Rizzo * krings already exist. Nothing to do. 325f0ea3689SLuigi Rizzo */ 326f0ea3689SLuigi Rizzo static int 327f0ea3689SLuigi Rizzo netmap_pipe_krings_create(struct netmap_adapter *na) 328f0ea3689SLuigi Rizzo { 329f0ea3689SLuigi Rizzo struct netmap_pipe_adapter *pna = 330f0ea3689SLuigi Rizzo (struct netmap_pipe_adapter *)na; 331f0ea3689SLuigi Rizzo struct netmap_adapter *ona = &pna->peer->up; 332f0ea3689SLuigi Rizzo int error = 0; 333847bf383SLuigi Rizzo enum txrx t; 334847bf383SLuigi Rizzo 335f0ea3689SLuigi Rizzo if (pna->peer_ref) { 336f0ea3689SLuigi Rizzo int i; 337f0ea3689SLuigi Rizzo 338f0ea3689SLuigi Rizzo /* case 1) above */ 339c3e9b4dbSLuiz Otavio O Souza ND("%p: case 1, create both ends", na); 340f0ea3689SLuigi Rizzo error = netmap_krings_create(na, 0); 341f0ea3689SLuigi Rizzo if (error) 342f0ea3689SLuigi Rizzo goto err; 343f0ea3689SLuigi Rizzo 34437e3a6d3SLuigi Rizzo /* create the krings of the other end */ 345f0ea3689SLuigi Rizzo error = netmap_krings_create(ona, 0); 346f0ea3689SLuigi Rizzo if (error) 34737e3a6d3SLuigi Rizzo goto del_krings1; 348f0ea3689SLuigi Rizzo 349f0ea3689SLuigi Rizzo /* cross link the krings */ 350847bf383SLuigi Rizzo for_rx_tx(t) { 351847bf383SLuigi Rizzo enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */ 352847bf383SLuigi Rizzo for (i = 0; i < nma_get_nrings(na, t); i++) { 353*2ff91c17SVincenzo Maffione NMR(na, t)[i]->pipe = NMR(ona, r)[i]; 354*2ff91c17SVincenzo Maffione NMR(ona, r)[i]->pipe = NMR(na, t)[i]; 355*2ff91c17SVincenzo Maffione /* mark all peer-adapter rings as fake */ 356*2ff91c17SVincenzo Maffione NMR(ona, r)[i]->nr_kflags |= NKR_FAKERING; 357847bf383SLuigi Rizzo } 358f0ea3689SLuigi Rizzo } 35937e3a6d3SLuigi Rizzo 360f0ea3689SLuigi Rizzo } 361f0ea3689SLuigi Rizzo return 0; 362f0ea3689SLuigi Rizzo 363f0ea3689SLuigi Rizzo del_krings1: 364f0ea3689SLuigi Rizzo netmap_krings_delete(na); 365f0ea3689SLuigi Rizzo err: 366f0ea3689SLuigi Rizzo return error; 367f0ea3689SLuigi Rizzo } 368f0ea3689SLuigi Rizzo 369f0ea3689SLuigi Rizzo /* netmap_pipe_reg. 370f0ea3689SLuigi Rizzo * 371f0ea3689SLuigi Rizzo * There are two cases on registration (onoff==1) 372f0ea3689SLuigi Rizzo * 373f0ea3689SLuigi Rizzo * 1.a) state is 374f0ea3689SLuigi Rizzo * 375f0ea3689SLuigi Rizzo * usr1 --> e1 --> e2 376f0ea3689SLuigi Rizzo * 37737e3a6d3SLuigi Rizzo * and we are e1. Create the needed rings of the 37837e3a6d3SLuigi Rizzo * other end. 379f0ea3689SLuigi Rizzo * 380f0ea3689SLuigi Rizzo * 1.b) state is 381f0ea3689SLuigi Rizzo * 382f0ea3689SLuigi Rizzo * usr1 --> e1 --> e2 <-- usr2 383f0ea3689SLuigi Rizzo * 384f0ea3689SLuigi Rizzo * and we are e2. Drop the ref e1 is holding. 385f0ea3689SLuigi Rizzo * 386f0ea3689SLuigi Rizzo * There are two additional cases on unregister (onoff==0) 387f0ea3689SLuigi Rizzo * 388f0ea3689SLuigi Rizzo * 2.a) state is 389f0ea3689SLuigi Rizzo * 390f0ea3689SLuigi Rizzo * usr1 --> e1 --> e2 391f0ea3689SLuigi Rizzo * 392f0ea3689SLuigi Rizzo * and we are e1. Nothing special to do, e2 will 393f0ea3689SLuigi Rizzo * be cleaned up by the destructor of e1. 394f0ea3689SLuigi Rizzo * 395f0ea3689SLuigi Rizzo * 2.b) state is 396f0ea3689SLuigi Rizzo * 397f0ea3689SLuigi Rizzo * usr1 --> e1 e2 <-- usr2 398f0ea3689SLuigi Rizzo * 399f0ea3689SLuigi Rizzo * and we are either e1 or e2. Add a ref from the 400*2ff91c17SVincenzo Maffione * other end. 401f0ea3689SLuigi Rizzo */ 402f0ea3689SLuigi Rizzo static int 403f0ea3689SLuigi Rizzo netmap_pipe_reg(struct netmap_adapter *na, int onoff) 404f0ea3689SLuigi Rizzo { 405f0ea3689SLuigi Rizzo struct netmap_pipe_adapter *pna = 406f0ea3689SLuigi Rizzo (struct netmap_pipe_adapter *)na; 40737e3a6d3SLuigi Rizzo struct netmap_adapter *ona = &pna->peer->up; 40837e3a6d3SLuigi Rizzo int i, error = 0; 409847bf383SLuigi Rizzo enum txrx t; 410847bf383SLuigi Rizzo 411f0ea3689SLuigi Rizzo ND("%p: onoff %d", na, onoff); 412f0ea3689SLuigi Rizzo if (onoff) { 41337e3a6d3SLuigi Rizzo for_rx_tx(t) { 414c3e9b4dbSLuiz Otavio O Souza for (i = 0; i < nma_get_nrings(na, t); i++) { 415*2ff91c17SVincenzo Maffione struct netmap_kring *kring = NMR(na, t)[i]; 41637e3a6d3SLuigi Rizzo 41737e3a6d3SLuigi Rizzo if (nm_kring_pending_on(kring)) { 418c3e9b4dbSLuiz Otavio O Souza /* mark the peer ring as needed */ 41937e3a6d3SLuigi Rizzo kring->pipe->nr_kflags |= NKR_NEEDRING; 42037e3a6d3SLuigi Rizzo } 42137e3a6d3SLuigi Rizzo } 42237e3a6d3SLuigi Rizzo } 42337e3a6d3SLuigi Rizzo 424*2ff91c17SVincenzo Maffione /* create all missing needed rings on the other end. 425*2ff91c17SVincenzo Maffione * Either our end, or the other, has been marked as 426*2ff91c17SVincenzo Maffione * fake, so the allocation will not be done twice. 427*2ff91c17SVincenzo Maffione */ 42837e3a6d3SLuigi Rizzo error = netmap_mem_rings_create(ona); 42937e3a6d3SLuigi Rizzo if (error) 43037e3a6d3SLuigi Rizzo return error; 43137e3a6d3SLuigi Rizzo 43237e3a6d3SLuigi Rizzo /* In case of no error we put our rings in netmap mode */ 43337e3a6d3SLuigi Rizzo for_rx_tx(t) { 43437e3a6d3SLuigi Rizzo for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { 435*2ff91c17SVincenzo Maffione struct netmap_kring *kring = NMR(na, t)[i]; 43637e3a6d3SLuigi Rizzo if (nm_kring_pending_on(kring)) { 437*2ff91c17SVincenzo Maffione struct netmap_kring *sring, *dring; 438*2ff91c17SVincenzo Maffione 439*2ff91c17SVincenzo Maffione /* copy the buffers from the non-fake ring */ 440*2ff91c17SVincenzo Maffione if (kring->nr_kflags & NKR_FAKERING) { 441*2ff91c17SVincenzo Maffione sring = kring->pipe; 442*2ff91c17SVincenzo Maffione dring = kring; 443*2ff91c17SVincenzo Maffione } else { 444*2ff91c17SVincenzo Maffione sring = kring; 445*2ff91c17SVincenzo Maffione dring = kring->pipe; 446*2ff91c17SVincenzo Maffione } 447*2ff91c17SVincenzo Maffione memcpy(dring->ring->slot, 448*2ff91c17SVincenzo Maffione sring->ring->slot, 449*2ff91c17SVincenzo Maffione sizeof(struct netmap_slot) * 450*2ff91c17SVincenzo Maffione sring->nkr_num_slots); 451*2ff91c17SVincenzo Maffione /* mark both rings as fake and needed, 452*2ff91c17SVincenzo Maffione * so that buffers will not be 453*2ff91c17SVincenzo Maffione * deleted by the standard machinery 454*2ff91c17SVincenzo Maffione * (we will delete them by ourselves in 455*2ff91c17SVincenzo Maffione * netmap_pipe_krings_delete) 456*2ff91c17SVincenzo Maffione */ 457*2ff91c17SVincenzo Maffione sring->nr_kflags |= 458*2ff91c17SVincenzo Maffione (NKR_FAKERING | NKR_NEEDRING); 459*2ff91c17SVincenzo Maffione dring->nr_kflags |= 460*2ff91c17SVincenzo Maffione (NKR_FAKERING | NKR_NEEDRING); 46137e3a6d3SLuigi Rizzo kring->nr_mode = NKR_NETMAP_ON; 46237e3a6d3SLuigi Rizzo } 46337e3a6d3SLuigi Rizzo } 46437e3a6d3SLuigi Rizzo } 46537e3a6d3SLuigi Rizzo if (na->active_fds == 0) 4664bf50f18SLuigi Rizzo na->na_flags |= NAF_NETMAP_ON; 467f0ea3689SLuigi Rizzo } else { 46837e3a6d3SLuigi Rizzo if (na->active_fds == 0) 4694bf50f18SLuigi Rizzo na->na_flags &= ~NAF_NETMAP_ON; 47037e3a6d3SLuigi Rizzo for_rx_tx(t) { 47137e3a6d3SLuigi Rizzo for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { 472*2ff91c17SVincenzo Maffione struct netmap_kring *kring = NMR(na, t)[i]; 47337e3a6d3SLuigi Rizzo 47437e3a6d3SLuigi Rizzo if (nm_kring_pending_off(kring)) { 47537e3a6d3SLuigi Rizzo kring->nr_mode = NKR_NETMAP_OFF; 476f0ea3689SLuigi Rizzo } 47737e3a6d3SLuigi Rizzo } 47837e3a6d3SLuigi Rizzo } 479c3e9b4dbSLuiz Otavio O Souza } 48037e3a6d3SLuigi Rizzo 48137e3a6d3SLuigi Rizzo if (na->active_fds) { 482c3e9b4dbSLuiz Otavio O Souza ND("active_fds %d", na->active_fds); 48337e3a6d3SLuigi Rizzo return 0; 48437e3a6d3SLuigi Rizzo } 48537e3a6d3SLuigi Rizzo 486f0ea3689SLuigi Rizzo if (pna->peer_ref) { 487f0ea3689SLuigi Rizzo ND("%p: case 1.a or 2.a, nothing to do", na); 488f0ea3689SLuigi Rizzo return 0; 489f0ea3689SLuigi Rizzo } 490f0ea3689SLuigi Rizzo if (onoff) { 491f0ea3689SLuigi Rizzo ND("%p: case 1.b, drop peer", na); 492f0ea3689SLuigi Rizzo pna->peer->peer_ref = 0; 493f0ea3689SLuigi Rizzo netmap_adapter_put(na); 494f0ea3689SLuigi Rizzo } else { 495f0ea3689SLuigi Rizzo ND("%p: case 2.b, grab peer", na); 496f0ea3689SLuigi Rizzo netmap_adapter_get(na); 497f0ea3689SLuigi Rizzo pna->peer->peer_ref = 1; 498f0ea3689SLuigi Rizzo } 49937e3a6d3SLuigi Rizzo return error; 500f0ea3689SLuigi Rizzo } 501f0ea3689SLuigi Rizzo 502f0ea3689SLuigi Rizzo /* netmap_pipe_krings_delete. 503f0ea3689SLuigi Rizzo * 504f0ea3689SLuigi Rizzo * There are two cases: 505f0ea3689SLuigi Rizzo * 506f0ea3689SLuigi Rizzo * 1) state is 507f0ea3689SLuigi Rizzo * 508f0ea3689SLuigi Rizzo * usr1 --> e1 --> e2 509f0ea3689SLuigi Rizzo * 510f0ea3689SLuigi Rizzo * and we are e1 (e2 is not registered, so krings_delete cannot be 511f0ea3689SLuigi Rizzo * called on it); 512f0ea3689SLuigi Rizzo * 513f0ea3689SLuigi Rizzo * 2) state is 514f0ea3689SLuigi Rizzo * 515f0ea3689SLuigi Rizzo * usr1 --> e1 e2 <-- usr2 516f0ea3689SLuigi Rizzo * 517f0ea3689SLuigi Rizzo * and we are either e1 or e2. 518f0ea3689SLuigi Rizzo * 519f0ea3689SLuigi Rizzo * In the former case we have to also delete the krings of e2; 520*2ff91c17SVincenzo Maffione * in the latter case we do nothing. 521f0ea3689SLuigi Rizzo */ 522f0ea3689SLuigi Rizzo static void 523f0ea3689SLuigi Rizzo netmap_pipe_krings_delete(struct netmap_adapter *na) 524f0ea3689SLuigi Rizzo { 525f0ea3689SLuigi Rizzo struct netmap_pipe_adapter *pna = 526f0ea3689SLuigi Rizzo (struct netmap_pipe_adapter *)na; 527*2ff91c17SVincenzo Maffione struct netmap_adapter *sna, *ona; /* na of the other end */ 528*2ff91c17SVincenzo Maffione enum txrx t; 529*2ff91c17SVincenzo Maffione int i; 530f0ea3689SLuigi Rizzo 531f0ea3689SLuigi Rizzo if (!pna->peer_ref) { 532f0ea3689SLuigi Rizzo ND("%p: case 2, kept alive by peer", na); 533f0ea3689SLuigi Rizzo return; 534f0ea3689SLuigi Rizzo } 535*2ff91c17SVincenzo Maffione ona = &pna->peer->up; 536f0ea3689SLuigi Rizzo /* case 1) above */ 537c3e9b4dbSLuiz Otavio O Souza ND("%p: case 1, deleting everything", na); 538*2ff91c17SVincenzo Maffione /* To avoid double-frees we zero-out all the buffers in the kernel part 539*2ff91c17SVincenzo Maffione * of each ring. The reason is this: If the user is behaving correctly, 540*2ff91c17SVincenzo Maffione * all buffers are found in exactly one slot in the userspace part of 541*2ff91c17SVincenzo Maffione * some ring. If the user is not behaving correctly, we cannot release 542*2ff91c17SVincenzo Maffione * buffers cleanly anyway. In the latter case, the allocator will 543*2ff91c17SVincenzo Maffione * return to a clean state only when all its users will close. 544*2ff91c17SVincenzo Maffione */ 545*2ff91c17SVincenzo Maffione sna = na; 546*2ff91c17SVincenzo Maffione cleanup: 547*2ff91c17SVincenzo Maffione for_rx_tx(t) { 548*2ff91c17SVincenzo Maffione for (i = 0; i < nma_get_nrings(sna, t) + 1; i++) { 549*2ff91c17SVincenzo Maffione struct netmap_kring *kring = NMR(sna, t)[i]; 550*2ff91c17SVincenzo Maffione struct netmap_ring *ring = kring->ring; 551*2ff91c17SVincenzo Maffione uint32_t j, lim = kring->nkr_num_slots - 1; 552*2ff91c17SVincenzo Maffione 553*2ff91c17SVincenzo Maffione ND("%s ring %p hwtail %u hwcur %u", 554*2ff91c17SVincenzo Maffione kring->name, ring, kring->nr_hwtail, kring->nr_hwcur); 555*2ff91c17SVincenzo Maffione 556*2ff91c17SVincenzo Maffione if (ring == NULL) 557*2ff91c17SVincenzo Maffione continue; 558*2ff91c17SVincenzo Maffione 559*2ff91c17SVincenzo Maffione if (kring->nr_hwtail == kring->nr_hwcur) 560*2ff91c17SVincenzo Maffione ring->slot[kring->nr_hwtail].buf_idx = 0; 561*2ff91c17SVincenzo Maffione 562*2ff91c17SVincenzo Maffione for (j = nm_next(kring->nr_hwtail, lim); 563*2ff91c17SVincenzo Maffione j != kring->nr_hwcur; 564*2ff91c17SVincenzo Maffione j = nm_next(j, lim)) 565*2ff91c17SVincenzo Maffione { 566*2ff91c17SVincenzo Maffione ND("%s[%d] %u", kring->name, j, ring->slot[j].buf_idx); 567*2ff91c17SVincenzo Maffione ring->slot[j].buf_idx = 0; 568*2ff91c17SVincenzo Maffione } 569*2ff91c17SVincenzo Maffione kring->nr_kflags &= ~(NKR_FAKERING | NKR_NEEDRING); 570*2ff91c17SVincenzo Maffione } 571*2ff91c17SVincenzo Maffione 572*2ff91c17SVincenzo Maffione } 573*2ff91c17SVincenzo Maffione if (sna != ona && ona->tx_rings) { 574*2ff91c17SVincenzo Maffione sna = ona; 575*2ff91c17SVincenzo Maffione goto cleanup; 576*2ff91c17SVincenzo Maffione } 577*2ff91c17SVincenzo Maffione 578*2ff91c17SVincenzo Maffione netmap_mem_rings_delete(na); 579f0ea3689SLuigi Rizzo netmap_krings_delete(na); /* also zeroes tx_rings etc. */ 580*2ff91c17SVincenzo Maffione 581f0ea3689SLuigi Rizzo if (ona->tx_rings == NULL) { 582f0ea3689SLuigi Rizzo /* already deleted, we must be on an 583f0ea3689SLuigi Rizzo * cleanup-after-error path */ 584f0ea3689SLuigi Rizzo return; 585f0ea3689SLuigi Rizzo } 586*2ff91c17SVincenzo Maffione netmap_mem_rings_delete(ona); 587f0ea3689SLuigi Rizzo netmap_krings_delete(ona); 588f0ea3689SLuigi Rizzo } 589f0ea3689SLuigi Rizzo 590f0ea3689SLuigi Rizzo 591f0ea3689SLuigi Rizzo static void 592f0ea3689SLuigi Rizzo netmap_pipe_dtor(struct netmap_adapter *na) 593f0ea3689SLuigi Rizzo { 594f0ea3689SLuigi Rizzo struct netmap_pipe_adapter *pna = 595f0ea3689SLuigi Rizzo (struct netmap_pipe_adapter *)na; 596c3e9b4dbSLuiz Otavio O Souza ND("%p %p", na, pna->parent_ifp); 597f0ea3689SLuigi Rizzo if (pna->peer_ref) { 598f0ea3689SLuigi Rizzo ND("%p: clean up peer", na); 599f0ea3689SLuigi Rizzo pna->peer_ref = 0; 600f0ea3689SLuigi Rizzo netmap_adapter_put(&pna->peer->up); 601f0ea3689SLuigi Rizzo } 602*2ff91c17SVincenzo Maffione if (pna->role == NM_PIPE_ROLE_MASTER) 603f0ea3689SLuigi Rizzo netmap_pipe_remove(pna->parent, pna); 604c3e9b4dbSLuiz Otavio O Souza if (pna->parent_ifp) 605c3e9b4dbSLuiz Otavio O Souza if_rele(pna->parent_ifp); 606f0ea3689SLuigi Rizzo netmap_adapter_put(pna->parent); 607f0ea3689SLuigi Rizzo pna->parent = NULL; 608f0ea3689SLuigi Rizzo } 609f0ea3689SLuigi Rizzo 610f0ea3689SLuigi Rizzo int 611*2ff91c17SVincenzo Maffione netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na, 612c3e9b4dbSLuiz Otavio O Souza struct netmap_mem_d *nmd, int create) 613f0ea3689SLuigi Rizzo { 614*2ff91c17SVincenzo Maffione struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body; 615f0ea3689SLuigi Rizzo struct netmap_adapter *pna; /* parent adapter */ 616*2ff91c17SVincenzo Maffione struct netmap_pipe_adapter *mna, *sna, *reqna; 61737e3a6d3SLuigi Rizzo struct ifnet *ifp = NULL; 618*2ff91c17SVincenzo Maffione const char *pipe_id = NULL; 619*2ff91c17SVincenzo Maffione int role = 0; 620c3e9b4dbSLuiz Otavio O Souza int error, retries = 0; 621*2ff91c17SVincenzo Maffione char *cbra; 622f0ea3689SLuigi Rizzo 623*2ff91c17SVincenzo Maffione /* Try to parse the pipe syntax 'xx{yy' or 'xx}yy'. */ 624*2ff91c17SVincenzo Maffione cbra = strrchr(hdr->nr_name, '{'); 625*2ff91c17SVincenzo Maffione if (cbra != NULL) { 626*2ff91c17SVincenzo Maffione role = NM_PIPE_ROLE_MASTER; 627*2ff91c17SVincenzo Maffione } else { 628*2ff91c17SVincenzo Maffione cbra = strrchr(hdr->nr_name, '}'); 629*2ff91c17SVincenzo Maffione if (cbra != NULL) { 630*2ff91c17SVincenzo Maffione role = NM_PIPE_ROLE_SLAVE; 631*2ff91c17SVincenzo Maffione } else { 632f0ea3689SLuigi Rizzo ND("not a pipe"); 633f0ea3689SLuigi Rizzo return 0; 634f0ea3689SLuigi Rizzo } 635*2ff91c17SVincenzo Maffione } 636*2ff91c17SVincenzo Maffione pipe_id = cbra + 1; 637*2ff91c17SVincenzo Maffione if (*pipe_id == '\0' || cbra == hdr->nr_name) { 638*2ff91c17SVincenzo Maffione /* Bracket is the last character, so pipe name is missing; 639*2ff91c17SVincenzo Maffione * or bracket is the first character, so base port name 640*2ff91c17SVincenzo Maffione * is missing. */ 641*2ff91c17SVincenzo Maffione return EINVAL; 642*2ff91c17SVincenzo Maffione } 643*2ff91c17SVincenzo Maffione 644*2ff91c17SVincenzo Maffione if (req->nr_mode != NR_REG_ALL_NIC && req->nr_mode != NR_REG_ONE_NIC) { 645*2ff91c17SVincenzo Maffione /* We only accept modes involving hardware rings. */ 646*2ff91c17SVincenzo Maffione return EINVAL; 647*2ff91c17SVincenzo Maffione } 648f0ea3689SLuigi Rizzo 649f0ea3689SLuigi Rizzo /* first, try to find the parent adapter */ 650c3e9b4dbSLuiz Otavio O Souza for (;;) { 651*2ff91c17SVincenzo Maffione char nr_name_orig[NETMAP_REQ_IFNAMSIZ]; 652c3e9b4dbSLuiz Otavio O Souza int create_error; 653c3e9b4dbSLuiz Otavio O Souza 654*2ff91c17SVincenzo Maffione /* Temporarily remove the pipe suffix. */ 655*2ff91c17SVincenzo Maffione strncpy(nr_name_orig, hdr->nr_name, sizeof(nr_name_orig)); 656*2ff91c17SVincenzo Maffione *cbra = '\0'; 657*2ff91c17SVincenzo Maffione error = netmap_get_na(hdr, &pna, &ifp, nmd, create); 658*2ff91c17SVincenzo Maffione /* Restore the pipe suffix. */ 659*2ff91c17SVincenzo Maffione strncpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name)); 660c3e9b4dbSLuiz Otavio O Souza if (!error) 661c3e9b4dbSLuiz Otavio O Souza break; 662c3e9b4dbSLuiz Otavio O Souza if (error != ENXIO || retries++) { 663f0ea3689SLuigi Rizzo ND("parent lookup failed: %d", error); 664f0ea3689SLuigi Rizzo return error; 665f0ea3689SLuigi Rizzo } 666c3e9b4dbSLuiz Otavio O Souza ND("try to create a persistent vale port"); 667c3e9b4dbSLuiz Otavio O Souza /* create a persistent vale port and try again */ 668*2ff91c17SVincenzo Maffione *cbra = '\0'; 669c3e9b4dbSLuiz Otavio O Souza NMG_UNLOCK(); 670*2ff91c17SVincenzo Maffione create_error = netmap_vi_create(hdr, 1 /* autodelete */); 671c3e9b4dbSLuiz Otavio O Souza NMG_LOCK(); 672*2ff91c17SVincenzo Maffione strncpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name)); 673c3e9b4dbSLuiz Otavio O Souza if (create_error && create_error != EEXIST) { 674c3e9b4dbSLuiz Otavio O Souza if (create_error != EOPNOTSUPP) { 675c3e9b4dbSLuiz Otavio O Souza D("failed to create a persistent vale port: %d", create_error); 676c3e9b4dbSLuiz Otavio O Souza } 677c3e9b4dbSLuiz Otavio O Souza return error; 678c3e9b4dbSLuiz Otavio O Souza } 679c3e9b4dbSLuiz Otavio O Souza } 680f0ea3689SLuigi Rizzo 681f0ea3689SLuigi Rizzo if (NETMAP_OWNED_BY_KERN(pna)) { 682f0ea3689SLuigi Rizzo ND("parent busy"); 683f0ea3689SLuigi Rizzo error = EBUSY; 684f0ea3689SLuigi Rizzo goto put_out; 685f0ea3689SLuigi Rizzo } 686f0ea3689SLuigi Rizzo 687f0ea3689SLuigi Rizzo /* next, lookup the pipe id in the parent list */ 688*2ff91c17SVincenzo Maffione reqna = NULL; 689f0ea3689SLuigi Rizzo mna = netmap_pipe_find(pna, pipe_id); 690f0ea3689SLuigi Rizzo if (mna) { 691f0ea3689SLuigi Rizzo if (mna->role == role) { 692*2ff91c17SVincenzo Maffione ND("found %s directly at %d", pipe_id, mna->parent_slot); 693*2ff91c17SVincenzo Maffione reqna = mna; 694f0ea3689SLuigi Rizzo } else { 695*2ff91c17SVincenzo Maffione ND("found %s indirectly at %d", pipe_id, mna->parent_slot); 696*2ff91c17SVincenzo Maffione reqna = mna->peer; 697f0ea3689SLuigi Rizzo } 698f0ea3689SLuigi Rizzo /* the pipe we have found already holds a ref to the parent, 699f0ea3689SLuigi Rizzo * so we need to drop the one we got from netmap_get_na() 700f0ea3689SLuigi Rizzo */ 701c3e9b4dbSLuiz Otavio O Souza netmap_unget_na(pna, ifp); 702f0ea3689SLuigi Rizzo goto found; 703f0ea3689SLuigi Rizzo } 704*2ff91c17SVincenzo Maffione ND("pipe %s not found, create %d", pipe_id, create); 705f0ea3689SLuigi Rizzo if (!create) { 706f0ea3689SLuigi Rizzo error = ENODEV; 707f0ea3689SLuigi Rizzo goto put_out; 708f0ea3689SLuigi Rizzo } 709f0ea3689SLuigi Rizzo /* we create both master and slave. 710f0ea3689SLuigi Rizzo * The endpoint we were asked for holds a reference to 711f0ea3689SLuigi Rizzo * the other one. 712f0ea3689SLuigi Rizzo */ 713c3e9b4dbSLuiz Otavio O Souza mna = nm_os_malloc(sizeof(*mna)); 714f0ea3689SLuigi Rizzo if (mna == NULL) { 715f0ea3689SLuigi Rizzo error = ENOMEM; 7164bf50f18SLuigi Rizzo goto put_out; 717f0ea3689SLuigi Rizzo } 718*2ff91c17SVincenzo Maffione snprintf(mna->up.name, sizeof(mna->up.name), "%s{%s", pna->name, pipe_id); 719f0ea3689SLuigi Rizzo 720*2ff91c17SVincenzo Maffione mna->role = NM_PIPE_ROLE_MASTER; 721f0ea3689SLuigi Rizzo mna->parent = pna; 722c3e9b4dbSLuiz Otavio O Souza mna->parent_ifp = ifp; 723f0ea3689SLuigi Rizzo 724f0ea3689SLuigi Rizzo mna->up.nm_txsync = netmap_pipe_txsync; 725f0ea3689SLuigi Rizzo mna->up.nm_rxsync = netmap_pipe_rxsync; 726f0ea3689SLuigi Rizzo mna->up.nm_register = netmap_pipe_reg; 727f0ea3689SLuigi Rizzo mna->up.nm_dtor = netmap_pipe_dtor; 728f0ea3689SLuigi Rizzo mna->up.nm_krings_create = netmap_pipe_krings_create; 729f0ea3689SLuigi Rizzo mna->up.nm_krings_delete = netmap_pipe_krings_delete; 730c3e9b4dbSLuiz Otavio O Souza mna->up.nm_mem = netmap_mem_get(pna->nm_mem); 731c3e9b4dbSLuiz Otavio O Souza mna->up.na_flags |= NAF_MEM_OWNER; 732f0ea3689SLuigi Rizzo mna->up.na_lut = pna->na_lut; 733f0ea3689SLuigi Rizzo 734*2ff91c17SVincenzo Maffione mna->up.num_tx_rings = req->nr_tx_rings; 735*2ff91c17SVincenzo Maffione nm_bound_var(&mna->up.num_tx_rings, 1, 736*2ff91c17SVincenzo Maffione 1, NM_PIPE_MAXRINGS, NULL); 737*2ff91c17SVincenzo Maffione mna->up.num_rx_rings = req->nr_rx_rings; 738*2ff91c17SVincenzo Maffione nm_bound_var(&mna->up.num_rx_rings, 1, 739*2ff91c17SVincenzo Maffione 1, NM_PIPE_MAXRINGS, NULL); 740*2ff91c17SVincenzo Maffione mna->up.num_tx_desc = req->nr_tx_slots; 741f0ea3689SLuigi Rizzo nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc, 742f0ea3689SLuigi Rizzo 1, NM_PIPE_MAXSLOTS, NULL); 743*2ff91c17SVincenzo Maffione mna->up.num_rx_desc = req->nr_rx_slots; 744f0ea3689SLuigi Rizzo nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc, 745f0ea3689SLuigi Rizzo 1, NM_PIPE_MAXSLOTS, NULL); 746f0ea3689SLuigi Rizzo error = netmap_attach_common(&mna->up); 747f0ea3689SLuigi Rizzo if (error) 7484bf50f18SLuigi Rizzo goto free_mna; 749f0ea3689SLuigi Rizzo /* register the master with the parent */ 750f0ea3689SLuigi Rizzo error = netmap_pipe_add(pna, mna); 751f0ea3689SLuigi Rizzo if (error) 752f0ea3689SLuigi Rizzo goto free_mna; 753f0ea3689SLuigi Rizzo 754f0ea3689SLuigi Rizzo /* create the slave */ 755c3e9b4dbSLuiz Otavio O Souza sna = nm_os_malloc(sizeof(*mna)); 756f0ea3689SLuigi Rizzo if (sna == NULL) { 757f0ea3689SLuigi Rizzo error = ENOMEM; 7589694aad3SLuigi Rizzo goto unregister_mna; 759f0ea3689SLuigi Rizzo } 760f0ea3689SLuigi Rizzo /* most fields are the same, copy from master and then fix */ 761f0ea3689SLuigi Rizzo *sna = *mna; 762c3e9b4dbSLuiz Otavio O Souza sna->up.nm_mem = netmap_mem_get(mna->up.nm_mem); 763*2ff91c17SVincenzo Maffione /* swap the number of tx/rx rings */ 764*2ff91c17SVincenzo Maffione sna->up.num_tx_rings = mna->up.num_rx_rings; 765*2ff91c17SVincenzo Maffione sna->up.num_rx_rings = mna->up.num_tx_rings; 766*2ff91c17SVincenzo Maffione snprintf(sna->up.name, sizeof(sna->up.name), "%s}%s", pna->name, pipe_id); 767*2ff91c17SVincenzo Maffione sna->role = NM_PIPE_ROLE_SLAVE; 768f0ea3689SLuigi Rizzo error = netmap_attach_common(&sna->up); 769f0ea3689SLuigi Rizzo if (error) 770f0ea3689SLuigi Rizzo goto free_sna; 771f0ea3689SLuigi Rizzo 772f0ea3689SLuigi Rizzo /* join the two endpoints */ 773f0ea3689SLuigi Rizzo mna->peer = sna; 774f0ea3689SLuigi Rizzo sna->peer = mna; 775f0ea3689SLuigi Rizzo 776f0ea3689SLuigi Rizzo /* we already have a reference to the parent, but we 777f0ea3689SLuigi Rizzo * need another one for the other endpoint we created 778f0ea3689SLuigi Rizzo */ 779f0ea3689SLuigi Rizzo netmap_adapter_get(pna); 780c3e9b4dbSLuiz Otavio O Souza /* likewise for the ifp, if any */ 781c3e9b4dbSLuiz Otavio O Souza if (ifp) 782c3e9b4dbSLuiz Otavio O Souza if_ref(ifp); 783f0ea3689SLuigi Rizzo 784*2ff91c17SVincenzo Maffione if (role == NM_PIPE_ROLE_MASTER) { 785*2ff91c17SVincenzo Maffione reqna = mna; 786f0ea3689SLuigi Rizzo mna->peer_ref = 1; 787f0ea3689SLuigi Rizzo netmap_adapter_get(&sna->up); 788f0ea3689SLuigi Rizzo } else { 789*2ff91c17SVincenzo Maffione reqna = sna; 790f0ea3689SLuigi Rizzo sna->peer_ref = 1; 791f0ea3689SLuigi Rizzo netmap_adapter_get(&mna->up); 792f0ea3689SLuigi Rizzo } 793f0ea3689SLuigi Rizzo ND("created master %p and slave %p", mna, sna); 794f0ea3689SLuigi Rizzo found: 795f0ea3689SLuigi Rizzo 796*2ff91c17SVincenzo Maffione ND("pipe %s %s at %p", pipe_id, 797*2ff91c17SVincenzo Maffione (reqna->role == NM_PIPE_ROLE_MASTER ? "master" : "slave"), reqna); 798*2ff91c17SVincenzo Maffione *na = &reqna->up; 799f0ea3689SLuigi Rizzo netmap_adapter_get(*na); 800f0ea3689SLuigi Rizzo 801f0ea3689SLuigi Rizzo /* keep the reference to the parent. 802f0ea3689SLuigi Rizzo * It will be released by the req destructor 803f0ea3689SLuigi Rizzo */ 804f0ea3689SLuigi Rizzo 805f0ea3689SLuigi Rizzo return 0; 806f0ea3689SLuigi Rizzo 807f0ea3689SLuigi Rizzo free_sna: 808c3e9b4dbSLuiz Otavio O Souza nm_os_free(sna); 8099694aad3SLuigi Rizzo unregister_mna: 8109694aad3SLuigi Rizzo netmap_pipe_remove(pna, mna); 811f0ea3689SLuigi Rizzo free_mna: 812c3e9b4dbSLuiz Otavio O Souza nm_os_free(mna); 813f0ea3689SLuigi Rizzo put_out: 81437e3a6d3SLuigi Rizzo netmap_unget_na(pna, ifp); 815f0ea3689SLuigi Rizzo return error; 816f0ea3689SLuigi Rizzo } 817f0ea3689SLuigi Rizzo 818f0ea3689SLuigi Rizzo 819f0ea3689SLuigi Rizzo #endif /* WITH_PIPES */ 820