12a7db7a6SVincenzo Maffione /* 22a7db7a6SVincenzo Maffione * Copyright (C) 2013-2016 Universita` di Pisa 32a7db7a6SVincenzo Maffione * All rights reserved. 42a7db7a6SVincenzo Maffione * 52a7db7a6SVincenzo Maffione * Redistribution and use in source and binary forms, with or without 62a7db7a6SVincenzo Maffione * modification, are permitted provided that the following conditions 72a7db7a6SVincenzo Maffione * are met: 82a7db7a6SVincenzo Maffione * 1. Redistributions of source code must retain the above copyright 92a7db7a6SVincenzo Maffione * notice, this list of conditions and the following disclaimer. 102a7db7a6SVincenzo Maffione * 2. Redistributions in binary form must reproduce the above copyright 112a7db7a6SVincenzo Maffione * notice, this list of conditions and the following disclaimer in the 122a7db7a6SVincenzo Maffione * documentation and/or other materials provided with the distribution. 132a7db7a6SVincenzo Maffione * 142a7db7a6SVincenzo Maffione * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 152a7db7a6SVincenzo Maffione * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 162a7db7a6SVincenzo Maffione * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 172a7db7a6SVincenzo Maffione * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 182a7db7a6SVincenzo Maffione * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 192a7db7a6SVincenzo Maffione * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 202a7db7a6SVincenzo Maffione * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 212a7db7a6SVincenzo Maffione * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 222a7db7a6SVincenzo Maffione * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 232a7db7a6SVincenzo Maffione * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 242a7db7a6SVincenzo Maffione * SUCH DAMAGE. 252a7db7a6SVincenzo Maffione */ 262a7db7a6SVincenzo Maffione 272a7db7a6SVincenzo Maffione 282a7db7a6SVincenzo Maffione /* 292a7db7a6SVincenzo Maffione * This module implements the VALE switch for netmap 302a7db7a6SVincenzo Maffione 312a7db7a6SVincenzo Maffione --- VALE SWITCH --- 322a7db7a6SVincenzo Maffione 332a7db7a6SVincenzo Maffione NMG_LOCK() serializes all modifications to switches and ports. 342a7db7a6SVincenzo Maffione A switch cannot be deleted until all ports are gone. 352a7db7a6SVincenzo Maffione 362a7db7a6SVincenzo Maffione For each switch, an SX lock (RWlock on linux) protects 372a7db7a6SVincenzo Maffione deletion of ports. When configuring or deleting a new port, the 382a7db7a6SVincenzo Maffione lock is acquired in exclusive mode (after holding NMG_LOCK). 392a7db7a6SVincenzo Maffione When forwarding, the lock is acquired in shared mode (without NMG_LOCK). 402a7db7a6SVincenzo Maffione The lock is held throughout the entire forwarding cycle, 412a7db7a6SVincenzo Maffione during which the thread may incur in a page fault. 422a7db7a6SVincenzo Maffione Hence it is important that sleepable shared locks are used. 432a7db7a6SVincenzo Maffione 442a7db7a6SVincenzo Maffione On the rx ring, the per-port lock is grabbed initially to reserve 452a7db7a6SVincenzo Maffione a number of slot in the ring, then the lock is released, 462a7db7a6SVincenzo Maffione packets are copied from source to destination, and then 472a7db7a6SVincenzo Maffione the lock is acquired again and the receive ring is updated. 482a7db7a6SVincenzo Maffione (A similar thing is done on the tx ring for NIC and host stack 492a7db7a6SVincenzo Maffione ports attached to the switch) 502a7db7a6SVincenzo Maffione 512a7db7a6SVincenzo Maffione */ 522a7db7a6SVincenzo Maffione 532a7db7a6SVincenzo Maffione /* 542a7db7a6SVincenzo Maffione * OS-specific code that is used only within this file. 552a7db7a6SVincenzo Maffione * Other OS-specific code that must be accessed by drivers 562a7db7a6SVincenzo Maffione * is present in netmap_kern.h 572a7db7a6SVincenzo Maffione */ 582a7db7a6SVincenzo Maffione 592a7db7a6SVincenzo Maffione #if defined(__FreeBSD__) 602a7db7a6SVincenzo Maffione #include <sys/cdefs.h> /* prerequisite */ 612a7db7a6SVincenzo Maffione __FBSDID("$FreeBSD$"); 622a7db7a6SVincenzo Maffione 632a7db7a6SVincenzo Maffione #include <sys/types.h> 642a7db7a6SVincenzo Maffione #include <sys/errno.h> 652a7db7a6SVincenzo Maffione #include <sys/param.h> /* defines used in kernel.h */ 662a7db7a6SVincenzo Maffione #include <sys/kernel.h> /* types used in module initialization */ 672a7db7a6SVincenzo Maffione #include <sys/conf.h> /* cdevsw struct, UID, GID */ 682a7db7a6SVincenzo Maffione #include <sys/sockio.h> 692a7db7a6SVincenzo Maffione #include <sys/socketvar.h> /* struct socket */ 702a7db7a6SVincenzo Maffione #include <sys/malloc.h> 712a7db7a6SVincenzo Maffione #include <sys/poll.h> 722a7db7a6SVincenzo Maffione #include <sys/rwlock.h> 732a7db7a6SVincenzo Maffione #include <sys/socket.h> /* sockaddrs */ 742a7db7a6SVincenzo Maffione #include <sys/selinfo.h> 752a7db7a6SVincenzo Maffione #include <sys/sysctl.h> 762a7db7a6SVincenzo Maffione #include <net/if.h> 772a7db7a6SVincenzo Maffione #include <net/if_var.h> 782a7db7a6SVincenzo Maffione #include <net/bpf.h> /* BIOCIMMEDIATE */ 792a7db7a6SVincenzo Maffione #include <machine/bus.h> /* bus_dmamap_* */ 802a7db7a6SVincenzo Maffione #include <sys/endian.h> 812a7db7a6SVincenzo Maffione #include <sys/refcount.h> 822a7db7a6SVincenzo Maffione #include <sys/smp.h> 832a7db7a6SVincenzo Maffione 842a7db7a6SVincenzo Maffione 852a7db7a6SVincenzo Maffione #elif defined(linux) 862a7db7a6SVincenzo Maffione 872a7db7a6SVincenzo Maffione #include "bsd_glue.h" 882a7db7a6SVincenzo Maffione 892a7db7a6SVincenzo Maffione #elif defined(__APPLE__) 902a7db7a6SVincenzo Maffione 912a7db7a6SVincenzo Maffione #warning OSX support is only partial 922a7db7a6SVincenzo Maffione #include "osx_glue.h" 932a7db7a6SVincenzo Maffione 942a7db7a6SVincenzo Maffione #elif defined(_WIN32) 952a7db7a6SVincenzo Maffione #include "win_glue.h" 962a7db7a6SVincenzo Maffione 972a7db7a6SVincenzo Maffione #else 982a7db7a6SVincenzo Maffione 992a7db7a6SVincenzo Maffione #error Unsupported platform 1002a7db7a6SVincenzo Maffione 1012a7db7a6SVincenzo Maffione #endif /* unsupported */ 1022a7db7a6SVincenzo Maffione 1032a7db7a6SVincenzo Maffione /* 1042a7db7a6SVincenzo Maffione * common headers 1052a7db7a6SVincenzo Maffione */ 1062a7db7a6SVincenzo Maffione 1072a7db7a6SVincenzo Maffione #include <net/netmap.h> 1082a7db7a6SVincenzo Maffione #include <dev/netmap/netmap_kern.h> 1092a7db7a6SVincenzo Maffione #include <dev/netmap/netmap_mem2.h> 1102a7db7a6SVincenzo Maffione 1112a7db7a6SVincenzo Maffione #include <dev/netmap/netmap_bdg.h> 1122a7db7a6SVincenzo Maffione 1132a7db7a6SVincenzo Maffione const char* 1142a7db7a6SVincenzo Maffione netmap_bdg_name(struct netmap_vp_adapter *vp) 1152a7db7a6SVincenzo Maffione { 1162a7db7a6SVincenzo Maffione struct nm_bridge *b = vp->na_bdg; 1172a7db7a6SVincenzo Maffione if (b == NULL) 1182a7db7a6SVincenzo Maffione return NULL; 1192a7db7a6SVincenzo Maffione return b->bdg_basename; 1202a7db7a6SVincenzo Maffione } 1212a7db7a6SVincenzo Maffione 1222a7db7a6SVincenzo Maffione 1232a7db7a6SVincenzo Maffione #ifndef CONFIG_NET_NS 1242a7db7a6SVincenzo Maffione /* 1252a7db7a6SVincenzo Maffione * XXX in principle nm_bridges could be created dynamically 1262a7db7a6SVincenzo Maffione * Right now we have a static array and deletions are protected 1272a7db7a6SVincenzo Maffione * by an exclusive lock. 1282a7db7a6SVincenzo Maffione */ 129b6e66be2SVincenzo Maffione struct nm_bridge *nm_bridges; 1302a7db7a6SVincenzo Maffione #endif /* !CONFIG_NET_NS */ 1312a7db7a6SVincenzo Maffione 1322a7db7a6SVincenzo Maffione 1332a7db7a6SVincenzo Maffione static int 1342a7db7a6SVincenzo Maffione nm_is_id_char(const char c) 1352a7db7a6SVincenzo Maffione { 1362a7db7a6SVincenzo Maffione return (c >= 'a' && c <= 'z') || 1372a7db7a6SVincenzo Maffione (c >= 'A' && c <= 'Z') || 1382a7db7a6SVincenzo Maffione (c >= '0' && c <= '9') || 1392a7db7a6SVincenzo Maffione (c == '_'); 1402a7db7a6SVincenzo Maffione } 1412a7db7a6SVincenzo Maffione 142b6e66be2SVincenzo Maffione /* Validate the name of a bdg port and return the 1432a7db7a6SVincenzo Maffione * position of the ":" character. */ 1442a7db7a6SVincenzo Maffione static int 145b6e66be2SVincenzo Maffione nm_bdg_name_validate(const char *name, size_t prefixlen) 1462a7db7a6SVincenzo Maffione { 1472a7db7a6SVincenzo Maffione int colon_pos = -1; 1482a7db7a6SVincenzo Maffione int i; 1492a7db7a6SVincenzo Maffione 150b6e66be2SVincenzo Maffione if (!name || strlen(name) < prefixlen) { 1512a7db7a6SVincenzo Maffione return -1; 1522a7db7a6SVincenzo Maffione } 1532a7db7a6SVincenzo Maffione 1542a7db7a6SVincenzo Maffione for (i = 0; i < NM_BDG_IFNAMSIZ && name[i]; i++) { 1552a7db7a6SVincenzo Maffione if (name[i] == ':') { 1562a7db7a6SVincenzo Maffione colon_pos = i; 1572a7db7a6SVincenzo Maffione break; 1582a7db7a6SVincenzo Maffione } else if (!nm_is_id_char(name[i])) { 1592a7db7a6SVincenzo Maffione return -1; 1602a7db7a6SVincenzo Maffione } 1612a7db7a6SVincenzo Maffione } 1622a7db7a6SVincenzo Maffione 1632a7db7a6SVincenzo Maffione if (strlen(name) - colon_pos > IFNAMSIZ) { 1642a7db7a6SVincenzo Maffione /* interface name too long */ 1652a7db7a6SVincenzo Maffione return -1; 1662a7db7a6SVincenzo Maffione } 1672a7db7a6SVincenzo Maffione 1682a7db7a6SVincenzo Maffione return colon_pos; 1692a7db7a6SVincenzo Maffione } 1702a7db7a6SVincenzo Maffione 1712a7db7a6SVincenzo Maffione /* 1722a7db7a6SVincenzo Maffione * locate a bridge among the existing ones. 1732a7db7a6SVincenzo Maffione * MUST BE CALLED WITH NMG_LOCK() 1742a7db7a6SVincenzo Maffione * 1752a7db7a6SVincenzo Maffione * a ':' in the name terminates the bridge name. Otherwise, just NM_NAME. 1762a7db7a6SVincenzo Maffione * We assume that this is called with a name of at least NM_NAME chars. 1772a7db7a6SVincenzo Maffione */ 1782a7db7a6SVincenzo Maffione struct nm_bridge * 1792a7db7a6SVincenzo Maffione nm_find_bridge(const char *name, int create, struct netmap_bdg_ops *ops) 1802a7db7a6SVincenzo Maffione { 1812a7db7a6SVincenzo Maffione int i, namelen; 1822a7db7a6SVincenzo Maffione struct nm_bridge *b = NULL, *bridges; 1832a7db7a6SVincenzo Maffione u_int num_bridges; 1842a7db7a6SVincenzo Maffione 1852a7db7a6SVincenzo Maffione NMG_LOCK_ASSERT(); 1862a7db7a6SVincenzo Maffione 1872a7db7a6SVincenzo Maffione netmap_bns_getbridges(&bridges, &num_bridges); 1882a7db7a6SVincenzo Maffione 189b6e66be2SVincenzo Maffione namelen = nm_bdg_name_validate(name, 190b6e66be2SVincenzo Maffione (ops != NULL ? strlen(ops->name) : 0)); 1912a7db7a6SVincenzo Maffione if (namelen < 0) { 192b6e66be2SVincenzo Maffione nm_prerr("invalid bridge name %s", name ? name : NULL); 1932a7db7a6SVincenzo Maffione return NULL; 1942a7db7a6SVincenzo Maffione } 1952a7db7a6SVincenzo Maffione 1962a7db7a6SVincenzo Maffione /* lookup the name, remember empty slot if there is one */ 1972a7db7a6SVincenzo Maffione for (i = 0; i < num_bridges; i++) { 1982a7db7a6SVincenzo Maffione struct nm_bridge *x = bridges + i; 1992a7db7a6SVincenzo Maffione 2002a7db7a6SVincenzo Maffione if ((x->bdg_flags & NM_BDG_ACTIVE) + x->bdg_active_ports == 0) { 2012a7db7a6SVincenzo Maffione if (create && b == NULL) 2022a7db7a6SVincenzo Maffione b = x; /* record empty slot */ 2032a7db7a6SVincenzo Maffione } else if (x->bdg_namelen != namelen) { 2042a7db7a6SVincenzo Maffione continue; 2052a7db7a6SVincenzo Maffione } else if (strncmp(name, x->bdg_basename, namelen) == 0) { 20675f4f3edSVincenzo Maffione nm_prdis("found '%.*s' at %d", namelen, name, i); 2072a7db7a6SVincenzo Maffione b = x; 2082a7db7a6SVincenzo Maffione break; 2092a7db7a6SVincenzo Maffione } 2102a7db7a6SVincenzo Maffione } 2112a7db7a6SVincenzo Maffione if (i == num_bridges && b) { /* name not found, can create entry */ 2122a7db7a6SVincenzo Maffione /* initialize the bridge */ 21375f4f3edSVincenzo Maffione nm_prdis("create new bridge %s with ports %d", b->bdg_basename, 2142a7db7a6SVincenzo Maffione b->bdg_active_ports); 2152a7db7a6SVincenzo Maffione b->ht = nm_os_malloc(sizeof(struct nm_hash_ent) * NM_BDG_HASH); 2162a7db7a6SVincenzo Maffione if (b->ht == NULL) { 217b6e66be2SVincenzo Maffione nm_prerr("failed to allocate hash table"); 2182a7db7a6SVincenzo Maffione return NULL; 2192a7db7a6SVincenzo Maffione } 2202a7db7a6SVincenzo Maffione strncpy(b->bdg_basename, name, namelen); 2212a7db7a6SVincenzo Maffione b->bdg_namelen = namelen; 2222a7db7a6SVincenzo Maffione b->bdg_active_ports = 0; 2232a7db7a6SVincenzo Maffione for (i = 0; i < NM_BDG_MAXPORTS; i++) 2242a7db7a6SVincenzo Maffione b->bdg_port_index[i] = i; 2252a7db7a6SVincenzo Maffione /* set the default function */ 226b6e66be2SVincenzo Maffione b->bdg_ops = b->bdg_saved_ops = *ops; 2272a7db7a6SVincenzo Maffione b->private_data = b->ht; 2282a7db7a6SVincenzo Maffione b->bdg_flags = 0; 2292a7db7a6SVincenzo Maffione NM_BNS_GET(b); 2302a7db7a6SVincenzo Maffione } 2312a7db7a6SVincenzo Maffione return b; 2322a7db7a6SVincenzo Maffione } 2332a7db7a6SVincenzo Maffione 2342a7db7a6SVincenzo Maffione 2352a7db7a6SVincenzo Maffione int 2362a7db7a6SVincenzo Maffione netmap_bdg_free(struct nm_bridge *b) 2372a7db7a6SVincenzo Maffione { 2382a7db7a6SVincenzo Maffione if ((b->bdg_flags & NM_BDG_ACTIVE) + b->bdg_active_ports != 0) { 2392a7db7a6SVincenzo Maffione return EBUSY; 2402a7db7a6SVincenzo Maffione } 2412a7db7a6SVincenzo Maffione 24275f4f3edSVincenzo Maffione nm_prdis("marking bridge %s as free", b->bdg_basename); 2432a7db7a6SVincenzo Maffione nm_os_free(b->ht); 244b6e66be2SVincenzo Maffione memset(&b->bdg_ops, 0, sizeof(b->bdg_ops)); 245b6e66be2SVincenzo Maffione memset(&b->bdg_saved_ops, 0, sizeof(b->bdg_saved_ops)); 2462a7db7a6SVincenzo Maffione b->bdg_flags = 0; 2472a7db7a6SVincenzo Maffione NM_BNS_PUT(b); 2482a7db7a6SVincenzo Maffione return 0; 2492a7db7a6SVincenzo Maffione } 2502a7db7a6SVincenzo Maffione 251b6e66be2SVincenzo Maffione /* Called by external kernel modules (e.g., Openvswitch). 252b6e66be2SVincenzo Maffione * to modify the private data previously given to regops(). 253b6e66be2SVincenzo Maffione * 'name' may be just bridge's name (including ':' if it 254b6e66be2SVincenzo Maffione * is not just NM_BDG_NAME). 255b6e66be2SVincenzo Maffione * Called without NMG_LOCK. 256b6e66be2SVincenzo Maffione */ 257b6e66be2SVincenzo Maffione int 258b6e66be2SVincenzo Maffione netmap_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callback, 259b6e66be2SVincenzo Maffione void *callback_data, void *auth_token) 260b6e66be2SVincenzo Maffione { 261b6e66be2SVincenzo Maffione void *private_data = NULL; 262b6e66be2SVincenzo Maffione struct nm_bridge *b; 263b6e66be2SVincenzo Maffione int error = 0; 264b6e66be2SVincenzo Maffione 265b6e66be2SVincenzo Maffione NMG_LOCK(); 266b6e66be2SVincenzo Maffione b = nm_find_bridge(name, 0 /* don't create */, NULL); 267b6e66be2SVincenzo Maffione if (!b) { 268b6e66be2SVincenzo Maffione error = EINVAL; 269b6e66be2SVincenzo Maffione goto unlock_update_priv; 270b6e66be2SVincenzo Maffione } 271b6e66be2SVincenzo Maffione if (!nm_bdg_valid_auth_token(b, auth_token)) { 272b6e66be2SVincenzo Maffione error = EACCES; 273b6e66be2SVincenzo Maffione goto unlock_update_priv; 274b6e66be2SVincenzo Maffione } 275b6e66be2SVincenzo Maffione BDG_WLOCK(b); 276b6e66be2SVincenzo Maffione private_data = callback(b->private_data, callback_data, &error); 277b6e66be2SVincenzo Maffione b->private_data = private_data; 278b6e66be2SVincenzo Maffione BDG_WUNLOCK(b); 279b6e66be2SVincenzo Maffione 280b6e66be2SVincenzo Maffione unlock_update_priv: 281b6e66be2SVincenzo Maffione NMG_UNLOCK(); 282b6e66be2SVincenzo Maffione return error; 283b6e66be2SVincenzo Maffione } 284b6e66be2SVincenzo Maffione 285b6e66be2SVincenzo Maffione 2862a7db7a6SVincenzo Maffione 2872a7db7a6SVincenzo Maffione /* remove from bridge b the ports in slots hw and sw 2882a7db7a6SVincenzo Maffione * (sw can be -1 if not needed) 2892a7db7a6SVincenzo Maffione */ 2902a7db7a6SVincenzo Maffione void 2912a7db7a6SVincenzo Maffione netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw) 2922a7db7a6SVincenzo Maffione { 2932a7db7a6SVincenzo Maffione int s_hw = hw, s_sw = sw; 2942a7db7a6SVincenzo Maffione int i, lim =b->bdg_active_ports; 2952a7db7a6SVincenzo Maffione uint32_t *tmp = b->tmp_bdg_port_index; 2962a7db7a6SVincenzo Maffione 2972a7db7a6SVincenzo Maffione /* 2982a7db7a6SVincenzo Maffione New algorithm: 2992a7db7a6SVincenzo Maffione make a copy of bdg_port_index; 3002a7db7a6SVincenzo Maffione lookup NA(ifp)->bdg_port and SWNA(ifp)->bdg_port 3012a7db7a6SVincenzo Maffione in the array of bdg_port_index, replacing them with 3022a7db7a6SVincenzo Maffione entries from the bottom of the array; 3032a7db7a6SVincenzo Maffione decrement bdg_active_ports; 3042a7db7a6SVincenzo Maffione acquire BDG_WLOCK() and copy back the array. 3052a7db7a6SVincenzo Maffione */ 3062a7db7a6SVincenzo Maffione 307b6e66be2SVincenzo Maffione if (netmap_debug & NM_DEBUG_BDG) 308b6e66be2SVincenzo Maffione nm_prinf("detach %d and %d (lim %d)", hw, sw, lim); 3092a7db7a6SVincenzo Maffione /* make a copy of the list of active ports, update it, 3102a7db7a6SVincenzo Maffione * and then copy back within BDG_WLOCK(). 3112a7db7a6SVincenzo Maffione */ 3122a7db7a6SVincenzo Maffione memcpy(b->tmp_bdg_port_index, b->bdg_port_index, sizeof(b->tmp_bdg_port_index)); 3132a7db7a6SVincenzo Maffione for (i = 0; (hw >= 0 || sw >= 0) && i < lim; ) { 3142a7db7a6SVincenzo Maffione if (hw >= 0 && tmp[i] == hw) { 31575f4f3edSVincenzo Maffione nm_prdis("detach hw %d at %d", hw, i); 3162a7db7a6SVincenzo Maffione lim--; /* point to last active port */ 3172a7db7a6SVincenzo Maffione tmp[i] = tmp[lim]; /* swap with i */ 3182a7db7a6SVincenzo Maffione tmp[lim] = hw; /* now this is inactive */ 3192a7db7a6SVincenzo Maffione hw = -1; 3202a7db7a6SVincenzo Maffione } else if (sw >= 0 && tmp[i] == sw) { 32175f4f3edSVincenzo Maffione nm_prdis("detach sw %d at %d", sw, i); 3222a7db7a6SVincenzo Maffione lim--; 3232a7db7a6SVincenzo Maffione tmp[i] = tmp[lim]; 3242a7db7a6SVincenzo Maffione tmp[lim] = sw; 3252a7db7a6SVincenzo Maffione sw = -1; 3262a7db7a6SVincenzo Maffione } else { 3272a7db7a6SVincenzo Maffione i++; 3282a7db7a6SVincenzo Maffione } 3292a7db7a6SVincenzo Maffione } 3302a7db7a6SVincenzo Maffione if (hw >= 0 || sw >= 0) { 331b6e66be2SVincenzo Maffione nm_prerr("delete failed hw %d sw %d, should panic...", hw, sw); 3322a7db7a6SVincenzo Maffione } 3332a7db7a6SVincenzo Maffione 3342a7db7a6SVincenzo Maffione BDG_WLOCK(b); 335b6e66be2SVincenzo Maffione if (b->bdg_ops.dtor) 336b6e66be2SVincenzo Maffione b->bdg_ops.dtor(b->bdg_ports[s_hw]); 3372a7db7a6SVincenzo Maffione b->bdg_ports[s_hw] = NULL; 3382a7db7a6SVincenzo Maffione if (s_sw >= 0) { 3392a7db7a6SVincenzo Maffione b->bdg_ports[s_sw] = NULL; 3402a7db7a6SVincenzo Maffione } 3412a7db7a6SVincenzo Maffione memcpy(b->bdg_port_index, b->tmp_bdg_port_index, sizeof(b->tmp_bdg_port_index)); 3422a7db7a6SVincenzo Maffione b->bdg_active_ports = lim; 3432a7db7a6SVincenzo Maffione BDG_WUNLOCK(b); 3442a7db7a6SVincenzo Maffione 34575f4f3edSVincenzo Maffione nm_prdis("now %d active ports", lim); 3462a7db7a6SVincenzo Maffione netmap_bdg_free(b); 3472a7db7a6SVincenzo Maffione } 3482a7db7a6SVincenzo Maffione 3492a7db7a6SVincenzo Maffione 3502a7db7a6SVincenzo Maffione /* nm_bdg_ctl callback for VALE ports */ 3512a7db7a6SVincenzo Maffione int 3522a7db7a6SVincenzo Maffione netmap_vp_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na) 3532a7db7a6SVincenzo Maffione { 3542a7db7a6SVincenzo Maffione struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter *)na; 3552a7db7a6SVincenzo Maffione struct nm_bridge *b = vpna->na_bdg; 3562a7db7a6SVincenzo Maffione 3572a7db7a6SVincenzo Maffione if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) { 3582a7db7a6SVincenzo Maffione return 0; /* nothing to do */ 3592a7db7a6SVincenzo Maffione } 3602a7db7a6SVincenzo Maffione if (b) { 3612a7db7a6SVincenzo Maffione netmap_set_all_rings(na, 0 /* disable */); 3622a7db7a6SVincenzo Maffione netmap_bdg_detach_common(b, vpna->bdg_port, -1); 3632a7db7a6SVincenzo Maffione vpna->na_bdg = NULL; 3642a7db7a6SVincenzo Maffione netmap_set_all_rings(na, 1 /* enable */); 3652a7db7a6SVincenzo Maffione } 3662a7db7a6SVincenzo Maffione /* I have took reference just for attach */ 3672a7db7a6SVincenzo Maffione netmap_adapter_put(na); 3682a7db7a6SVincenzo Maffione return 0; 3692a7db7a6SVincenzo Maffione } 3702a7db7a6SVincenzo Maffione 3712a7db7a6SVincenzo Maffione int 3722a7db7a6SVincenzo Maffione netmap_default_bdg_attach(const char *name, struct netmap_adapter *na, 3732a7db7a6SVincenzo Maffione struct nm_bridge *b) 3742a7db7a6SVincenzo Maffione { 3752a7db7a6SVincenzo Maffione return NM_NEED_BWRAP; 3762a7db7a6SVincenzo Maffione } 3772a7db7a6SVincenzo Maffione 3782a7db7a6SVincenzo Maffione /* Try to get a reference to a netmap adapter attached to a VALE switch. 3792a7db7a6SVincenzo Maffione * If the adapter is found (or is created), this function returns 0, a 3802a7db7a6SVincenzo Maffione * non NULL pointer is returned into *na, and the caller holds a 3812a7db7a6SVincenzo Maffione * reference to the adapter. 3822a7db7a6SVincenzo Maffione * If an adapter is not found, then no reference is grabbed and the 3832a7db7a6SVincenzo Maffione * function returns an error code, or 0 if there is just a VALE prefix 3842a7db7a6SVincenzo Maffione * mismatch. Therefore the caller holds a reference when 3852a7db7a6SVincenzo Maffione * (*na != NULL && return == 0). 3862a7db7a6SVincenzo Maffione */ 3872a7db7a6SVincenzo Maffione int 3882a7db7a6SVincenzo Maffione netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na, 3892a7db7a6SVincenzo Maffione struct netmap_mem_d *nmd, int create, struct netmap_bdg_ops *ops) 3902a7db7a6SVincenzo Maffione { 3912a7db7a6SVincenzo Maffione char *nr_name = hdr->nr_name; 3922a7db7a6SVincenzo Maffione const char *ifname; 3932a7db7a6SVincenzo Maffione struct ifnet *ifp = NULL; 3942a7db7a6SVincenzo Maffione int error = 0; 3952a7db7a6SVincenzo Maffione struct netmap_vp_adapter *vpna, *hostna = NULL; 3962a7db7a6SVincenzo Maffione struct nm_bridge *b; 3972a7db7a6SVincenzo Maffione uint32_t i, j; 3982a7db7a6SVincenzo Maffione uint32_t cand = NM_BDG_NOPORT, cand2 = NM_BDG_NOPORT; 3992a7db7a6SVincenzo Maffione int needed; 4002a7db7a6SVincenzo Maffione 4012a7db7a6SVincenzo Maffione *na = NULL; /* default return value */ 4022a7db7a6SVincenzo Maffione 4032a7db7a6SVincenzo Maffione /* first try to see if this is a bridge port. */ 4042a7db7a6SVincenzo Maffione NMG_LOCK_ASSERT(); 4052a7db7a6SVincenzo Maffione if (strncmp(nr_name, ops->name, strlen(ops->name) - 1)) { 4062a7db7a6SVincenzo Maffione return 0; /* no error, but no VALE prefix */ 4072a7db7a6SVincenzo Maffione } 4082a7db7a6SVincenzo Maffione 4092a7db7a6SVincenzo Maffione b = nm_find_bridge(nr_name, create, ops); 4102a7db7a6SVincenzo Maffione if (b == NULL) { 41175f4f3edSVincenzo Maffione nm_prdis("no bridges available for '%s'", nr_name); 4122a7db7a6SVincenzo Maffione return (create ? ENOMEM : ENXIO); 4132a7db7a6SVincenzo Maffione } 4142a7db7a6SVincenzo Maffione if (strlen(nr_name) < b->bdg_namelen) /* impossible */ 4152a7db7a6SVincenzo Maffione panic("x"); 4162a7db7a6SVincenzo Maffione 4172a7db7a6SVincenzo Maffione /* Now we are sure that name starts with the bridge's name, 4182a7db7a6SVincenzo Maffione * lookup the port in the bridge. We need to scan the entire 4192a7db7a6SVincenzo Maffione * list. It is not important to hold a WLOCK on the bridge 4202a7db7a6SVincenzo Maffione * during the search because NMG_LOCK already guarantees 4212a7db7a6SVincenzo Maffione * that there are no other possible writers. 4222a7db7a6SVincenzo Maffione */ 4232a7db7a6SVincenzo Maffione 4242a7db7a6SVincenzo Maffione /* lookup in the local list of ports */ 4252a7db7a6SVincenzo Maffione for (j = 0; j < b->bdg_active_ports; j++) { 4262a7db7a6SVincenzo Maffione i = b->bdg_port_index[j]; 4272a7db7a6SVincenzo Maffione vpna = b->bdg_ports[i]; 42875f4f3edSVincenzo Maffione nm_prdis("checking %s", vpna->up.name); 4292a7db7a6SVincenzo Maffione if (!strcmp(vpna->up.name, nr_name)) { 4302a7db7a6SVincenzo Maffione netmap_adapter_get(&vpna->up); 43175f4f3edSVincenzo Maffione nm_prdis("found existing if %s refs %d", nr_name) 4322a7db7a6SVincenzo Maffione *na = &vpna->up; 4332a7db7a6SVincenzo Maffione return 0; 4342a7db7a6SVincenzo Maffione } 4352a7db7a6SVincenzo Maffione } 4362a7db7a6SVincenzo Maffione /* not found, should we create it? */ 4372a7db7a6SVincenzo Maffione if (!create) 4382a7db7a6SVincenzo Maffione return ENXIO; 4392a7db7a6SVincenzo Maffione /* yes we should, see if we have space to attach entries */ 4402a7db7a6SVincenzo Maffione needed = 2; /* in some cases we only need 1 */ 4412a7db7a6SVincenzo Maffione if (b->bdg_active_ports + needed >= NM_BDG_MAXPORTS) { 442b6e66be2SVincenzo Maffione nm_prerr("bridge full %d, cannot create new port", b->bdg_active_ports); 4432a7db7a6SVincenzo Maffione return ENOMEM; 4442a7db7a6SVincenzo Maffione } 4452a7db7a6SVincenzo Maffione /* record the next two ports available, but do not allocate yet */ 4462a7db7a6SVincenzo Maffione cand = b->bdg_port_index[b->bdg_active_ports]; 4472a7db7a6SVincenzo Maffione cand2 = b->bdg_port_index[b->bdg_active_ports + 1]; 44875f4f3edSVincenzo Maffione nm_prdis("+++ bridge %s port %s used %d avail %d %d", 4492a7db7a6SVincenzo Maffione b->bdg_basename, ifname, b->bdg_active_ports, cand, cand2); 4502a7db7a6SVincenzo Maffione 4512a7db7a6SVincenzo Maffione /* 4522a7db7a6SVincenzo Maffione * try see if there is a matching NIC with this name 4532a7db7a6SVincenzo Maffione * (after the bridge's name) 4542a7db7a6SVincenzo Maffione */ 4552a7db7a6SVincenzo Maffione ifname = nr_name + b->bdg_namelen + 1; 4562a7db7a6SVincenzo Maffione ifp = ifunit_ref(ifname); 4572a7db7a6SVincenzo Maffione if (!ifp) { 4582a7db7a6SVincenzo Maffione /* Create an ephemeral virtual port. 4592a7db7a6SVincenzo Maffione * This block contains all the ephemeral-specific logic. 4602a7db7a6SVincenzo Maffione */ 4612a7db7a6SVincenzo Maffione 4622a7db7a6SVincenzo Maffione if (hdr->nr_reqtype != NETMAP_REQ_REGISTER) { 4632a7db7a6SVincenzo Maffione error = EINVAL; 4642a7db7a6SVincenzo Maffione goto out; 4652a7db7a6SVincenzo Maffione } 4662a7db7a6SVincenzo Maffione 4672a7db7a6SVincenzo Maffione /* bdg_netmap_attach creates a struct netmap_adapter */ 468b6e66be2SVincenzo Maffione error = b->bdg_ops.vp_create(hdr, NULL, nmd, &vpna); 4692a7db7a6SVincenzo Maffione if (error) { 470b6e66be2SVincenzo Maffione if (netmap_debug & NM_DEBUG_BDG) 471b6e66be2SVincenzo Maffione nm_prerr("error %d", error); 4722a7db7a6SVincenzo Maffione goto out; 4732a7db7a6SVincenzo Maffione } 4742a7db7a6SVincenzo Maffione /* shortcut - we can skip get_hw_na(), 4752a7db7a6SVincenzo Maffione * ownership check and nm_bdg_attach() 4762a7db7a6SVincenzo Maffione */ 4772a7db7a6SVincenzo Maffione 4782a7db7a6SVincenzo Maffione } else { 4792a7db7a6SVincenzo Maffione struct netmap_adapter *hw; 4802a7db7a6SVincenzo Maffione 4812a7db7a6SVincenzo Maffione /* the vale:nic syntax is only valid for some commands */ 4822a7db7a6SVincenzo Maffione switch (hdr->nr_reqtype) { 4832a7db7a6SVincenzo Maffione case NETMAP_REQ_VALE_ATTACH: 4842a7db7a6SVincenzo Maffione case NETMAP_REQ_VALE_DETACH: 4852a7db7a6SVincenzo Maffione case NETMAP_REQ_VALE_POLLING_ENABLE: 4862a7db7a6SVincenzo Maffione case NETMAP_REQ_VALE_POLLING_DISABLE: 4872a7db7a6SVincenzo Maffione break; /* ok */ 4882a7db7a6SVincenzo Maffione default: 4892a7db7a6SVincenzo Maffione error = EINVAL; 4902a7db7a6SVincenzo Maffione goto out; 4912a7db7a6SVincenzo Maffione } 4922a7db7a6SVincenzo Maffione 4932a7db7a6SVincenzo Maffione error = netmap_get_hw_na(ifp, nmd, &hw); 4942a7db7a6SVincenzo Maffione if (error || hw == NULL) 4952a7db7a6SVincenzo Maffione goto out; 4962a7db7a6SVincenzo Maffione 4972a7db7a6SVincenzo Maffione /* host adapter might not be created */ 4982a7db7a6SVincenzo Maffione error = hw->nm_bdg_attach(nr_name, hw, b); 4992a7db7a6SVincenzo Maffione if (error == NM_NEED_BWRAP) { 500b6e66be2SVincenzo Maffione error = b->bdg_ops.bwrap_attach(nr_name, hw); 5012a7db7a6SVincenzo Maffione } 5022a7db7a6SVincenzo Maffione if (error) 5032a7db7a6SVincenzo Maffione goto out; 5042a7db7a6SVincenzo Maffione vpna = hw->na_vp; 5052a7db7a6SVincenzo Maffione hostna = hw->na_hostvp; 5062a7db7a6SVincenzo Maffione if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) { 5072a7db7a6SVincenzo Maffione /* Check if we need to skip the host rings. */ 5082a7db7a6SVincenzo Maffione struct nmreq_vale_attach *areq = 5092a7db7a6SVincenzo Maffione (struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body; 5102a7db7a6SVincenzo Maffione if (areq->reg.nr_mode != NR_REG_NIC_SW) { 5112a7db7a6SVincenzo Maffione hostna = NULL; 5122a7db7a6SVincenzo Maffione } 5132a7db7a6SVincenzo Maffione } 5142a7db7a6SVincenzo Maffione } 5152a7db7a6SVincenzo Maffione 5162a7db7a6SVincenzo Maffione BDG_WLOCK(b); 5172a7db7a6SVincenzo Maffione vpna->bdg_port = cand; 51875f4f3edSVincenzo Maffione nm_prdis("NIC %p to bridge port %d", vpna, cand); 5192a7db7a6SVincenzo Maffione /* bind the port to the bridge (virtual ports are not active) */ 5202a7db7a6SVincenzo Maffione b->bdg_ports[cand] = vpna; 5212a7db7a6SVincenzo Maffione vpna->na_bdg = b; 5222a7db7a6SVincenzo Maffione b->bdg_active_ports++; 5232a7db7a6SVincenzo Maffione if (hostna != NULL) { 5242a7db7a6SVincenzo Maffione /* also bind the host stack to the bridge */ 5252a7db7a6SVincenzo Maffione b->bdg_ports[cand2] = hostna; 5262a7db7a6SVincenzo Maffione hostna->bdg_port = cand2; 5272a7db7a6SVincenzo Maffione hostna->na_bdg = b; 5282a7db7a6SVincenzo Maffione b->bdg_active_ports++; 52975f4f3edSVincenzo Maffione nm_prdis("host %p to bridge port %d", hostna, cand2); 5302a7db7a6SVincenzo Maffione } 53175f4f3edSVincenzo Maffione nm_prdis("if %s refs %d", ifname, vpna->up.na_refcount); 5322a7db7a6SVincenzo Maffione BDG_WUNLOCK(b); 5332a7db7a6SVincenzo Maffione *na = &vpna->up; 5342a7db7a6SVincenzo Maffione netmap_adapter_get(*na); 5352a7db7a6SVincenzo Maffione 5362a7db7a6SVincenzo Maffione out: 5372a7db7a6SVincenzo Maffione if (ifp) 5382a7db7a6SVincenzo Maffione if_rele(ifp); 5392a7db7a6SVincenzo Maffione 5402a7db7a6SVincenzo Maffione return error; 5412a7db7a6SVincenzo Maffione } 5422a7db7a6SVincenzo Maffione 543a6d768d8SVincenzo Maffione /* Process NETMAP_REQ_VALE_ATTACH. 544a6d768d8SVincenzo Maffione */ 545a6d768d8SVincenzo Maffione int 546a6d768d8SVincenzo Maffione netmap_bdg_attach(struct nmreq_header *hdr, void *auth_token) 547a6d768d8SVincenzo Maffione { 548a6d768d8SVincenzo Maffione struct nmreq_vale_attach *req = 549a6d768d8SVincenzo Maffione (struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body; 550a6d768d8SVincenzo Maffione struct netmap_vp_adapter * vpna; 551a6d768d8SVincenzo Maffione struct netmap_adapter *na = NULL; 552a6d768d8SVincenzo Maffione struct netmap_mem_d *nmd = NULL; 553a6d768d8SVincenzo Maffione struct nm_bridge *b = NULL; 554a6d768d8SVincenzo Maffione int error; 555a6d768d8SVincenzo Maffione 556a6d768d8SVincenzo Maffione NMG_LOCK(); 557a6d768d8SVincenzo Maffione /* permission check for modified bridges */ 558a6d768d8SVincenzo Maffione b = nm_find_bridge(hdr->nr_name, 0 /* don't create */, NULL); 559a6d768d8SVincenzo Maffione if (b && !nm_bdg_valid_auth_token(b, auth_token)) { 560a6d768d8SVincenzo Maffione error = EACCES; 561a6d768d8SVincenzo Maffione goto unlock_exit; 562a6d768d8SVincenzo Maffione } 563a6d768d8SVincenzo Maffione 564a6d768d8SVincenzo Maffione if (req->reg.nr_mem_id) { 565a6d768d8SVincenzo Maffione nmd = netmap_mem_find(req->reg.nr_mem_id); 566a6d768d8SVincenzo Maffione if (nmd == NULL) { 567a6d768d8SVincenzo Maffione error = EINVAL; 568a6d768d8SVincenzo Maffione goto unlock_exit; 569a6d768d8SVincenzo Maffione } 570a6d768d8SVincenzo Maffione } 571a6d768d8SVincenzo Maffione 572a6d768d8SVincenzo Maffione /* check for existing one */ 573a6d768d8SVincenzo Maffione error = netmap_get_vale_na(hdr, &na, nmd, 0); 574a6d768d8SVincenzo Maffione if (na) { 575a6d768d8SVincenzo Maffione error = EBUSY; 576a6d768d8SVincenzo Maffione goto unref_exit; 577a6d768d8SVincenzo Maffione } 578a6d768d8SVincenzo Maffione error = netmap_get_vale_na(hdr, &na, 579a6d768d8SVincenzo Maffione nmd, 1 /* create if not exists */); 580a6d768d8SVincenzo Maffione if (error) { /* no device */ 581a6d768d8SVincenzo Maffione goto unlock_exit; 582a6d768d8SVincenzo Maffione } 583a6d768d8SVincenzo Maffione 584a6d768d8SVincenzo Maffione if (na == NULL) { /* VALE prefix missing */ 585a6d768d8SVincenzo Maffione error = EINVAL; 586a6d768d8SVincenzo Maffione goto unlock_exit; 587a6d768d8SVincenzo Maffione } 588a6d768d8SVincenzo Maffione 589a6d768d8SVincenzo Maffione if (NETMAP_OWNED_BY_ANY(na)) { 590a6d768d8SVincenzo Maffione error = EBUSY; 591a6d768d8SVincenzo Maffione goto unref_exit; 592a6d768d8SVincenzo Maffione } 593a6d768d8SVincenzo Maffione 594a6d768d8SVincenzo Maffione if (na->nm_bdg_ctl) { 595a6d768d8SVincenzo Maffione /* nop for VALE ports. The bwrap needs to put the hwna 596a6d768d8SVincenzo Maffione * in netmap mode (see netmap_bwrap_bdg_ctl) 597a6d768d8SVincenzo Maffione */ 598a6d768d8SVincenzo Maffione error = na->nm_bdg_ctl(hdr, na); 599a6d768d8SVincenzo Maffione if (error) 600a6d768d8SVincenzo Maffione goto unref_exit; 601a6d768d8SVincenzo Maffione nm_prdis("registered %s to netmap-mode", na->name); 602a6d768d8SVincenzo Maffione } 603a6d768d8SVincenzo Maffione vpna = (struct netmap_vp_adapter *)na; 604a6d768d8SVincenzo Maffione req->port_index = vpna->bdg_port; 605a6d768d8SVincenzo Maffione 606a6d768d8SVincenzo Maffione if (nmd) 607a6d768d8SVincenzo Maffione netmap_mem_put(nmd); 608a6d768d8SVincenzo Maffione 609a6d768d8SVincenzo Maffione NMG_UNLOCK(); 610a6d768d8SVincenzo Maffione return 0; 611a6d768d8SVincenzo Maffione 612a6d768d8SVincenzo Maffione unref_exit: 613a6d768d8SVincenzo Maffione netmap_adapter_put(na); 614a6d768d8SVincenzo Maffione unlock_exit: 615a6d768d8SVincenzo Maffione if (nmd) 616a6d768d8SVincenzo Maffione netmap_mem_put(nmd); 617a6d768d8SVincenzo Maffione 618a6d768d8SVincenzo Maffione NMG_UNLOCK(); 619a6d768d8SVincenzo Maffione return error; 620a6d768d8SVincenzo Maffione } 621a6d768d8SVincenzo Maffione 622b6e66be2SVincenzo Maffione 6232a7db7a6SVincenzo Maffione int 6242a7db7a6SVincenzo Maffione nm_is_bwrap(struct netmap_adapter *na) 6252a7db7a6SVincenzo Maffione { 6262a7db7a6SVincenzo Maffione return na->nm_register == netmap_bwrap_reg; 6272a7db7a6SVincenzo Maffione } 6282a7db7a6SVincenzo Maffione 629a6d768d8SVincenzo Maffione /* Process NETMAP_REQ_VALE_DETACH. 630a6d768d8SVincenzo Maffione */ 631a6d768d8SVincenzo Maffione int 632a6d768d8SVincenzo Maffione netmap_bdg_detach(struct nmreq_header *hdr, void *auth_token) 633a6d768d8SVincenzo Maffione { 634a6d768d8SVincenzo Maffione int error; 635a6d768d8SVincenzo Maffione 636a6d768d8SVincenzo Maffione NMG_LOCK(); 637a6d768d8SVincenzo Maffione error = netmap_bdg_detach_locked(hdr, auth_token); 638a6d768d8SVincenzo Maffione NMG_UNLOCK(); 639a6d768d8SVincenzo Maffione return error; 640a6d768d8SVincenzo Maffione } 641a6d768d8SVincenzo Maffione 642a6d768d8SVincenzo Maffione int 643a6d768d8SVincenzo Maffione netmap_bdg_detach_locked(struct nmreq_header *hdr, void *auth_token) 644a6d768d8SVincenzo Maffione { 645a6d768d8SVincenzo Maffione struct nmreq_vale_detach *nmreq_det = (void *)(uintptr_t)hdr->nr_body; 646a6d768d8SVincenzo Maffione struct netmap_vp_adapter *vpna; 647a6d768d8SVincenzo Maffione struct netmap_adapter *na; 648a6d768d8SVincenzo Maffione struct nm_bridge *b = NULL; 649a6d768d8SVincenzo Maffione int error; 650a6d768d8SVincenzo Maffione 651a6d768d8SVincenzo Maffione /* permission check for modified bridges */ 652a6d768d8SVincenzo Maffione b = nm_find_bridge(hdr->nr_name, 0 /* don't create */, NULL); 653a6d768d8SVincenzo Maffione if (b && !nm_bdg_valid_auth_token(b, auth_token)) { 654a6d768d8SVincenzo Maffione error = EACCES; 655a6d768d8SVincenzo Maffione goto error_exit; 656a6d768d8SVincenzo Maffione } 657a6d768d8SVincenzo Maffione 658a6d768d8SVincenzo Maffione error = netmap_get_vale_na(hdr, &na, NULL, 0 /* don't create */); 659a6d768d8SVincenzo Maffione if (error) { /* no device, or another bridge or user owns the device */ 660a6d768d8SVincenzo Maffione goto error_exit; 661a6d768d8SVincenzo Maffione } 662a6d768d8SVincenzo Maffione 663a6d768d8SVincenzo Maffione if (na == NULL) { /* VALE prefix missing */ 664a6d768d8SVincenzo Maffione error = EINVAL; 665a6d768d8SVincenzo Maffione goto error_exit; 666a6d768d8SVincenzo Maffione } else if (nm_is_bwrap(na) && 667a6d768d8SVincenzo Maffione ((struct netmap_bwrap_adapter *)na)->na_polling_state) { 668a6d768d8SVincenzo Maffione /* Don't detach a NIC with polling */ 669a6d768d8SVincenzo Maffione error = EBUSY; 670a6d768d8SVincenzo Maffione goto unref_exit; 671a6d768d8SVincenzo Maffione } 672a6d768d8SVincenzo Maffione 673a6d768d8SVincenzo Maffione vpna = (struct netmap_vp_adapter *)na; 674a6d768d8SVincenzo Maffione if (na->na_vp != vpna) { 675a6d768d8SVincenzo Maffione /* trying to detach first attach of VALE persistent port attached 676a6d768d8SVincenzo Maffione * to 2 bridges 677a6d768d8SVincenzo Maffione */ 678a6d768d8SVincenzo Maffione error = EBUSY; 679a6d768d8SVincenzo Maffione goto unref_exit; 680a6d768d8SVincenzo Maffione } 681a6d768d8SVincenzo Maffione nmreq_det->port_index = vpna->bdg_port; 682a6d768d8SVincenzo Maffione 683a6d768d8SVincenzo Maffione if (na->nm_bdg_ctl) { 684a6d768d8SVincenzo Maffione /* remove the port from bridge. The bwrap 685a6d768d8SVincenzo Maffione * also needs to put the hwna in normal mode 686a6d768d8SVincenzo Maffione */ 687a6d768d8SVincenzo Maffione error = na->nm_bdg_ctl(hdr, na); 688a6d768d8SVincenzo Maffione } 689a6d768d8SVincenzo Maffione 690a6d768d8SVincenzo Maffione unref_exit: 691a6d768d8SVincenzo Maffione netmap_adapter_put(na); 692a6d768d8SVincenzo Maffione error_exit: 693a6d768d8SVincenzo Maffione return error; 694a6d768d8SVincenzo Maffione 695a6d768d8SVincenzo Maffione } 696a6d768d8SVincenzo Maffione 6972a7db7a6SVincenzo Maffione 6982a7db7a6SVincenzo Maffione struct nm_bdg_polling_state; 6992a7db7a6SVincenzo Maffione struct 7002a7db7a6SVincenzo Maffione nm_bdg_kthread { 7012a7db7a6SVincenzo Maffione struct nm_kctx *nmk; 7022a7db7a6SVincenzo Maffione u_int qfirst; 7032a7db7a6SVincenzo Maffione u_int qlast; 7042a7db7a6SVincenzo Maffione struct nm_bdg_polling_state *bps; 7052a7db7a6SVincenzo Maffione }; 7062a7db7a6SVincenzo Maffione 7072a7db7a6SVincenzo Maffione struct nm_bdg_polling_state { 7082a7db7a6SVincenzo Maffione bool configured; 7092a7db7a6SVincenzo Maffione bool stopped; 7102a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna; 7112a7db7a6SVincenzo Maffione uint32_t mode; 7122a7db7a6SVincenzo Maffione u_int qfirst; 7132a7db7a6SVincenzo Maffione u_int qlast; 7142a7db7a6SVincenzo Maffione u_int cpu_from; 7152a7db7a6SVincenzo Maffione u_int ncpus; 7162a7db7a6SVincenzo Maffione struct nm_bdg_kthread *kthreads; 7172a7db7a6SVincenzo Maffione }; 7182a7db7a6SVincenzo Maffione 7192a7db7a6SVincenzo Maffione static void 720b6e66be2SVincenzo Maffione netmap_bwrap_polling(void *data) 7212a7db7a6SVincenzo Maffione { 7222a7db7a6SVincenzo Maffione struct nm_bdg_kthread *nbk = data; 7232a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna; 7242a7db7a6SVincenzo Maffione u_int qfirst, qlast, i; 7252a7db7a6SVincenzo Maffione struct netmap_kring **kring0, *kring; 7262a7db7a6SVincenzo Maffione 7272a7db7a6SVincenzo Maffione if (!nbk) 7282a7db7a6SVincenzo Maffione return; 7292a7db7a6SVincenzo Maffione qfirst = nbk->qfirst; 7302a7db7a6SVincenzo Maffione qlast = nbk->qlast; 7312a7db7a6SVincenzo Maffione bna = nbk->bps->bna; 7322a7db7a6SVincenzo Maffione kring0 = NMR(bna->hwna, NR_RX); 7332a7db7a6SVincenzo Maffione 7342a7db7a6SVincenzo Maffione for (i = qfirst; i < qlast; i++) { 7352a7db7a6SVincenzo Maffione kring = kring0[i]; 7362a7db7a6SVincenzo Maffione kring->nm_notify(kring, 0); 7372a7db7a6SVincenzo Maffione } 7382a7db7a6SVincenzo Maffione } 7392a7db7a6SVincenzo Maffione 7402a7db7a6SVincenzo Maffione static int 7412a7db7a6SVincenzo Maffione nm_bdg_create_kthreads(struct nm_bdg_polling_state *bps) 7422a7db7a6SVincenzo Maffione { 7432a7db7a6SVincenzo Maffione struct nm_kctx_cfg kcfg; 7442a7db7a6SVincenzo Maffione int i, j; 7452a7db7a6SVincenzo Maffione 7462a7db7a6SVincenzo Maffione bps->kthreads = nm_os_malloc(sizeof(struct nm_bdg_kthread) * bps->ncpus); 7472a7db7a6SVincenzo Maffione if (bps->kthreads == NULL) 7482a7db7a6SVincenzo Maffione return ENOMEM; 7492a7db7a6SVincenzo Maffione 7502a7db7a6SVincenzo Maffione bzero(&kcfg, sizeof(kcfg)); 7512a7db7a6SVincenzo Maffione kcfg.worker_fn = netmap_bwrap_polling; 7522a7db7a6SVincenzo Maffione for (i = 0; i < bps->ncpus; i++) { 7532a7db7a6SVincenzo Maffione struct nm_bdg_kthread *t = bps->kthreads + i; 7542a7db7a6SVincenzo Maffione int all = (bps->ncpus == 1 && 7552a7db7a6SVincenzo Maffione bps->mode == NETMAP_POLLING_MODE_SINGLE_CPU); 7562a7db7a6SVincenzo Maffione int affinity = bps->cpu_from + i; 7572a7db7a6SVincenzo Maffione 7582a7db7a6SVincenzo Maffione t->bps = bps; 7592a7db7a6SVincenzo Maffione t->qfirst = all ? bps->qfirst /* must be 0 */: affinity; 7602a7db7a6SVincenzo Maffione t->qlast = all ? bps->qlast : t->qfirst + 1; 761b6e66be2SVincenzo Maffione if (netmap_verbose) 762b6e66be2SVincenzo Maffione nm_prinf("kthread %d a:%u qf:%u ql:%u", i, affinity, t->qfirst, 7632a7db7a6SVincenzo Maffione t->qlast); 7642a7db7a6SVincenzo Maffione 7652a7db7a6SVincenzo Maffione kcfg.type = i; 7662a7db7a6SVincenzo Maffione kcfg.worker_private = t; 7672a7db7a6SVincenzo Maffione t->nmk = nm_os_kctx_create(&kcfg, NULL); 7682a7db7a6SVincenzo Maffione if (t->nmk == NULL) { 7692a7db7a6SVincenzo Maffione goto cleanup; 7702a7db7a6SVincenzo Maffione } 7712a7db7a6SVincenzo Maffione nm_os_kctx_worker_setaff(t->nmk, affinity); 7722a7db7a6SVincenzo Maffione } 7732a7db7a6SVincenzo Maffione return 0; 7742a7db7a6SVincenzo Maffione 7752a7db7a6SVincenzo Maffione cleanup: 7762a7db7a6SVincenzo Maffione for (j = 0; j < i; j++) { 7772a7db7a6SVincenzo Maffione struct nm_bdg_kthread *t = bps->kthreads + i; 7782a7db7a6SVincenzo Maffione nm_os_kctx_destroy(t->nmk); 7792a7db7a6SVincenzo Maffione } 7802a7db7a6SVincenzo Maffione nm_os_free(bps->kthreads); 7812a7db7a6SVincenzo Maffione return EFAULT; 7822a7db7a6SVincenzo Maffione } 7832a7db7a6SVincenzo Maffione 7842a7db7a6SVincenzo Maffione /* A variant of ptnetmap_start_kthreads() */ 7852a7db7a6SVincenzo Maffione static int 7862a7db7a6SVincenzo Maffione nm_bdg_polling_start_kthreads(struct nm_bdg_polling_state *bps) 7872a7db7a6SVincenzo Maffione { 7882a7db7a6SVincenzo Maffione int error, i, j; 7892a7db7a6SVincenzo Maffione 7902a7db7a6SVincenzo Maffione if (!bps) { 791b6e66be2SVincenzo Maffione nm_prerr("polling is not configured"); 7922a7db7a6SVincenzo Maffione return EFAULT; 7932a7db7a6SVincenzo Maffione } 7942a7db7a6SVincenzo Maffione bps->stopped = false; 7952a7db7a6SVincenzo Maffione 7962a7db7a6SVincenzo Maffione for (i = 0; i < bps->ncpus; i++) { 7972a7db7a6SVincenzo Maffione struct nm_bdg_kthread *t = bps->kthreads + i; 7982a7db7a6SVincenzo Maffione error = nm_os_kctx_worker_start(t->nmk); 7992a7db7a6SVincenzo Maffione if (error) { 800b6e66be2SVincenzo Maffione nm_prerr("error in nm_kthread_start(): %d", error); 8012a7db7a6SVincenzo Maffione goto cleanup; 8022a7db7a6SVincenzo Maffione } 8032a7db7a6SVincenzo Maffione } 8042a7db7a6SVincenzo Maffione return 0; 8052a7db7a6SVincenzo Maffione 8062a7db7a6SVincenzo Maffione cleanup: 8072a7db7a6SVincenzo Maffione for (j = 0; j < i; j++) { 8082a7db7a6SVincenzo Maffione struct nm_bdg_kthread *t = bps->kthreads + i; 8092a7db7a6SVincenzo Maffione nm_os_kctx_worker_stop(t->nmk); 8102a7db7a6SVincenzo Maffione } 8112a7db7a6SVincenzo Maffione bps->stopped = true; 8122a7db7a6SVincenzo Maffione return error; 8132a7db7a6SVincenzo Maffione } 8142a7db7a6SVincenzo Maffione 8152a7db7a6SVincenzo Maffione static void 8162a7db7a6SVincenzo Maffione nm_bdg_polling_stop_delete_kthreads(struct nm_bdg_polling_state *bps) 8172a7db7a6SVincenzo Maffione { 8182a7db7a6SVincenzo Maffione int i; 8192a7db7a6SVincenzo Maffione 8202a7db7a6SVincenzo Maffione if (!bps) 8212a7db7a6SVincenzo Maffione return; 8222a7db7a6SVincenzo Maffione 8232a7db7a6SVincenzo Maffione for (i = 0; i < bps->ncpus; i++) { 8242a7db7a6SVincenzo Maffione struct nm_bdg_kthread *t = bps->kthreads + i; 8252a7db7a6SVincenzo Maffione nm_os_kctx_worker_stop(t->nmk); 8262a7db7a6SVincenzo Maffione nm_os_kctx_destroy(t->nmk); 8272a7db7a6SVincenzo Maffione } 8282a7db7a6SVincenzo Maffione bps->stopped = true; 8292a7db7a6SVincenzo Maffione } 8302a7db7a6SVincenzo Maffione 8312a7db7a6SVincenzo Maffione static int 8322a7db7a6SVincenzo Maffione get_polling_cfg(struct nmreq_vale_polling *req, struct netmap_adapter *na, 8332a7db7a6SVincenzo Maffione struct nm_bdg_polling_state *bps) 8342a7db7a6SVincenzo Maffione { 8352a7db7a6SVincenzo Maffione unsigned int avail_cpus, core_from; 8362a7db7a6SVincenzo Maffione unsigned int qfirst, qlast; 8372a7db7a6SVincenzo Maffione uint32_t i = req->nr_first_cpu_id; 8382a7db7a6SVincenzo Maffione uint32_t req_cpus = req->nr_num_polling_cpus; 8392a7db7a6SVincenzo Maffione 8402a7db7a6SVincenzo Maffione avail_cpus = nm_os_ncpus(); 8412a7db7a6SVincenzo Maffione 8422a7db7a6SVincenzo Maffione if (req_cpus == 0) { 843b6e66be2SVincenzo Maffione nm_prerr("req_cpus must be > 0"); 8442a7db7a6SVincenzo Maffione return EINVAL; 8452a7db7a6SVincenzo Maffione } else if (req_cpus >= avail_cpus) { 846b6e66be2SVincenzo Maffione nm_prerr("Cannot use all the CPUs in the system"); 8472a7db7a6SVincenzo Maffione return EINVAL; 8482a7db7a6SVincenzo Maffione } 8492a7db7a6SVincenzo Maffione 8502a7db7a6SVincenzo Maffione if (req->nr_mode == NETMAP_POLLING_MODE_MULTI_CPU) { 8512a7db7a6SVincenzo Maffione /* Use a separate core for each ring. If nr_num_polling_cpus>1 8522a7db7a6SVincenzo Maffione * more consecutive rings are polled. 8532a7db7a6SVincenzo Maffione * For example, if nr_first_cpu_id=2 and nr_num_polling_cpus=2, 8542a7db7a6SVincenzo Maffione * ring 2 and 3 are polled by core 2 and 3, respectively. */ 8552a7db7a6SVincenzo Maffione if (i + req_cpus > nma_get_nrings(na, NR_RX)) { 856b6e66be2SVincenzo Maffione nm_prerr("Rings %u-%u not in range (have %d rings)", 8572a7db7a6SVincenzo Maffione i, i + req_cpus, nma_get_nrings(na, NR_RX)); 8582a7db7a6SVincenzo Maffione return EINVAL; 8592a7db7a6SVincenzo Maffione } 8602a7db7a6SVincenzo Maffione qfirst = i; 8612a7db7a6SVincenzo Maffione qlast = qfirst + req_cpus; 8622a7db7a6SVincenzo Maffione core_from = qfirst; 8632a7db7a6SVincenzo Maffione 8642a7db7a6SVincenzo Maffione } else if (req->nr_mode == NETMAP_POLLING_MODE_SINGLE_CPU) { 8652a7db7a6SVincenzo Maffione /* Poll all the rings using a core specified by nr_first_cpu_id. 8662a7db7a6SVincenzo Maffione * the number of cores must be 1. */ 8672a7db7a6SVincenzo Maffione if (req_cpus != 1) { 868b6e66be2SVincenzo Maffione nm_prerr("ncpus must be 1 for NETMAP_POLLING_MODE_SINGLE_CPU " 8692a7db7a6SVincenzo Maffione "(was %d)", req_cpus); 8702a7db7a6SVincenzo Maffione return EINVAL; 8712a7db7a6SVincenzo Maffione } 8722a7db7a6SVincenzo Maffione qfirst = 0; 8732a7db7a6SVincenzo Maffione qlast = nma_get_nrings(na, NR_RX); 8742a7db7a6SVincenzo Maffione core_from = i; 8752a7db7a6SVincenzo Maffione } else { 876b6e66be2SVincenzo Maffione nm_prerr("Invalid polling mode"); 8772a7db7a6SVincenzo Maffione return EINVAL; 8782a7db7a6SVincenzo Maffione } 8792a7db7a6SVincenzo Maffione 8802a7db7a6SVincenzo Maffione bps->mode = req->nr_mode; 8812a7db7a6SVincenzo Maffione bps->qfirst = qfirst; 8822a7db7a6SVincenzo Maffione bps->qlast = qlast; 8832a7db7a6SVincenzo Maffione bps->cpu_from = core_from; 8842a7db7a6SVincenzo Maffione bps->ncpus = req_cpus; 885b6e66be2SVincenzo Maffione nm_prinf("%s qfirst %u qlast %u cpu_from %u ncpus %u", 8862a7db7a6SVincenzo Maffione req->nr_mode == NETMAP_POLLING_MODE_MULTI_CPU ? 8872a7db7a6SVincenzo Maffione "MULTI" : "SINGLE", 8882a7db7a6SVincenzo Maffione qfirst, qlast, core_from, req_cpus); 8892a7db7a6SVincenzo Maffione return 0; 8902a7db7a6SVincenzo Maffione } 8912a7db7a6SVincenzo Maffione 8922a7db7a6SVincenzo Maffione static int 8932a7db7a6SVincenzo Maffione nm_bdg_ctl_polling_start(struct nmreq_vale_polling *req, struct netmap_adapter *na) 8942a7db7a6SVincenzo Maffione { 8952a7db7a6SVincenzo Maffione struct nm_bdg_polling_state *bps; 8962a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna; 8972a7db7a6SVincenzo Maffione int error; 8982a7db7a6SVincenzo Maffione 8992a7db7a6SVincenzo Maffione bna = (struct netmap_bwrap_adapter *)na; 9002a7db7a6SVincenzo Maffione if (bna->na_polling_state) { 901b6e66be2SVincenzo Maffione nm_prerr("ERROR adapter already in polling mode"); 9022a7db7a6SVincenzo Maffione return EFAULT; 9032a7db7a6SVincenzo Maffione } 9042a7db7a6SVincenzo Maffione 9052a7db7a6SVincenzo Maffione bps = nm_os_malloc(sizeof(*bps)); 9062a7db7a6SVincenzo Maffione if (!bps) 9072a7db7a6SVincenzo Maffione return ENOMEM; 9082a7db7a6SVincenzo Maffione bps->configured = false; 9092a7db7a6SVincenzo Maffione bps->stopped = true; 9102a7db7a6SVincenzo Maffione 9112a7db7a6SVincenzo Maffione if (get_polling_cfg(req, na, bps)) { 9122a7db7a6SVincenzo Maffione nm_os_free(bps); 9132a7db7a6SVincenzo Maffione return EINVAL; 9142a7db7a6SVincenzo Maffione } 9152a7db7a6SVincenzo Maffione 9162a7db7a6SVincenzo Maffione if (nm_bdg_create_kthreads(bps)) { 9172a7db7a6SVincenzo Maffione nm_os_free(bps); 9182a7db7a6SVincenzo Maffione return EFAULT; 9192a7db7a6SVincenzo Maffione } 9202a7db7a6SVincenzo Maffione 9212a7db7a6SVincenzo Maffione bps->configured = true; 9222a7db7a6SVincenzo Maffione bna->na_polling_state = bps; 9232a7db7a6SVincenzo Maffione bps->bna = bna; 9242a7db7a6SVincenzo Maffione 9252a7db7a6SVincenzo Maffione /* disable interrupts if possible */ 9262a7db7a6SVincenzo Maffione nma_intr_enable(bna->hwna, 0); 9272a7db7a6SVincenzo Maffione /* start kthread now */ 9282a7db7a6SVincenzo Maffione error = nm_bdg_polling_start_kthreads(bps); 9292a7db7a6SVincenzo Maffione if (error) { 930b6e66be2SVincenzo Maffione nm_prerr("ERROR nm_bdg_polling_start_kthread()"); 9312a7db7a6SVincenzo Maffione nm_os_free(bps->kthreads); 9322a7db7a6SVincenzo Maffione nm_os_free(bps); 9332a7db7a6SVincenzo Maffione bna->na_polling_state = NULL; 9342a7db7a6SVincenzo Maffione nma_intr_enable(bna->hwna, 1); 9352a7db7a6SVincenzo Maffione } 9362a7db7a6SVincenzo Maffione return error; 9372a7db7a6SVincenzo Maffione } 9382a7db7a6SVincenzo Maffione 9392a7db7a6SVincenzo Maffione static int 9402a7db7a6SVincenzo Maffione nm_bdg_ctl_polling_stop(struct netmap_adapter *na) 9412a7db7a6SVincenzo Maffione { 9422a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter *)na; 9432a7db7a6SVincenzo Maffione struct nm_bdg_polling_state *bps; 9442a7db7a6SVincenzo Maffione 9452a7db7a6SVincenzo Maffione if (!bna->na_polling_state) { 946b6e66be2SVincenzo Maffione nm_prerr("ERROR adapter is not in polling mode"); 9472a7db7a6SVincenzo Maffione return EFAULT; 9482a7db7a6SVincenzo Maffione } 9492a7db7a6SVincenzo Maffione bps = bna->na_polling_state; 9502a7db7a6SVincenzo Maffione nm_bdg_polling_stop_delete_kthreads(bna->na_polling_state); 9512a7db7a6SVincenzo Maffione bps->configured = false; 9522a7db7a6SVincenzo Maffione nm_os_free(bps); 9532a7db7a6SVincenzo Maffione bna->na_polling_state = NULL; 954*45c67e8fSVincenzo Maffione /* re-enable interrupts */ 9552a7db7a6SVincenzo Maffione nma_intr_enable(bna->hwna, 1); 9562a7db7a6SVincenzo Maffione return 0; 9572a7db7a6SVincenzo Maffione } 9582a7db7a6SVincenzo Maffione 9592a7db7a6SVincenzo Maffione int 9602a7db7a6SVincenzo Maffione nm_bdg_polling(struct nmreq_header *hdr) 9612a7db7a6SVincenzo Maffione { 9622a7db7a6SVincenzo Maffione struct nmreq_vale_polling *req = 9632a7db7a6SVincenzo Maffione (struct nmreq_vale_polling *)(uintptr_t)hdr->nr_body; 9642a7db7a6SVincenzo Maffione struct netmap_adapter *na = NULL; 9652a7db7a6SVincenzo Maffione int error = 0; 9662a7db7a6SVincenzo Maffione 9672a7db7a6SVincenzo Maffione NMG_LOCK(); 9682a7db7a6SVincenzo Maffione error = netmap_get_vale_na(hdr, &na, NULL, /*create=*/0); 9692a7db7a6SVincenzo Maffione if (na && !error) { 9702a7db7a6SVincenzo Maffione if (!nm_is_bwrap(na)) { 9712a7db7a6SVincenzo Maffione error = EOPNOTSUPP; 9722a7db7a6SVincenzo Maffione } else if (hdr->nr_reqtype == NETMAP_BDG_POLLING_ON) { 9732a7db7a6SVincenzo Maffione error = nm_bdg_ctl_polling_start(req, na); 9742a7db7a6SVincenzo Maffione if (!error) 9752a7db7a6SVincenzo Maffione netmap_adapter_get(na); 9762a7db7a6SVincenzo Maffione } else { 9772a7db7a6SVincenzo Maffione error = nm_bdg_ctl_polling_stop(na); 9782a7db7a6SVincenzo Maffione if (!error) 9792a7db7a6SVincenzo Maffione netmap_adapter_put(na); 9802a7db7a6SVincenzo Maffione } 9812a7db7a6SVincenzo Maffione netmap_adapter_put(na); 9822a7db7a6SVincenzo Maffione } else if (!na && !error) { 9832a7db7a6SVincenzo Maffione /* Not VALE port. */ 9842a7db7a6SVincenzo Maffione error = EINVAL; 9852a7db7a6SVincenzo Maffione } 9862a7db7a6SVincenzo Maffione NMG_UNLOCK(); 9872a7db7a6SVincenzo Maffione 9882a7db7a6SVincenzo Maffione return error; 9892a7db7a6SVincenzo Maffione } 9902a7db7a6SVincenzo Maffione 9912a7db7a6SVincenzo Maffione /* Called by external kernel modules (e.g., Openvswitch). 9922a7db7a6SVincenzo Maffione * to set configure/lookup/dtor functions of a VALE instance. 9932a7db7a6SVincenzo Maffione * Register callbacks to the given bridge. 'name' may be just 9942a7db7a6SVincenzo Maffione * bridge's name (including ':' if it is not just NM_BDG_NAME). 9952a7db7a6SVincenzo Maffione * 9962a7db7a6SVincenzo Maffione * Called without NMG_LOCK. 9972a7db7a6SVincenzo Maffione */ 9982a7db7a6SVincenzo Maffione 9992a7db7a6SVincenzo Maffione int 10002a7db7a6SVincenzo Maffione netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data, void *auth_token) 10012a7db7a6SVincenzo Maffione { 10022a7db7a6SVincenzo Maffione struct nm_bridge *b; 10032a7db7a6SVincenzo Maffione int error = 0; 10042a7db7a6SVincenzo Maffione 10052a7db7a6SVincenzo Maffione NMG_LOCK(); 10062a7db7a6SVincenzo Maffione b = nm_find_bridge(name, 0 /* don't create */, NULL); 10072a7db7a6SVincenzo Maffione if (!b) { 10082a7db7a6SVincenzo Maffione error = ENXIO; 10092a7db7a6SVincenzo Maffione goto unlock_regops; 10102a7db7a6SVincenzo Maffione } 10112a7db7a6SVincenzo Maffione if (!nm_bdg_valid_auth_token(b, auth_token)) { 10122a7db7a6SVincenzo Maffione error = EACCES; 10132a7db7a6SVincenzo Maffione goto unlock_regops; 10142a7db7a6SVincenzo Maffione } 10152a7db7a6SVincenzo Maffione 10162a7db7a6SVincenzo Maffione BDG_WLOCK(b); 10172a7db7a6SVincenzo Maffione if (!bdg_ops) { 10182a7db7a6SVincenzo Maffione /* resetting the bridge */ 10192a7db7a6SVincenzo Maffione bzero(b->ht, sizeof(struct nm_hash_ent) * NM_BDG_HASH); 1020b6e66be2SVincenzo Maffione b->bdg_ops = b->bdg_saved_ops; 10212a7db7a6SVincenzo Maffione b->private_data = b->ht; 10222a7db7a6SVincenzo Maffione } else { 10232a7db7a6SVincenzo Maffione /* modifying the bridge */ 10242a7db7a6SVincenzo Maffione b->private_data = private_data; 1025b6e66be2SVincenzo Maffione #define nm_bdg_override(m) if (bdg_ops->m) b->bdg_ops.m = bdg_ops->m 1026b6e66be2SVincenzo Maffione nm_bdg_override(lookup); 1027b6e66be2SVincenzo Maffione nm_bdg_override(config); 1028b6e66be2SVincenzo Maffione nm_bdg_override(dtor); 1029b6e66be2SVincenzo Maffione nm_bdg_override(vp_create); 1030b6e66be2SVincenzo Maffione nm_bdg_override(bwrap_attach); 1031b6e66be2SVincenzo Maffione #undef nm_bdg_override 1032b6e66be2SVincenzo Maffione 10332a7db7a6SVincenzo Maffione } 10342a7db7a6SVincenzo Maffione BDG_WUNLOCK(b); 10352a7db7a6SVincenzo Maffione 10362a7db7a6SVincenzo Maffione unlock_regops: 10372a7db7a6SVincenzo Maffione NMG_UNLOCK(); 10382a7db7a6SVincenzo Maffione return error; 10392a7db7a6SVincenzo Maffione } 10402a7db7a6SVincenzo Maffione 10412a7db7a6SVincenzo Maffione 10422a7db7a6SVincenzo Maffione int 10432a7db7a6SVincenzo Maffione netmap_bdg_config(struct nm_ifreq *nr) 10442a7db7a6SVincenzo Maffione { 10452a7db7a6SVincenzo Maffione struct nm_bridge *b; 10462a7db7a6SVincenzo Maffione int error = EINVAL; 10472a7db7a6SVincenzo Maffione 10482a7db7a6SVincenzo Maffione NMG_LOCK(); 10492a7db7a6SVincenzo Maffione b = nm_find_bridge(nr->nifr_name, 0, NULL); 10502a7db7a6SVincenzo Maffione if (!b) { 10512a7db7a6SVincenzo Maffione NMG_UNLOCK(); 10522a7db7a6SVincenzo Maffione return error; 10532a7db7a6SVincenzo Maffione } 10542a7db7a6SVincenzo Maffione NMG_UNLOCK(); 10552a7db7a6SVincenzo Maffione /* Don't call config() with NMG_LOCK() held */ 10562a7db7a6SVincenzo Maffione BDG_RLOCK(b); 1057b6e66be2SVincenzo Maffione if (b->bdg_ops.config != NULL) 1058b6e66be2SVincenzo Maffione error = b->bdg_ops.config(nr); 10592a7db7a6SVincenzo Maffione BDG_RUNLOCK(b); 10602a7db7a6SVincenzo Maffione return error; 10612a7db7a6SVincenzo Maffione } 10622a7db7a6SVincenzo Maffione 10632a7db7a6SVincenzo Maffione 10642a7db7a6SVincenzo Maffione /* nm_register callback for VALE ports */ 10652a7db7a6SVincenzo Maffione int 10662a7db7a6SVincenzo Maffione netmap_vp_reg(struct netmap_adapter *na, int onoff) 10672a7db7a6SVincenzo Maffione { 10682a7db7a6SVincenzo Maffione struct netmap_vp_adapter *vpna = 10692a7db7a6SVincenzo Maffione (struct netmap_vp_adapter*)na; 10702a7db7a6SVincenzo Maffione 10712a7db7a6SVincenzo Maffione /* persistent ports may be put in netmap mode 10722a7db7a6SVincenzo Maffione * before being attached to a bridge 10732a7db7a6SVincenzo Maffione */ 10742a7db7a6SVincenzo Maffione if (vpna->na_bdg) 10752a7db7a6SVincenzo Maffione BDG_WLOCK(vpna->na_bdg); 10762a7db7a6SVincenzo Maffione if (onoff) { 107775f4f3edSVincenzo Maffione netmap_krings_mode_commit(na, onoff); 10782a7db7a6SVincenzo Maffione if (na->active_fds == 0) 10792a7db7a6SVincenzo Maffione na->na_flags |= NAF_NETMAP_ON; 10802a7db7a6SVincenzo Maffione /* XXX on FreeBSD, persistent VALE ports should also 10812a7db7a6SVincenzo Maffione * toggle IFCAP_NETMAP in na->ifp (2014-03-16) 10822a7db7a6SVincenzo Maffione */ 10832a7db7a6SVincenzo Maffione } else { 10842a7db7a6SVincenzo Maffione if (na->active_fds == 0) 10852a7db7a6SVincenzo Maffione na->na_flags &= ~NAF_NETMAP_ON; 108675f4f3edSVincenzo Maffione netmap_krings_mode_commit(na, onoff); 10872a7db7a6SVincenzo Maffione } 10882a7db7a6SVincenzo Maffione if (vpna->na_bdg) 10892a7db7a6SVincenzo Maffione BDG_WUNLOCK(vpna->na_bdg); 10902a7db7a6SVincenzo Maffione return 0; 10912a7db7a6SVincenzo Maffione } 10922a7db7a6SVincenzo Maffione 10932a7db7a6SVincenzo Maffione 10942a7db7a6SVincenzo Maffione /* rxsync code used by VALE ports nm_rxsync callback and also 10952a7db7a6SVincenzo Maffione * internally by the brwap 10962a7db7a6SVincenzo Maffione */ 10972a7db7a6SVincenzo Maffione static int 10982a7db7a6SVincenzo Maffione netmap_vp_rxsync_locked(struct netmap_kring *kring, int flags) 10992a7db7a6SVincenzo Maffione { 11002a7db7a6SVincenzo Maffione struct netmap_adapter *na = kring->na; 11012a7db7a6SVincenzo Maffione struct netmap_ring *ring = kring->ring; 11022a7db7a6SVincenzo Maffione u_int nm_i, lim = kring->nkr_num_slots - 1; 11032a7db7a6SVincenzo Maffione u_int head = kring->rhead; 11042a7db7a6SVincenzo Maffione int n; 11052a7db7a6SVincenzo Maffione 11062a7db7a6SVincenzo Maffione if (head > lim) { 1107b6e66be2SVincenzo Maffione nm_prerr("ouch dangerous reset!!!"); 11082a7db7a6SVincenzo Maffione n = netmap_ring_reinit(kring); 11092a7db7a6SVincenzo Maffione goto done; 11102a7db7a6SVincenzo Maffione } 11112a7db7a6SVincenzo Maffione 11122a7db7a6SVincenzo Maffione /* First part, import newly received packets. */ 11132a7db7a6SVincenzo Maffione /* actually nothing to do here, they are already in the kring */ 11142a7db7a6SVincenzo Maffione 11152a7db7a6SVincenzo Maffione /* Second part, skip past packets that userspace has released. */ 11162a7db7a6SVincenzo Maffione nm_i = kring->nr_hwcur; 11172a7db7a6SVincenzo Maffione if (nm_i != head) { 11182a7db7a6SVincenzo Maffione /* consistency check, but nothing really important here */ 11192a7db7a6SVincenzo Maffione for (n = 0; likely(nm_i != head); n++) { 11202a7db7a6SVincenzo Maffione struct netmap_slot *slot = &ring->slot[nm_i]; 11212a7db7a6SVincenzo Maffione void *addr = NMB(na, slot); 11222a7db7a6SVincenzo Maffione 11232a7db7a6SVincenzo Maffione if (addr == NETMAP_BUF_BASE(kring->na)) { /* bad buf */ 1124b6e66be2SVincenzo Maffione nm_prerr("bad buffer index %d, ignore ?", 11252a7db7a6SVincenzo Maffione slot->buf_idx); 11262a7db7a6SVincenzo Maffione } 11272a7db7a6SVincenzo Maffione slot->flags &= ~NS_BUF_CHANGED; 11282a7db7a6SVincenzo Maffione nm_i = nm_next(nm_i, lim); 11292a7db7a6SVincenzo Maffione } 11302a7db7a6SVincenzo Maffione kring->nr_hwcur = head; 11312a7db7a6SVincenzo Maffione } 11322a7db7a6SVincenzo Maffione 11332a7db7a6SVincenzo Maffione n = 0; 11342a7db7a6SVincenzo Maffione done: 11352a7db7a6SVincenzo Maffione return n; 11362a7db7a6SVincenzo Maffione } 11372a7db7a6SVincenzo Maffione 11382a7db7a6SVincenzo Maffione /* 11392a7db7a6SVincenzo Maffione * nm_rxsync callback for VALE ports 11402a7db7a6SVincenzo Maffione * user process reading from a VALE switch. 11412a7db7a6SVincenzo Maffione * Already protected against concurrent calls from userspace, 11422a7db7a6SVincenzo Maffione * but we must acquire the queue's lock to protect against 11432a7db7a6SVincenzo Maffione * writers on the same queue. 11442a7db7a6SVincenzo Maffione */ 11452a7db7a6SVincenzo Maffione int 11462a7db7a6SVincenzo Maffione netmap_vp_rxsync(struct netmap_kring *kring, int flags) 11472a7db7a6SVincenzo Maffione { 11482a7db7a6SVincenzo Maffione int n; 11492a7db7a6SVincenzo Maffione 11502a7db7a6SVincenzo Maffione mtx_lock(&kring->q_lock); 11512a7db7a6SVincenzo Maffione n = netmap_vp_rxsync_locked(kring, flags); 11522a7db7a6SVincenzo Maffione mtx_unlock(&kring->q_lock); 11532a7db7a6SVincenzo Maffione return n; 11542a7db7a6SVincenzo Maffione } 11552a7db7a6SVincenzo Maffione 11562a7db7a6SVincenzo Maffione int 11572a7db7a6SVincenzo Maffione netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna, 11582a7db7a6SVincenzo Maffione struct netmap_bdg_ops *ops) 11592a7db7a6SVincenzo Maffione { 11602a7db7a6SVincenzo Maffione return ops->bwrap_attach(nr_name, hwna); 11612a7db7a6SVincenzo Maffione } 11622a7db7a6SVincenzo Maffione 11632a7db7a6SVincenzo Maffione 11642a7db7a6SVincenzo Maffione /* Bridge wrapper code (bwrap). 11652a7db7a6SVincenzo Maffione * This is used to connect a non-VALE-port netmap_adapter (hwna) to a 11662a7db7a6SVincenzo Maffione * VALE switch. 11672a7db7a6SVincenzo Maffione * The main task is to swap the meaning of tx and rx rings to match the 11682a7db7a6SVincenzo Maffione * expectations of the VALE switch code (see nm_bdg_flush). 11692a7db7a6SVincenzo Maffione * 11702a7db7a6SVincenzo Maffione * The bwrap works by interposing a netmap_bwrap_adapter between the 11712a7db7a6SVincenzo Maffione * rest of the system and the hwna. The netmap_bwrap_adapter looks like 11722a7db7a6SVincenzo Maffione * a netmap_vp_adapter to the rest the system, but, internally, it 11732a7db7a6SVincenzo Maffione * translates all callbacks to what the hwna expects. 11742a7db7a6SVincenzo Maffione * 11752a7db7a6SVincenzo Maffione * Note that we have to intercept callbacks coming from two sides: 11762a7db7a6SVincenzo Maffione * 11772a7db7a6SVincenzo Maffione * - callbacks coming from the netmap module are intercepted by 11782a7db7a6SVincenzo Maffione * passing around the netmap_bwrap_adapter instead of the hwna 11792a7db7a6SVincenzo Maffione * 11802a7db7a6SVincenzo Maffione * - callbacks coming from outside of the netmap module only know 11812a7db7a6SVincenzo Maffione * about the hwna. This, however, only happens in interrupt 11822a7db7a6SVincenzo Maffione * handlers, where only the hwna->nm_notify callback is called. 11832a7db7a6SVincenzo Maffione * What the bwrap does is to overwrite the hwna->nm_notify callback 11842a7db7a6SVincenzo Maffione * with its own netmap_bwrap_intr_notify. 11852a7db7a6SVincenzo Maffione * XXX This assumes that the hwna->nm_notify callback was the 11862a7db7a6SVincenzo Maffione * standard netmap_notify(), as it is the case for nic adapters. 11872a7db7a6SVincenzo Maffione * Any additional action performed by hwna->nm_notify will not be 11882a7db7a6SVincenzo Maffione * performed by netmap_bwrap_intr_notify. 11892a7db7a6SVincenzo Maffione * 11902a7db7a6SVincenzo Maffione * Additionally, the bwrap can optionally attach the host rings pair 11912a7db7a6SVincenzo Maffione * of the wrapped adapter to a different port of the switch. 11922a7db7a6SVincenzo Maffione */ 11932a7db7a6SVincenzo Maffione 11942a7db7a6SVincenzo Maffione 11952a7db7a6SVincenzo Maffione static void 11962a7db7a6SVincenzo Maffione netmap_bwrap_dtor(struct netmap_adapter *na) 11972a7db7a6SVincenzo Maffione { 11982a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter*)na; 11992a7db7a6SVincenzo Maffione struct netmap_adapter *hwna = bna->hwna; 12002a7db7a6SVincenzo Maffione struct nm_bridge *b = bna->up.na_bdg, 12012a7db7a6SVincenzo Maffione *bh = bna->host.na_bdg; 12022a7db7a6SVincenzo Maffione 12032a7db7a6SVincenzo Maffione if (bna->host.up.nm_mem) 12042a7db7a6SVincenzo Maffione netmap_mem_put(bna->host.up.nm_mem); 12052a7db7a6SVincenzo Maffione 12062a7db7a6SVincenzo Maffione if (b) { 12072a7db7a6SVincenzo Maffione netmap_bdg_detach_common(b, bna->up.bdg_port, 12082a7db7a6SVincenzo Maffione (bh ? bna->host.bdg_port : -1)); 12092a7db7a6SVincenzo Maffione } 12102a7db7a6SVincenzo Maffione 121175f4f3edSVincenzo Maffione nm_prdis("na %p", na); 12122a7db7a6SVincenzo Maffione na->ifp = NULL; 12132a7db7a6SVincenzo Maffione bna->host.up.ifp = NULL; 12142a7db7a6SVincenzo Maffione hwna->na_vp = bna->saved_na_vp; 12152a7db7a6SVincenzo Maffione hwna->na_hostvp = NULL; 12162a7db7a6SVincenzo Maffione hwna->na_private = NULL; 12172a7db7a6SVincenzo Maffione hwna->na_flags &= ~NAF_BUSY; 12182a7db7a6SVincenzo Maffione netmap_adapter_put(hwna); 12192a7db7a6SVincenzo Maffione 12202a7db7a6SVincenzo Maffione } 12212a7db7a6SVincenzo Maffione 12222a7db7a6SVincenzo Maffione 12232a7db7a6SVincenzo Maffione /* 12242a7db7a6SVincenzo Maffione * Intr callback for NICs connected to a bridge. 12252a7db7a6SVincenzo Maffione * Simply ignore tx interrupts (maybe we could try to recover space ?) 12262a7db7a6SVincenzo Maffione * and pass received packets from nic to the bridge. 12272a7db7a6SVincenzo Maffione * 12282a7db7a6SVincenzo Maffione * XXX TODO check locking: this is called from the interrupt 12292a7db7a6SVincenzo Maffione * handler so we should make sure that the interface is not 12302a7db7a6SVincenzo Maffione * disconnected while passing down an interrupt. 12312a7db7a6SVincenzo Maffione * 12322a7db7a6SVincenzo Maffione * Note, no user process can access this NIC or the host stack. 12332a7db7a6SVincenzo Maffione * The only part of the ring that is significant are the slots, 12342a7db7a6SVincenzo Maffione * and head/cur/tail are set from the kring as needed 12352a7db7a6SVincenzo Maffione * (part as a receive ring, part as a transmit ring). 12362a7db7a6SVincenzo Maffione * 12372a7db7a6SVincenzo Maffione * callback that overwrites the hwna notify callback. 12382a7db7a6SVincenzo Maffione * Packets come from the outside or from the host stack and are put on an 12392a7db7a6SVincenzo Maffione * hwna rx ring. 12402a7db7a6SVincenzo Maffione * The bridge wrapper then sends the packets through the bridge. 12412a7db7a6SVincenzo Maffione */ 1242a6d768d8SVincenzo Maffione int 12432a7db7a6SVincenzo Maffione netmap_bwrap_intr_notify(struct netmap_kring *kring, int flags) 12442a7db7a6SVincenzo Maffione { 12452a7db7a6SVincenzo Maffione struct netmap_adapter *na = kring->na; 12462a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna = na->na_private; 12472a7db7a6SVincenzo Maffione struct netmap_kring *bkring; 12482a7db7a6SVincenzo Maffione struct netmap_vp_adapter *vpna = &bna->up; 12492a7db7a6SVincenzo Maffione u_int ring_nr = kring->ring_id; 12502a7db7a6SVincenzo Maffione int ret = NM_IRQ_COMPLETED; 12512a7db7a6SVincenzo Maffione int error; 12522a7db7a6SVincenzo Maffione 1253b6e66be2SVincenzo Maffione if (netmap_debug & NM_DEBUG_RXINTR) 1254b6e66be2SVincenzo Maffione nm_prinf("%s %s 0x%x", na->name, kring->name, flags); 12552a7db7a6SVincenzo Maffione 12562a7db7a6SVincenzo Maffione bkring = vpna->up.tx_rings[ring_nr]; 12572a7db7a6SVincenzo Maffione 12582a7db7a6SVincenzo Maffione /* make sure the ring is not disabled */ 12592a7db7a6SVincenzo Maffione if (nm_kr_tryget(kring, 0 /* can't sleep */, NULL)) { 12602a7db7a6SVincenzo Maffione return EIO; 12612a7db7a6SVincenzo Maffione } 12622a7db7a6SVincenzo Maffione 1263b6e66be2SVincenzo Maffione if (netmap_debug & NM_DEBUG_RXINTR) 1264b6e66be2SVincenzo Maffione nm_prinf("%s head %d cur %d tail %d", na->name, 12652a7db7a6SVincenzo Maffione kring->rhead, kring->rcur, kring->rtail); 12662a7db7a6SVincenzo Maffione 12672a7db7a6SVincenzo Maffione /* simulate a user wakeup on the rx ring 12682a7db7a6SVincenzo Maffione * fetch packets that have arrived. 12692a7db7a6SVincenzo Maffione */ 12702a7db7a6SVincenzo Maffione error = kring->nm_sync(kring, 0); 12712a7db7a6SVincenzo Maffione if (error) 12722a7db7a6SVincenzo Maffione goto put_out; 12732a7db7a6SVincenzo Maffione if (kring->nr_hwcur == kring->nr_hwtail) { 12742a7db7a6SVincenzo Maffione if (netmap_verbose) 1275a56136a1SVincenzo Maffione nm_prlim(1, "interrupt with no packets on %s", 1276a56136a1SVincenzo Maffione kring->name); 12772a7db7a6SVincenzo Maffione goto put_out; 12782a7db7a6SVincenzo Maffione } 12792a7db7a6SVincenzo Maffione 12802a7db7a6SVincenzo Maffione /* new packets are kring->rcur to kring->nr_hwtail, and the bkring 12812a7db7a6SVincenzo Maffione * had hwcur == bkring->rhead. So advance bkring->rhead to kring->nr_hwtail 12822a7db7a6SVincenzo Maffione * to push all packets out. 12832a7db7a6SVincenzo Maffione */ 12842a7db7a6SVincenzo Maffione bkring->rhead = bkring->rcur = kring->nr_hwtail; 12852a7db7a6SVincenzo Maffione 12862a7db7a6SVincenzo Maffione bkring->nm_sync(bkring, flags); 12872a7db7a6SVincenzo Maffione 12882a7db7a6SVincenzo Maffione /* mark all buffers as released on this ring */ 12892a7db7a6SVincenzo Maffione kring->rhead = kring->rcur = kring->rtail = kring->nr_hwtail; 12902a7db7a6SVincenzo Maffione /* another call to actually release the buffers */ 12912a7db7a6SVincenzo Maffione error = kring->nm_sync(kring, 0); 12922a7db7a6SVincenzo Maffione 12932a7db7a6SVincenzo Maffione /* The second rxsync may have further advanced hwtail. If this happens, 12942a7db7a6SVincenzo Maffione * return NM_IRQ_RESCHED, otherwise just return NM_IRQ_COMPLETED. */ 12952a7db7a6SVincenzo Maffione if (kring->rcur != kring->nr_hwtail) { 12962a7db7a6SVincenzo Maffione ret = NM_IRQ_RESCHED; 12972a7db7a6SVincenzo Maffione } 12982a7db7a6SVincenzo Maffione put_out: 12992a7db7a6SVincenzo Maffione nm_kr_put(kring); 13002a7db7a6SVincenzo Maffione 13012a7db7a6SVincenzo Maffione return error ? error : ret; 13022a7db7a6SVincenzo Maffione } 13032a7db7a6SVincenzo Maffione 13042a7db7a6SVincenzo Maffione 13052a7db7a6SVincenzo Maffione /* nm_register callback for bwrap */ 13062a7db7a6SVincenzo Maffione int 13072a7db7a6SVincenzo Maffione netmap_bwrap_reg(struct netmap_adapter *na, int onoff) 13082a7db7a6SVincenzo Maffione { 13092a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna = 13102a7db7a6SVincenzo Maffione (struct netmap_bwrap_adapter *)na; 13112a7db7a6SVincenzo Maffione struct netmap_adapter *hwna = bna->hwna; 13122a7db7a6SVincenzo Maffione struct netmap_vp_adapter *hostna = &bna->host; 13132a7db7a6SVincenzo Maffione int error, i; 13142a7db7a6SVincenzo Maffione enum txrx t; 13152a7db7a6SVincenzo Maffione 131675f4f3edSVincenzo Maffione nm_prdis("%s %s", na->name, onoff ? "on" : "off"); 13172a7db7a6SVincenzo Maffione 13182a7db7a6SVincenzo Maffione if (onoff) { 13192a7db7a6SVincenzo Maffione /* netmap_do_regif has been called on the bwrap na. 13202a7db7a6SVincenzo Maffione * We need to pass the information about the 13212a7db7a6SVincenzo Maffione * memory allocator down to the hwna before 13222a7db7a6SVincenzo Maffione * putting it in netmap mode 13232a7db7a6SVincenzo Maffione */ 13242a7db7a6SVincenzo Maffione hwna->na_lut = na->na_lut; 13252a7db7a6SVincenzo Maffione 13262a7db7a6SVincenzo Maffione if (hostna->na_bdg) { 13272a7db7a6SVincenzo Maffione /* if the host rings have been attached to switch, 13282a7db7a6SVincenzo Maffione * we need to copy the memory allocator information 13292a7db7a6SVincenzo Maffione * in the hostna also 13302a7db7a6SVincenzo Maffione */ 13312a7db7a6SVincenzo Maffione hostna->up.na_lut = na->na_lut; 13322a7db7a6SVincenzo Maffione } 13332a7db7a6SVincenzo Maffione 13342a7db7a6SVincenzo Maffione } 13352a7db7a6SVincenzo Maffione 13362a7db7a6SVincenzo Maffione /* pass down the pending ring state information */ 13372a7db7a6SVincenzo Maffione for_rx_tx(t) { 13382a7db7a6SVincenzo Maffione for (i = 0; i < netmap_all_rings(na, t); i++) { 13392a7db7a6SVincenzo Maffione NMR(hwna, nm_txrx_swap(t))[i]->nr_pending_mode = 13402a7db7a6SVincenzo Maffione NMR(na, t)[i]->nr_pending_mode; 13412a7db7a6SVincenzo Maffione } 13422a7db7a6SVincenzo Maffione } 13432a7db7a6SVincenzo Maffione 13442a7db7a6SVincenzo Maffione /* forward the request to the hwna */ 13452a7db7a6SVincenzo Maffione error = hwna->nm_register(hwna, onoff); 13462a7db7a6SVincenzo Maffione if (error) 13472a7db7a6SVincenzo Maffione return error; 13482a7db7a6SVincenzo Maffione 13492a7db7a6SVincenzo Maffione /* copy up the current ring state information */ 13502a7db7a6SVincenzo Maffione for_rx_tx(t) { 13512a7db7a6SVincenzo Maffione for (i = 0; i < netmap_all_rings(na, t); i++) { 13522a7db7a6SVincenzo Maffione struct netmap_kring *kring = NMR(hwna, nm_txrx_swap(t))[i]; 13532a7db7a6SVincenzo Maffione NMR(na, t)[i]->nr_mode = kring->nr_mode; 13542a7db7a6SVincenzo Maffione } 13552a7db7a6SVincenzo Maffione } 13562a7db7a6SVincenzo Maffione 13572a7db7a6SVincenzo Maffione /* impersonate a netmap_vp_adapter */ 13582a7db7a6SVincenzo Maffione netmap_vp_reg(na, onoff); 13592a7db7a6SVincenzo Maffione if (hostna->na_bdg) 13602a7db7a6SVincenzo Maffione netmap_vp_reg(&hostna->up, onoff); 13612a7db7a6SVincenzo Maffione 13622a7db7a6SVincenzo Maffione if (onoff) { 13632a7db7a6SVincenzo Maffione u_int i; 13642a7db7a6SVincenzo Maffione /* intercept the hwna nm_nofify callback on the hw rings */ 13652a7db7a6SVincenzo Maffione for (i = 0; i < hwna->num_rx_rings; i++) { 13662a7db7a6SVincenzo Maffione hwna->rx_rings[i]->save_notify = hwna->rx_rings[i]->nm_notify; 1367a6d768d8SVincenzo Maffione hwna->rx_rings[i]->nm_notify = bna->nm_intr_notify; 13682a7db7a6SVincenzo Maffione } 13692a7db7a6SVincenzo Maffione i = hwna->num_rx_rings; /* for safety */ 13702a7db7a6SVincenzo Maffione /* save the host ring notify unconditionally */ 13712a7db7a6SVincenzo Maffione for (; i < netmap_real_rings(hwna, NR_RX); i++) { 13722a7db7a6SVincenzo Maffione hwna->rx_rings[i]->save_notify = 13732a7db7a6SVincenzo Maffione hwna->rx_rings[i]->nm_notify; 13742a7db7a6SVincenzo Maffione if (hostna->na_bdg) { 13752a7db7a6SVincenzo Maffione /* also intercept the host ring notify */ 13762a7db7a6SVincenzo Maffione hwna->rx_rings[i]->nm_notify = 13772a7db7a6SVincenzo Maffione netmap_bwrap_intr_notify; 13782a7db7a6SVincenzo Maffione na->tx_rings[i]->nm_sync = na->nm_txsync; 13792a7db7a6SVincenzo Maffione } 13802a7db7a6SVincenzo Maffione } 13812a7db7a6SVincenzo Maffione if (na->active_fds == 0) 13822a7db7a6SVincenzo Maffione na->na_flags |= NAF_NETMAP_ON; 13832a7db7a6SVincenzo Maffione } else { 13842a7db7a6SVincenzo Maffione u_int i; 13852a7db7a6SVincenzo Maffione 13862a7db7a6SVincenzo Maffione if (na->active_fds == 0) 13872a7db7a6SVincenzo Maffione na->na_flags &= ~NAF_NETMAP_ON; 13882a7db7a6SVincenzo Maffione 13892a7db7a6SVincenzo Maffione /* reset all notify callbacks (including host ring) */ 13902a7db7a6SVincenzo Maffione for (i = 0; i < netmap_all_rings(hwna, NR_RX); i++) { 13912a7db7a6SVincenzo Maffione hwna->rx_rings[i]->nm_notify = 13922a7db7a6SVincenzo Maffione hwna->rx_rings[i]->save_notify; 13932a7db7a6SVincenzo Maffione hwna->rx_rings[i]->save_notify = NULL; 13942a7db7a6SVincenzo Maffione } 13952a7db7a6SVincenzo Maffione hwna->na_lut.lut = NULL; 13962a7db7a6SVincenzo Maffione hwna->na_lut.plut = NULL; 13972a7db7a6SVincenzo Maffione hwna->na_lut.objtotal = 0; 13982a7db7a6SVincenzo Maffione hwna->na_lut.objsize = 0; 13992a7db7a6SVincenzo Maffione 14002a7db7a6SVincenzo Maffione /* reset the number of host rings to default */ 14012a7db7a6SVincenzo Maffione for_rx_tx(t) { 14022a7db7a6SVincenzo Maffione nma_set_host_nrings(hwna, t, 1); 14032a7db7a6SVincenzo Maffione } 14042a7db7a6SVincenzo Maffione 14052a7db7a6SVincenzo Maffione } 14062a7db7a6SVincenzo Maffione 14072a7db7a6SVincenzo Maffione return 0; 14082a7db7a6SVincenzo Maffione } 14092a7db7a6SVincenzo Maffione 14102a7db7a6SVincenzo Maffione /* nm_config callback for bwrap */ 14112a7db7a6SVincenzo Maffione static int 14122a7db7a6SVincenzo Maffione netmap_bwrap_config(struct netmap_adapter *na, struct nm_config_info *info) 14132a7db7a6SVincenzo Maffione { 14142a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna = 14152a7db7a6SVincenzo Maffione (struct netmap_bwrap_adapter *)na; 14162a7db7a6SVincenzo Maffione struct netmap_adapter *hwna = bna->hwna; 14172a7db7a6SVincenzo Maffione int error; 14182a7db7a6SVincenzo Maffione 1419a6d768d8SVincenzo Maffione /* cache the lut in the embedded host adapter */ 1420a6d768d8SVincenzo Maffione error = netmap_mem_get_lut(hwna->nm_mem, &bna->host.up.na_lut); 1421a6d768d8SVincenzo Maffione if (error) 1422a6d768d8SVincenzo Maffione return error; 1423a6d768d8SVincenzo Maffione 14242a7db7a6SVincenzo Maffione /* Forward the request to the hwna. It may happen that nobody 14252a7db7a6SVincenzo Maffione * registered hwna yet, so netmap_mem_get_lut() may have not 14262a7db7a6SVincenzo Maffione * been called yet. */ 14272a7db7a6SVincenzo Maffione error = netmap_mem_get_lut(hwna->nm_mem, &hwna->na_lut); 14282a7db7a6SVincenzo Maffione if (error) 14292a7db7a6SVincenzo Maffione return error; 14302a7db7a6SVincenzo Maffione netmap_update_config(hwna); 14312a7db7a6SVincenzo Maffione /* swap the results and propagate */ 14322a7db7a6SVincenzo Maffione info->num_tx_rings = hwna->num_rx_rings; 14332a7db7a6SVincenzo Maffione info->num_tx_descs = hwna->num_rx_desc; 14342a7db7a6SVincenzo Maffione info->num_rx_rings = hwna->num_tx_rings; 14352a7db7a6SVincenzo Maffione info->num_rx_descs = hwna->num_tx_desc; 14362a7db7a6SVincenzo Maffione info->rx_buf_maxsize = hwna->rx_buf_maxsize; 14372a7db7a6SVincenzo Maffione 1438a6d768d8SVincenzo Maffione if (na->na_flags & NAF_HOST_RINGS) { 1439a6d768d8SVincenzo Maffione struct netmap_adapter *hostna = &bna->host.up; 1440a6d768d8SVincenzo Maffione enum txrx t; 1441a6d768d8SVincenzo Maffione 1442a6d768d8SVincenzo Maffione /* limit the number of host rings to that of hw */ 1443a6d768d8SVincenzo Maffione if (na->na_flags & NAF_HOST_ALL) { 1444a6d768d8SVincenzo Maffione hostna->num_tx_rings = nma_get_nrings(hwna, NR_RX); 1445a6d768d8SVincenzo Maffione hostna->num_rx_rings = nma_get_nrings(hwna, NR_TX); 1446a6d768d8SVincenzo Maffione } else { 1447a6d768d8SVincenzo Maffione nm_bound_var(&hostna->num_tx_rings, 1, 1, 1448a6d768d8SVincenzo Maffione nma_get_nrings(hwna, NR_TX), NULL); 1449a6d768d8SVincenzo Maffione nm_bound_var(&hostna->num_rx_rings, 1, 1, 1450a6d768d8SVincenzo Maffione nma_get_nrings(hwna, NR_RX), NULL); 1451a6d768d8SVincenzo Maffione } 1452a6d768d8SVincenzo Maffione for_rx_tx(t) { 1453a6d768d8SVincenzo Maffione enum txrx r = nm_txrx_swap(t); 1454a6d768d8SVincenzo Maffione u_int nr = nma_get_nrings(hostna, t); 1455a6d768d8SVincenzo Maffione 1456a6d768d8SVincenzo Maffione nma_set_host_nrings(na, t, nr); 1457a6d768d8SVincenzo Maffione if (nma_get_host_nrings(hwna, t) < nr) { 1458a6d768d8SVincenzo Maffione nma_set_host_nrings(hwna, t, nr); 1459a6d768d8SVincenzo Maffione } 1460a6d768d8SVincenzo Maffione nma_set_ndesc(hostna, t, nma_get_ndesc(hwna, r)); 1461a6d768d8SVincenzo Maffione } 1462a6d768d8SVincenzo Maffione } 1463a6d768d8SVincenzo Maffione 14642a7db7a6SVincenzo Maffione return 0; 14652a7db7a6SVincenzo Maffione } 14662a7db7a6SVincenzo Maffione 1467a6d768d8SVincenzo Maffione /* nm_bufcfg callback for bwrap */ 1468a6d768d8SVincenzo Maffione static int 1469a6d768d8SVincenzo Maffione netmap_bwrap_bufcfg(struct netmap_kring *kring, uint64_t target) 1470a6d768d8SVincenzo Maffione { 1471a6d768d8SVincenzo Maffione struct netmap_adapter *na = kring->na; 1472a6d768d8SVincenzo Maffione struct netmap_bwrap_adapter *bna = 1473a6d768d8SVincenzo Maffione (struct netmap_bwrap_adapter *)na; 1474a6d768d8SVincenzo Maffione struct netmap_adapter *hwna = bna->hwna; 1475a6d768d8SVincenzo Maffione struct netmap_kring *hwkring; 1476a6d768d8SVincenzo Maffione enum txrx r; 1477a6d768d8SVincenzo Maffione int error; 1478a6d768d8SVincenzo Maffione 1479a6d768d8SVincenzo Maffione /* we need the hw kring that corresponds to the bwrap one: 1480a6d768d8SVincenzo Maffione * remember that rx and tx are swapped 1481a6d768d8SVincenzo Maffione */ 1482a6d768d8SVincenzo Maffione r = nm_txrx_swap(kring->tx); 1483a6d768d8SVincenzo Maffione hwkring = NMR(hwna, r)[kring->ring_id]; 1484a6d768d8SVincenzo Maffione 1485a6d768d8SVincenzo Maffione /* copy down the offset information, forward the request 1486a6d768d8SVincenzo Maffione * and copy up the results 1487a6d768d8SVincenzo Maffione */ 1488a6d768d8SVincenzo Maffione hwkring->offset_mask = kring->offset_mask; 1489a6d768d8SVincenzo Maffione hwkring->offset_max = kring->offset_max; 1490a6d768d8SVincenzo Maffione hwkring->offset_gap = kring->offset_gap; 1491a6d768d8SVincenzo Maffione 1492a6d768d8SVincenzo Maffione error = hwkring->nm_bufcfg(hwkring, target); 1493a6d768d8SVincenzo Maffione if (error) 1494a6d768d8SVincenzo Maffione return error; 1495a6d768d8SVincenzo Maffione 1496a6d768d8SVincenzo Maffione kring->hwbuf_len = hwkring->hwbuf_len; 1497a6d768d8SVincenzo Maffione kring->buf_align = hwkring->buf_align; 1498a6d768d8SVincenzo Maffione 1499a6d768d8SVincenzo Maffione return 0; 1500a6d768d8SVincenzo Maffione } 15012a7db7a6SVincenzo Maffione 15022a7db7a6SVincenzo Maffione /* nm_krings_create callback for bwrap */ 15032a7db7a6SVincenzo Maffione int 15042a7db7a6SVincenzo Maffione netmap_bwrap_krings_create_common(struct netmap_adapter *na) 15052a7db7a6SVincenzo Maffione { 15062a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna = 15072a7db7a6SVincenzo Maffione (struct netmap_bwrap_adapter *)na; 15082a7db7a6SVincenzo Maffione struct netmap_adapter *hwna = bna->hwna; 15092a7db7a6SVincenzo Maffione struct netmap_adapter *hostna = &bna->host.up; 15102a7db7a6SVincenzo Maffione int i, error = 0; 15112a7db7a6SVincenzo Maffione enum txrx t; 15122a7db7a6SVincenzo Maffione 15132a7db7a6SVincenzo Maffione /* also create the hwna krings */ 15142a7db7a6SVincenzo Maffione error = hwna->nm_krings_create(hwna); 15152a7db7a6SVincenzo Maffione if (error) { 15162a7db7a6SVincenzo Maffione return error; 15172a7db7a6SVincenzo Maffione } 15182a7db7a6SVincenzo Maffione 15192a7db7a6SVincenzo Maffione /* increment the usage counter for all the hwna krings */ 15202a7db7a6SVincenzo Maffione for_rx_tx(t) { 15212a7db7a6SVincenzo Maffione for (i = 0; i < netmap_all_rings(hwna, t); i++) { 15222a7db7a6SVincenzo Maffione NMR(hwna, t)[i]->users++; 1523a6d768d8SVincenzo Maffione /* this to prevent deletion of the rings through 1524a6d768d8SVincenzo Maffione * our krings, instead of through the hwna ones */ 1525a6d768d8SVincenzo Maffione NMR(na, t)[i]->nr_kflags |= NKR_NEEDRING; 15262a7db7a6SVincenzo Maffione } 15272a7db7a6SVincenzo Maffione } 15282a7db7a6SVincenzo Maffione 15292a7db7a6SVincenzo Maffione /* now create the actual rings */ 15302a7db7a6SVincenzo Maffione error = netmap_mem_rings_create(hwna); 15312a7db7a6SVincenzo Maffione if (error) { 15322a7db7a6SVincenzo Maffione goto err_dec_users; 15332a7db7a6SVincenzo Maffione } 15342a7db7a6SVincenzo Maffione 15352a7db7a6SVincenzo Maffione /* cross-link the netmap rings 15362a7db7a6SVincenzo Maffione * The original number of rings comes from hwna, 15372a7db7a6SVincenzo Maffione * rx rings on one side equals tx rings on the other. 15382a7db7a6SVincenzo Maffione */ 15392a7db7a6SVincenzo Maffione for_rx_tx(t) { 15402a7db7a6SVincenzo Maffione enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */ 15412a7db7a6SVincenzo Maffione for (i = 0; i < netmap_all_rings(hwna, r); i++) { 15422a7db7a6SVincenzo Maffione NMR(na, t)[i]->nkr_num_slots = NMR(hwna, r)[i]->nkr_num_slots; 15432a7db7a6SVincenzo Maffione NMR(na, t)[i]->ring = NMR(hwna, r)[i]->ring; 15442a7db7a6SVincenzo Maffione } 15452a7db7a6SVincenzo Maffione } 15462a7db7a6SVincenzo Maffione 15472a7db7a6SVincenzo Maffione if (na->na_flags & NAF_HOST_RINGS) { 15482a7db7a6SVincenzo Maffione /* the hostna rings are the host rings of the bwrap. 15492a7db7a6SVincenzo Maffione * The corresponding krings must point back to the 15502a7db7a6SVincenzo Maffione * hostna 15512a7db7a6SVincenzo Maffione */ 15522a7db7a6SVincenzo Maffione hostna->tx_rings = &na->tx_rings[na->num_tx_rings]; 15532a7db7a6SVincenzo Maffione hostna->rx_rings = &na->rx_rings[na->num_rx_rings]; 15542a7db7a6SVincenzo Maffione for_rx_tx(t) { 15552a7db7a6SVincenzo Maffione for (i = 0; i < nma_get_nrings(hostna, t); i++) { 15562a7db7a6SVincenzo Maffione NMR(hostna, t)[i]->na = hostna; 15572a7db7a6SVincenzo Maffione } 15582a7db7a6SVincenzo Maffione } 15592a7db7a6SVincenzo Maffione } 15602a7db7a6SVincenzo Maffione 15612a7db7a6SVincenzo Maffione return 0; 15622a7db7a6SVincenzo Maffione 15632a7db7a6SVincenzo Maffione err_dec_users: 15642a7db7a6SVincenzo Maffione for_rx_tx(t) { 15652a7db7a6SVincenzo Maffione for (i = 0; i < netmap_all_rings(hwna, t); i++) { 15662a7db7a6SVincenzo Maffione NMR(hwna, t)[i]->users--; 1567a6d768d8SVincenzo Maffione NMR(na, t)[i]->users--; 15682a7db7a6SVincenzo Maffione } 15692a7db7a6SVincenzo Maffione } 15702a7db7a6SVincenzo Maffione hwna->nm_krings_delete(hwna); 15712a7db7a6SVincenzo Maffione return error; 15722a7db7a6SVincenzo Maffione } 15732a7db7a6SVincenzo Maffione 15742a7db7a6SVincenzo Maffione 15752a7db7a6SVincenzo Maffione void 15762a7db7a6SVincenzo Maffione netmap_bwrap_krings_delete_common(struct netmap_adapter *na) 15772a7db7a6SVincenzo Maffione { 15782a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna = 15792a7db7a6SVincenzo Maffione (struct netmap_bwrap_adapter *)na; 15802a7db7a6SVincenzo Maffione struct netmap_adapter *hwna = bna->hwna; 15812a7db7a6SVincenzo Maffione enum txrx t; 15822a7db7a6SVincenzo Maffione int i; 15832a7db7a6SVincenzo Maffione 158475f4f3edSVincenzo Maffione nm_prdis("%s", na->name); 15852a7db7a6SVincenzo Maffione 15862a7db7a6SVincenzo Maffione /* decrement the usage counter for all the hwna krings */ 15872a7db7a6SVincenzo Maffione for_rx_tx(t) { 15882a7db7a6SVincenzo Maffione for (i = 0; i < netmap_all_rings(hwna, t); i++) { 15892a7db7a6SVincenzo Maffione NMR(hwna, t)[i]->users--; 1590a6d768d8SVincenzo Maffione NMR(na, t)[i]->users--; 15912a7db7a6SVincenzo Maffione } 15922a7db7a6SVincenzo Maffione } 15932a7db7a6SVincenzo Maffione 15942a7db7a6SVincenzo Maffione /* delete any netmap rings that are no longer needed */ 15952a7db7a6SVincenzo Maffione netmap_mem_rings_delete(hwna); 15962a7db7a6SVincenzo Maffione hwna->nm_krings_delete(hwna); 15972a7db7a6SVincenzo Maffione } 15982a7db7a6SVincenzo Maffione 15992a7db7a6SVincenzo Maffione 16002a7db7a6SVincenzo Maffione /* notify method for the bridge-->hwna direction */ 16012a7db7a6SVincenzo Maffione int 16022a7db7a6SVincenzo Maffione netmap_bwrap_notify(struct netmap_kring *kring, int flags) 16032a7db7a6SVincenzo Maffione { 16042a7db7a6SVincenzo Maffione struct netmap_adapter *na = kring->na; 16052a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna = na->na_private; 16062a7db7a6SVincenzo Maffione struct netmap_adapter *hwna = bna->hwna; 16072a7db7a6SVincenzo Maffione u_int ring_n = kring->ring_id; 16082a7db7a6SVincenzo Maffione u_int lim = kring->nkr_num_slots - 1; 16092a7db7a6SVincenzo Maffione struct netmap_kring *hw_kring; 16102a7db7a6SVincenzo Maffione int error; 16112a7db7a6SVincenzo Maffione 161275f4f3edSVincenzo Maffione nm_prdis("%s: na %s hwna %s", 16132a7db7a6SVincenzo Maffione (kring ? kring->name : "NULL!"), 16142a7db7a6SVincenzo Maffione (na ? na->name : "NULL!"), 16152a7db7a6SVincenzo Maffione (hwna ? hwna->name : "NULL!")); 16162a7db7a6SVincenzo Maffione hw_kring = hwna->tx_rings[ring_n]; 16172a7db7a6SVincenzo Maffione 16182a7db7a6SVincenzo Maffione if (nm_kr_tryget(hw_kring, 0, NULL)) { 16192a7db7a6SVincenzo Maffione return ENXIO; 16202a7db7a6SVincenzo Maffione } 16212a7db7a6SVincenzo Maffione 16222a7db7a6SVincenzo Maffione /* first step: simulate a user wakeup on the rx ring */ 16232a7db7a6SVincenzo Maffione netmap_vp_rxsync(kring, flags); 162475f4f3edSVincenzo Maffione nm_prdis("%s[%d] PRE rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)", 16252a7db7a6SVincenzo Maffione na->name, ring_n, 16262a7db7a6SVincenzo Maffione kring->nr_hwcur, kring->nr_hwtail, kring->nkr_hwlease, 1627b6e66be2SVincenzo Maffione kring->rhead, kring->rcur, kring->rtail, 1628b6e66be2SVincenzo Maffione hw_kring->nr_hwcur, hw_kring->nr_hwtail, hw_kring->rtail); 16292a7db7a6SVincenzo Maffione /* second step: the new packets are sent on the tx ring 16302a7db7a6SVincenzo Maffione * (which is actually the same ring) 16312a7db7a6SVincenzo Maffione */ 16322a7db7a6SVincenzo Maffione hw_kring->rhead = hw_kring->rcur = kring->nr_hwtail; 16332a7db7a6SVincenzo Maffione error = hw_kring->nm_sync(hw_kring, flags); 16342a7db7a6SVincenzo Maffione if (error) 16352a7db7a6SVincenzo Maffione goto put_out; 16362a7db7a6SVincenzo Maffione 16372a7db7a6SVincenzo Maffione /* third step: now we are back the rx ring */ 16382a7db7a6SVincenzo Maffione /* claim ownership on all hw owned bufs */ 16392a7db7a6SVincenzo Maffione kring->rhead = kring->rcur = nm_next(hw_kring->nr_hwtail, lim); /* skip past reserved slot */ 16402a7db7a6SVincenzo Maffione 16412a7db7a6SVincenzo Maffione /* fourth step: the user goes to sleep again, causing another rxsync */ 16422a7db7a6SVincenzo Maffione netmap_vp_rxsync(kring, flags); 164375f4f3edSVincenzo Maffione nm_prdis("%s[%d] PST rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)", 16442a7db7a6SVincenzo Maffione na->name, ring_n, 16452a7db7a6SVincenzo Maffione kring->nr_hwcur, kring->nr_hwtail, kring->nkr_hwlease, 1646b6e66be2SVincenzo Maffione kring->rhead, kring->rcur, kring->rtail, 16472a7db7a6SVincenzo Maffione hw_kring->nr_hwcur, hw_kring->nr_hwtail, hw_kring->rtail); 16482a7db7a6SVincenzo Maffione put_out: 16492a7db7a6SVincenzo Maffione nm_kr_put(hw_kring); 16502a7db7a6SVincenzo Maffione 16512a7db7a6SVincenzo Maffione return error ? error : NM_IRQ_COMPLETED; 16522a7db7a6SVincenzo Maffione } 16532a7db7a6SVincenzo Maffione 16542a7db7a6SVincenzo Maffione 16552a7db7a6SVincenzo Maffione /* nm_bdg_ctl callback for the bwrap. 1656c7c78055SVincenzo Maffione * Called on bridge-attach and detach, as an effect of valectl -[ahd]. 16572a7db7a6SVincenzo Maffione * On attach, it needs to provide a fake netmap_priv_d structure and 16582a7db7a6SVincenzo Maffione * perform a netmap_do_regif() on the bwrap. This will put both the 16592a7db7a6SVincenzo Maffione * bwrap and the hwna in netmap mode, with the netmap rings shared 16602a7db7a6SVincenzo Maffione * and cross linked. Moroever, it will start intercepting interrupts 16612a7db7a6SVincenzo Maffione * directed to hwna. 16622a7db7a6SVincenzo Maffione */ 16632a7db7a6SVincenzo Maffione static int 16642a7db7a6SVincenzo Maffione netmap_bwrap_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na) 16652a7db7a6SVincenzo Maffione { 16662a7db7a6SVincenzo Maffione struct netmap_priv_d *npriv; 16672a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter*)na; 16682a7db7a6SVincenzo Maffione int error = 0; 16692a7db7a6SVincenzo Maffione 16702a7db7a6SVincenzo Maffione if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) { 16712a7db7a6SVincenzo Maffione struct nmreq_vale_attach *req = 16722a7db7a6SVincenzo Maffione (struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body; 16732a7db7a6SVincenzo Maffione if (req->reg.nr_ringid != 0 || 16742a7db7a6SVincenzo Maffione (req->reg.nr_mode != NR_REG_ALL_NIC && 16752a7db7a6SVincenzo Maffione req->reg.nr_mode != NR_REG_NIC_SW)) { 16762a7db7a6SVincenzo Maffione /* We only support attaching all the NIC rings 16772a7db7a6SVincenzo Maffione * and/or the host stack. */ 16782a7db7a6SVincenzo Maffione return EINVAL; 16792a7db7a6SVincenzo Maffione } 16802a7db7a6SVincenzo Maffione if (NETMAP_OWNED_BY_ANY(na)) { 16812a7db7a6SVincenzo Maffione return EBUSY; 16822a7db7a6SVincenzo Maffione } 16832a7db7a6SVincenzo Maffione if (bna->na_kpriv) { 16842a7db7a6SVincenzo Maffione /* nothing to do */ 16852a7db7a6SVincenzo Maffione return 0; 16862a7db7a6SVincenzo Maffione } 16872a7db7a6SVincenzo Maffione npriv = netmap_priv_new(); 16882a7db7a6SVincenzo Maffione if (npriv == NULL) 16892a7db7a6SVincenzo Maffione return ENOMEM; 16902a7db7a6SVincenzo Maffione npriv->np_ifp = na->ifp; /* let the priv destructor release the ref */ 1691ee0005f1SVincenzo Maffione error = netmap_do_regif(npriv, na, hdr); 16922a7db7a6SVincenzo Maffione if (error) { 16932a7db7a6SVincenzo Maffione netmap_priv_delete(npriv); 1694a6d768d8SVincenzo Maffione netmap_mem_restore(bna->hwna); 16952a7db7a6SVincenzo Maffione return error; 16962a7db7a6SVincenzo Maffione } 16972a7db7a6SVincenzo Maffione bna->na_kpriv = npriv; 16982a7db7a6SVincenzo Maffione na->na_flags |= NAF_BUSY; 16992a7db7a6SVincenzo Maffione } else { 17002a7db7a6SVincenzo Maffione if (na->active_fds == 0) /* not registered */ 17012a7db7a6SVincenzo Maffione return EINVAL; 17022a7db7a6SVincenzo Maffione netmap_priv_delete(bna->na_kpriv); 17032a7db7a6SVincenzo Maffione bna->na_kpriv = NULL; 17042a7db7a6SVincenzo Maffione na->na_flags &= ~NAF_BUSY; 1705a6d768d8SVincenzo Maffione netmap_mem_restore(bna->hwna); 17062a7db7a6SVincenzo Maffione } 17072a7db7a6SVincenzo Maffione 17082a7db7a6SVincenzo Maffione return error; 17092a7db7a6SVincenzo Maffione } 17102a7db7a6SVincenzo Maffione 17112a7db7a6SVincenzo Maffione /* attach a bridge wrapper to the 'real' device */ 17122a7db7a6SVincenzo Maffione int 17132a7db7a6SVincenzo Maffione netmap_bwrap_attach_common(struct netmap_adapter *na, 17142a7db7a6SVincenzo Maffione struct netmap_adapter *hwna) 17152a7db7a6SVincenzo Maffione { 17162a7db7a6SVincenzo Maffione struct netmap_bwrap_adapter *bna; 17172a7db7a6SVincenzo Maffione struct netmap_adapter *hostna = NULL; 17182a7db7a6SVincenzo Maffione int error = 0; 17192a7db7a6SVincenzo Maffione enum txrx t; 17202a7db7a6SVincenzo Maffione 17212a7db7a6SVincenzo Maffione /* make sure the NIC is not already in use */ 17222a7db7a6SVincenzo Maffione if (NETMAP_OWNED_BY_ANY(hwna)) { 1723b6e66be2SVincenzo Maffione nm_prerr("NIC %s busy, cannot attach to bridge", hwna->name); 17242a7db7a6SVincenzo Maffione return EBUSY; 17252a7db7a6SVincenzo Maffione } 17262a7db7a6SVincenzo Maffione 17272a7db7a6SVincenzo Maffione bna = (struct netmap_bwrap_adapter *)na; 17282a7db7a6SVincenzo Maffione /* make bwrap ifp point to the real ifp */ 17292a7db7a6SVincenzo Maffione na->ifp = hwna->ifp; 17302a7db7a6SVincenzo Maffione if_ref(na->ifp); 17312a7db7a6SVincenzo Maffione na->na_private = bna; 17322a7db7a6SVincenzo Maffione /* fill the ring data for the bwrap adapter with rx/tx meanings 17332a7db7a6SVincenzo Maffione * swapped. The real cross-linking will be done during register, 17342a7db7a6SVincenzo Maffione * when all the krings will have been created. 17352a7db7a6SVincenzo Maffione */ 17362a7db7a6SVincenzo Maffione for_rx_tx(t) { 17372a7db7a6SVincenzo Maffione enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */ 17382a7db7a6SVincenzo Maffione nma_set_nrings(na, t, nma_get_nrings(hwna, r)); 17392a7db7a6SVincenzo Maffione nma_set_ndesc(na, t, nma_get_ndesc(hwna, r)); 17402a7db7a6SVincenzo Maffione } 17412a7db7a6SVincenzo Maffione na->nm_dtor = netmap_bwrap_dtor; 17422a7db7a6SVincenzo Maffione na->nm_config = netmap_bwrap_config; 1743a6d768d8SVincenzo Maffione na->nm_bufcfg = netmap_bwrap_bufcfg; 17442a7db7a6SVincenzo Maffione na->nm_bdg_ctl = netmap_bwrap_bdg_ctl; 17452a7db7a6SVincenzo Maffione na->pdev = hwna->pdev; 17462a7db7a6SVincenzo Maffione na->nm_mem = netmap_mem_get(hwna->nm_mem); 17472a7db7a6SVincenzo Maffione na->virt_hdr_len = hwna->virt_hdr_len; 17482a7db7a6SVincenzo Maffione na->rx_buf_maxsize = hwna->rx_buf_maxsize; 17492a7db7a6SVincenzo Maffione 17502a7db7a6SVincenzo Maffione bna->hwna = hwna; 17512a7db7a6SVincenzo Maffione netmap_adapter_get(hwna); 17522a7db7a6SVincenzo Maffione hwna->na_private = bna; /* weak reference */ 17532a7db7a6SVincenzo Maffione bna->saved_na_vp = hwna->na_vp; 17542a7db7a6SVincenzo Maffione hwna->na_vp = &bna->up; 17552a7db7a6SVincenzo Maffione bna->up.up.na_vp = &(bna->up); 17562a7db7a6SVincenzo Maffione 17572a7db7a6SVincenzo Maffione if (hwna->na_flags & NAF_HOST_RINGS) { 17582a7db7a6SVincenzo Maffione if (hwna->na_flags & NAF_SW_ONLY) 17592a7db7a6SVincenzo Maffione na->na_flags |= NAF_SW_ONLY; 17602a7db7a6SVincenzo Maffione na->na_flags |= NAF_HOST_RINGS; 17612a7db7a6SVincenzo Maffione hostna = &bna->host.up; 17622a7db7a6SVincenzo Maffione 17632a7db7a6SVincenzo Maffione snprintf(hostna->name, sizeof(hostna->name), "%s^", na->name); 17642a7db7a6SVincenzo Maffione hostna->ifp = hwna->ifp; 17652a7db7a6SVincenzo Maffione // hostna->nm_txsync = netmap_bwrap_host_txsync; 17662a7db7a6SVincenzo Maffione // hostna->nm_rxsync = netmap_bwrap_host_rxsync; 17672a7db7a6SVincenzo Maffione hostna->nm_mem = netmap_mem_get(na->nm_mem); 17682a7db7a6SVincenzo Maffione hostna->na_private = bna; 17692a7db7a6SVincenzo Maffione hostna->na_vp = &bna->up; 17702a7db7a6SVincenzo Maffione na->na_hostvp = hwna->na_hostvp = 17712a7db7a6SVincenzo Maffione hostna->na_hostvp = &bna->host; 17722a7db7a6SVincenzo Maffione hostna->na_flags = NAF_BUSY; /* prevent NIOCREGIF */ 17732a7db7a6SVincenzo Maffione hostna->rx_buf_maxsize = hwna->rx_buf_maxsize; 1774a6d768d8SVincenzo Maffione /* bwrap_config() will determine the number of host rings */ 17752a7db7a6SVincenzo Maffione } 1776b6e66be2SVincenzo Maffione if (hwna->na_flags & NAF_MOREFRAG) 1777b6e66be2SVincenzo Maffione na->na_flags |= NAF_MOREFRAG; 17782a7db7a6SVincenzo Maffione 177975f4f3edSVincenzo Maffione nm_prdis("%s<->%s txr %d txd %d rxr %d rxd %d", 17802a7db7a6SVincenzo Maffione na->name, ifp->if_xname, 17812a7db7a6SVincenzo Maffione na->num_tx_rings, na->num_tx_desc, 17822a7db7a6SVincenzo Maffione na->num_rx_rings, na->num_rx_desc); 17832a7db7a6SVincenzo Maffione 17842a7db7a6SVincenzo Maffione error = netmap_attach_common(na); 17852a7db7a6SVincenzo Maffione if (error) { 17862a7db7a6SVincenzo Maffione goto err_put; 17872a7db7a6SVincenzo Maffione } 17882a7db7a6SVincenzo Maffione hwna->na_flags |= NAF_BUSY; 17892a7db7a6SVincenzo Maffione return 0; 17902a7db7a6SVincenzo Maffione 17912a7db7a6SVincenzo Maffione err_put: 17922a7db7a6SVincenzo Maffione hwna->na_vp = hwna->na_hostvp = NULL; 17932a7db7a6SVincenzo Maffione netmap_adapter_put(hwna); 17942a7db7a6SVincenzo Maffione return error; 17952a7db7a6SVincenzo Maffione 17962a7db7a6SVincenzo Maffione } 17972a7db7a6SVincenzo Maffione 17982a7db7a6SVincenzo Maffione struct nm_bridge * 17992a7db7a6SVincenzo Maffione netmap_init_bridges2(u_int n) 18002a7db7a6SVincenzo Maffione { 18012a7db7a6SVincenzo Maffione int i; 18022a7db7a6SVincenzo Maffione struct nm_bridge *b; 18032a7db7a6SVincenzo Maffione 18042a7db7a6SVincenzo Maffione b = nm_os_malloc(sizeof(struct nm_bridge) * n); 18052a7db7a6SVincenzo Maffione if (b == NULL) 18062a7db7a6SVincenzo Maffione return NULL; 18072a7db7a6SVincenzo Maffione for (i = 0; i < n; i++) 18082a7db7a6SVincenzo Maffione BDG_RWINIT(&b[i]); 18092a7db7a6SVincenzo Maffione return b; 18102a7db7a6SVincenzo Maffione } 18112a7db7a6SVincenzo Maffione 18122a7db7a6SVincenzo Maffione void 18132a7db7a6SVincenzo Maffione netmap_uninit_bridges2(struct nm_bridge *b, u_int n) 18142a7db7a6SVincenzo Maffione { 18152a7db7a6SVincenzo Maffione int i; 18162a7db7a6SVincenzo Maffione 18172a7db7a6SVincenzo Maffione if (b == NULL) 18182a7db7a6SVincenzo Maffione return; 18192a7db7a6SVincenzo Maffione 18202a7db7a6SVincenzo Maffione for (i = 0; i < n; i++) 18212a7db7a6SVincenzo Maffione BDG_RWDESTROY(&b[i]); 18222a7db7a6SVincenzo Maffione nm_os_free(b); 18232a7db7a6SVincenzo Maffione } 18242a7db7a6SVincenzo Maffione 18252a7db7a6SVincenzo Maffione int 18262a7db7a6SVincenzo Maffione netmap_init_bridges(void) 18272a7db7a6SVincenzo Maffione { 18282a7db7a6SVincenzo Maffione #ifdef CONFIG_NET_NS 18292a7db7a6SVincenzo Maffione return netmap_bns_register(); 18302a7db7a6SVincenzo Maffione #else 18312a7db7a6SVincenzo Maffione nm_bridges = netmap_init_bridges2(NM_BRIDGES); 18322a7db7a6SVincenzo Maffione if (nm_bridges == NULL) 18332a7db7a6SVincenzo Maffione return ENOMEM; 18342a7db7a6SVincenzo Maffione return 0; 18352a7db7a6SVincenzo Maffione #endif 18362a7db7a6SVincenzo Maffione } 18372a7db7a6SVincenzo Maffione 18382a7db7a6SVincenzo Maffione void 18392a7db7a6SVincenzo Maffione netmap_uninit_bridges(void) 18402a7db7a6SVincenzo Maffione { 18412a7db7a6SVincenzo Maffione #ifdef CONFIG_NET_NS 18422a7db7a6SVincenzo Maffione netmap_bns_unregister(); 18432a7db7a6SVincenzo Maffione #else 18442a7db7a6SVincenzo Maffione netmap_uninit_bridges2(nm_bridges, NM_BRIDGES); 18452a7db7a6SVincenzo Maffione #endif 18462a7db7a6SVincenzo Maffione } 1847