1*2a7db7a6SVincenzo Maffione /* 2*2a7db7a6SVincenzo Maffione * Copyright (C) 2013-2016 Universita` di Pisa 3*2a7db7a6SVincenzo Maffione * All rights reserved. 4*2a7db7a6SVincenzo Maffione * 5*2a7db7a6SVincenzo Maffione * Redistribution and use in source and binary forms, with or without 6*2a7db7a6SVincenzo Maffione * modification, are permitted provided that the following conditions 7*2a7db7a6SVincenzo Maffione * are met: 8*2a7db7a6SVincenzo Maffione * 1. Redistributions of source code must retain the above copyright 9*2a7db7a6SVincenzo Maffione * notice, this list of conditions and the following disclaimer. 10*2a7db7a6SVincenzo Maffione * 2. Redistributions in binary form must reproduce the above copyright 11*2a7db7a6SVincenzo Maffione * notice, this list of conditions and the following disclaimer in the 12*2a7db7a6SVincenzo Maffione * documentation and/or other materials provided with the distribution. 13*2a7db7a6SVincenzo Maffione * 14*2a7db7a6SVincenzo Maffione * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*2a7db7a6SVincenzo Maffione * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*2a7db7a6SVincenzo Maffione * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*2a7db7a6SVincenzo Maffione * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*2a7db7a6SVincenzo Maffione * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*2a7db7a6SVincenzo Maffione * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*2a7db7a6SVincenzo Maffione * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*2a7db7a6SVincenzo Maffione * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*2a7db7a6SVincenzo Maffione * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*2a7db7a6SVincenzo Maffione * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*2a7db7a6SVincenzo Maffione * SUCH DAMAGE. 25*2a7db7a6SVincenzo Maffione */ 26*2a7db7a6SVincenzo Maffione 27*2a7db7a6SVincenzo Maffione 28*2a7db7a6SVincenzo Maffione /* 29*2a7db7a6SVincenzo Maffione * This module implements the VALE switch for netmap 30*2a7db7a6SVincenzo Maffione 31*2a7db7a6SVincenzo Maffione --- VALE SWITCH --- 32*2a7db7a6SVincenzo Maffione 33*2a7db7a6SVincenzo Maffione NMG_LOCK() serializes all modifications to switches and ports. 34*2a7db7a6SVincenzo Maffione A switch cannot be deleted until all ports are gone. 35*2a7db7a6SVincenzo Maffione 36*2a7db7a6SVincenzo Maffione For each switch, an SX lock (RWlock on linux) protects 37*2a7db7a6SVincenzo Maffione deletion of ports. When configuring or deleting a new port, the 38*2a7db7a6SVincenzo Maffione lock is acquired in exclusive mode (after holding NMG_LOCK). 39*2a7db7a6SVincenzo Maffione When forwarding, the lock is acquired in shared mode (without NMG_LOCK). 40*2a7db7a6SVincenzo Maffione The lock is held throughout the entire forwarding cycle, 41*2a7db7a6SVincenzo Maffione during which the thread may incur in a page fault. 42*2a7db7a6SVincenzo Maffione Hence it is important that sleepable shared locks are used. 43*2a7db7a6SVincenzo Maffione 44*2a7db7a6SVincenzo Maffione On the rx ring, the per-port lock is grabbed initially to reserve 45*2a7db7a6SVincenzo Maffione a number of slot in the ring, then the lock is released, 46*2a7db7a6SVincenzo Maffione packets are copied from source to destination, and then 47*2a7db7a6SVincenzo Maffione the lock is acquired again and the receive ring is updated. 48*2a7db7a6SVincenzo Maffione (A similar thing is done on the tx ring for NIC and host stack 49*2a7db7a6SVincenzo Maffione ports attached to the switch) 50*2a7db7a6SVincenzo Maffione 51*2a7db7a6SVincenzo Maffione */ 52*2a7db7a6SVincenzo Maffione 53*2a7db7a6SVincenzo Maffione /* 54*2a7db7a6SVincenzo Maffione * OS-specific code that is used only within this file. 55*2a7db7a6SVincenzo Maffione * Other OS-specific code that must be accessed by drivers 56*2a7db7a6SVincenzo Maffione * is present in netmap_kern.h 57*2a7db7a6SVincenzo Maffione */ 58*2a7db7a6SVincenzo Maffione 59*2a7db7a6SVincenzo Maffione #if defined(__FreeBSD__) 60*2a7db7a6SVincenzo Maffione #include <sys/cdefs.h> /* prerequisite */ 61*2a7db7a6SVincenzo Maffione __FBSDID("$FreeBSD$"); 62*2a7db7a6SVincenzo Maffione 63*2a7db7a6SVincenzo Maffione #include <sys/types.h> 64*2a7db7a6SVincenzo Maffione #include <sys/errno.h> 65*2a7db7a6SVincenzo Maffione #include <sys/param.h> /* defines used in kernel.h */ 66*2a7db7a6SVincenzo Maffione #include <sys/kernel.h> /* types used in module initialization */ 67*2a7db7a6SVincenzo Maffione #include <sys/conf.h> /* cdevsw struct, UID, GID */ 68*2a7db7a6SVincenzo Maffione #include <sys/sockio.h> 69*2a7db7a6SVincenzo Maffione #include <sys/socketvar.h> /* struct socket */ 70*2a7db7a6SVincenzo Maffione #include <sys/malloc.h> 71*2a7db7a6SVincenzo Maffione #include <sys/poll.h> 72*2a7db7a6SVincenzo Maffione #include <sys/rwlock.h> 73*2a7db7a6SVincenzo Maffione #include <sys/socket.h> /* sockaddrs */ 74*2a7db7a6SVincenzo Maffione #include <sys/selinfo.h> 75*2a7db7a6SVincenzo Maffione #include <sys/sysctl.h> 76*2a7db7a6SVincenzo Maffione #include <net/if.h> 77*2a7db7a6SVincenzo Maffione #include <net/if_var.h> 78*2a7db7a6SVincenzo Maffione #include <net/bpf.h> /* BIOCIMMEDIATE */ 79*2a7db7a6SVincenzo Maffione #include <machine/bus.h> /* bus_dmamap_* */ 80*2a7db7a6SVincenzo Maffione #include <sys/endian.h> 81*2a7db7a6SVincenzo Maffione #include <sys/refcount.h> 82*2a7db7a6SVincenzo Maffione #include <sys/smp.h> 83*2a7db7a6SVincenzo Maffione 84*2a7db7a6SVincenzo Maffione 85*2a7db7a6SVincenzo Maffione #elif defined(linux) 86*2a7db7a6SVincenzo Maffione 87*2a7db7a6SVincenzo Maffione #include "bsd_glue.h" 88*2a7db7a6SVincenzo Maffione 89*2a7db7a6SVincenzo Maffione #elif defined(__APPLE__) 90*2a7db7a6SVincenzo Maffione 91*2a7db7a6SVincenzo Maffione #warning OSX support is only partial 92*2a7db7a6SVincenzo Maffione #include "osx_glue.h" 93*2a7db7a6SVincenzo Maffione 94*2a7db7a6SVincenzo Maffione #elif defined(_WIN32) 95*2a7db7a6SVincenzo Maffione #include "win_glue.h" 96*2a7db7a6SVincenzo Maffione 97*2a7db7a6SVincenzo Maffione #else 98*2a7db7a6SVincenzo Maffione 99*2a7db7a6SVincenzo Maffione #error Unsupported platform 100*2a7db7a6SVincenzo Maffione 101*2a7db7a6SVincenzo Maffione #endif /* unsupported */ 102*2a7db7a6SVincenzo Maffione 103*2a7db7a6SVincenzo Maffione /* 104*2a7db7a6SVincenzo Maffione * common headers 105*2a7db7a6SVincenzo Maffione */ 106*2a7db7a6SVincenzo Maffione 107*2a7db7a6SVincenzo Maffione #include <net/netmap.h> 108*2a7db7a6SVincenzo Maffione #include <dev/netmap/netmap_kern.h> 109*2a7db7a6SVincenzo Maffione #include <dev/netmap/netmap_mem2.h> 110*2a7db7a6SVincenzo Maffione 111*2a7db7a6SVincenzo Maffione #include <dev/netmap/netmap_bdg.h> 112*2a7db7a6SVincenzo Maffione 113*2a7db7a6SVincenzo Maffione const char* 114*2a7db7a6SVincenzo Maffione netmap_bdg_name(struct netmap_vp_adapter *vp) 115*2a7db7a6SVincenzo Maffione { 116*2a7db7a6SVincenzo Maffione struct nm_bridge *b = vp->na_bdg; 117*2a7db7a6SVincenzo Maffione if (b == NULL) 118*2a7db7a6SVincenzo Maffione return NULL; 119*2a7db7a6SVincenzo Maffione return b->bdg_basename; 120*2a7db7a6SVincenzo Maffione } 121*2a7db7a6SVincenzo Maffione 122*2a7db7a6SVincenzo Maffione 123*2a7db7a6SVincenzo Maffione #ifndef CONFIG_NET_NS 124*2a7db7a6SVincenzo Maffione /* 125*2a7db7a6SVincenzo Maffione * XXX in principle nm_bridges could be created dynamically 126*2a7db7a6SVincenzo Maffione * Right now we have a static array and deletions are protected 127*2a7db7a6SVincenzo Maffione * by an exclusive lock. 128*2a7db7a6SVincenzo Maffione */ 129*2a7db7a6SVincenzo Maffione static struct nm_bridge *nm_bridges; 130*2a7db7a6SVincenzo Maffione #endif /* !CONFIG_NET_NS */ 131*2a7db7a6SVincenzo Maffione 132*2a7db7a6SVincenzo Maffione 133*2a7db7a6SVincenzo Maffione static int 134*2a7db7a6SVincenzo Maffione nm_is_id_char(const char c) 135*2a7db7a6SVincenzo Maffione { 136*2a7db7a6SVincenzo Maffione return (c >= 'a' && c <= 'z') || 137*2a7db7a6SVincenzo Maffione (c >= 'A' && c <= 'Z') || 138*2a7db7a6SVincenzo Maffione (c >= '0' && c <= '9') || 139*2a7db7a6SVincenzo Maffione (c == '_'); 140*2a7db7a6SVincenzo Maffione } 141*2a7db7a6SVincenzo Maffione 142*2a7db7a6SVincenzo Maffione /* Validate the name of a VALE bridge port and return the 143*2a7db7a6SVincenzo Maffione * position of the ":" character. */ 144*2a7db7a6SVincenzo Maffione static int 145*2a7db7a6SVincenzo Maffione nm_vale_name_validate(const char *name) 146*2a7db7a6SVincenzo Maffione { 147*2a7db7a6SVincenzo Maffione int colon_pos = -1; 148*2a7db7a6SVincenzo Maffione int i; 149*2a7db7a6SVincenzo Maffione 150*2a7db7a6SVincenzo Maffione if (!name || strlen(name) < strlen(NM_BDG_NAME)) { 151*2a7db7a6SVincenzo Maffione return -1; 152*2a7db7a6SVincenzo Maffione } 153*2a7db7a6SVincenzo Maffione 154*2a7db7a6SVincenzo Maffione for (i = 0; i < NM_BDG_IFNAMSIZ && name[i]; i++) { 155*2a7db7a6SVincenzo Maffione if (name[i] == ':') { 156*2a7db7a6SVincenzo Maffione colon_pos = i; 157*2a7db7a6SVincenzo Maffione break; 158*2a7db7a6SVincenzo Maffione } else if (!nm_is_id_char(name[i])) { 159*2a7db7a6SVincenzo Maffione return -1; 160*2a7db7a6SVincenzo Maffione } 161*2a7db7a6SVincenzo Maffione } 162*2a7db7a6SVincenzo Maffione 163*2a7db7a6SVincenzo Maffione if (strlen(name) - colon_pos > IFNAMSIZ) { 164*2a7db7a6SVincenzo Maffione /* interface name too long */ 165*2a7db7a6SVincenzo Maffione return -1; 166*2a7db7a6SVincenzo Maffione } 167*2a7db7a6SVincenzo Maffione 168*2a7db7a6SVincenzo Maffione return colon_pos; 169*2a7db7a6SVincenzo Maffione } 170*2a7db7a6SVincenzo Maffione 171*2a7db7a6SVincenzo Maffione /* 172*2a7db7a6SVincenzo Maffione * locate a bridge among the existing ones. 173*2a7db7a6SVincenzo Maffione * MUST BE CALLED WITH NMG_LOCK() 174*2a7db7a6SVincenzo Maffione * 175*2a7db7a6SVincenzo Maffione * a ':' in the name terminates the bridge name. Otherwise, just NM_NAME. 176*2a7db7a6SVincenzo Maffione * We assume that this is called with a name of at least NM_NAME chars. 177*2a7db7a6SVincenzo Maffione */ 178*2a7db7a6SVincenzo Maffione struct nm_bridge * 179*2a7db7a6SVincenzo Maffione nm_find_bridge(const char *name, int create, struct netmap_bdg_ops *ops) 180*2a7db7a6SVincenzo Maffione { 181*2a7db7a6SVincenzo Maffione int i, namelen; 182*2a7db7a6SVincenzo Maffione struct nm_bridge *b = NULL, *bridges; 183*2a7db7a6SVincenzo Maffione u_int num_bridges; 184*2a7db7a6SVincenzo Maffione 185*2a7db7a6SVincenzo Maffione NMG_LOCK_ASSERT(); 186*2a7db7a6SVincenzo Maffione 187*2a7db7a6SVincenzo Maffione netmap_bns_getbridges(&bridges, &num_bridges); 188*2a7db7a6SVincenzo Maffione 189*2a7db7a6SVincenzo Maffione namelen = nm_vale_name_validate(name); 190*2a7db7a6SVincenzo Maffione if (namelen < 0) { 191*2a7db7a6SVincenzo Maffione D("invalid bridge name %s", name ? name : NULL); 192*2a7db7a6SVincenzo Maffione return NULL; 193*2a7db7a6SVincenzo Maffione } 194*2a7db7a6SVincenzo Maffione 195*2a7db7a6SVincenzo Maffione /* lookup the name, remember empty slot if there is one */ 196*2a7db7a6SVincenzo Maffione for (i = 0; i < num_bridges; i++) { 197*2a7db7a6SVincenzo Maffione struct nm_bridge *x = bridges + i; 198*2a7db7a6SVincenzo Maffione 199*2a7db7a6SVincenzo Maffione if ((x->bdg_flags & NM_BDG_ACTIVE) + x->bdg_active_ports == 0) { 200*2a7db7a6SVincenzo Maffione if (create && b == NULL) 201*2a7db7a6SVincenzo Maffione b = x; /* record empty slot */ 202*2a7db7a6SVincenzo Maffione } else if (x->bdg_namelen != namelen) { 203*2a7db7a6SVincenzo Maffione continue; 204*2a7db7a6SVincenzo Maffione } else if (strncmp(name, x->bdg_basename, namelen) == 0) { 205*2a7db7a6SVincenzo Maffione ND("found '%.*s' at %d", namelen, name, i); 206*2a7db7a6SVincenzo Maffione b = x; 207*2a7db7a6SVincenzo Maffione break; 208*2a7db7a6SVincenzo Maffione } 209*2a7db7a6SVincenzo Maffione } 210*2a7db7a6SVincenzo Maffione if (i == num_bridges && b) { /* name not found, can create entry */ 211*2a7db7a6SVincenzo Maffione /* initialize the bridge */ 212*2a7db7a6SVincenzo Maffione ND("create new bridge %s with ports %d", b->bdg_basename, 213*2a7db7a6SVincenzo Maffione b->bdg_active_ports); 214*2a7db7a6SVincenzo Maffione b->ht = nm_os_malloc(sizeof(struct nm_hash_ent) * NM_BDG_HASH); 215*2a7db7a6SVincenzo Maffione if (b->ht == NULL) { 216*2a7db7a6SVincenzo Maffione D("failed to allocate hash table"); 217*2a7db7a6SVincenzo Maffione return NULL; 218*2a7db7a6SVincenzo Maffione } 219*2a7db7a6SVincenzo Maffione strncpy(b->bdg_basename, name, namelen); 220*2a7db7a6SVincenzo Maffione b->bdg_namelen = namelen; 221*2a7db7a6SVincenzo Maffione b->bdg_active_ports = 0; 222*2a7db7a6SVincenzo Maffione for (i = 0; i < NM_BDG_MAXPORTS; i++) 223*2a7db7a6SVincenzo Maffione b->bdg_port_index[i] = i; 224*2a7db7a6SVincenzo Maffione /* set the default function */ 225*2a7db7a6SVincenzo Maffione b->bdg_ops = ops; 226*2a7db7a6SVincenzo Maffione b->private_data = b->ht; 227*2a7db7a6SVincenzo Maffione b->bdg_flags = 0; 228*2a7db7a6SVincenzo Maffione NM_BNS_GET(b); 229*2a7db7a6SVincenzo Maffione } 230*2a7db7a6SVincenzo Maffione return b; 231*2a7db7a6SVincenzo Maffione } 232*2a7db7a6SVincenzo Maffione 233*2a7db7a6SVincenzo Maffione 234*2a7db7a6SVincenzo Maffione int 235*2a7db7a6SVincenzo Maffione netmap_bdg_free(struct nm_bridge *b) 236*2a7db7a6SVincenzo Maffione { 237*2a7db7a6SVincenzo Maffione if ((b->bdg_flags & NM_BDG_ACTIVE) + b->bdg_active_ports != 0) { 238*2a7db7a6SVincenzo Maffione return EBUSY; 239*2a7db7a6SVincenzo Maffione } 240*2a7db7a6SVincenzo Maffione 241*2a7db7a6SVincenzo Maffione ND("marking bridge %s as free", b->bdg_basename); 242*2a7db7a6SVincenzo Maffione nm_os_free(b->ht); 243*2a7db7a6SVincenzo Maffione b->bdg_ops = NULL; 244*2a7db7a6SVincenzo Maffione b->bdg_flags = 0; 245*2a7db7a6SVincenzo Maffione NM_BNS_PUT(b); 246*2a7db7a6SVincenzo Maffione return 0; 247*2a7db7a6SVincenzo Maffione } 248*2a7db7a6SVincenzo Maffione 249*2a7db7a6SVincenzo Maffione 250*2a7db7a6SVincenzo Maffione /* remove from bridge b the ports in slots hw and sw 251*2a7db7a6SVincenzo Maffione * (sw can be -1 if not needed) 252*2a7db7a6SVincenzo Maffione */ 253*2a7db7a6SVincenzo Maffione void 254*2a7db7a6SVincenzo Maffione netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw) 255*2a7db7a6SVincenzo Maffione { 256*2a7db7a6SVincenzo Maffione int s_hw = hw, s_sw = sw; 257*2a7db7a6SVincenzo Maffione int i, lim =b->bdg_active_ports; 258*2a7db7a6SVincenzo Maffione uint32_t *tmp = b->tmp_bdg_port_index; 259*2a7db7a6SVincenzo Maffione 260*2a7db7a6SVincenzo Maffione /* 261*2a7db7a6SVincenzo Maffione New algorithm: 262*2a7db7a6SVincenzo Maffione make a copy of bdg_port_index; 263*2a7db7a6SVincenzo Maffione lookup NA(ifp)->bdg_port and SWNA(ifp)->bdg_port 264*2a7db7a6SVincenzo Maffione in the array of bdg_port_index, replacing them with 265*2a7db7a6SVincenzo Maffione entries from the bottom of the array; 266*2a7db7a6SVincenzo Maffione decrement bdg_active_ports; 267*2a7db7a6SVincenzo Maffione acquire BDG_WLOCK() and copy back the array. 268*2a7db7a6SVincenzo Maffione */ 269*2a7db7a6SVincenzo Maffione 270*2a7db7a6SVincenzo Maffione if (netmap_verbose) 271*2a7db7a6SVincenzo Maffione D("detach %d and %d (lim %d)", hw, sw, lim); 272*2a7db7a6SVincenzo Maffione /* make a copy of the list of active ports, update it, 273*2a7db7a6SVincenzo Maffione * and then copy back within BDG_WLOCK(). 274*2a7db7a6SVincenzo Maffione */ 275*2a7db7a6SVincenzo Maffione memcpy(b->tmp_bdg_port_index, b->bdg_port_index, sizeof(b->tmp_bdg_port_index)); 276*2a7db7a6SVincenzo Maffione for (i = 0; (hw >= 0 || sw >= 0) && i < lim; ) { 277*2a7db7a6SVincenzo Maffione if (hw >= 0 && tmp[i] == hw) { 278*2a7db7a6SVincenzo Maffione ND("detach hw %d at %d", hw, i); 279*2a7db7a6SVincenzo Maffione lim--; /* point to last active port */ 280*2a7db7a6SVincenzo Maffione tmp[i] = tmp[lim]; /* swap with i */ 281*2a7db7a6SVincenzo Maffione tmp[lim] = hw; /* now this is inactive */ 282*2a7db7a6SVincenzo Maffione hw = -1; 283*2a7db7a6SVincenzo Maffione } else if (sw >= 0 && tmp[i] == sw) { 284*2a7db7a6SVincenzo Maffione ND("detach sw %d at %d", sw, i); 285*2a7db7a6SVincenzo Maffione lim--; 286*2a7db7a6SVincenzo Maffione tmp[i] = tmp[lim]; 287*2a7db7a6SVincenzo Maffione tmp[lim] = sw; 288*2a7db7a6SVincenzo Maffione sw = -1; 289*2a7db7a6SVincenzo Maffione } else { 290*2a7db7a6SVincenzo Maffione i++; 291*2a7db7a6SVincenzo Maffione } 292*2a7db7a6SVincenzo Maffione } 293*2a7db7a6SVincenzo Maffione if (hw >= 0 || sw >= 0) { 294*2a7db7a6SVincenzo Maffione D("XXX delete failed hw %d sw %d, should panic...", hw, sw); 295*2a7db7a6SVincenzo Maffione } 296*2a7db7a6SVincenzo Maffione 297*2a7db7a6SVincenzo Maffione BDG_WLOCK(b); 298*2a7db7a6SVincenzo Maffione if (b->bdg_ops->dtor) 299*2a7db7a6SVincenzo Maffione b->bdg_ops->dtor(b->bdg_ports[s_hw]); 300*2a7db7a6SVincenzo Maffione b->bdg_ports[s_hw] = NULL; 301*2a7db7a6SVincenzo Maffione if (s_sw >= 0) { 302*2a7db7a6SVincenzo Maffione b->bdg_ports[s_sw] = NULL; 303*2a7db7a6SVincenzo Maffione } 304*2a7db7a6SVincenzo Maffione memcpy(b->bdg_port_index, b->tmp_bdg_port_index, sizeof(b->tmp_bdg_port_index)); 305*2a7db7a6SVincenzo Maffione b->bdg_active_ports = lim; 306*2a7db7a6SVincenzo Maffione BDG_WUNLOCK(b); 307*2a7db7a6SVincenzo Maffione 308*2a7db7a6SVincenzo Maffione ND("now %d active ports", lim); 309*2a7db7a6SVincenzo Maffione netmap_bdg_free(b); 310*2a7db7a6SVincenzo Maffione } 311*2a7db7a6SVincenzo Maffione 312*2a7db7a6SVincenzo Maffione 313*2a7db7a6SVincenzo Maffione /* nm_bdg_ctl callback for VALE ports */ 314*2a7db7a6SVincenzo Maffione int 315*2a7db7a6SVincenzo Maffione netmap_vp_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na) 316*2a7db7a6SVincenzo Maffione { 317*2a7db7a6SVincenzo Maffione struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter *)na; 318*2a7db7a6SVincenzo Maffione struct nm_bridge *b = vpna->na_bdg; 319*2a7db7a6SVincenzo Maffione 320*2a7db7a6SVincenzo Maffione if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) { 321*2a7db7a6SVincenzo Maffione return 0; /* nothing to do */ 322*2a7db7a6SVincenzo Maffione } 323*2a7db7a6SVincenzo Maffione if (b) { 324*2a7db7a6SVincenzo Maffione netmap_set_all_rings(na, 0 /* disable */); 325*2a7db7a6SVincenzo Maffione netmap_bdg_detach_common(b, vpna->bdg_port, -1); 326*2a7db7a6SVincenzo Maffione vpna->na_bdg = NULL; 327*2a7db7a6SVincenzo Maffione netmap_set_all_rings(na, 1 /* enable */); 328*2a7db7a6SVincenzo Maffione } 329*2a7db7a6SVincenzo Maffione /* I have took reference just for attach */ 330*2a7db7a6SVincenzo Maffione netmap_adapter_put(na); 331*2a7db7a6SVincenzo Maffione return 0; 332*2a7db7a6SVincenzo Maffione } 333*2a7db7a6SVincenzo Maffione 334*2a7db7a6SVincenzo Maffione int 335*2a7db7a6SVincenzo Maffione netmap_default_bdg_attach(const char *name, struct netmap_adapter *na, 336*2a7db7a6SVincenzo Maffione struct nm_bridge *b) 337*2a7db7a6SVincenzo Maffione { 338*2a7db7a6SVincenzo Maffione return NM_NEED_BWRAP; 339*2a7db7a6SVincenzo Maffione } 340*2a7db7a6SVincenzo Maffione 341*2a7db7a6SVincenzo Maffione /* Try to get a reference to a netmap adapter attached to a VALE switch. 342*2a7db7a6SVincenzo Maffione * If the adapter is found (or is created), this function returns 0, a 343*2a7db7a6SVincenzo Maffione * non NULL pointer is returned into *na, and the caller holds a 344*2a7db7a6SVincenzo Maffione * reference to the adapter. 345*2a7db7a6SVincenzo Maffione * If an adapter is not found, then no reference is grabbed and the 346*2a7db7a6SVincenzo Maffione * function returns an error code, or 0 if there is just a VALE prefix 347*2a7db7a6SVincenzo Maffione * mismatch. Therefore the caller holds a reference when 348*2a7db7a6SVincenzo Maffione * (*na != NULL && return == 0). 349*2a7db7a6SVincenzo Maffione */ 350*2a7db7a6SVincenzo Maffione int 351*2a7db7a6SVincenzo Maffione netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na, 352*2a7db7a6SVincenzo Maffione struct netmap_mem_d *nmd, int create, struct netmap_bdg_ops *ops) 353*2a7db7a6SVincenzo Maffione { 354*2a7db7a6SVincenzo Maffione char *nr_name = hdr->nr_name; 355*2a7db7a6SVincenzo Maffione const char *ifname; 356*2a7db7a6SVincenzo Maffione struct ifnet *ifp = NULL; 357*2a7db7a6SVincenzo Maffione int error = 0; 358*2a7db7a6SVincenzo Maffione struct netmap_vp_adapter *vpna, *hostna = NULL; 359*2a7db7a6SVincenzo Maffione struct nm_bridge *b; 360*2a7db7a6SVincenzo Maffione uint32_t i, j; 361*2a7db7a6SVincenzo Maffione uint32_t cand = NM_BDG_NOPORT, cand2 = NM_BDG_NOPORT; 362*2a7db7a6SVincenzo Maffione int needed; 363*2a7db7a6SVincenzo Maffione 364*2a7db7a6SVincenzo Maffione *na = NULL; /* default return value */ 365*2a7db7a6SVincenzo Maffione 366*2a7db7a6SVincenzo Maffione /* first try to see if this is a bridge port. */ 367*2a7db7a6SVincenzo Maffione NMG_LOCK_ASSERT(); 368*2a7db7a6SVincenzo Maffione if (strncmp(nr_name, ops->name, strlen(ops->name) - 1)) { 369*2a7db7a6SVincenzo Maffione return 0; /* no error, but no VALE prefix */ 370*2a7db7a6SVincenzo Maffione } 371*2a7db7a6SVincenzo Maffione 372*2a7db7a6SVincenzo Maffione b = nm_find_bridge(nr_name, create, ops); 373*2a7db7a6SVincenzo Maffione if (b == NULL) { 374*2a7db7a6SVincenzo Maffione ND("no bridges available for '%s'", nr_name); 375*2a7db7a6SVincenzo Maffione return (create ? ENOMEM : ENXIO); 376*2a7db7a6SVincenzo Maffione } 377*2a7db7a6SVincenzo Maffione if (strlen(nr_name) < b->bdg_namelen) /* impossible */ 378*2a7db7a6SVincenzo Maffione panic("x"); 379*2a7db7a6SVincenzo Maffione 380*2a7db7a6SVincenzo Maffione /* Now we are sure that name starts with the bridge's name, 381*2a7db7a6SVincenzo Maffione * lookup the port in the bridge. We need to scan the entire 382*2a7db7a6SVincenzo Maffione * list. It is not important to hold a WLOCK on the bridge 383*2a7db7a6SVincenzo Maffione * during the search because NMG_LOCK already guarantees 384*2a7db7a6SVincenzo Maffione * that there are no other possible writers. 385*2a7db7a6SVincenzo Maffione */ 386*2a7db7a6SVincenzo Maffione 387*2a7db7a6SVincenzo Maffione /* lookup in the local list of ports */ 388*2a7db7a6SVincenzo Maffione for (j = 0; j < b->bdg_active_ports; j++) { 389*2a7db7a6SVincenzo Maffione i = b->bdg_port_index[j]; 390*2a7db7a6SVincenzo Maffione vpna = b->bdg_ports[i]; 391*2a7db7a6SVincenzo Maffione ND("checking %s", vpna->up.name); 392*2a7db7a6SVincenzo Maffione if (!strcmp(vpna->up.name, nr_name)) { 393*2a7db7a6SVincenzo Maffione netmap_adapter_get(&vpna->up); 394*2a7db7a6SVincenzo Maffione ND("found existing if %s refs %d", nr_name) 395*2a7db7a6SVincenzo Maffione *na = &vpna->up; 396*2a7db7a6SVincenzo Maffione return 0; 397*2a7db7a6SVincenzo Maffione } 398*2a7db7a6SVincenzo Maffione } 399*2a7db7a6SVincenzo Maffione /* not found, should we create it? */ 400*2a7db7a6SVincenzo Maffione if (!create) 401*2a7db7a6SVincenzo Maffione return ENXIO; 402*2a7db7a6SVincenzo Maffione /* yes we should, see if we have space to attach entries */ 403*2a7db7a6SVincenzo Maffione needed = 2; /* in some cases we only need 1 */ 404*2a7db7a6SVincenzo Maffione if (b->bdg_active_ports + needed >= NM_BDG_MAXPORTS) { 405*2a7db7a6SVincenzo Maffione D("bridge full %d, cannot create new port", b->bdg_active_ports); 406*2a7db7a6SVincenzo Maffione return ENOMEM; 407*2a7db7a6SVincenzo Maffione } 408*2a7db7a6SVincenzo Maffione /* record the next two ports available, but do not allocate yet */ 409*2a7db7a6SVincenzo Maffione cand = b->bdg_port_index[b->bdg_active_ports]; 410*2a7db7a6SVincenzo Maffione cand2 = b->bdg_port_index[b->bdg_active_ports + 1]; 411*2a7db7a6SVincenzo Maffione ND("+++ bridge %s port %s used %d avail %d %d", 412*2a7db7a6SVincenzo Maffione b->bdg_basename, ifname, b->bdg_active_ports, cand, cand2); 413*2a7db7a6SVincenzo Maffione 414*2a7db7a6SVincenzo Maffione /* 415*2a7db7a6SVincenzo Maffione * try see if there is a matching NIC with this name 416*2a7db7a6SVincenzo Maffione * (after the bridge's name) 417*2a7db7a6SVincenzo Maffione */ 418*2a7db7a6SVincenzo Maffione ifname = nr_name + b->bdg_namelen + 1; 419*2a7db7a6SVincenzo Maffione ifp = ifunit_ref(ifname); 420*2a7db7a6SVincenzo Maffione if (!ifp) { 421*2a7db7a6SVincenzo Maffione /* Create an ephemeral virtual port. 422*2a7db7a6SVincenzo Maffione * This block contains all the ephemeral-specific logic. 423*2a7db7a6SVincenzo Maffione */ 424*2a7db7a6SVincenzo Maffione 425*2a7db7a6SVincenzo Maffione if (hdr->nr_reqtype != NETMAP_REQ_REGISTER) { 426*2a7db7a6SVincenzo Maffione error = EINVAL; 427*2a7db7a6SVincenzo Maffione goto out; 428*2a7db7a6SVincenzo Maffione } 429*2a7db7a6SVincenzo Maffione 430*2a7db7a6SVincenzo Maffione /* bdg_netmap_attach creates a struct netmap_adapter */ 431*2a7db7a6SVincenzo Maffione error = b->bdg_ops->vp_create(hdr, NULL, nmd, &vpna); 432*2a7db7a6SVincenzo Maffione if (error) { 433*2a7db7a6SVincenzo Maffione D("error %d", error); 434*2a7db7a6SVincenzo Maffione goto out; 435*2a7db7a6SVincenzo Maffione } 436*2a7db7a6SVincenzo Maffione /* shortcut - we can skip get_hw_na(), 437*2a7db7a6SVincenzo Maffione * ownership check and nm_bdg_attach() 438*2a7db7a6SVincenzo Maffione */ 439*2a7db7a6SVincenzo Maffione 440*2a7db7a6SVincenzo Maffione } else { 441*2a7db7a6SVincenzo Maffione struct netmap_adapter *hw; 442*2a7db7a6SVincenzo Maffione 443*2a7db7a6SVincenzo Maffione /* the vale:nic syntax is only valid for some commands */ 444*2a7db7a6SVincenzo Maffione switch (hdr->nr_reqtype) { 445*2a7db7a6SVincenzo Maffione case NETMAP_REQ_VALE_ATTACH: 446*2a7db7a6SVincenzo Maffione case NETMAP_REQ_VALE_DETACH: 447*2a7db7a6SVincenzo Maffione case NETMAP_REQ_VALE_POLLING_ENABLE: 448*2a7db7a6SVincenzo Maffione case NETMAP_REQ_VALE_POLLING_DISABLE: 449*2a7db7a6SVincenzo Maffione break; /* ok */ 450*2a7db7a6SVincenzo Maffione default: 451*2a7db7a6SVincenzo Maffione error = EINVAL; 452*2a7db7a6SVincenzo Maffione goto out; 453*2a7db7a6SVincenzo Maffione } 454*2a7db7a6SVincenzo Maffione 455*2a7db7a6SVincenzo Maffione error = netmap_get_hw_na(ifp, nmd, &hw); 456*2a7db7a6SVincenzo Maffione if (error || hw == NULL) 457*2a7db7a6SVincenzo Maffione goto out; 458*2a7db7a6SVincenzo Maffione 459*2a7db7a6SVincenzo Maffione /* host adapter might not be created */ 460*2a7db7a6SVincenzo Maffione error = hw->nm_bdg_attach(nr_name, hw, b); 461*2a7db7a6SVincenzo Maffione if (error == NM_NEED_BWRAP) { 462*2a7db7a6SVincenzo Maffione error = b->bdg_ops->bwrap_attach(nr_name, hw); 463*2a7db7a6SVincenzo Maffione } 464*2a7db7a6SVincenzo Maffione if (error) 465*2a7db7a6SVincenzo Maffione goto out; 466*2a7db7a6SVincenzo Maffione vpna = hw->na_vp; 467*2a7db7a6SVincenzo Maffione hostna = hw->na_hostvp; 468*2a7db7a6SVincenzo Maffione if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) { 469*2a7db7a6SVincenzo Maffione /* Check if we need to skip the host rings. */ 470*2a7db7a6SVincenzo Maffione struct nmreq_vale_attach *areq = 471*2a7db7a6SVincenzo Maffione (struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body; 472*2a7db7a6SVincenzo Maffione if (areq->reg.nr_mode != NR_REG_NIC_SW) { 473*2a7db7a6SVincenzo Maffione hostna = NULL; 474*2a7db7a6SVincenzo Maffione } 475*2a7db7a6SVincenzo Maffione } 476*2a7db7a6SVincenzo Maffione } 477*2a7db7a6SVincenzo Maffione 478*2a7db7a6SVincenzo Maffione BDG_WLOCK(b); 479*2a7db7a6SVincenzo Maffione vpna->bdg_port = cand; 480*2a7db7a6SVincenzo Maffione ND("NIC %p to bridge port %d", vpna, cand); 481*2a7db7a6SVincenzo Maffione /* bind the port to the bridge (virtual ports are not active) */ 482*2a7db7a6SVincenzo Maffione b->bdg_ports[cand] = vpna; 483*2a7db7a6SVincenzo Maffione vpna->na_bdg = b; 484*2a7db7a6SVincenzo Maffione b->bdg_active_ports++; 485*2a7db7a6SVincenzo Maffione if (hostna != NULL) { 486*2a7db7a6SVincenzo Maffione /* also bind the host stack to the bridge */ 487*2a7db7a6SVincenzo Maffione b->bdg_ports[cand2] = hostna; 488*2a7db7a6SVincenzo Maffione hostna->bdg_port = cand2; 489*2a7db7a6SVincenzo Maffione hostna->na_bdg = b; 490*2a7db7a6SVincenzo Maffione b->bdg_active_ports++; 491*2a7db7a6SVincenzo Maffione ND("host %p to bridge port %d", hostna, cand2); 492*2a7db7a6SVincenzo Maffione } 493*2a7db7a6SVincenzo Maffione ND("if %s refs %d", ifname, vpna->up.na_refcount); 494*2a7db7a6SVincenzo Maffione BDG_WUNLOCK(b); 495*2a7db7a6SVincenzo Maffione *na = &vpna->up; 496*2a7db7a6SVincenzo Maffione netmap_adapter_get(*na); 497*2a7db7a6SVincenzo Maffione 498*2a7db7a6SVincenzo Maffione out: 499*2a7db7a6SVincenzo Maffione if (ifp) 500*2a7db7a6SVincenzo Maffione if_rele(ifp); 501*2a7db7a6SVincenzo Maffione 502*2a7db7a6SVincenzo Maffione return error; 503*2a7db7a6SVincenzo Maffione } 504*2a7db7a6SVincenzo Maffione 505*2a7db7a6SVincenzo Maffione /* Process NETMAP_REQ_VALE_ATTACH. 506*2a7db7a6SVincenzo Maffione */ 507*2a7db7a6SVincenzo Maffione int 508*2a7db7a6SVincenzo Maffione nm_bdg_ctl_attach(struct nmreq_header *hdr, void *auth_token) 509*2a7db7a6SVincenzo Maffione { 510*2a7db7a6SVincenzo Maffione struct nmreq_vale_attach *req = 511*2a7db7a6SVincenzo Maffione (struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body; 512*2a7db7a6SVincenzo Maffione struct netmap_vp_adapter * vpna; 513*2a7db7a6SVincenzo Maffione struct netmap_adapter *na = NULL; 514*2a7db7a6SVincenzo Maffione struct netmap_mem_d *nmd = NULL; 515*2a7db7a6SVincenzo Maffione struct nm_bridge *b = NULL; 516*2a7db7a6SVincenzo Maffione int error; 517*2a7db7a6SVincenzo Maffione 518*2a7db7a6SVincenzo Maffione NMG_LOCK(); 519*2a7db7a6SVincenzo Maffione /* permission check for modified bridges */ 520*2a7db7a6SVincenzo Maffione b = nm_find_bridge(hdr->nr_name, 0 /* don't create */, NULL); 521*2a7db7a6SVincenzo Maffione if (b && !nm_bdg_valid_auth_token(b, auth_token)) { 522*2a7db7a6SVincenzo Maffione error = EACCES; 523*2a7db7a6SVincenzo Maffione goto unlock_exit; 524*2a7db7a6SVincenzo Maffione } 525*2a7db7a6SVincenzo Maffione 526*2a7db7a6SVincenzo Maffione if (req->reg.nr_mem_id) { 527*2a7db7a6SVincenzo Maffione nmd = netmap_mem_find(req->reg.nr_mem_id); 528*2a7db7a6SVincenzo Maffione if (nmd == NULL) { 529*2a7db7a6SVincenzo Maffione error = EINVAL; 530*2a7db7a6SVincenzo Maffione goto unlock_exit; 531*2a7db7a6SVincenzo Maffione } 532*2a7db7a6SVincenzo Maffione } 533*2a7db7a6SVincenzo Maffione 534*2a7db7a6SVincenzo Maffione /* check for existing one */ 535*2a7db7a6SVincenzo Maffione error = netmap_get_vale_na(hdr, &na, nmd, 0); 536*2a7db7a6SVincenzo Maffione if (na) { 537*2a7db7a6SVincenzo Maffione error = EBUSY; 538*2a7db7a6SVincenzo Maffione goto unref_exit; 539*2a7db7a6SVincenzo Maffione } 540*2a7db7a6SVincenzo Maffione error = netmap_get_vale_na(hdr, &na, 541*2a7db7a6SVincenzo Maffione nmd, 1 /* create if not exists */); 542*2a7db7a6SVincenzo Maffione if (error) { /* no device */ 543*2a7db7a6SVincenzo Maffione goto unlock_exit; 544*2a7db7a6SVincenzo Maffione } 545*2a7db7a6SVincenzo Maffione 546*2a7db7a6SVincenzo Maffione if (na == NULL) { /* VALE prefix missing */ 547*2a7db7a6SVincenzo Maffione error = EINVAL; 548*2a7db7a6SVincenzo Maffione goto unlock_exit; 549*2a7db7a6SVincenzo Maffione } 550*2a7db7a6SVincenzo Maffione 551*2a7db7a6SVincenzo Maffione if (NETMAP_OWNED_BY_ANY(na)) { 552*2a7db7a6SVincenzo Maffione error = EBUSY; 553*2a7db7a6SVincenzo Maffione goto unref_exit; 554*2a7db7a6SVincenzo Maffione } 555*2a7db7a6SVincenzo Maffione 556*2a7db7a6SVincenzo Maffione if (na->nm_bdg_ctl) { 557*2a7db7a6SVincenzo Maffione /* nop for VALE ports. The bwrap needs to put the hwna 558*2a7db7a6SVincenzo Maffione * in netmap mode (see netmap_bwrap_bdg_ctl) 559*2a7db7a6SVincenzo Maffione */ 560*2a7db7a6SVincenzo Maffione error = na->nm_bdg_ctl(hdr, na); 561*2a7db7a6SVincenzo Maffione if (error) 562*2a7db7a6SVincenzo Maffione goto unref_exit; 563*2a7db7a6SVincenzo Maffione ND("registered %s to netmap-mode", na->name); 564*2a7db7a6SVincenzo Maffione } 565*2a7db7a6SVincenzo Maffione vpna = (struct netmap_vp_adapter *)na; 566*2a7db7a6SVincenzo Maffione req->port_index = vpna->bdg_port; 567*2a7db7a6SVincenzo Maffione NMG_UNLOCK(); 568*2a7db7a6SVincenzo Maffione return 0; 569*2a7db7a6SVincenzo Maffione 570*2a7db7a6SVincenzo Maffione unref_exit: 571*2a7db7a6SVincenzo Maffione netmap_adapter_put(na); 572*2a7db7a6SVincenzo Maffione unlock_exit: 573*2a7db7a6SVincenzo Maffione NMG_UNLOCK(); 574*2a7db7a6SVincenzo Maffione return error; 575*2a7db7a6SVincenzo Maffione } 576*2a7db7a6SVincenzo Maffione 577*2a7db7a6SVincenzo Maffione static inline int 578*2a7db7a6SVincenzo Maffione nm_is_bwrap(struct netmap_adapter *na) 579*2a7db7a6SVincenzo Maffione { 580*2a7db7a6SVincenzo Maffione return na->nm_register == netmap_bwrap_reg; 581*2a7db7a6SVincenzo Maffione } 582*2a7db7a6SVincenzo Maffione 583*2a7db7a6SVincenzo Maffione /* Process NETMAP_REQ_VALE_DETACH. 584*2a7db7a6SVincenzo Maffione */ 585*2a7db7a6SVincenzo Maffione int 586*2a7db7a6SVincenzo Maffione nm_bdg_ctl_detach(struct nmreq_header *hdr, void *auth_token) 587*2a7db7a6SVincenzo Maffione { 588*2a7db7a6SVincenzo Maffione struct nmreq_vale_detach *nmreq_det = (void *)(uintptr_t)hdr->nr_body; 589*2a7db7a6SVincenzo Maffione struct netmap_vp_adapter *vpna; 590*2a7db7a6SVincenzo Maffione struct netmap_adapter *na; 591*2a7db7a6SVincenzo Maffione struct nm_bridge *b = NULL; 592*2a7db7a6SVincenzo Maffione int error; 593*2a7db7a6SVincenzo Maffione 594*2a7db7a6SVincenzo Maffione NMG_LOCK(); 595*2a7db7a6SVincenzo Maffione /* permission check for modified bridges */ 596*2a7db7a6SVincenzo Maffione b = nm_find_bridge(hdr->nr_name, 0 /* don't create */, NULL); 597*2a7db7a6SVincenzo Maffione if (b && !nm_bdg_valid_auth_token(b, auth_token)) { 598*2a7db7a6SVincenzo Maffione error = EACCES; 599*2a7db7a6SVincenzo Maffione goto unlock_exit; 600*2a7db7a6SVincenzo Maffione } 601*2a7db7a6SVincenzo Maffione 602*2a7db7a6SVincenzo Maffione error = netmap_get_vale_na(hdr, &na, NULL, 0 /* don't create */); 603*2a7db7a6SVincenzo Maffione if (error) { /* no device, or another bridge or user owns the device */ 604*2a7db7a6SVincenzo Maffione goto unlock_exit; 605*2a7db7a6SVincenzo Maffione } 606*2a7db7a6SVincenzo Maffione 607*2a7db7a6SVincenzo Maffione if (na == NULL) { /* VALE prefix missing */ 608*2a7db7a6SVincenzo Maffione error = EINVAL; 609*2a7db7a6SVincenzo Maffione goto unlock_exit; 610*2a7db7a6SVincenzo Maffione } else if (nm_is_bwrap(na) && 611*2a7db7a6SVincenzo Maffione ((struct netmap_bwrap_adapter *)na)->na_polling_state) { 612*2a7db7a6SVincenzo Maffione /* Don't detach a NIC with polling */ 613*2a7db7a6SVincenzo Maffione error = EBUSY; 614*2a7db7a6SVincenzo Maffione goto unref_exit; 615*2a7db7a6SVincenzo Maffione } 616*2a7db7a6SVincenzo Maffione 617*2a7db7a6SVincenzo Maffione vpna = (struct netmap_vp_adapter *)na; 618*2a7db7a6SVincenzo Maffione if (na->na_vp != vpna) { 619*2a7db7a6SVincenzo Maffione /* trying to detach first attach of VALE persistent port attached 620*2a7db7a6SVincenzo Maffione * to 2 bridges 621*2a7db7a6SVincenzo Maffione */ 622*2a7db7a6SVincenzo Maffione error = EBUSY; 623*2a7db7a6SVincenzo Maffione goto unref_exit; 624*2a7db7a6SVincenzo Maffione } 625*2a7db7a6SVincenzo Maffione nmreq_det->port_index = vpna->bdg_port; 626*2a7db7a6SVincenzo Maffione 627*2a7db7a6SVincenzo Maffione if (na->nm_bdg_ctl) { 628*2a7db7a6SVincenzo Maffione /* remove the port from bridge. The bwrap 629*2a7db7a6SVincenzo Maffione * also needs to put the hwna in normal mode 630*2a7db7a6SVincenzo Maffione */ 631*2a7db7a6SVincenzo Maffione error = na->nm_bdg_ctl(hdr, na); 632*2a7db7a6SVincenzo Maffione } 633*2a7db7a6SVincenzo Maffione 634*2a7db7a6SVincenzo Maffione unref_exit: 635*2a7db7a6SVincenzo Maffione netmap_adapter_put(na); 636*2a7db7a6SVincenzo Maffione unlock_exit: 637*2a7db7a6SVincenzo Maffione NMG_UNLOCK(); 638*2a7db7a6SVincenzo Maffione return error; 639*2a7db7a6SVincenzo Maffione 640*2a7db7a6SVincenzo Maffione } 641*2a7db7a6SVincenzo Maffione 642*2a7db7a6SVincenzo Maffione struct nm_bdg_polling_state; 643*2a7db7a6SVincenzo Maffione struct 644*2a7db7a6SVincenzo Maffione nm_bdg_kthread { 645*2a7db7a6SVincenzo Maffione struct nm_kctx *nmk; 646*2a7db7a6SVincenzo Maffione u_int qfirst; 647*2a7db7a6SVincenzo Maffione u_int qlast; 648*2a7db7a6SVincenzo Maffione struct nm_bdg_polling_state *bps; 649*2a7db7a6SVincenzo Maffione }; 650*2a7db7a6SVincenzo Maffione 651*2a7db7a6SVincenzo Maffione struct nm_bdg_polling_state { 652*2a7db7a6SVincenzo Maffione bool configured; 653*2a7db7a6SVincenzo Maffione bool stopped; 654*2a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna; 655*2a7db7a6SVincenzo Maffione uint32_t mode; 656*2a7db7a6SVincenzo Maffione u_int qfirst; 657*2a7db7a6SVincenzo Maffione u_int qlast; 658*2a7db7a6SVincenzo Maffione u_int cpu_from; 659*2a7db7a6SVincenzo Maffione u_int ncpus; 660*2a7db7a6SVincenzo Maffione struct nm_bdg_kthread *kthreads; 661*2a7db7a6SVincenzo Maffione }; 662*2a7db7a6SVincenzo Maffione 663*2a7db7a6SVincenzo Maffione static void 664*2a7db7a6SVincenzo Maffione netmap_bwrap_polling(void *data, int is_kthread) 665*2a7db7a6SVincenzo Maffione { 666*2a7db7a6SVincenzo Maffione struct nm_bdg_kthread *nbk = data; 667*2a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna; 668*2a7db7a6SVincenzo Maffione u_int qfirst, qlast, i; 669*2a7db7a6SVincenzo Maffione struct netmap_kring **kring0, *kring; 670*2a7db7a6SVincenzo Maffione 671*2a7db7a6SVincenzo Maffione if (!nbk) 672*2a7db7a6SVincenzo Maffione return; 673*2a7db7a6SVincenzo Maffione qfirst = nbk->qfirst; 674*2a7db7a6SVincenzo Maffione qlast = nbk->qlast; 675*2a7db7a6SVincenzo Maffione bna = nbk->bps->bna; 676*2a7db7a6SVincenzo Maffione kring0 = NMR(bna->hwna, NR_RX); 677*2a7db7a6SVincenzo Maffione 678*2a7db7a6SVincenzo Maffione for (i = qfirst; i < qlast; i++) { 679*2a7db7a6SVincenzo Maffione kring = kring0[i]; 680*2a7db7a6SVincenzo Maffione kring->nm_notify(kring, 0); 681*2a7db7a6SVincenzo Maffione } 682*2a7db7a6SVincenzo Maffione } 683*2a7db7a6SVincenzo Maffione 684*2a7db7a6SVincenzo Maffione static int 685*2a7db7a6SVincenzo Maffione nm_bdg_create_kthreads(struct nm_bdg_polling_state *bps) 686*2a7db7a6SVincenzo Maffione { 687*2a7db7a6SVincenzo Maffione struct nm_kctx_cfg kcfg; 688*2a7db7a6SVincenzo Maffione int i, j; 689*2a7db7a6SVincenzo Maffione 690*2a7db7a6SVincenzo Maffione bps->kthreads = nm_os_malloc(sizeof(struct nm_bdg_kthread) * bps->ncpus); 691*2a7db7a6SVincenzo Maffione if (bps->kthreads == NULL) 692*2a7db7a6SVincenzo Maffione return ENOMEM; 693*2a7db7a6SVincenzo Maffione 694*2a7db7a6SVincenzo Maffione bzero(&kcfg, sizeof(kcfg)); 695*2a7db7a6SVincenzo Maffione kcfg.worker_fn = netmap_bwrap_polling; 696*2a7db7a6SVincenzo Maffione kcfg.use_kthread = 1; 697*2a7db7a6SVincenzo Maffione for (i = 0; i < bps->ncpus; i++) { 698*2a7db7a6SVincenzo Maffione struct nm_bdg_kthread *t = bps->kthreads + i; 699*2a7db7a6SVincenzo Maffione int all = (bps->ncpus == 1 && 700*2a7db7a6SVincenzo Maffione bps->mode == NETMAP_POLLING_MODE_SINGLE_CPU); 701*2a7db7a6SVincenzo Maffione int affinity = bps->cpu_from + i; 702*2a7db7a6SVincenzo Maffione 703*2a7db7a6SVincenzo Maffione t->bps = bps; 704*2a7db7a6SVincenzo Maffione t->qfirst = all ? bps->qfirst /* must be 0 */: affinity; 705*2a7db7a6SVincenzo Maffione t->qlast = all ? bps->qlast : t->qfirst + 1; 706*2a7db7a6SVincenzo Maffione D("kthread %d a:%u qf:%u ql:%u", i, affinity, t->qfirst, 707*2a7db7a6SVincenzo Maffione t->qlast); 708*2a7db7a6SVincenzo Maffione 709*2a7db7a6SVincenzo Maffione kcfg.type = i; 710*2a7db7a6SVincenzo Maffione kcfg.worker_private = t; 711*2a7db7a6SVincenzo Maffione t->nmk = nm_os_kctx_create(&kcfg, NULL); 712*2a7db7a6SVincenzo Maffione if (t->nmk == NULL) { 713*2a7db7a6SVincenzo Maffione goto cleanup; 714*2a7db7a6SVincenzo Maffione } 715*2a7db7a6SVincenzo Maffione nm_os_kctx_worker_setaff(t->nmk, affinity); 716*2a7db7a6SVincenzo Maffione } 717*2a7db7a6SVincenzo Maffione return 0; 718*2a7db7a6SVincenzo Maffione 719*2a7db7a6SVincenzo Maffione cleanup: 720*2a7db7a6SVincenzo Maffione for (j = 0; j < i; j++) { 721*2a7db7a6SVincenzo Maffione struct nm_bdg_kthread *t = bps->kthreads + i; 722*2a7db7a6SVincenzo Maffione nm_os_kctx_destroy(t->nmk); 723*2a7db7a6SVincenzo Maffione } 724*2a7db7a6SVincenzo Maffione nm_os_free(bps->kthreads); 725*2a7db7a6SVincenzo Maffione return EFAULT; 726*2a7db7a6SVincenzo Maffione } 727*2a7db7a6SVincenzo Maffione 728*2a7db7a6SVincenzo Maffione /* A variant of ptnetmap_start_kthreads() */ 729*2a7db7a6SVincenzo Maffione static int 730*2a7db7a6SVincenzo Maffione nm_bdg_polling_start_kthreads(struct nm_bdg_polling_state *bps) 731*2a7db7a6SVincenzo Maffione { 732*2a7db7a6SVincenzo Maffione int error, i, j; 733*2a7db7a6SVincenzo Maffione 734*2a7db7a6SVincenzo Maffione if (!bps) { 735*2a7db7a6SVincenzo Maffione D("polling is not configured"); 736*2a7db7a6SVincenzo Maffione return EFAULT; 737*2a7db7a6SVincenzo Maffione } 738*2a7db7a6SVincenzo Maffione bps->stopped = false; 739*2a7db7a6SVincenzo Maffione 740*2a7db7a6SVincenzo Maffione for (i = 0; i < bps->ncpus; i++) { 741*2a7db7a6SVincenzo Maffione struct nm_bdg_kthread *t = bps->kthreads + i; 742*2a7db7a6SVincenzo Maffione error = nm_os_kctx_worker_start(t->nmk); 743*2a7db7a6SVincenzo Maffione if (error) { 744*2a7db7a6SVincenzo Maffione D("error in nm_kthread_start()"); 745*2a7db7a6SVincenzo Maffione goto cleanup; 746*2a7db7a6SVincenzo Maffione } 747*2a7db7a6SVincenzo Maffione } 748*2a7db7a6SVincenzo Maffione return 0; 749*2a7db7a6SVincenzo Maffione 750*2a7db7a6SVincenzo Maffione cleanup: 751*2a7db7a6SVincenzo Maffione for (j = 0; j < i; j++) { 752*2a7db7a6SVincenzo Maffione struct nm_bdg_kthread *t = bps->kthreads + i; 753*2a7db7a6SVincenzo Maffione nm_os_kctx_worker_stop(t->nmk); 754*2a7db7a6SVincenzo Maffione } 755*2a7db7a6SVincenzo Maffione bps->stopped = true; 756*2a7db7a6SVincenzo Maffione return error; 757*2a7db7a6SVincenzo Maffione } 758*2a7db7a6SVincenzo Maffione 759*2a7db7a6SVincenzo Maffione static void 760*2a7db7a6SVincenzo Maffione nm_bdg_polling_stop_delete_kthreads(struct nm_bdg_polling_state *bps) 761*2a7db7a6SVincenzo Maffione { 762*2a7db7a6SVincenzo Maffione int i; 763*2a7db7a6SVincenzo Maffione 764*2a7db7a6SVincenzo Maffione if (!bps) 765*2a7db7a6SVincenzo Maffione return; 766*2a7db7a6SVincenzo Maffione 767*2a7db7a6SVincenzo Maffione for (i = 0; i < bps->ncpus; i++) { 768*2a7db7a6SVincenzo Maffione struct nm_bdg_kthread *t = bps->kthreads + i; 769*2a7db7a6SVincenzo Maffione nm_os_kctx_worker_stop(t->nmk); 770*2a7db7a6SVincenzo Maffione nm_os_kctx_destroy(t->nmk); 771*2a7db7a6SVincenzo Maffione } 772*2a7db7a6SVincenzo Maffione bps->stopped = true; 773*2a7db7a6SVincenzo Maffione } 774*2a7db7a6SVincenzo Maffione 775*2a7db7a6SVincenzo Maffione static int 776*2a7db7a6SVincenzo Maffione get_polling_cfg(struct nmreq_vale_polling *req, struct netmap_adapter *na, 777*2a7db7a6SVincenzo Maffione struct nm_bdg_polling_state *bps) 778*2a7db7a6SVincenzo Maffione { 779*2a7db7a6SVincenzo Maffione unsigned int avail_cpus, core_from; 780*2a7db7a6SVincenzo Maffione unsigned int qfirst, qlast; 781*2a7db7a6SVincenzo Maffione uint32_t i = req->nr_first_cpu_id; 782*2a7db7a6SVincenzo Maffione uint32_t req_cpus = req->nr_num_polling_cpus; 783*2a7db7a6SVincenzo Maffione 784*2a7db7a6SVincenzo Maffione avail_cpus = nm_os_ncpus(); 785*2a7db7a6SVincenzo Maffione 786*2a7db7a6SVincenzo Maffione if (req_cpus == 0) { 787*2a7db7a6SVincenzo Maffione D("req_cpus must be > 0"); 788*2a7db7a6SVincenzo Maffione return EINVAL; 789*2a7db7a6SVincenzo Maffione } else if (req_cpus >= avail_cpus) { 790*2a7db7a6SVincenzo Maffione D("Cannot use all the CPUs in the system"); 791*2a7db7a6SVincenzo Maffione return EINVAL; 792*2a7db7a6SVincenzo Maffione } 793*2a7db7a6SVincenzo Maffione 794*2a7db7a6SVincenzo Maffione if (req->nr_mode == NETMAP_POLLING_MODE_MULTI_CPU) { 795*2a7db7a6SVincenzo Maffione /* Use a separate core for each ring. If nr_num_polling_cpus>1 796*2a7db7a6SVincenzo Maffione * more consecutive rings are polled. 797*2a7db7a6SVincenzo Maffione * For example, if nr_first_cpu_id=2 and nr_num_polling_cpus=2, 798*2a7db7a6SVincenzo Maffione * ring 2 and 3 are polled by core 2 and 3, respectively. */ 799*2a7db7a6SVincenzo Maffione if (i + req_cpus > nma_get_nrings(na, NR_RX)) { 800*2a7db7a6SVincenzo Maffione D("Rings %u-%u not in range (have %d rings)", 801*2a7db7a6SVincenzo Maffione i, i + req_cpus, nma_get_nrings(na, NR_RX)); 802*2a7db7a6SVincenzo Maffione return EINVAL; 803*2a7db7a6SVincenzo Maffione } 804*2a7db7a6SVincenzo Maffione qfirst = i; 805*2a7db7a6SVincenzo Maffione qlast = qfirst + req_cpus; 806*2a7db7a6SVincenzo Maffione core_from = qfirst; 807*2a7db7a6SVincenzo Maffione 808*2a7db7a6SVincenzo Maffione } else if (req->nr_mode == NETMAP_POLLING_MODE_SINGLE_CPU) { 809*2a7db7a6SVincenzo Maffione /* Poll all the rings using a core specified by nr_first_cpu_id. 810*2a7db7a6SVincenzo Maffione * the number of cores must be 1. */ 811*2a7db7a6SVincenzo Maffione if (req_cpus != 1) { 812*2a7db7a6SVincenzo Maffione D("ncpus must be 1 for NETMAP_POLLING_MODE_SINGLE_CPU " 813*2a7db7a6SVincenzo Maffione "(was %d)", req_cpus); 814*2a7db7a6SVincenzo Maffione return EINVAL; 815*2a7db7a6SVincenzo Maffione } 816*2a7db7a6SVincenzo Maffione qfirst = 0; 817*2a7db7a6SVincenzo Maffione qlast = nma_get_nrings(na, NR_RX); 818*2a7db7a6SVincenzo Maffione core_from = i; 819*2a7db7a6SVincenzo Maffione } else { 820*2a7db7a6SVincenzo Maffione D("Invalid polling mode"); 821*2a7db7a6SVincenzo Maffione return EINVAL; 822*2a7db7a6SVincenzo Maffione } 823*2a7db7a6SVincenzo Maffione 824*2a7db7a6SVincenzo Maffione bps->mode = req->nr_mode; 825*2a7db7a6SVincenzo Maffione bps->qfirst = qfirst; 826*2a7db7a6SVincenzo Maffione bps->qlast = qlast; 827*2a7db7a6SVincenzo Maffione bps->cpu_from = core_from; 828*2a7db7a6SVincenzo Maffione bps->ncpus = req_cpus; 829*2a7db7a6SVincenzo Maffione D("%s qfirst %u qlast %u cpu_from %u ncpus %u", 830*2a7db7a6SVincenzo Maffione req->nr_mode == NETMAP_POLLING_MODE_MULTI_CPU ? 831*2a7db7a6SVincenzo Maffione "MULTI" : "SINGLE", 832*2a7db7a6SVincenzo Maffione qfirst, qlast, core_from, req_cpus); 833*2a7db7a6SVincenzo Maffione return 0; 834*2a7db7a6SVincenzo Maffione } 835*2a7db7a6SVincenzo Maffione 836*2a7db7a6SVincenzo Maffione static int 837*2a7db7a6SVincenzo Maffione nm_bdg_ctl_polling_start(struct nmreq_vale_polling *req, struct netmap_adapter *na) 838*2a7db7a6SVincenzo Maffione { 839*2a7db7a6SVincenzo Maffione struct nm_bdg_polling_state *bps; 840*2a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna; 841*2a7db7a6SVincenzo Maffione int error; 842*2a7db7a6SVincenzo Maffione 843*2a7db7a6SVincenzo Maffione bna = (struct netmap_bwrap_adapter *)na; 844*2a7db7a6SVincenzo Maffione if (bna->na_polling_state) { 845*2a7db7a6SVincenzo Maffione D("ERROR adapter already in polling mode"); 846*2a7db7a6SVincenzo Maffione return EFAULT; 847*2a7db7a6SVincenzo Maffione } 848*2a7db7a6SVincenzo Maffione 849*2a7db7a6SVincenzo Maffione bps = nm_os_malloc(sizeof(*bps)); 850*2a7db7a6SVincenzo Maffione if (!bps) 851*2a7db7a6SVincenzo Maffione return ENOMEM; 852*2a7db7a6SVincenzo Maffione bps->configured = false; 853*2a7db7a6SVincenzo Maffione bps->stopped = true; 854*2a7db7a6SVincenzo Maffione 855*2a7db7a6SVincenzo Maffione if (get_polling_cfg(req, na, bps)) { 856*2a7db7a6SVincenzo Maffione nm_os_free(bps); 857*2a7db7a6SVincenzo Maffione return EINVAL; 858*2a7db7a6SVincenzo Maffione } 859*2a7db7a6SVincenzo Maffione 860*2a7db7a6SVincenzo Maffione if (nm_bdg_create_kthreads(bps)) { 861*2a7db7a6SVincenzo Maffione nm_os_free(bps); 862*2a7db7a6SVincenzo Maffione return EFAULT; 863*2a7db7a6SVincenzo Maffione } 864*2a7db7a6SVincenzo Maffione 865*2a7db7a6SVincenzo Maffione bps->configured = true; 866*2a7db7a6SVincenzo Maffione bna->na_polling_state = bps; 867*2a7db7a6SVincenzo Maffione bps->bna = bna; 868*2a7db7a6SVincenzo Maffione 869*2a7db7a6SVincenzo Maffione /* disable interrupts if possible */ 870*2a7db7a6SVincenzo Maffione nma_intr_enable(bna->hwna, 0); 871*2a7db7a6SVincenzo Maffione /* start kthread now */ 872*2a7db7a6SVincenzo Maffione error = nm_bdg_polling_start_kthreads(bps); 873*2a7db7a6SVincenzo Maffione if (error) { 874*2a7db7a6SVincenzo Maffione D("ERROR nm_bdg_polling_start_kthread()"); 875*2a7db7a6SVincenzo Maffione nm_os_free(bps->kthreads); 876*2a7db7a6SVincenzo Maffione nm_os_free(bps); 877*2a7db7a6SVincenzo Maffione bna->na_polling_state = NULL; 878*2a7db7a6SVincenzo Maffione nma_intr_enable(bna->hwna, 1); 879*2a7db7a6SVincenzo Maffione } 880*2a7db7a6SVincenzo Maffione return error; 881*2a7db7a6SVincenzo Maffione } 882*2a7db7a6SVincenzo Maffione 883*2a7db7a6SVincenzo Maffione static int 884*2a7db7a6SVincenzo Maffione nm_bdg_ctl_polling_stop(struct netmap_adapter *na) 885*2a7db7a6SVincenzo Maffione { 886*2a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter *)na; 887*2a7db7a6SVincenzo Maffione struct nm_bdg_polling_state *bps; 888*2a7db7a6SVincenzo Maffione 889*2a7db7a6SVincenzo Maffione if (!bna->na_polling_state) { 890*2a7db7a6SVincenzo Maffione D("ERROR adapter is not in polling mode"); 891*2a7db7a6SVincenzo Maffione return EFAULT; 892*2a7db7a6SVincenzo Maffione } 893*2a7db7a6SVincenzo Maffione bps = bna->na_polling_state; 894*2a7db7a6SVincenzo Maffione nm_bdg_polling_stop_delete_kthreads(bna->na_polling_state); 895*2a7db7a6SVincenzo Maffione bps->configured = false; 896*2a7db7a6SVincenzo Maffione nm_os_free(bps); 897*2a7db7a6SVincenzo Maffione bna->na_polling_state = NULL; 898*2a7db7a6SVincenzo Maffione /* reenable interrupts */ 899*2a7db7a6SVincenzo Maffione nma_intr_enable(bna->hwna, 1); 900*2a7db7a6SVincenzo Maffione return 0; 901*2a7db7a6SVincenzo Maffione } 902*2a7db7a6SVincenzo Maffione 903*2a7db7a6SVincenzo Maffione int 904*2a7db7a6SVincenzo Maffione nm_bdg_polling(struct nmreq_header *hdr) 905*2a7db7a6SVincenzo Maffione { 906*2a7db7a6SVincenzo Maffione struct nmreq_vale_polling *req = 907*2a7db7a6SVincenzo Maffione (struct nmreq_vale_polling *)(uintptr_t)hdr->nr_body; 908*2a7db7a6SVincenzo Maffione struct netmap_adapter *na = NULL; 909*2a7db7a6SVincenzo Maffione int error = 0; 910*2a7db7a6SVincenzo Maffione 911*2a7db7a6SVincenzo Maffione NMG_LOCK(); 912*2a7db7a6SVincenzo Maffione error = netmap_get_vale_na(hdr, &na, NULL, /*create=*/0); 913*2a7db7a6SVincenzo Maffione if (na && !error) { 914*2a7db7a6SVincenzo Maffione if (!nm_is_bwrap(na)) { 915*2a7db7a6SVincenzo Maffione error = EOPNOTSUPP; 916*2a7db7a6SVincenzo Maffione } else if (hdr->nr_reqtype == NETMAP_BDG_POLLING_ON) { 917*2a7db7a6SVincenzo Maffione error = nm_bdg_ctl_polling_start(req, na); 918*2a7db7a6SVincenzo Maffione if (!error) 919*2a7db7a6SVincenzo Maffione netmap_adapter_get(na); 920*2a7db7a6SVincenzo Maffione } else { 921*2a7db7a6SVincenzo Maffione error = nm_bdg_ctl_polling_stop(na); 922*2a7db7a6SVincenzo Maffione if (!error) 923*2a7db7a6SVincenzo Maffione netmap_adapter_put(na); 924*2a7db7a6SVincenzo Maffione } 925*2a7db7a6SVincenzo Maffione netmap_adapter_put(na); 926*2a7db7a6SVincenzo Maffione } else if (!na && !error) { 927*2a7db7a6SVincenzo Maffione /* Not VALE port. */ 928*2a7db7a6SVincenzo Maffione error = EINVAL; 929*2a7db7a6SVincenzo Maffione } 930*2a7db7a6SVincenzo Maffione NMG_UNLOCK(); 931*2a7db7a6SVincenzo Maffione 932*2a7db7a6SVincenzo Maffione return error; 933*2a7db7a6SVincenzo Maffione } 934*2a7db7a6SVincenzo Maffione 935*2a7db7a6SVincenzo Maffione /* Process NETMAP_REQ_VALE_LIST. */ 936*2a7db7a6SVincenzo Maffione int 937*2a7db7a6SVincenzo Maffione netmap_bdg_list(struct nmreq_header *hdr) 938*2a7db7a6SVincenzo Maffione { 939*2a7db7a6SVincenzo Maffione struct nmreq_vale_list *req = 940*2a7db7a6SVincenzo Maffione (struct nmreq_vale_list *)(uintptr_t)hdr->nr_body; 941*2a7db7a6SVincenzo Maffione int namelen = strlen(hdr->nr_name); 942*2a7db7a6SVincenzo Maffione struct nm_bridge *b, *bridges; 943*2a7db7a6SVincenzo Maffione struct netmap_vp_adapter *vpna; 944*2a7db7a6SVincenzo Maffione int error = 0, i, j; 945*2a7db7a6SVincenzo Maffione u_int num_bridges; 946*2a7db7a6SVincenzo Maffione 947*2a7db7a6SVincenzo Maffione netmap_bns_getbridges(&bridges, &num_bridges); 948*2a7db7a6SVincenzo Maffione 949*2a7db7a6SVincenzo Maffione /* this is used to enumerate bridges and ports */ 950*2a7db7a6SVincenzo Maffione if (namelen) { /* look up indexes of bridge and port */ 951*2a7db7a6SVincenzo Maffione if (strncmp(hdr->nr_name, NM_BDG_NAME, 952*2a7db7a6SVincenzo Maffione strlen(NM_BDG_NAME))) { 953*2a7db7a6SVincenzo Maffione return EINVAL; 954*2a7db7a6SVincenzo Maffione } 955*2a7db7a6SVincenzo Maffione NMG_LOCK(); 956*2a7db7a6SVincenzo Maffione b = nm_find_bridge(hdr->nr_name, 0 /* don't create */, NULL); 957*2a7db7a6SVincenzo Maffione if (!b) { 958*2a7db7a6SVincenzo Maffione NMG_UNLOCK(); 959*2a7db7a6SVincenzo Maffione return ENOENT; 960*2a7db7a6SVincenzo Maffione } 961*2a7db7a6SVincenzo Maffione 962*2a7db7a6SVincenzo Maffione req->nr_bridge_idx = b - bridges; /* bridge index */ 963*2a7db7a6SVincenzo Maffione req->nr_port_idx = NM_BDG_NOPORT; 964*2a7db7a6SVincenzo Maffione for (j = 0; j < b->bdg_active_ports; j++) { 965*2a7db7a6SVincenzo Maffione i = b->bdg_port_index[j]; 966*2a7db7a6SVincenzo Maffione vpna = b->bdg_ports[i]; 967*2a7db7a6SVincenzo Maffione if (vpna == NULL) { 968*2a7db7a6SVincenzo Maffione D("This should not happen"); 969*2a7db7a6SVincenzo Maffione continue; 970*2a7db7a6SVincenzo Maffione } 971*2a7db7a6SVincenzo Maffione /* the former and the latter identify a 972*2a7db7a6SVincenzo Maffione * virtual port and a NIC, respectively 973*2a7db7a6SVincenzo Maffione */ 974*2a7db7a6SVincenzo Maffione if (!strcmp(vpna->up.name, hdr->nr_name)) { 975*2a7db7a6SVincenzo Maffione req->nr_port_idx = i; /* port index */ 976*2a7db7a6SVincenzo Maffione break; 977*2a7db7a6SVincenzo Maffione } 978*2a7db7a6SVincenzo Maffione } 979*2a7db7a6SVincenzo Maffione NMG_UNLOCK(); 980*2a7db7a6SVincenzo Maffione } else { 981*2a7db7a6SVincenzo Maffione /* return the first non-empty entry starting from 982*2a7db7a6SVincenzo Maffione * bridge nr_arg1 and port nr_arg2. 983*2a7db7a6SVincenzo Maffione * 984*2a7db7a6SVincenzo Maffione * Users can detect the end of the same bridge by 985*2a7db7a6SVincenzo Maffione * seeing the new and old value of nr_arg1, and can 986*2a7db7a6SVincenzo Maffione * detect the end of all the bridge by error != 0 987*2a7db7a6SVincenzo Maffione */ 988*2a7db7a6SVincenzo Maffione i = req->nr_bridge_idx; 989*2a7db7a6SVincenzo Maffione j = req->nr_port_idx; 990*2a7db7a6SVincenzo Maffione 991*2a7db7a6SVincenzo Maffione NMG_LOCK(); 992*2a7db7a6SVincenzo Maffione for (error = ENOENT; i < NM_BRIDGES; i++) { 993*2a7db7a6SVincenzo Maffione b = bridges + i; 994*2a7db7a6SVincenzo Maffione for ( ; j < NM_BDG_MAXPORTS; j++) { 995*2a7db7a6SVincenzo Maffione if (b->bdg_ports[j] == NULL) 996*2a7db7a6SVincenzo Maffione continue; 997*2a7db7a6SVincenzo Maffione vpna = b->bdg_ports[j]; 998*2a7db7a6SVincenzo Maffione /* write back the VALE switch name */ 999*2a7db7a6SVincenzo Maffione strncpy(hdr->nr_name, vpna->up.name, 1000*2a7db7a6SVincenzo Maffione (size_t)IFNAMSIZ); 1001*2a7db7a6SVincenzo Maffione error = 0; 1002*2a7db7a6SVincenzo Maffione goto out; 1003*2a7db7a6SVincenzo Maffione } 1004*2a7db7a6SVincenzo Maffione j = 0; /* following bridges scan from 0 */ 1005*2a7db7a6SVincenzo Maffione } 1006*2a7db7a6SVincenzo Maffione out: 1007*2a7db7a6SVincenzo Maffione req->nr_bridge_idx = i; 1008*2a7db7a6SVincenzo Maffione req->nr_port_idx = j; 1009*2a7db7a6SVincenzo Maffione NMG_UNLOCK(); 1010*2a7db7a6SVincenzo Maffione } 1011*2a7db7a6SVincenzo Maffione 1012*2a7db7a6SVincenzo Maffione return error; 1013*2a7db7a6SVincenzo Maffione } 1014*2a7db7a6SVincenzo Maffione 1015*2a7db7a6SVincenzo Maffione /* Called by external kernel modules (e.g., Openvswitch). 1016*2a7db7a6SVincenzo Maffione * to set configure/lookup/dtor functions of a VALE instance. 1017*2a7db7a6SVincenzo Maffione * Register callbacks to the given bridge. 'name' may be just 1018*2a7db7a6SVincenzo Maffione * bridge's name (including ':' if it is not just NM_BDG_NAME). 1019*2a7db7a6SVincenzo Maffione * 1020*2a7db7a6SVincenzo Maffione * Called without NMG_LOCK. 1021*2a7db7a6SVincenzo Maffione */ 1022*2a7db7a6SVincenzo Maffione 1023*2a7db7a6SVincenzo Maffione int 1024*2a7db7a6SVincenzo Maffione netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data, void *auth_token) 1025*2a7db7a6SVincenzo Maffione { 1026*2a7db7a6SVincenzo Maffione struct nm_bridge *b; 1027*2a7db7a6SVincenzo Maffione int error = 0; 1028*2a7db7a6SVincenzo Maffione 1029*2a7db7a6SVincenzo Maffione NMG_LOCK(); 1030*2a7db7a6SVincenzo Maffione b = nm_find_bridge(name, 0 /* don't create */, NULL); 1031*2a7db7a6SVincenzo Maffione if (!b) { 1032*2a7db7a6SVincenzo Maffione error = ENXIO; 1033*2a7db7a6SVincenzo Maffione goto unlock_regops; 1034*2a7db7a6SVincenzo Maffione } 1035*2a7db7a6SVincenzo Maffione if (!nm_bdg_valid_auth_token(b, auth_token)) { 1036*2a7db7a6SVincenzo Maffione error = EACCES; 1037*2a7db7a6SVincenzo Maffione goto unlock_regops; 1038*2a7db7a6SVincenzo Maffione } 1039*2a7db7a6SVincenzo Maffione 1040*2a7db7a6SVincenzo Maffione BDG_WLOCK(b); 1041*2a7db7a6SVincenzo Maffione if (!bdg_ops) { 1042*2a7db7a6SVincenzo Maffione /* resetting the bridge */ 1043*2a7db7a6SVincenzo Maffione bzero(b->ht, sizeof(struct nm_hash_ent) * NM_BDG_HASH); 1044*2a7db7a6SVincenzo Maffione b->bdg_ops = NULL; 1045*2a7db7a6SVincenzo Maffione b->private_data = b->ht; 1046*2a7db7a6SVincenzo Maffione } else { 1047*2a7db7a6SVincenzo Maffione /* modifying the bridge */ 1048*2a7db7a6SVincenzo Maffione b->private_data = private_data; 1049*2a7db7a6SVincenzo Maffione b->bdg_ops = bdg_ops; 1050*2a7db7a6SVincenzo Maffione } 1051*2a7db7a6SVincenzo Maffione BDG_WUNLOCK(b); 1052*2a7db7a6SVincenzo Maffione 1053*2a7db7a6SVincenzo Maffione unlock_regops: 1054*2a7db7a6SVincenzo Maffione NMG_UNLOCK(); 1055*2a7db7a6SVincenzo Maffione return error; 1056*2a7db7a6SVincenzo Maffione } 1057*2a7db7a6SVincenzo Maffione 1058*2a7db7a6SVincenzo Maffione 1059*2a7db7a6SVincenzo Maffione int 1060*2a7db7a6SVincenzo Maffione netmap_bdg_config(struct nm_ifreq *nr) 1061*2a7db7a6SVincenzo Maffione { 1062*2a7db7a6SVincenzo Maffione struct nm_bridge *b; 1063*2a7db7a6SVincenzo Maffione int error = EINVAL; 1064*2a7db7a6SVincenzo Maffione 1065*2a7db7a6SVincenzo Maffione NMG_LOCK(); 1066*2a7db7a6SVincenzo Maffione b = nm_find_bridge(nr->nifr_name, 0, NULL); 1067*2a7db7a6SVincenzo Maffione if (!b) { 1068*2a7db7a6SVincenzo Maffione NMG_UNLOCK(); 1069*2a7db7a6SVincenzo Maffione return error; 1070*2a7db7a6SVincenzo Maffione } 1071*2a7db7a6SVincenzo Maffione NMG_UNLOCK(); 1072*2a7db7a6SVincenzo Maffione /* Don't call config() with NMG_LOCK() held */ 1073*2a7db7a6SVincenzo Maffione BDG_RLOCK(b); 1074*2a7db7a6SVincenzo Maffione if (b->bdg_ops->config != NULL) 1075*2a7db7a6SVincenzo Maffione error = b->bdg_ops->config(nr); 1076*2a7db7a6SVincenzo Maffione BDG_RUNLOCK(b); 1077*2a7db7a6SVincenzo Maffione return error; 1078*2a7db7a6SVincenzo Maffione } 1079*2a7db7a6SVincenzo Maffione 1080*2a7db7a6SVincenzo Maffione 1081*2a7db7a6SVincenzo Maffione /* nm_register callback for VALE ports */ 1082*2a7db7a6SVincenzo Maffione int 1083*2a7db7a6SVincenzo Maffione netmap_vp_reg(struct netmap_adapter *na, int onoff) 1084*2a7db7a6SVincenzo Maffione { 1085*2a7db7a6SVincenzo Maffione struct netmap_vp_adapter *vpna = 1086*2a7db7a6SVincenzo Maffione (struct netmap_vp_adapter*)na; 1087*2a7db7a6SVincenzo Maffione enum txrx t; 1088*2a7db7a6SVincenzo Maffione int i; 1089*2a7db7a6SVincenzo Maffione 1090*2a7db7a6SVincenzo Maffione /* persistent ports may be put in netmap mode 1091*2a7db7a6SVincenzo Maffione * before being attached to a bridge 1092*2a7db7a6SVincenzo Maffione */ 1093*2a7db7a6SVincenzo Maffione if (vpna->na_bdg) 1094*2a7db7a6SVincenzo Maffione BDG_WLOCK(vpna->na_bdg); 1095*2a7db7a6SVincenzo Maffione if (onoff) { 1096*2a7db7a6SVincenzo Maffione for_rx_tx(t) { 1097*2a7db7a6SVincenzo Maffione for (i = 0; i < netmap_real_rings(na, t); i++) { 1098*2a7db7a6SVincenzo Maffione struct netmap_kring *kring = NMR(na, t)[i]; 1099*2a7db7a6SVincenzo Maffione 1100*2a7db7a6SVincenzo Maffione if (nm_kring_pending_on(kring)) 1101*2a7db7a6SVincenzo Maffione kring->nr_mode = NKR_NETMAP_ON; 1102*2a7db7a6SVincenzo Maffione } 1103*2a7db7a6SVincenzo Maffione } 1104*2a7db7a6SVincenzo Maffione if (na->active_fds == 0) 1105*2a7db7a6SVincenzo Maffione na->na_flags |= NAF_NETMAP_ON; 1106*2a7db7a6SVincenzo Maffione /* XXX on FreeBSD, persistent VALE ports should also 1107*2a7db7a6SVincenzo Maffione * toggle IFCAP_NETMAP in na->ifp (2014-03-16) 1108*2a7db7a6SVincenzo Maffione */ 1109*2a7db7a6SVincenzo Maffione } else { 1110*2a7db7a6SVincenzo Maffione if (na->active_fds == 0) 1111*2a7db7a6SVincenzo Maffione na->na_flags &= ~NAF_NETMAP_ON; 1112*2a7db7a6SVincenzo Maffione for_rx_tx(t) { 1113*2a7db7a6SVincenzo Maffione for (i = 0; i < netmap_real_rings(na, t); i++) { 1114*2a7db7a6SVincenzo Maffione struct netmap_kring *kring = NMR(na, t)[i]; 1115*2a7db7a6SVincenzo Maffione 1116*2a7db7a6SVincenzo Maffione if (nm_kring_pending_off(kring)) 1117*2a7db7a6SVincenzo Maffione kring->nr_mode = NKR_NETMAP_OFF; 1118*2a7db7a6SVincenzo Maffione } 1119*2a7db7a6SVincenzo Maffione } 1120*2a7db7a6SVincenzo Maffione } 1121*2a7db7a6SVincenzo Maffione if (vpna->na_bdg) 1122*2a7db7a6SVincenzo Maffione BDG_WUNLOCK(vpna->na_bdg); 1123*2a7db7a6SVincenzo Maffione return 0; 1124*2a7db7a6SVincenzo Maffione } 1125*2a7db7a6SVincenzo Maffione 1126*2a7db7a6SVincenzo Maffione 1127*2a7db7a6SVincenzo Maffione /* rxsync code used by VALE ports nm_rxsync callback and also 1128*2a7db7a6SVincenzo Maffione * internally by the brwap 1129*2a7db7a6SVincenzo Maffione */ 1130*2a7db7a6SVincenzo Maffione static int 1131*2a7db7a6SVincenzo Maffione netmap_vp_rxsync_locked(struct netmap_kring *kring, int flags) 1132*2a7db7a6SVincenzo Maffione { 1133*2a7db7a6SVincenzo Maffione struct netmap_adapter *na = kring->na; 1134*2a7db7a6SVincenzo Maffione struct netmap_ring *ring = kring->ring; 1135*2a7db7a6SVincenzo Maffione u_int nm_i, lim = kring->nkr_num_slots - 1; 1136*2a7db7a6SVincenzo Maffione u_int head = kring->rhead; 1137*2a7db7a6SVincenzo Maffione int n; 1138*2a7db7a6SVincenzo Maffione 1139*2a7db7a6SVincenzo Maffione if (head > lim) { 1140*2a7db7a6SVincenzo Maffione D("ouch dangerous reset!!!"); 1141*2a7db7a6SVincenzo Maffione n = netmap_ring_reinit(kring); 1142*2a7db7a6SVincenzo Maffione goto done; 1143*2a7db7a6SVincenzo Maffione } 1144*2a7db7a6SVincenzo Maffione 1145*2a7db7a6SVincenzo Maffione /* First part, import newly received packets. */ 1146*2a7db7a6SVincenzo Maffione /* actually nothing to do here, they are already in the kring */ 1147*2a7db7a6SVincenzo Maffione 1148*2a7db7a6SVincenzo Maffione /* Second part, skip past packets that userspace has released. */ 1149*2a7db7a6SVincenzo Maffione nm_i = kring->nr_hwcur; 1150*2a7db7a6SVincenzo Maffione if (nm_i != head) { 1151*2a7db7a6SVincenzo Maffione /* consistency check, but nothing really important here */ 1152*2a7db7a6SVincenzo Maffione for (n = 0; likely(nm_i != head); n++) { 1153*2a7db7a6SVincenzo Maffione struct netmap_slot *slot = &ring->slot[nm_i]; 1154*2a7db7a6SVincenzo Maffione void *addr = NMB(na, slot); 1155*2a7db7a6SVincenzo Maffione 1156*2a7db7a6SVincenzo Maffione if (addr == NETMAP_BUF_BASE(kring->na)) { /* bad buf */ 1157*2a7db7a6SVincenzo Maffione D("bad buffer index %d, ignore ?", 1158*2a7db7a6SVincenzo Maffione slot->buf_idx); 1159*2a7db7a6SVincenzo Maffione } 1160*2a7db7a6SVincenzo Maffione slot->flags &= ~NS_BUF_CHANGED; 1161*2a7db7a6SVincenzo Maffione nm_i = nm_next(nm_i, lim); 1162*2a7db7a6SVincenzo Maffione } 1163*2a7db7a6SVincenzo Maffione kring->nr_hwcur = head; 1164*2a7db7a6SVincenzo Maffione } 1165*2a7db7a6SVincenzo Maffione 1166*2a7db7a6SVincenzo Maffione n = 0; 1167*2a7db7a6SVincenzo Maffione done: 1168*2a7db7a6SVincenzo Maffione return n; 1169*2a7db7a6SVincenzo Maffione } 1170*2a7db7a6SVincenzo Maffione 1171*2a7db7a6SVincenzo Maffione /* 1172*2a7db7a6SVincenzo Maffione * nm_rxsync callback for VALE ports 1173*2a7db7a6SVincenzo Maffione * user process reading from a VALE switch. 1174*2a7db7a6SVincenzo Maffione * Already protected against concurrent calls from userspace, 1175*2a7db7a6SVincenzo Maffione * but we must acquire the queue's lock to protect against 1176*2a7db7a6SVincenzo Maffione * writers on the same queue. 1177*2a7db7a6SVincenzo Maffione */ 1178*2a7db7a6SVincenzo Maffione int 1179*2a7db7a6SVincenzo Maffione netmap_vp_rxsync(struct netmap_kring *kring, int flags) 1180*2a7db7a6SVincenzo Maffione { 1181*2a7db7a6SVincenzo Maffione int n; 1182*2a7db7a6SVincenzo Maffione 1183*2a7db7a6SVincenzo Maffione mtx_lock(&kring->q_lock); 1184*2a7db7a6SVincenzo Maffione n = netmap_vp_rxsync_locked(kring, flags); 1185*2a7db7a6SVincenzo Maffione mtx_unlock(&kring->q_lock); 1186*2a7db7a6SVincenzo Maffione return n; 1187*2a7db7a6SVincenzo Maffione } 1188*2a7db7a6SVincenzo Maffione 1189*2a7db7a6SVincenzo Maffione int 1190*2a7db7a6SVincenzo Maffione netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna, 1191*2a7db7a6SVincenzo Maffione struct netmap_bdg_ops *ops) 1192*2a7db7a6SVincenzo Maffione { 1193*2a7db7a6SVincenzo Maffione return ops->bwrap_attach(nr_name, hwna); 1194*2a7db7a6SVincenzo Maffione } 1195*2a7db7a6SVincenzo Maffione 1196*2a7db7a6SVincenzo Maffione 1197*2a7db7a6SVincenzo Maffione /* Bridge wrapper code (bwrap). 1198*2a7db7a6SVincenzo Maffione * This is used to connect a non-VALE-port netmap_adapter (hwna) to a 1199*2a7db7a6SVincenzo Maffione * VALE switch. 1200*2a7db7a6SVincenzo Maffione * The main task is to swap the meaning of tx and rx rings to match the 1201*2a7db7a6SVincenzo Maffione * expectations of the VALE switch code (see nm_bdg_flush). 1202*2a7db7a6SVincenzo Maffione * 1203*2a7db7a6SVincenzo Maffione * The bwrap works by interposing a netmap_bwrap_adapter between the 1204*2a7db7a6SVincenzo Maffione * rest of the system and the hwna. The netmap_bwrap_adapter looks like 1205*2a7db7a6SVincenzo Maffione * a netmap_vp_adapter to the rest the system, but, internally, it 1206*2a7db7a6SVincenzo Maffione * translates all callbacks to what the hwna expects. 1207*2a7db7a6SVincenzo Maffione * 1208*2a7db7a6SVincenzo Maffione * Note that we have to intercept callbacks coming from two sides: 1209*2a7db7a6SVincenzo Maffione * 1210*2a7db7a6SVincenzo Maffione * - callbacks coming from the netmap module are intercepted by 1211*2a7db7a6SVincenzo Maffione * passing around the netmap_bwrap_adapter instead of the hwna 1212*2a7db7a6SVincenzo Maffione * 1213*2a7db7a6SVincenzo Maffione * - callbacks coming from outside of the netmap module only know 1214*2a7db7a6SVincenzo Maffione * about the hwna. This, however, only happens in interrupt 1215*2a7db7a6SVincenzo Maffione * handlers, where only the hwna->nm_notify callback is called. 1216*2a7db7a6SVincenzo Maffione * What the bwrap does is to overwrite the hwna->nm_notify callback 1217*2a7db7a6SVincenzo Maffione * with its own netmap_bwrap_intr_notify. 1218*2a7db7a6SVincenzo Maffione * XXX This assumes that the hwna->nm_notify callback was the 1219*2a7db7a6SVincenzo Maffione * standard netmap_notify(), as it is the case for nic adapters. 1220*2a7db7a6SVincenzo Maffione * Any additional action performed by hwna->nm_notify will not be 1221*2a7db7a6SVincenzo Maffione * performed by netmap_bwrap_intr_notify. 1222*2a7db7a6SVincenzo Maffione * 1223*2a7db7a6SVincenzo Maffione * Additionally, the bwrap can optionally attach the host rings pair 1224*2a7db7a6SVincenzo Maffione * of the wrapped adapter to a different port of the switch. 1225*2a7db7a6SVincenzo Maffione */ 1226*2a7db7a6SVincenzo Maffione 1227*2a7db7a6SVincenzo Maffione 1228*2a7db7a6SVincenzo Maffione static void 1229*2a7db7a6SVincenzo Maffione netmap_bwrap_dtor(struct netmap_adapter *na) 1230*2a7db7a6SVincenzo Maffione { 1231*2a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter*)na; 1232*2a7db7a6SVincenzo Maffione struct netmap_adapter *hwna = bna->hwna; 1233*2a7db7a6SVincenzo Maffione struct nm_bridge *b = bna->up.na_bdg, 1234*2a7db7a6SVincenzo Maffione *bh = bna->host.na_bdg; 1235*2a7db7a6SVincenzo Maffione 1236*2a7db7a6SVincenzo Maffione if (bna->host.up.nm_mem) 1237*2a7db7a6SVincenzo Maffione netmap_mem_put(bna->host.up.nm_mem); 1238*2a7db7a6SVincenzo Maffione 1239*2a7db7a6SVincenzo Maffione if (b) { 1240*2a7db7a6SVincenzo Maffione netmap_bdg_detach_common(b, bna->up.bdg_port, 1241*2a7db7a6SVincenzo Maffione (bh ? bna->host.bdg_port : -1)); 1242*2a7db7a6SVincenzo Maffione } 1243*2a7db7a6SVincenzo Maffione 1244*2a7db7a6SVincenzo Maffione ND("na %p", na); 1245*2a7db7a6SVincenzo Maffione na->ifp = NULL; 1246*2a7db7a6SVincenzo Maffione bna->host.up.ifp = NULL; 1247*2a7db7a6SVincenzo Maffione hwna->na_vp = bna->saved_na_vp; 1248*2a7db7a6SVincenzo Maffione hwna->na_hostvp = NULL; 1249*2a7db7a6SVincenzo Maffione hwna->na_private = NULL; 1250*2a7db7a6SVincenzo Maffione hwna->na_flags &= ~NAF_BUSY; 1251*2a7db7a6SVincenzo Maffione netmap_adapter_put(hwna); 1252*2a7db7a6SVincenzo Maffione 1253*2a7db7a6SVincenzo Maffione } 1254*2a7db7a6SVincenzo Maffione 1255*2a7db7a6SVincenzo Maffione 1256*2a7db7a6SVincenzo Maffione /* 1257*2a7db7a6SVincenzo Maffione * Intr callback for NICs connected to a bridge. 1258*2a7db7a6SVincenzo Maffione * Simply ignore tx interrupts (maybe we could try to recover space ?) 1259*2a7db7a6SVincenzo Maffione * and pass received packets from nic to the bridge. 1260*2a7db7a6SVincenzo Maffione * 1261*2a7db7a6SVincenzo Maffione * XXX TODO check locking: this is called from the interrupt 1262*2a7db7a6SVincenzo Maffione * handler so we should make sure that the interface is not 1263*2a7db7a6SVincenzo Maffione * disconnected while passing down an interrupt. 1264*2a7db7a6SVincenzo Maffione * 1265*2a7db7a6SVincenzo Maffione * Note, no user process can access this NIC or the host stack. 1266*2a7db7a6SVincenzo Maffione * The only part of the ring that is significant are the slots, 1267*2a7db7a6SVincenzo Maffione * and head/cur/tail are set from the kring as needed 1268*2a7db7a6SVincenzo Maffione * (part as a receive ring, part as a transmit ring). 1269*2a7db7a6SVincenzo Maffione * 1270*2a7db7a6SVincenzo Maffione * callback that overwrites the hwna notify callback. 1271*2a7db7a6SVincenzo Maffione * Packets come from the outside or from the host stack and are put on an 1272*2a7db7a6SVincenzo Maffione * hwna rx ring. 1273*2a7db7a6SVincenzo Maffione * The bridge wrapper then sends the packets through the bridge. 1274*2a7db7a6SVincenzo Maffione */ 1275*2a7db7a6SVincenzo Maffione static int 1276*2a7db7a6SVincenzo Maffione netmap_bwrap_intr_notify(struct netmap_kring *kring, int flags) 1277*2a7db7a6SVincenzo Maffione { 1278*2a7db7a6SVincenzo Maffione struct netmap_adapter *na = kring->na; 1279*2a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna = na->na_private; 1280*2a7db7a6SVincenzo Maffione struct netmap_kring *bkring; 1281*2a7db7a6SVincenzo Maffione struct netmap_vp_adapter *vpna = &bna->up; 1282*2a7db7a6SVincenzo Maffione u_int ring_nr = kring->ring_id; 1283*2a7db7a6SVincenzo Maffione int ret = NM_IRQ_COMPLETED; 1284*2a7db7a6SVincenzo Maffione int error; 1285*2a7db7a6SVincenzo Maffione 1286*2a7db7a6SVincenzo Maffione if (netmap_verbose) 1287*2a7db7a6SVincenzo Maffione D("%s %s 0x%x", na->name, kring->name, flags); 1288*2a7db7a6SVincenzo Maffione 1289*2a7db7a6SVincenzo Maffione bkring = vpna->up.tx_rings[ring_nr]; 1290*2a7db7a6SVincenzo Maffione 1291*2a7db7a6SVincenzo Maffione /* make sure the ring is not disabled */ 1292*2a7db7a6SVincenzo Maffione if (nm_kr_tryget(kring, 0 /* can't sleep */, NULL)) { 1293*2a7db7a6SVincenzo Maffione return EIO; 1294*2a7db7a6SVincenzo Maffione } 1295*2a7db7a6SVincenzo Maffione 1296*2a7db7a6SVincenzo Maffione if (netmap_verbose) 1297*2a7db7a6SVincenzo Maffione D("%s head %d cur %d tail %d", na->name, 1298*2a7db7a6SVincenzo Maffione kring->rhead, kring->rcur, kring->rtail); 1299*2a7db7a6SVincenzo Maffione 1300*2a7db7a6SVincenzo Maffione /* simulate a user wakeup on the rx ring 1301*2a7db7a6SVincenzo Maffione * fetch packets that have arrived. 1302*2a7db7a6SVincenzo Maffione */ 1303*2a7db7a6SVincenzo Maffione error = kring->nm_sync(kring, 0); 1304*2a7db7a6SVincenzo Maffione if (error) 1305*2a7db7a6SVincenzo Maffione goto put_out; 1306*2a7db7a6SVincenzo Maffione if (kring->nr_hwcur == kring->nr_hwtail) { 1307*2a7db7a6SVincenzo Maffione if (netmap_verbose) 1308*2a7db7a6SVincenzo Maffione D("how strange, interrupt with no packets on %s", 1309*2a7db7a6SVincenzo Maffione na->name); 1310*2a7db7a6SVincenzo Maffione goto put_out; 1311*2a7db7a6SVincenzo Maffione } 1312*2a7db7a6SVincenzo Maffione 1313*2a7db7a6SVincenzo Maffione /* new packets are kring->rcur to kring->nr_hwtail, and the bkring 1314*2a7db7a6SVincenzo Maffione * had hwcur == bkring->rhead. So advance bkring->rhead to kring->nr_hwtail 1315*2a7db7a6SVincenzo Maffione * to push all packets out. 1316*2a7db7a6SVincenzo Maffione */ 1317*2a7db7a6SVincenzo Maffione bkring->rhead = bkring->rcur = kring->nr_hwtail; 1318*2a7db7a6SVincenzo Maffione 1319*2a7db7a6SVincenzo Maffione bkring->nm_sync(bkring, flags); 1320*2a7db7a6SVincenzo Maffione 1321*2a7db7a6SVincenzo Maffione /* mark all buffers as released on this ring */ 1322*2a7db7a6SVincenzo Maffione kring->rhead = kring->rcur = kring->rtail = kring->nr_hwtail; 1323*2a7db7a6SVincenzo Maffione /* another call to actually release the buffers */ 1324*2a7db7a6SVincenzo Maffione error = kring->nm_sync(kring, 0); 1325*2a7db7a6SVincenzo Maffione 1326*2a7db7a6SVincenzo Maffione /* The second rxsync may have further advanced hwtail. If this happens, 1327*2a7db7a6SVincenzo Maffione * return NM_IRQ_RESCHED, otherwise just return NM_IRQ_COMPLETED. */ 1328*2a7db7a6SVincenzo Maffione if (kring->rcur != kring->nr_hwtail) { 1329*2a7db7a6SVincenzo Maffione ret = NM_IRQ_RESCHED; 1330*2a7db7a6SVincenzo Maffione } 1331*2a7db7a6SVincenzo Maffione put_out: 1332*2a7db7a6SVincenzo Maffione nm_kr_put(kring); 1333*2a7db7a6SVincenzo Maffione 1334*2a7db7a6SVincenzo Maffione return error ? error : ret; 1335*2a7db7a6SVincenzo Maffione } 1336*2a7db7a6SVincenzo Maffione 1337*2a7db7a6SVincenzo Maffione 1338*2a7db7a6SVincenzo Maffione /* nm_register callback for bwrap */ 1339*2a7db7a6SVincenzo Maffione int 1340*2a7db7a6SVincenzo Maffione netmap_bwrap_reg(struct netmap_adapter *na, int onoff) 1341*2a7db7a6SVincenzo Maffione { 1342*2a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna = 1343*2a7db7a6SVincenzo Maffione (struct netmap_bwrap_adapter *)na; 1344*2a7db7a6SVincenzo Maffione struct netmap_adapter *hwna = bna->hwna; 1345*2a7db7a6SVincenzo Maffione struct netmap_vp_adapter *hostna = &bna->host; 1346*2a7db7a6SVincenzo Maffione int error, i; 1347*2a7db7a6SVincenzo Maffione enum txrx t; 1348*2a7db7a6SVincenzo Maffione 1349*2a7db7a6SVincenzo Maffione ND("%s %s", na->name, onoff ? "on" : "off"); 1350*2a7db7a6SVincenzo Maffione 1351*2a7db7a6SVincenzo Maffione if (onoff) { 1352*2a7db7a6SVincenzo Maffione /* netmap_do_regif has been called on the bwrap na. 1353*2a7db7a6SVincenzo Maffione * We need to pass the information about the 1354*2a7db7a6SVincenzo Maffione * memory allocator down to the hwna before 1355*2a7db7a6SVincenzo Maffione * putting it in netmap mode 1356*2a7db7a6SVincenzo Maffione */ 1357*2a7db7a6SVincenzo Maffione hwna->na_lut = na->na_lut; 1358*2a7db7a6SVincenzo Maffione 1359*2a7db7a6SVincenzo Maffione if (hostna->na_bdg) { 1360*2a7db7a6SVincenzo Maffione /* if the host rings have been attached to switch, 1361*2a7db7a6SVincenzo Maffione * we need to copy the memory allocator information 1362*2a7db7a6SVincenzo Maffione * in the hostna also 1363*2a7db7a6SVincenzo Maffione */ 1364*2a7db7a6SVincenzo Maffione hostna->up.na_lut = na->na_lut; 1365*2a7db7a6SVincenzo Maffione } 1366*2a7db7a6SVincenzo Maffione 1367*2a7db7a6SVincenzo Maffione } 1368*2a7db7a6SVincenzo Maffione 1369*2a7db7a6SVincenzo Maffione /* pass down the pending ring state information */ 1370*2a7db7a6SVincenzo Maffione for_rx_tx(t) { 1371*2a7db7a6SVincenzo Maffione for (i = 0; i < netmap_all_rings(na, t); i++) { 1372*2a7db7a6SVincenzo Maffione NMR(hwna, nm_txrx_swap(t))[i]->nr_pending_mode = 1373*2a7db7a6SVincenzo Maffione NMR(na, t)[i]->nr_pending_mode; 1374*2a7db7a6SVincenzo Maffione } 1375*2a7db7a6SVincenzo Maffione } 1376*2a7db7a6SVincenzo Maffione 1377*2a7db7a6SVincenzo Maffione /* forward the request to the hwna */ 1378*2a7db7a6SVincenzo Maffione error = hwna->nm_register(hwna, onoff); 1379*2a7db7a6SVincenzo Maffione if (error) 1380*2a7db7a6SVincenzo Maffione return error; 1381*2a7db7a6SVincenzo Maffione 1382*2a7db7a6SVincenzo Maffione /* copy up the current ring state information */ 1383*2a7db7a6SVincenzo Maffione for_rx_tx(t) { 1384*2a7db7a6SVincenzo Maffione for (i = 0; i < netmap_all_rings(na, t); i++) { 1385*2a7db7a6SVincenzo Maffione struct netmap_kring *kring = NMR(hwna, nm_txrx_swap(t))[i]; 1386*2a7db7a6SVincenzo Maffione NMR(na, t)[i]->nr_mode = kring->nr_mode; 1387*2a7db7a6SVincenzo Maffione } 1388*2a7db7a6SVincenzo Maffione } 1389*2a7db7a6SVincenzo Maffione 1390*2a7db7a6SVincenzo Maffione /* impersonate a netmap_vp_adapter */ 1391*2a7db7a6SVincenzo Maffione netmap_vp_reg(na, onoff); 1392*2a7db7a6SVincenzo Maffione if (hostna->na_bdg) 1393*2a7db7a6SVincenzo Maffione netmap_vp_reg(&hostna->up, onoff); 1394*2a7db7a6SVincenzo Maffione 1395*2a7db7a6SVincenzo Maffione if (onoff) { 1396*2a7db7a6SVincenzo Maffione u_int i; 1397*2a7db7a6SVincenzo Maffione /* intercept the hwna nm_nofify callback on the hw rings */ 1398*2a7db7a6SVincenzo Maffione for (i = 0; i < hwna->num_rx_rings; i++) { 1399*2a7db7a6SVincenzo Maffione hwna->rx_rings[i]->save_notify = hwna->rx_rings[i]->nm_notify; 1400*2a7db7a6SVincenzo Maffione hwna->rx_rings[i]->nm_notify = netmap_bwrap_intr_notify; 1401*2a7db7a6SVincenzo Maffione } 1402*2a7db7a6SVincenzo Maffione i = hwna->num_rx_rings; /* for safety */ 1403*2a7db7a6SVincenzo Maffione /* save the host ring notify unconditionally */ 1404*2a7db7a6SVincenzo Maffione for (; i < netmap_real_rings(hwna, NR_RX); i++) { 1405*2a7db7a6SVincenzo Maffione hwna->rx_rings[i]->save_notify = 1406*2a7db7a6SVincenzo Maffione hwna->rx_rings[i]->nm_notify; 1407*2a7db7a6SVincenzo Maffione if (hostna->na_bdg) { 1408*2a7db7a6SVincenzo Maffione /* also intercept the host ring notify */ 1409*2a7db7a6SVincenzo Maffione hwna->rx_rings[i]->nm_notify = 1410*2a7db7a6SVincenzo Maffione netmap_bwrap_intr_notify; 1411*2a7db7a6SVincenzo Maffione na->tx_rings[i]->nm_sync = na->nm_txsync; 1412*2a7db7a6SVincenzo Maffione } 1413*2a7db7a6SVincenzo Maffione } 1414*2a7db7a6SVincenzo Maffione if (na->active_fds == 0) 1415*2a7db7a6SVincenzo Maffione na->na_flags |= NAF_NETMAP_ON; 1416*2a7db7a6SVincenzo Maffione } else { 1417*2a7db7a6SVincenzo Maffione u_int i; 1418*2a7db7a6SVincenzo Maffione 1419*2a7db7a6SVincenzo Maffione if (na->active_fds == 0) 1420*2a7db7a6SVincenzo Maffione na->na_flags &= ~NAF_NETMAP_ON; 1421*2a7db7a6SVincenzo Maffione 1422*2a7db7a6SVincenzo Maffione /* reset all notify callbacks (including host ring) */ 1423*2a7db7a6SVincenzo Maffione for (i = 0; i < netmap_all_rings(hwna, NR_RX); i++) { 1424*2a7db7a6SVincenzo Maffione hwna->rx_rings[i]->nm_notify = 1425*2a7db7a6SVincenzo Maffione hwna->rx_rings[i]->save_notify; 1426*2a7db7a6SVincenzo Maffione hwna->rx_rings[i]->save_notify = NULL; 1427*2a7db7a6SVincenzo Maffione } 1428*2a7db7a6SVincenzo Maffione hwna->na_lut.lut = NULL; 1429*2a7db7a6SVincenzo Maffione hwna->na_lut.plut = NULL; 1430*2a7db7a6SVincenzo Maffione hwna->na_lut.objtotal = 0; 1431*2a7db7a6SVincenzo Maffione hwna->na_lut.objsize = 0; 1432*2a7db7a6SVincenzo Maffione 1433*2a7db7a6SVincenzo Maffione /* pass ownership of the netmap rings to the hwna */ 1434*2a7db7a6SVincenzo Maffione for_rx_tx(t) { 1435*2a7db7a6SVincenzo Maffione for (i = 0; i < netmap_all_rings(na, t); i++) { 1436*2a7db7a6SVincenzo Maffione NMR(na, t)[i]->ring = NULL; 1437*2a7db7a6SVincenzo Maffione } 1438*2a7db7a6SVincenzo Maffione } 1439*2a7db7a6SVincenzo Maffione /* reset the number of host rings to default */ 1440*2a7db7a6SVincenzo Maffione for_rx_tx(t) { 1441*2a7db7a6SVincenzo Maffione nma_set_host_nrings(hwna, t, 1); 1442*2a7db7a6SVincenzo Maffione } 1443*2a7db7a6SVincenzo Maffione 1444*2a7db7a6SVincenzo Maffione } 1445*2a7db7a6SVincenzo Maffione 1446*2a7db7a6SVincenzo Maffione return 0; 1447*2a7db7a6SVincenzo Maffione } 1448*2a7db7a6SVincenzo Maffione 1449*2a7db7a6SVincenzo Maffione /* nm_config callback for bwrap */ 1450*2a7db7a6SVincenzo Maffione static int 1451*2a7db7a6SVincenzo Maffione netmap_bwrap_config(struct netmap_adapter *na, struct nm_config_info *info) 1452*2a7db7a6SVincenzo Maffione { 1453*2a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna = 1454*2a7db7a6SVincenzo Maffione (struct netmap_bwrap_adapter *)na; 1455*2a7db7a6SVincenzo Maffione struct netmap_adapter *hwna = bna->hwna; 1456*2a7db7a6SVincenzo Maffione int error; 1457*2a7db7a6SVincenzo Maffione 1458*2a7db7a6SVincenzo Maffione /* Forward the request to the hwna. It may happen that nobody 1459*2a7db7a6SVincenzo Maffione * registered hwna yet, so netmap_mem_get_lut() may have not 1460*2a7db7a6SVincenzo Maffione * been called yet. */ 1461*2a7db7a6SVincenzo Maffione error = netmap_mem_get_lut(hwna->nm_mem, &hwna->na_lut); 1462*2a7db7a6SVincenzo Maffione if (error) 1463*2a7db7a6SVincenzo Maffione return error; 1464*2a7db7a6SVincenzo Maffione netmap_update_config(hwna); 1465*2a7db7a6SVincenzo Maffione /* swap the results and propagate */ 1466*2a7db7a6SVincenzo Maffione info->num_tx_rings = hwna->num_rx_rings; 1467*2a7db7a6SVincenzo Maffione info->num_tx_descs = hwna->num_rx_desc; 1468*2a7db7a6SVincenzo Maffione info->num_rx_rings = hwna->num_tx_rings; 1469*2a7db7a6SVincenzo Maffione info->num_rx_descs = hwna->num_tx_desc; 1470*2a7db7a6SVincenzo Maffione info->rx_buf_maxsize = hwna->rx_buf_maxsize; 1471*2a7db7a6SVincenzo Maffione 1472*2a7db7a6SVincenzo Maffione return 0; 1473*2a7db7a6SVincenzo Maffione } 1474*2a7db7a6SVincenzo Maffione 1475*2a7db7a6SVincenzo Maffione 1476*2a7db7a6SVincenzo Maffione /* nm_krings_create callback for bwrap */ 1477*2a7db7a6SVincenzo Maffione int 1478*2a7db7a6SVincenzo Maffione netmap_bwrap_krings_create_common(struct netmap_adapter *na) 1479*2a7db7a6SVincenzo Maffione { 1480*2a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna = 1481*2a7db7a6SVincenzo Maffione (struct netmap_bwrap_adapter *)na; 1482*2a7db7a6SVincenzo Maffione struct netmap_adapter *hwna = bna->hwna; 1483*2a7db7a6SVincenzo Maffione struct netmap_adapter *hostna = &bna->host.up; 1484*2a7db7a6SVincenzo Maffione int i, error = 0; 1485*2a7db7a6SVincenzo Maffione enum txrx t; 1486*2a7db7a6SVincenzo Maffione 1487*2a7db7a6SVincenzo Maffione /* also create the hwna krings */ 1488*2a7db7a6SVincenzo Maffione error = hwna->nm_krings_create(hwna); 1489*2a7db7a6SVincenzo Maffione if (error) { 1490*2a7db7a6SVincenzo Maffione return error; 1491*2a7db7a6SVincenzo Maffione } 1492*2a7db7a6SVincenzo Maffione 1493*2a7db7a6SVincenzo Maffione /* increment the usage counter for all the hwna krings */ 1494*2a7db7a6SVincenzo Maffione for_rx_tx(t) { 1495*2a7db7a6SVincenzo Maffione for (i = 0; i < netmap_all_rings(hwna, t); i++) { 1496*2a7db7a6SVincenzo Maffione NMR(hwna, t)[i]->users++; 1497*2a7db7a6SVincenzo Maffione } 1498*2a7db7a6SVincenzo Maffione } 1499*2a7db7a6SVincenzo Maffione 1500*2a7db7a6SVincenzo Maffione /* now create the actual rings */ 1501*2a7db7a6SVincenzo Maffione error = netmap_mem_rings_create(hwna); 1502*2a7db7a6SVincenzo Maffione if (error) { 1503*2a7db7a6SVincenzo Maffione goto err_dec_users; 1504*2a7db7a6SVincenzo Maffione } 1505*2a7db7a6SVincenzo Maffione 1506*2a7db7a6SVincenzo Maffione /* cross-link the netmap rings 1507*2a7db7a6SVincenzo Maffione * The original number of rings comes from hwna, 1508*2a7db7a6SVincenzo Maffione * rx rings on one side equals tx rings on the other. 1509*2a7db7a6SVincenzo Maffione */ 1510*2a7db7a6SVincenzo Maffione for_rx_tx(t) { 1511*2a7db7a6SVincenzo Maffione enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */ 1512*2a7db7a6SVincenzo Maffione for (i = 0; i < netmap_all_rings(hwna, r); i++) { 1513*2a7db7a6SVincenzo Maffione NMR(na, t)[i]->nkr_num_slots = NMR(hwna, r)[i]->nkr_num_slots; 1514*2a7db7a6SVincenzo Maffione NMR(na, t)[i]->ring = NMR(hwna, r)[i]->ring; 1515*2a7db7a6SVincenzo Maffione } 1516*2a7db7a6SVincenzo Maffione } 1517*2a7db7a6SVincenzo Maffione 1518*2a7db7a6SVincenzo Maffione if (na->na_flags & NAF_HOST_RINGS) { 1519*2a7db7a6SVincenzo Maffione /* the hostna rings are the host rings of the bwrap. 1520*2a7db7a6SVincenzo Maffione * The corresponding krings must point back to the 1521*2a7db7a6SVincenzo Maffione * hostna 1522*2a7db7a6SVincenzo Maffione */ 1523*2a7db7a6SVincenzo Maffione hostna->tx_rings = &na->tx_rings[na->num_tx_rings]; 1524*2a7db7a6SVincenzo Maffione hostna->rx_rings = &na->rx_rings[na->num_rx_rings]; 1525*2a7db7a6SVincenzo Maffione for_rx_tx(t) { 1526*2a7db7a6SVincenzo Maffione for (i = 0; i < nma_get_nrings(hostna, t); i++) { 1527*2a7db7a6SVincenzo Maffione NMR(hostna, t)[i]->na = hostna; 1528*2a7db7a6SVincenzo Maffione } 1529*2a7db7a6SVincenzo Maffione } 1530*2a7db7a6SVincenzo Maffione } 1531*2a7db7a6SVincenzo Maffione 1532*2a7db7a6SVincenzo Maffione return 0; 1533*2a7db7a6SVincenzo Maffione 1534*2a7db7a6SVincenzo Maffione err_dec_users: 1535*2a7db7a6SVincenzo Maffione for_rx_tx(t) { 1536*2a7db7a6SVincenzo Maffione for (i = 0; i < netmap_all_rings(hwna, t); i++) { 1537*2a7db7a6SVincenzo Maffione NMR(hwna, t)[i]->users--; 1538*2a7db7a6SVincenzo Maffione } 1539*2a7db7a6SVincenzo Maffione } 1540*2a7db7a6SVincenzo Maffione hwna->nm_krings_delete(hwna); 1541*2a7db7a6SVincenzo Maffione return error; 1542*2a7db7a6SVincenzo Maffione } 1543*2a7db7a6SVincenzo Maffione 1544*2a7db7a6SVincenzo Maffione 1545*2a7db7a6SVincenzo Maffione void 1546*2a7db7a6SVincenzo Maffione netmap_bwrap_krings_delete_common(struct netmap_adapter *na) 1547*2a7db7a6SVincenzo Maffione { 1548*2a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna = 1549*2a7db7a6SVincenzo Maffione (struct netmap_bwrap_adapter *)na; 1550*2a7db7a6SVincenzo Maffione struct netmap_adapter *hwna = bna->hwna; 1551*2a7db7a6SVincenzo Maffione enum txrx t; 1552*2a7db7a6SVincenzo Maffione int i; 1553*2a7db7a6SVincenzo Maffione 1554*2a7db7a6SVincenzo Maffione ND("%s", na->name); 1555*2a7db7a6SVincenzo Maffione 1556*2a7db7a6SVincenzo Maffione /* decrement the usage counter for all the hwna krings */ 1557*2a7db7a6SVincenzo Maffione for_rx_tx(t) { 1558*2a7db7a6SVincenzo Maffione for (i = 0; i < netmap_all_rings(hwna, t); i++) { 1559*2a7db7a6SVincenzo Maffione NMR(hwna, t)[i]->users--; 1560*2a7db7a6SVincenzo Maffione } 1561*2a7db7a6SVincenzo Maffione } 1562*2a7db7a6SVincenzo Maffione 1563*2a7db7a6SVincenzo Maffione /* delete any netmap rings that are no longer needed */ 1564*2a7db7a6SVincenzo Maffione netmap_mem_rings_delete(hwna); 1565*2a7db7a6SVincenzo Maffione hwna->nm_krings_delete(hwna); 1566*2a7db7a6SVincenzo Maffione } 1567*2a7db7a6SVincenzo Maffione 1568*2a7db7a6SVincenzo Maffione 1569*2a7db7a6SVincenzo Maffione /* notify method for the bridge-->hwna direction */ 1570*2a7db7a6SVincenzo Maffione int 1571*2a7db7a6SVincenzo Maffione netmap_bwrap_notify(struct netmap_kring *kring, int flags) 1572*2a7db7a6SVincenzo Maffione { 1573*2a7db7a6SVincenzo Maffione struct netmap_adapter *na = kring->na; 1574*2a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna = na->na_private; 1575*2a7db7a6SVincenzo Maffione struct netmap_adapter *hwna = bna->hwna; 1576*2a7db7a6SVincenzo Maffione u_int ring_n = kring->ring_id; 1577*2a7db7a6SVincenzo Maffione u_int lim = kring->nkr_num_slots - 1; 1578*2a7db7a6SVincenzo Maffione struct netmap_kring *hw_kring; 1579*2a7db7a6SVincenzo Maffione int error; 1580*2a7db7a6SVincenzo Maffione 1581*2a7db7a6SVincenzo Maffione ND("%s: na %s hwna %s", 1582*2a7db7a6SVincenzo Maffione (kring ? kring->name : "NULL!"), 1583*2a7db7a6SVincenzo Maffione (na ? na->name : "NULL!"), 1584*2a7db7a6SVincenzo Maffione (hwna ? hwna->name : "NULL!")); 1585*2a7db7a6SVincenzo Maffione hw_kring = hwna->tx_rings[ring_n]; 1586*2a7db7a6SVincenzo Maffione 1587*2a7db7a6SVincenzo Maffione if (nm_kr_tryget(hw_kring, 0, NULL)) { 1588*2a7db7a6SVincenzo Maffione return ENXIO; 1589*2a7db7a6SVincenzo Maffione } 1590*2a7db7a6SVincenzo Maffione 1591*2a7db7a6SVincenzo Maffione /* first step: simulate a user wakeup on the rx ring */ 1592*2a7db7a6SVincenzo Maffione netmap_vp_rxsync(kring, flags); 1593*2a7db7a6SVincenzo Maffione ND("%s[%d] PRE rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)", 1594*2a7db7a6SVincenzo Maffione na->name, ring_n, 1595*2a7db7a6SVincenzo Maffione kring->nr_hwcur, kring->nr_hwtail, kring->nkr_hwlease, 1596*2a7db7a6SVincenzo Maffione ring->head, ring->cur, ring->tail, 1597*2a7db7a6SVincenzo Maffione hw_kring->nr_hwcur, hw_kring->nr_hwtail, hw_ring->rtail); 1598*2a7db7a6SVincenzo Maffione /* second step: the new packets are sent on the tx ring 1599*2a7db7a6SVincenzo Maffione * (which is actually the same ring) 1600*2a7db7a6SVincenzo Maffione */ 1601*2a7db7a6SVincenzo Maffione hw_kring->rhead = hw_kring->rcur = kring->nr_hwtail; 1602*2a7db7a6SVincenzo Maffione error = hw_kring->nm_sync(hw_kring, flags); 1603*2a7db7a6SVincenzo Maffione if (error) 1604*2a7db7a6SVincenzo Maffione goto put_out; 1605*2a7db7a6SVincenzo Maffione 1606*2a7db7a6SVincenzo Maffione /* third step: now we are back the rx ring */ 1607*2a7db7a6SVincenzo Maffione /* claim ownership on all hw owned bufs */ 1608*2a7db7a6SVincenzo Maffione kring->rhead = kring->rcur = nm_next(hw_kring->nr_hwtail, lim); /* skip past reserved slot */ 1609*2a7db7a6SVincenzo Maffione 1610*2a7db7a6SVincenzo Maffione /* fourth step: the user goes to sleep again, causing another rxsync */ 1611*2a7db7a6SVincenzo Maffione netmap_vp_rxsync(kring, flags); 1612*2a7db7a6SVincenzo Maffione ND("%s[%d] PST rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)", 1613*2a7db7a6SVincenzo Maffione na->name, ring_n, 1614*2a7db7a6SVincenzo Maffione kring->nr_hwcur, kring->nr_hwtail, kring->nkr_hwlease, 1615*2a7db7a6SVincenzo Maffione ring->head, ring->cur, ring->tail, 1616*2a7db7a6SVincenzo Maffione hw_kring->nr_hwcur, hw_kring->nr_hwtail, hw_kring->rtail); 1617*2a7db7a6SVincenzo Maffione put_out: 1618*2a7db7a6SVincenzo Maffione nm_kr_put(hw_kring); 1619*2a7db7a6SVincenzo Maffione 1620*2a7db7a6SVincenzo Maffione return error ? error : NM_IRQ_COMPLETED; 1621*2a7db7a6SVincenzo Maffione } 1622*2a7db7a6SVincenzo Maffione 1623*2a7db7a6SVincenzo Maffione 1624*2a7db7a6SVincenzo Maffione /* nm_bdg_ctl callback for the bwrap. 1625*2a7db7a6SVincenzo Maffione * Called on bridge-attach and detach, as an effect of vale-ctl -[ahd]. 1626*2a7db7a6SVincenzo Maffione * On attach, it needs to provide a fake netmap_priv_d structure and 1627*2a7db7a6SVincenzo Maffione * perform a netmap_do_regif() on the bwrap. This will put both the 1628*2a7db7a6SVincenzo Maffione * bwrap and the hwna in netmap mode, with the netmap rings shared 1629*2a7db7a6SVincenzo Maffione * and cross linked. Moroever, it will start intercepting interrupts 1630*2a7db7a6SVincenzo Maffione * directed to hwna. 1631*2a7db7a6SVincenzo Maffione */ 1632*2a7db7a6SVincenzo Maffione static int 1633*2a7db7a6SVincenzo Maffione netmap_bwrap_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na) 1634*2a7db7a6SVincenzo Maffione { 1635*2a7db7a6SVincenzo Maffione struct netmap_priv_d *npriv; 1636*2a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter*)na; 1637*2a7db7a6SVincenzo Maffione int error = 0; 1638*2a7db7a6SVincenzo Maffione 1639*2a7db7a6SVincenzo Maffione if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) { 1640*2a7db7a6SVincenzo Maffione struct nmreq_vale_attach *req = 1641*2a7db7a6SVincenzo Maffione (struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body; 1642*2a7db7a6SVincenzo Maffione if (req->reg.nr_ringid != 0 || 1643*2a7db7a6SVincenzo Maffione (req->reg.nr_mode != NR_REG_ALL_NIC && 1644*2a7db7a6SVincenzo Maffione req->reg.nr_mode != NR_REG_NIC_SW)) { 1645*2a7db7a6SVincenzo Maffione /* We only support attaching all the NIC rings 1646*2a7db7a6SVincenzo Maffione * and/or the host stack. */ 1647*2a7db7a6SVincenzo Maffione return EINVAL; 1648*2a7db7a6SVincenzo Maffione } 1649*2a7db7a6SVincenzo Maffione if (NETMAP_OWNED_BY_ANY(na)) { 1650*2a7db7a6SVincenzo Maffione return EBUSY; 1651*2a7db7a6SVincenzo Maffione } 1652*2a7db7a6SVincenzo Maffione if (bna->na_kpriv) { 1653*2a7db7a6SVincenzo Maffione /* nothing to do */ 1654*2a7db7a6SVincenzo Maffione return 0; 1655*2a7db7a6SVincenzo Maffione } 1656*2a7db7a6SVincenzo Maffione npriv = netmap_priv_new(); 1657*2a7db7a6SVincenzo Maffione if (npriv == NULL) 1658*2a7db7a6SVincenzo Maffione return ENOMEM; 1659*2a7db7a6SVincenzo Maffione npriv->np_ifp = na->ifp; /* let the priv destructor release the ref */ 1660*2a7db7a6SVincenzo Maffione error = netmap_do_regif(npriv, na, req->reg.nr_mode, 1661*2a7db7a6SVincenzo Maffione req->reg.nr_ringid, req->reg.nr_flags); 1662*2a7db7a6SVincenzo Maffione if (error) { 1663*2a7db7a6SVincenzo Maffione netmap_priv_delete(npriv); 1664*2a7db7a6SVincenzo Maffione return error; 1665*2a7db7a6SVincenzo Maffione } 1666*2a7db7a6SVincenzo Maffione bna->na_kpriv = npriv; 1667*2a7db7a6SVincenzo Maffione na->na_flags |= NAF_BUSY; 1668*2a7db7a6SVincenzo Maffione } else { 1669*2a7db7a6SVincenzo Maffione if (na->active_fds == 0) /* not registered */ 1670*2a7db7a6SVincenzo Maffione return EINVAL; 1671*2a7db7a6SVincenzo Maffione netmap_priv_delete(bna->na_kpriv); 1672*2a7db7a6SVincenzo Maffione bna->na_kpriv = NULL; 1673*2a7db7a6SVincenzo Maffione na->na_flags &= ~NAF_BUSY; 1674*2a7db7a6SVincenzo Maffione } 1675*2a7db7a6SVincenzo Maffione 1676*2a7db7a6SVincenzo Maffione return error; 1677*2a7db7a6SVincenzo Maffione } 1678*2a7db7a6SVincenzo Maffione 1679*2a7db7a6SVincenzo Maffione /* attach a bridge wrapper to the 'real' device */ 1680*2a7db7a6SVincenzo Maffione int 1681*2a7db7a6SVincenzo Maffione netmap_bwrap_attach_common(struct netmap_adapter *na, 1682*2a7db7a6SVincenzo Maffione struct netmap_adapter *hwna) 1683*2a7db7a6SVincenzo Maffione { 1684*2a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna; 1685*2a7db7a6SVincenzo Maffione struct netmap_adapter *hostna = NULL; 1686*2a7db7a6SVincenzo Maffione int error = 0; 1687*2a7db7a6SVincenzo Maffione enum txrx t; 1688*2a7db7a6SVincenzo Maffione 1689*2a7db7a6SVincenzo Maffione /* make sure the NIC is not already in use */ 1690*2a7db7a6SVincenzo Maffione if (NETMAP_OWNED_BY_ANY(hwna)) { 1691*2a7db7a6SVincenzo Maffione D("NIC %s busy, cannot attach to bridge", hwna->name); 1692*2a7db7a6SVincenzo Maffione return EBUSY; 1693*2a7db7a6SVincenzo Maffione } 1694*2a7db7a6SVincenzo Maffione 1695*2a7db7a6SVincenzo Maffione bna = (struct netmap_bwrap_adapter *)na; 1696*2a7db7a6SVincenzo Maffione /* make bwrap ifp point to the real ifp */ 1697*2a7db7a6SVincenzo Maffione na->ifp = hwna->ifp; 1698*2a7db7a6SVincenzo Maffione if_ref(na->ifp); 1699*2a7db7a6SVincenzo Maffione na->na_private = bna; 1700*2a7db7a6SVincenzo Maffione /* fill the ring data for the bwrap adapter with rx/tx meanings 1701*2a7db7a6SVincenzo Maffione * swapped. The real cross-linking will be done during register, 1702*2a7db7a6SVincenzo Maffione * when all the krings will have been created. 1703*2a7db7a6SVincenzo Maffione */ 1704*2a7db7a6SVincenzo Maffione for_rx_tx(t) { 1705*2a7db7a6SVincenzo Maffione enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */ 1706*2a7db7a6SVincenzo Maffione nma_set_nrings(na, t, nma_get_nrings(hwna, r)); 1707*2a7db7a6SVincenzo Maffione nma_set_ndesc(na, t, nma_get_ndesc(hwna, r)); 1708*2a7db7a6SVincenzo Maffione } 1709*2a7db7a6SVincenzo Maffione na->nm_dtor = netmap_bwrap_dtor; 1710*2a7db7a6SVincenzo Maffione na->nm_config = netmap_bwrap_config; 1711*2a7db7a6SVincenzo Maffione na->nm_bdg_ctl = netmap_bwrap_bdg_ctl; 1712*2a7db7a6SVincenzo Maffione na->pdev = hwna->pdev; 1713*2a7db7a6SVincenzo Maffione na->nm_mem = netmap_mem_get(hwna->nm_mem); 1714*2a7db7a6SVincenzo Maffione na->virt_hdr_len = hwna->virt_hdr_len; 1715*2a7db7a6SVincenzo Maffione na->rx_buf_maxsize = hwna->rx_buf_maxsize; 1716*2a7db7a6SVincenzo Maffione 1717*2a7db7a6SVincenzo Maffione bna->hwna = hwna; 1718*2a7db7a6SVincenzo Maffione netmap_adapter_get(hwna); 1719*2a7db7a6SVincenzo Maffione hwna->na_private = bna; /* weak reference */ 1720*2a7db7a6SVincenzo Maffione bna->saved_na_vp = hwna->na_vp; 1721*2a7db7a6SVincenzo Maffione hwna->na_vp = &bna->up; 1722*2a7db7a6SVincenzo Maffione bna->up.up.na_vp = &(bna->up); 1723*2a7db7a6SVincenzo Maffione 1724*2a7db7a6SVincenzo Maffione if (hwna->na_flags & NAF_HOST_RINGS) { 1725*2a7db7a6SVincenzo Maffione if (hwna->na_flags & NAF_SW_ONLY) 1726*2a7db7a6SVincenzo Maffione na->na_flags |= NAF_SW_ONLY; 1727*2a7db7a6SVincenzo Maffione na->na_flags |= NAF_HOST_RINGS; 1728*2a7db7a6SVincenzo Maffione hostna = &bna->host.up; 1729*2a7db7a6SVincenzo Maffione 1730*2a7db7a6SVincenzo Maffione /* limit the number of host rings to that of hw */ 1731*2a7db7a6SVincenzo Maffione nm_bound_var(&hostna->num_tx_rings, 1, 1, 1732*2a7db7a6SVincenzo Maffione nma_get_nrings(hwna, NR_TX), NULL); 1733*2a7db7a6SVincenzo Maffione nm_bound_var(&hostna->num_rx_rings, 1, 1, 1734*2a7db7a6SVincenzo Maffione nma_get_nrings(hwna, NR_RX), NULL); 1735*2a7db7a6SVincenzo Maffione 1736*2a7db7a6SVincenzo Maffione snprintf(hostna->name, sizeof(hostna->name), "%s^", na->name); 1737*2a7db7a6SVincenzo Maffione hostna->ifp = hwna->ifp; 1738*2a7db7a6SVincenzo Maffione for_rx_tx(t) { 1739*2a7db7a6SVincenzo Maffione enum txrx r = nm_txrx_swap(t); 1740*2a7db7a6SVincenzo Maffione u_int nr = nma_get_nrings(hostna, t); 1741*2a7db7a6SVincenzo Maffione 1742*2a7db7a6SVincenzo Maffione nma_set_nrings(hostna, t, nr); 1743*2a7db7a6SVincenzo Maffione nma_set_host_nrings(na, t, nr); 1744*2a7db7a6SVincenzo Maffione if (nma_get_host_nrings(hwna, t) < nr) { 1745*2a7db7a6SVincenzo Maffione nma_set_host_nrings(hwna, t, nr); 1746*2a7db7a6SVincenzo Maffione } 1747*2a7db7a6SVincenzo Maffione nma_set_ndesc(hostna, t, nma_get_ndesc(hwna, r)); 1748*2a7db7a6SVincenzo Maffione } 1749*2a7db7a6SVincenzo Maffione // hostna->nm_txsync = netmap_bwrap_host_txsync; 1750*2a7db7a6SVincenzo Maffione // hostna->nm_rxsync = netmap_bwrap_host_rxsync; 1751*2a7db7a6SVincenzo Maffione hostna->nm_mem = netmap_mem_get(na->nm_mem); 1752*2a7db7a6SVincenzo Maffione hostna->na_private = bna; 1753*2a7db7a6SVincenzo Maffione hostna->na_vp = &bna->up; 1754*2a7db7a6SVincenzo Maffione na->na_hostvp = hwna->na_hostvp = 1755*2a7db7a6SVincenzo Maffione hostna->na_hostvp = &bna->host; 1756*2a7db7a6SVincenzo Maffione hostna->na_flags = NAF_BUSY; /* prevent NIOCREGIF */ 1757*2a7db7a6SVincenzo Maffione hostna->rx_buf_maxsize = hwna->rx_buf_maxsize; 1758*2a7db7a6SVincenzo Maffione } 1759*2a7db7a6SVincenzo Maffione 1760*2a7db7a6SVincenzo Maffione ND("%s<->%s txr %d txd %d rxr %d rxd %d", 1761*2a7db7a6SVincenzo Maffione na->name, ifp->if_xname, 1762*2a7db7a6SVincenzo Maffione na->num_tx_rings, na->num_tx_desc, 1763*2a7db7a6SVincenzo Maffione na->num_rx_rings, na->num_rx_desc); 1764*2a7db7a6SVincenzo Maffione 1765*2a7db7a6SVincenzo Maffione error = netmap_attach_common(na); 1766*2a7db7a6SVincenzo Maffione if (error) { 1767*2a7db7a6SVincenzo Maffione goto err_put; 1768*2a7db7a6SVincenzo Maffione } 1769*2a7db7a6SVincenzo Maffione hwna->na_flags |= NAF_BUSY; 1770*2a7db7a6SVincenzo Maffione return 0; 1771*2a7db7a6SVincenzo Maffione 1772*2a7db7a6SVincenzo Maffione err_put: 1773*2a7db7a6SVincenzo Maffione hwna->na_vp = hwna->na_hostvp = NULL; 1774*2a7db7a6SVincenzo Maffione netmap_adapter_put(hwna); 1775*2a7db7a6SVincenzo Maffione return error; 1776*2a7db7a6SVincenzo Maffione 1777*2a7db7a6SVincenzo Maffione } 1778*2a7db7a6SVincenzo Maffione 1779*2a7db7a6SVincenzo Maffione struct nm_bridge * 1780*2a7db7a6SVincenzo Maffione netmap_init_bridges2(u_int n) 1781*2a7db7a6SVincenzo Maffione { 1782*2a7db7a6SVincenzo Maffione int i; 1783*2a7db7a6SVincenzo Maffione struct nm_bridge *b; 1784*2a7db7a6SVincenzo Maffione 1785*2a7db7a6SVincenzo Maffione b = nm_os_malloc(sizeof(struct nm_bridge) * n); 1786*2a7db7a6SVincenzo Maffione if (b == NULL) 1787*2a7db7a6SVincenzo Maffione return NULL; 1788*2a7db7a6SVincenzo Maffione for (i = 0; i < n; i++) 1789*2a7db7a6SVincenzo Maffione BDG_RWINIT(&b[i]); 1790*2a7db7a6SVincenzo Maffione return b; 1791*2a7db7a6SVincenzo Maffione } 1792*2a7db7a6SVincenzo Maffione 1793*2a7db7a6SVincenzo Maffione void 1794*2a7db7a6SVincenzo Maffione netmap_uninit_bridges2(struct nm_bridge *b, u_int n) 1795*2a7db7a6SVincenzo Maffione { 1796*2a7db7a6SVincenzo Maffione int i; 1797*2a7db7a6SVincenzo Maffione 1798*2a7db7a6SVincenzo Maffione if (b == NULL) 1799*2a7db7a6SVincenzo Maffione return; 1800*2a7db7a6SVincenzo Maffione 1801*2a7db7a6SVincenzo Maffione for (i = 0; i < n; i++) 1802*2a7db7a6SVincenzo Maffione BDG_RWDESTROY(&b[i]); 1803*2a7db7a6SVincenzo Maffione nm_os_free(b); 1804*2a7db7a6SVincenzo Maffione } 1805*2a7db7a6SVincenzo Maffione 1806*2a7db7a6SVincenzo Maffione int 1807*2a7db7a6SVincenzo Maffione netmap_init_bridges(void) 1808*2a7db7a6SVincenzo Maffione { 1809*2a7db7a6SVincenzo Maffione #ifdef CONFIG_NET_NS 1810*2a7db7a6SVincenzo Maffione return netmap_bns_register(); 1811*2a7db7a6SVincenzo Maffione #else 1812*2a7db7a6SVincenzo Maffione nm_bridges = netmap_init_bridges2(NM_BRIDGES); 1813*2a7db7a6SVincenzo Maffione if (nm_bridges == NULL) 1814*2a7db7a6SVincenzo Maffione return ENOMEM; 1815*2a7db7a6SVincenzo Maffione return 0; 1816*2a7db7a6SVincenzo Maffione #endif 1817*2a7db7a6SVincenzo Maffione } 1818*2a7db7a6SVincenzo Maffione 1819*2a7db7a6SVincenzo Maffione void 1820*2a7db7a6SVincenzo Maffione netmap_uninit_bridges(void) 1821*2a7db7a6SVincenzo Maffione { 1822*2a7db7a6SVincenzo Maffione #ifdef CONFIG_NET_NS 1823*2a7db7a6SVincenzo Maffione netmap_bns_unregister(); 1824*2a7db7a6SVincenzo Maffione #else 1825*2a7db7a6SVincenzo Maffione netmap_uninit_bridges2(nm_bridges, NM_BRIDGES); 1826*2a7db7a6SVincenzo Maffione #endif 1827*2a7db7a6SVincenzo Maffione } 1828