1f9790aebSLuigi Rizzo /* 217885a7bSLuigi Rizzo * Copyright (C) 2013-2014 Universita` di Pisa. All rights reserved. 3f9790aebSLuigi Rizzo * 4f9790aebSLuigi Rizzo * Redistribution and use in source and binary forms, with or without 5f9790aebSLuigi Rizzo * modification, are permitted provided that the following conditions 6f9790aebSLuigi Rizzo * are met: 7f9790aebSLuigi Rizzo * 1. Redistributions of source code must retain the above copyright 8f9790aebSLuigi Rizzo * notice, this list of conditions and the following disclaimer. 9f9790aebSLuigi Rizzo * 2. Redistributions in binary form must reproduce the above copyright 10f9790aebSLuigi Rizzo * notice, this list of conditions and the following disclaimer in the 11f9790aebSLuigi Rizzo * documentation and/or other materials provided with the distribution. 12f9790aebSLuigi Rizzo * 13f9790aebSLuigi Rizzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14f9790aebSLuigi Rizzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15f9790aebSLuigi Rizzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16f9790aebSLuigi Rizzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17f9790aebSLuigi Rizzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18f9790aebSLuigi Rizzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19f9790aebSLuigi Rizzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20f9790aebSLuigi Rizzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21f9790aebSLuigi Rizzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22f9790aebSLuigi Rizzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23f9790aebSLuigi Rizzo * SUCH DAMAGE. 24f9790aebSLuigi Rizzo */ 25f9790aebSLuigi Rizzo 26f9790aebSLuigi Rizzo 27f9790aebSLuigi Rizzo /* 28f9790aebSLuigi Rizzo * This module implements the VALE switch for netmap 29f9790aebSLuigi Rizzo 30f9790aebSLuigi Rizzo --- VALE SWITCH --- 31f9790aebSLuigi Rizzo 32f9790aebSLuigi Rizzo NMG_LOCK() serializes all modifications to switches and ports. 33f9790aebSLuigi Rizzo A switch cannot be deleted until all ports are gone. 34f9790aebSLuigi Rizzo 35f9790aebSLuigi Rizzo For each switch, an SX lock (RWlock on linux) protects 36f9790aebSLuigi Rizzo deletion of ports. When configuring or deleting a new port, the 37f9790aebSLuigi Rizzo lock is acquired in exclusive mode (after holding NMG_LOCK). 38f9790aebSLuigi Rizzo When forwarding, the lock is acquired in shared mode (without NMG_LOCK). 39f9790aebSLuigi Rizzo The lock is held throughout the entire forwarding cycle, 40f9790aebSLuigi Rizzo during which the thread may incur in a page fault. 41f9790aebSLuigi Rizzo Hence it is important that sleepable shared locks are used. 42f9790aebSLuigi Rizzo 43f9790aebSLuigi Rizzo On the rx ring, the per-port lock is grabbed initially to reserve 44f9790aebSLuigi Rizzo a number of slot in the ring, then the lock is released, 45f9790aebSLuigi Rizzo packets are copied from source to destination, and then 46f9790aebSLuigi Rizzo the lock is acquired again and the receive ring is updated. 47f9790aebSLuigi Rizzo (A similar thing is done on the tx ring for NIC and host stack 48f9790aebSLuigi Rizzo ports attached to the switch) 49f9790aebSLuigi Rizzo 50f9790aebSLuigi Rizzo */ 51f9790aebSLuigi Rizzo 52f9790aebSLuigi Rizzo /* 53f9790aebSLuigi Rizzo * OS-specific code that is used only within this file. 54f9790aebSLuigi Rizzo * Other OS-specific code that must be accessed by drivers 55f9790aebSLuigi Rizzo * is present in netmap_kern.h 56f9790aebSLuigi Rizzo */ 57f9790aebSLuigi Rizzo 58f9790aebSLuigi Rizzo #if defined(__FreeBSD__) 59f9790aebSLuigi Rizzo #include <sys/cdefs.h> /* prerequisite */ 60f9790aebSLuigi Rizzo __FBSDID("$FreeBSD$"); 61f9790aebSLuigi Rizzo 62f9790aebSLuigi Rizzo #include <sys/types.h> 63f9790aebSLuigi Rizzo #include <sys/errno.h> 64f9790aebSLuigi Rizzo #include <sys/param.h> /* defines used in kernel.h */ 65f9790aebSLuigi Rizzo #include <sys/kernel.h> /* types used in module initialization */ 66f9790aebSLuigi Rizzo #include <sys/conf.h> /* cdevsw struct, UID, GID */ 67f9790aebSLuigi Rizzo #include <sys/sockio.h> 68f9790aebSLuigi Rizzo #include <sys/socketvar.h> /* struct socket */ 69f9790aebSLuigi Rizzo #include <sys/malloc.h> 70f9790aebSLuigi Rizzo #include <sys/poll.h> 71f9790aebSLuigi Rizzo #include <sys/rwlock.h> 72f9790aebSLuigi Rizzo #include <sys/socket.h> /* sockaddrs */ 73f9790aebSLuigi Rizzo #include <sys/selinfo.h> 74f9790aebSLuigi Rizzo #include <sys/sysctl.h> 75f9790aebSLuigi Rizzo #include <net/if.h> 76f9790aebSLuigi Rizzo #include <net/if_var.h> 77f9790aebSLuigi Rizzo #include <net/bpf.h> /* BIOCIMMEDIATE */ 78f9790aebSLuigi Rizzo #include <machine/bus.h> /* bus_dmamap_* */ 79f9790aebSLuigi Rizzo #include <sys/endian.h> 80f9790aebSLuigi Rizzo #include <sys/refcount.h> 81f9790aebSLuigi Rizzo 82f9790aebSLuigi Rizzo 83f9790aebSLuigi Rizzo #define BDG_RWLOCK_T struct rwlock // struct rwlock 84f9790aebSLuigi Rizzo 85f9790aebSLuigi Rizzo #define BDG_RWINIT(b) \ 86f9790aebSLuigi Rizzo rw_init_flags(&(b)->bdg_lock, "bdg lock", RW_NOWITNESS) 87f9790aebSLuigi Rizzo #define BDG_WLOCK(b) rw_wlock(&(b)->bdg_lock) 88f9790aebSLuigi Rizzo #define BDG_WUNLOCK(b) rw_wunlock(&(b)->bdg_lock) 89f9790aebSLuigi Rizzo #define BDG_RLOCK(b) rw_rlock(&(b)->bdg_lock) 90f9790aebSLuigi Rizzo #define BDG_RTRYLOCK(b) rw_try_rlock(&(b)->bdg_lock) 91f9790aebSLuigi Rizzo #define BDG_RUNLOCK(b) rw_runlock(&(b)->bdg_lock) 92f9790aebSLuigi Rizzo #define BDG_RWDESTROY(b) rw_destroy(&(b)->bdg_lock) 93f9790aebSLuigi Rizzo 94f9790aebSLuigi Rizzo 95f9790aebSLuigi Rizzo #elif defined(linux) 96f9790aebSLuigi Rizzo 97f9790aebSLuigi Rizzo #include "bsd_glue.h" 98f9790aebSLuigi Rizzo 99f9790aebSLuigi Rizzo #elif defined(__APPLE__) 100f9790aebSLuigi Rizzo 101f9790aebSLuigi Rizzo #warning OSX support is only partial 102f9790aebSLuigi Rizzo #include "osx_glue.h" 103f9790aebSLuigi Rizzo 104f9790aebSLuigi Rizzo #else 105f9790aebSLuigi Rizzo 106f9790aebSLuigi Rizzo #error Unsupported platform 107f9790aebSLuigi Rizzo 108f9790aebSLuigi Rizzo #endif /* unsupported */ 109f9790aebSLuigi Rizzo 110f9790aebSLuigi Rizzo /* 111f9790aebSLuigi Rizzo * common headers 112f9790aebSLuigi Rizzo */ 113f9790aebSLuigi Rizzo 114f9790aebSLuigi Rizzo #include <net/netmap.h> 115f9790aebSLuigi Rizzo #include <dev/netmap/netmap_kern.h> 116f9790aebSLuigi Rizzo #include <dev/netmap/netmap_mem2.h> 117f9790aebSLuigi Rizzo 118f9790aebSLuigi Rizzo #ifdef WITH_VALE 119f9790aebSLuigi Rizzo 120f9790aebSLuigi Rizzo /* 121f9790aebSLuigi Rizzo * system parameters (most of them in netmap_kern.h) 122f9790aebSLuigi Rizzo * NM_NAME prefix for switch port names, default "vale" 123f9790aebSLuigi Rizzo * NM_BDG_MAXPORTS number of ports 124f9790aebSLuigi Rizzo * NM_BRIDGES max number of switches in the system. 125f9790aebSLuigi Rizzo * XXX should become a sysctl or tunable 126f9790aebSLuigi Rizzo * 127f9790aebSLuigi Rizzo * Switch ports are named valeX:Y where X is the switch name and Y 128f9790aebSLuigi Rizzo * is the port. If Y matches a physical interface name, the port is 129f9790aebSLuigi Rizzo * connected to a physical device. 130f9790aebSLuigi Rizzo * 131f9790aebSLuigi Rizzo * Unlike physical interfaces, switch ports use their own memory region 132f9790aebSLuigi Rizzo * for rings and buffers. 133f9790aebSLuigi Rizzo * The virtual interfaces use per-queue lock instead of core lock. 134f9790aebSLuigi Rizzo * In the tx loop, we aggregate traffic in batches to make all operations 135f9790aebSLuigi Rizzo * faster. The batch size is bridge_batch. 136f9790aebSLuigi Rizzo */ 137f9790aebSLuigi Rizzo #define NM_BDG_MAXRINGS 16 /* XXX unclear how many. */ 138f9790aebSLuigi Rizzo #define NM_BDG_MAXSLOTS 4096 /* XXX same as above */ 139f9790aebSLuigi Rizzo #define NM_BRIDGE_RINGSIZE 1024 /* in the device */ 140f9790aebSLuigi Rizzo #define NM_BDG_HASH 1024 /* forwarding table entries */ 141f9790aebSLuigi Rizzo #define NM_BDG_BATCH 1024 /* entries in the forwarding buffer */ 142f9790aebSLuigi Rizzo #define NM_MULTISEG 64 /* max size of a chain of bufs */ 143f9790aebSLuigi Rizzo /* actual size of the tables */ 144f9790aebSLuigi Rizzo #define NM_BDG_BATCH_MAX (NM_BDG_BATCH + NM_MULTISEG) 145f9790aebSLuigi Rizzo /* NM_FT_NULL terminates a list of slots in the ft */ 146f9790aebSLuigi Rizzo #define NM_FT_NULL NM_BDG_BATCH_MAX 147f9790aebSLuigi Rizzo #define NM_BRIDGES 8 /* number of bridges */ 148f9790aebSLuigi Rizzo 149f9790aebSLuigi Rizzo 150f9790aebSLuigi Rizzo /* 151f9790aebSLuigi Rizzo * bridge_batch is set via sysctl to the max batch size to be 152f9790aebSLuigi Rizzo * used in the bridge. The actual value may be larger as the 153f9790aebSLuigi Rizzo * last packet in the block may overflow the size. 154f9790aebSLuigi Rizzo */ 155f9790aebSLuigi Rizzo int bridge_batch = NM_BDG_BATCH; /* bridge batch size */ 156f9790aebSLuigi Rizzo SYSCTL_DECL(_dev_netmap); 157f9790aebSLuigi Rizzo SYSCTL_INT(_dev_netmap, OID_AUTO, bridge_batch, CTLFLAG_RW, &bridge_batch, 0 , ""); 158f9790aebSLuigi Rizzo 159f9790aebSLuigi Rizzo 160f9790aebSLuigi Rizzo static int bdg_netmap_attach(struct nmreq *nmr, struct ifnet *ifp); 161f9790aebSLuigi Rizzo static int bdg_netmap_reg(struct netmap_adapter *na, int onoff); 162f9790aebSLuigi Rizzo static int netmap_bwrap_attach(struct ifnet *, struct ifnet *); 163f9790aebSLuigi Rizzo static int netmap_bwrap_register(struct netmap_adapter *, int onoff); 164f9790aebSLuigi Rizzo int kern_netmap_regif(struct nmreq *nmr); 165f9790aebSLuigi Rizzo 166f9790aebSLuigi Rizzo /* 167f9790aebSLuigi Rizzo * Each transmit queue accumulates a batch of packets into 168f9790aebSLuigi Rizzo * a structure before forwarding. Packets to the same 169f9790aebSLuigi Rizzo * destination are put in a list using ft_next as a link field. 170f9790aebSLuigi Rizzo * ft_frags and ft_next are valid only on the first fragment. 171f9790aebSLuigi Rizzo */ 172f9790aebSLuigi Rizzo struct nm_bdg_fwd { /* forwarding entry for a bridge */ 173f9790aebSLuigi Rizzo void *ft_buf; /* netmap or indirect buffer */ 174f9790aebSLuigi Rizzo uint8_t ft_frags; /* how many fragments (only on 1st frag) */ 175f9790aebSLuigi Rizzo uint8_t _ft_port; /* dst port (unused) */ 176f9790aebSLuigi Rizzo uint16_t ft_flags; /* flags, e.g. indirect */ 177f9790aebSLuigi Rizzo uint16_t ft_len; /* src fragment len */ 178f9790aebSLuigi Rizzo uint16_t ft_next; /* next packet to same destination */ 179f9790aebSLuigi Rizzo }; 180f9790aebSLuigi Rizzo 181f9790aebSLuigi Rizzo /* 182f9790aebSLuigi Rizzo * For each output interface, nm_bdg_q is used to construct a list. 183f9790aebSLuigi Rizzo * bq_len is the number of output buffers (we can have coalescing 184f9790aebSLuigi Rizzo * during the copy). 185f9790aebSLuigi Rizzo */ 186f9790aebSLuigi Rizzo struct nm_bdg_q { 187f9790aebSLuigi Rizzo uint16_t bq_head; 188f9790aebSLuigi Rizzo uint16_t bq_tail; 189f9790aebSLuigi Rizzo uint32_t bq_len; /* number of buffers */ 190f9790aebSLuigi Rizzo }; 191f9790aebSLuigi Rizzo 192f9790aebSLuigi Rizzo /* XXX revise this */ 193f9790aebSLuigi Rizzo struct nm_hash_ent { 194f9790aebSLuigi Rizzo uint64_t mac; /* the top 2 bytes are the epoch */ 195f9790aebSLuigi Rizzo uint64_t ports; 196f9790aebSLuigi Rizzo }; 197f9790aebSLuigi Rizzo 198f9790aebSLuigi Rizzo /* 199f9790aebSLuigi Rizzo * nm_bridge is a descriptor for a VALE switch. 200f9790aebSLuigi Rizzo * Interfaces for a bridge are all in bdg_ports[]. 201f9790aebSLuigi Rizzo * The array has fixed size, an empty entry does not terminate 202f9790aebSLuigi Rizzo * the search, but lookups only occur on attach/detach so we 203f9790aebSLuigi Rizzo * don't mind if they are slow. 204f9790aebSLuigi Rizzo * 205f9790aebSLuigi Rizzo * The bridge is non blocking on the transmit ports: excess 206f9790aebSLuigi Rizzo * packets are dropped if there is no room on the output port. 207f9790aebSLuigi Rizzo * 208f9790aebSLuigi Rizzo * bdg_lock protects accesses to the bdg_ports array. 209f9790aebSLuigi Rizzo * This is a rw lock (or equivalent). 210f9790aebSLuigi Rizzo */ 211f9790aebSLuigi Rizzo struct nm_bridge { 212f9790aebSLuigi Rizzo /* XXX what is the proper alignment/layout ? */ 213f9790aebSLuigi Rizzo BDG_RWLOCK_T bdg_lock; /* protects bdg_ports */ 214f9790aebSLuigi Rizzo int bdg_namelen; 215f9790aebSLuigi Rizzo uint32_t bdg_active_ports; /* 0 means free */ 216f9790aebSLuigi Rizzo char bdg_basename[IFNAMSIZ]; 217f9790aebSLuigi Rizzo 218f9790aebSLuigi Rizzo /* Indexes of active ports (up to active_ports) 219f9790aebSLuigi Rizzo * and all other remaining ports. 220f9790aebSLuigi Rizzo */ 221f9790aebSLuigi Rizzo uint8_t bdg_port_index[NM_BDG_MAXPORTS]; 222f9790aebSLuigi Rizzo 223f9790aebSLuigi Rizzo struct netmap_vp_adapter *bdg_ports[NM_BDG_MAXPORTS]; 224f9790aebSLuigi Rizzo 225f9790aebSLuigi Rizzo 226f9790aebSLuigi Rizzo /* 227f9790aebSLuigi Rizzo * The function to decide the destination port. 228f9790aebSLuigi Rizzo * It returns either of an index of the destination port, 229f9790aebSLuigi Rizzo * NM_BDG_BROADCAST to broadcast this packet, or NM_BDG_NOPORT not to 230f9790aebSLuigi Rizzo * forward this packet. ring_nr is the source ring index, and the 231f9790aebSLuigi Rizzo * function may overwrite this value to forward this packet to a 232f9790aebSLuigi Rizzo * different ring index. 233f9790aebSLuigi Rizzo * This function must be set by netmap_bdgctl(). 234f9790aebSLuigi Rizzo */ 235f9790aebSLuigi Rizzo bdg_lookup_fn_t nm_bdg_lookup; 236f9790aebSLuigi Rizzo 237f9790aebSLuigi Rizzo /* the forwarding table, MAC+ports. 238f9790aebSLuigi Rizzo * XXX should be changed to an argument to be passed to 239f9790aebSLuigi Rizzo * the lookup function, and allocated on attach 240f9790aebSLuigi Rizzo */ 241f9790aebSLuigi Rizzo struct nm_hash_ent ht[NM_BDG_HASH]; 242f9790aebSLuigi Rizzo }; 243f9790aebSLuigi Rizzo 244f9790aebSLuigi Rizzo 245f9790aebSLuigi Rizzo /* 246f9790aebSLuigi Rizzo * XXX in principle nm_bridges could be created dynamically 247f9790aebSLuigi Rizzo * Right now we have a static array and deletions are protected 248f9790aebSLuigi Rizzo * by an exclusive lock. 249f9790aebSLuigi Rizzo */ 250f9790aebSLuigi Rizzo struct nm_bridge nm_bridges[NM_BRIDGES]; 251f9790aebSLuigi Rizzo 252f9790aebSLuigi Rizzo 253f9790aebSLuigi Rizzo /* 254f9790aebSLuigi Rizzo * this is a slightly optimized copy routine which rounds 255f9790aebSLuigi Rizzo * to multiple of 64 bytes and is often faster than dealing 256f9790aebSLuigi Rizzo * with other odd sizes. We assume there is enough room 257f9790aebSLuigi Rizzo * in the source and destination buffers. 258f9790aebSLuigi Rizzo * 259f9790aebSLuigi Rizzo * XXX only for multiples of 64 bytes, non overlapped. 260f9790aebSLuigi Rizzo */ 261f9790aebSLuigi Rizzo static inline void 262f9790aebSLuigi Rizzo pkt_copy(void *_src, void *_dst, int l) 263f9790aebSLuigi Rizzo { 264f9790aebSLuigi Rizzo uint64_t *src = _src; 265f9790aebSLuigi Rizzo uint64_t *dst = _dst; 266f9790aebSLuigi Rizzo if (unlikely(l >= 1024)) { 267f9790aebSLuigi Rizzo memcpy(dst, src, l); 268f9790aebSLuigi Rizzo return; 269f9790aebSLuigi Rizzo } 270f9790aebSLuigi Rizzo for (; likely(l > 0); l-=64) { 271f9790aebSLuigi Rizzo *dst++ = *src++; 272f9790aebSLuigi Rizzo *dst++ = *src++; 273f9790aebSLuigi Rizzo *dst++ = *src++; 274f9790aebSLuigi Rizzo *dst++ = *src++; 275f9790aebSLuigi Rizzo *dst++ = *src++; 276f9790aebSLuigi Rizzo *dst++ = *src++; 277f9790aebSLuigi Rizzo *dst++ = *src++; 278f9790aebSLuigi Rizzo *dst++ = *src++; 279f9790aebSLuigi Rizzo } 280f9790aebSLuigi Rizzo } 281f9790aebSLuigi Rizzo 282f9790aebSLuigi Rizzo 283f9790aebSLuigi Rizzo /* 284f9790aebSLuigi Rizzo * locate a bridge among the existing ones. 285f9790aebSLuigi Rizzo * MUST BE CALLED WITH NMG_LOCK() 286f9790aebSLuigi Rizzo * 287f9790aebSLuigi Rizzo * a ':' in the name terminates the bridge name. Otherwise, just NM_NAME. 288f9790aebSLuigi Rizzo * We assume that this is called with a name of at least NM_NAME chars. 289f9790aebSLuigi Rizzo */ 290f9790aebSLuigi Rizzo static struct nm_bridge * 291f9790aebSLuigi Rizzo nm_find_bridge(const char *name, int create) 292f9790aebSLuigi Rizzo { 293f9790aebSLuigi Rizzo int i, l, namelen; 294f9790aebSLuigi Rizzo struct nm_bridge *b = NULL; 295f9790aebSLuigi Rizzo 296f9790aebSLuigi Rizzo NMG_LOCK_ASSERT(); 297f9790aebSLuigi Rizzo 298f9790aebSLuigi Rizzo namelen = strlen(NM_NAME); /* base length */ 299f9790aebSLuigi Rizzo l = name ? strlen(name) : 0; /* actual length */ 300f9790aebSLuigi Rizzo if (l < namelen) { 301f9790aebSLuigi Rizzo D("invalid bridge name %s", name ? name : NULL); 302f9790aebSLuigi Rizzo return NULL; 303f9790aebSLuigi Rizzo } 304f9790aebSLuigi Rizzo for (i = namelen + 1; i < l; i++) { 305f9790aebSLuigi Rizzo if (name[i] == ':') { 306f9790aebSLuigi Rizzo namelen = i; 307f9790aebSLuigi Rizzo break; 308f9790aebSLuigi Rizzo } 309f9790aebSLuigi Rizzo } 310f9790aebSLuigi Rizzo if (namelen >= IFNAMSIZ) 311f9790aebSLuigi Rizzo namelen = IFNAMSIZ; 312f9790aebSLuigi Rizzo ND("--- prefix is '%.*s' ---", namelen, name); 313f9790aebSLuigi Rizzo 314f9790aebSLuigi Rizzo /* lookup the name, remember empty slot if there is one */ 315f9790aebSLuigi Rizzo for (i = 0; i < NM_BRIDGES; i++) { 316f9790aebSLuigi Rizzo struct nm_bridge *x = nm_bridges + i; 317f9790aebSLuigi Rizzo 318f9790aebSLuigi Rizzo if (x->bdg_active_ports == 0) { 319f9790aebSLuigi Rizzo if (create && b == NULL) 320f9790aebSLuigi Rizzo b = x; /* record empty slot */ 321f9790aebSLuigi Rizzo } else if (x->bdg_namelen != namelen) { 322f9790aebSLuigi Rizzo continue; 323f9790aebSLuigi Rizzo } else if (strncmp(name, x->bdg_basename, namelen) == 0) { 324f9790aebSLuigi Rizzo ND("found '%.*s' at %d", namelen, name, i); 325f9790aebSLuigi Rizzo b = x; 326f9790aebSLuigi Rizzo break; 327f9790aebSLuigi Rizzo } 328f9790aebSLuigi Rizzo } 329f9790aebSLuigi Rizzo if (i == NM_BRIDGES && b) { /* name not found, can create entry */ 330f9790aebSLuigi Rizzo /* initialize the bridge */ 331f9790aebSLuigi Rizzo strncpy(b->bdg_basename, name, namelen); 332f9790aebSLuigi Rizzo ND("create new bridge %s with ports %d", b->bdg_basename, 333f9790aebSLuigi Rizzo b->bdg_active_ports); 334f9790aebSLuigi Rizzo b->bdg_namelen = namelen; 335f9790aebSLuigi Rizzo b->bdg_active_ports = 0; 336f9790aebSLuigi Rizzo for (i = 0; i < NM_BDG_MAXPORTS; i++) 337f9790aebSLuigi Rizzo b->bdg_port_index[i] = i; 338f9790aebSLuigi Rizzo /* set the default function */ 339f9790aebSLuigi Rizzo b->nm_bdg_lookup = netmap_bdg_learning; 340f9790aebSLuigi Rizzo /* reset the MAC address table */ 341f9790aebSLuigi Rizzo bzero(b->ht, sizeof(struct nm_hash_ent) * NM_BDG_HASH); 342f9790aebSLuigi Rizzo } 343f9790aebSLuigi Rizzo return b; 344f9790aebSLuigi Rizzo } 345f9790aebSLuigi Rizzo 346f9790aebSLuigi Rizzo 347f9790aebSLuigi Rizzo /* 348f9790aebSLuigi Rizzo * Free the forwarding tables for rings attached to switch ports. 349f9790aebSLuigi Rizzo */ 350f9790aebSLuigi Rizzo static void 351f9790aebSLuigi Rizzo nm_free_bdgfwd(struct netmap_adapter *na) 352f9790aebSLuigi Rizzo { 353f9790aebSLuigi Rizzo int nrings, i; 354f9790aebSLuigi Rizzo struct netmap_kring *kring; 355f9790aebSLuigi Rizzo 356f9790aebSLuigi Rizzo NMG_LOCK_ASSERT(); 35717885a7bSLuigi Rizzo nrings = na->num_tx_rings; 35817885a7bSLuigi Rizzo kring = na->tx_rings; 359f9790aebSLuigi Rizzo for (i = 0; i < nrings; i++) { 360f9790aebSLuigi Rizzo if (kring[i].nkr_ft) { 361f9790aebSLuigi Rizzo free(kring[i].nkr_ft, M_DEVBUF); 362f9790aebSLuigi Rizzo kring[i].nkr_ft = NULL; /* protect from freeing twice */ 363f9790aebSLuigi Rizzo } 364f9790aebSLuigi Rizzo } 365f9790aebSLuigi Rizzo } 366f9790aebSLuigi Rizzo 367f9790aebSLuigi Rizzo 368f9790aebSLuigi Rizzo /* 369f9790aebSLuigi Rizzo * Allocate the forwarding tables for the rings attached to the bridge ports. 370f9790aebSLuigi Rizzo */ 371f9790aebSLuigi Rizzo static int 372f9790aebSLuigi Rizzo nm_alloc_bdgfwd(struct netmap_adapter *na) 373f9790aebSLuigi Rizzo { 374f9790aebSLuigi Rizzo int nrings, l, i, num_dstq; 375f9790aebSLuigi Rizzo struct netmap_kring *kring; 376f9790aebSLuigi Rizzo 377f9790aebSLuigi Rizzo NMG_LOCK_ASSERT(); 378f9790aebSLuigi Rizzo /* all port:rings + broadcast */ 379f9790aebSLuigi Rizzo num_dstq = NM_BDG_MAXPORTS * NM_BDG_MAXRINGS + 1; 380f9790aebSLuigi Rizzo l = sizeof(struct nm_bdg_fwd) * NM_BDG_BATCH_MAX; 381f9790aebSLuigi Rizzo l += sizeof(struct nm_bdg_q) * num_dstq; 382f9790aebSLuigi Rizzo l += sizeof(uint16_t) * NM_BDG_BATCH_MAX; 383f9790aebSLuigi Rizzo 384f9790aebSLuigi Rizzo nrings = na->num_tx_rings + 1; 385f9790aebSLuigi Rizzo kring = na->tx_rings; 386f9790aebSLuigi Rizzo for (i = 0; i < nrings; i++) { 387f9790aebSLuigi Rizzo struct nm_bdg_fwd *ft; 388f9790aebSLuigi Rizzo struct nm_bdg_q *dstq; 389f9790aebSLuigi Rizzo int j; 390f9790aebSLuigi Rizzo 391f9790aebSLuigi Rizzo ft = malloc(l, M_DEVBUF, M_NOWAIT | M_ZERO); 392f9790aebSLuigi Rizzo if (!ft) { 393f9790aebSLuigi Rizzo nm_free_bdgfwd(na); 394f9790aebSLuigi Rizzo return ENOMEM; 395f9790aebSLuigi Rizzo } 396f9790aebSLuigi Rizzo dstq = (struct nm_bdg_q *)(ft + NM_BDG_BATCH_MAX); 397f9790aebSLuigi Rizzo for (j = 0; j < num_dstq; j++) { 398f9790aebSLuigi Rizzo dstq[j].bq_head = dstq[j].bq_tail = NM_FT_NULL; 399f9790aebSLuigi Rizzo dstq[j].bq_len = 0; 400f9790aebSLuigi Rizzo } 401f9790aebSLuigi Rizzo kring[i].nkr_ft = ft; 402f9790aebSLuigi Rizzo } 403f9790aebSLuigi Rizzo return 0; 404f9790aebSLuigi Rizzo } 405f9790aebSLuigi Rizzo 406f9790aebSLuigi Rizzo 407f9790aebSLuigi Rizzo static void 408f9790aebSLuigi Rizzo netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw) 409f9790aebSLuigi Rizzo { 410f9790aebSLuigi Rizzo int s_hw = hw, s_sw = sw; 411f9790aebSLuigi Rizzo int i, lim =b->bdg_active_ports; 412f9790aebSLuigi Rizzo uint8_t tmp[NM_BDG_MAXPORTS]; 413f9790aebSLuigi Rizzo 414f9790aebSLuigi Rizzo /* 415f9790aebSLuigi Rizzo New algorithm: 416f9790aebSLuigi Rizzo make a copy of bdg_port_index; 417f9790aebSLuigi Rizzo lookup NA(ifp)->bdg_port and SWNA(ifp)->bdg_port 418f9790aebSLuigi Rizzo in the array of bdg_port_index, replacing them with 419f9790aebSLuigi Rizzo entries from the bottom of the array; 420f9790aebSLuigi Rizzo decrement bdg_active_ports; 421f9790aebSLuigi Rizzo acquire BDG_WLOCK() and copy back the array. 422f9790aebSLuigi Rizzo */ 423f9790aebSLuigi Rizzo 424f9790aebSLuigi Rizzo D("detach %d and %d (lim %d)", hw, sw, lim); 425f9790aebSLuigi Rizzo /* make a copy of the list of active ports, update it, 426f9790aebSLuigi Rizzo * and then copy back within BDG_WLOCK(). 427f9790aebSLuigi Rizzo */ 428f9790aebSLuigi Rizzo memcpy(tmp, b->bdg_port_index, sizeof(tmp)); 429f9790aebSLuigi Rizzo for (i = 0; (hw >= 0 || sw >= 0) && i < lim; ) { 430f9790aebSLuigi Rizzo if (hw >= 0 && tmp[i] == hw) { 431f9790aebSLuigi Rizzo ND("detach hw %d at %d", hw, i); 432f9790aebSLuigi Rizzo lim--; /* point to last active port */ 433f9790aebSLuigi Rizzo tmp[i] = tmp[lim]; /* swap with i */ 434f9790aebSLuigi Rizzo tmp[lim] = hw; /* now this is inactive */ 435f9790aebSLuigi Rizzo hw = -1; 436f9790aebSLuigi Rizzo } else if (sw >= 0 && tmp[i] == sw) { 437f9790aebSLuigi Rizzo ND("detach sw %d at %d", sw, i); 438f9790aebSLuigi Rizzo lim--; 439f9790aebSLuigi Rizzo tmp[i] = tmp[lim]; 440f9790aebSLuigi Rizzo tmp[lim] = sw; 441f9790aebSLuigi Rizzo sw = -1; 442f9790aebSLuigi Rizzo } else { 443f9790aebSLuigi Rizzo i++; 444f9790aebSLuigi Rizzo } 445f9790aebSLuigi Rizzo } 446f9790aebSLuigi Rizzo if (hw >= 0 || sw >= 0) { 447f9790aebSLuigi Rizzo D("XXX delete failed hw %d sw %d, should panic...", hw, sw); 448f9790aebSLuigi Rizzo } 449f9790aebSLuigi Rizzo 450f9790aebSLuigi Rizzo BDG_WLOCK(b); 451f9790aebSLuigi Rizzo b->bdg_ports[s_hw] = NULL; 452f9790aebSLuigi Rizzo if (s_sw >= 0) { 453f9790aebSLuigi Rizzo b->bdg_ports[s_sw] = NULL; 454f9790aebSLuigi Rizzo } 455f9790aebSLuigi Rizzo memcpy(b->bdg_port_index, tmp, sizeof(tmp)); 456f9790aebSLuigi Rizzo b->bdg_active_ports = lim; 457f9790aebSLuigi Rizzo BDG_WUNLOCK(b); 458f9790aebSLuigi Rizzo 459f9790aebSLuigi Rizzo ND("now %d active ports", lim); 460f9790aebSLuigi Rizzo if (lim == 0) { 461f9790aebSLuigi Rizzo ND("marking bridge %s as free", b->bdg_basename); 462f9790aebSLuigi Rizzo b->nm_bdg_lookup = NULL; 463f9790aebSLuigi Rizzo } 464f9790aebSLuigi Rizzo } 465f9790aebSLuigi Rizzo 46617885a7bSLuigi Rizzo 467f9790aebSLuigi Rizzo static void 468f9790aebSLuigi Rizzo netmap_adapter_vp_dtor(struct netmap_adapter *na) 469f9790aebSLuigi Rizzo { 470f9790aebSLuigi Rizzo struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter*)na; 471f9790aebSLuigi Rizzo struct nm_bridge *b = vpna->na_bdg; 472f9790aebSLuigi Rizzo struct ifnet *ifp = na->ifp; 473f9790aebSLuigi Rizzo 474f9790aebSLuigi Rizzo ND("%s has %d references", NM_IFPNAME(ifp), na->na_refcount); 475f9790aebSLuigi Rizzo 476f9790aebSLuigi Rizzo if (b) { 477f9790aebSLuigi Rizzo netmap_bdg_detach_common(b, vpna->bdg_port, -1); 478f9790aebSLuigi Rizzo } 479f9790aebSLuigi Rizzo 480f9790aebSLuigi Rizzo bzero(ifp, sizeof(*ifp)); 481f9790aebSLuigi Rizzo free(ifp, M_DEVBUF); 482f9790aebSLuigi Rizzo na->ifp = NULL; 483f9790aebSLuigi Rizzo } 484f9790aebSLuigi Rizzo 48517885a7bSLuigi Rizzo 48617885a7bSLuigi Rizzo /* Try to get a reference to a netmap adapter attached to a VALE switch. 48717885a7bSLuigi Rizzo * If the adapter is found (or is created), this function returns 0, a 48817885a7bSLuigi Rizzo * non NULL pointer is returned into *na, and the caller holds a 48917885a7bSLuigi Rizzo * reference to the adapter. 49017885a7bSLuigi Rizzo * If an adapter is not found, then no reference is grabbed and the 49117885a7bSLuigi Rizzo * function returns an error code, or 0 if there is just a VALE prefix 49217885a7bSLuigi Rizzo * mismatch. Therefore the caller holds a reference when 49317885a7bSLuigi Rizzo * (*na != NULL && return == 0). 49417885a7bSLuigi Rizzo */ 495f9790aebSLuigi Rizzo int 496f9790aebSLuigi Rizzo netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na, int create) 497f9790aebSLuigi Rizzo { 498f9790aebSLuigi Rizzo const char *name = nmr->nr_name; 499f9790aebSLuigi Rizzo struct ifnet *ifp; 500f9790aebSLuigi Rizzo int error = 0; 501f9790aebSLuigi Rizzo struct netmap_adapter *ret; 502f9790aebSLuigi Rizzo struct netmap_vp_adapter *vpna; 503f9790aebSLuigi Rizzo struct nm_bridge *b; 504f9790aebSLuigi Rizzo int i, j, cand = -1, cand2 = -1; 505f9790aebSLuigi Rizzo int needed; 506f9790aebSLuigi Rizzo 507f9790aebSLuigi Rizzo *na = NULL; /* default return value */ 508f9790aebSLuigi Rizzo 509f9790aebSLuigi Rizzo /* first try to see if this is a bridge port. */ 510f9790aebSLuigi Rizzo NMG_LOCK_ASSERT(); 511f9790aebSLuigi Rizzo if (strncmp(name, NM_NAME, sizeof(NM_NAME) - 1)) { 512f9790aebSLuigi Rizzo return 0; /* no error, but no VALE prefix */ 513f9790aebSLuigi Rizzo } 514f9790aebSLuigi Rizzo 515f9790aebSLuigi Rizzo b = nm_find_bridge(name, create); 516f9790aebSLuigi Rizzo if (b == NULL) { 517f9790aebSLuigi Rizzo D("no bridges available for '%s'", name); 518f9790aebSLuigi Rizzo return (ENXIO); 519f9790aebSLuigi Rizzo } 520f9790aebSLuigi Rizzo 521f9790aebSLuigi Rizzo /* Now we are sure that name starts with the bridge's name, 522f9790aebSLuigi Rizzo * lookup the port in the bridge. We need to scan the entire 523f9790aebSLuigi Rizzo * list. It is not important to hold a WLOCK on the bridge 524f9790aebSLuigi Rizzo * during the search because NMG_LOCK already guarantees 525f9790aebSLuigi Rizzo * that there are no other possible writers. 526f9790aebSLuigi Rizzo */ 527f9790aebSLuigi Rizzo 528f9790aebSLuigi Rizzo /* lookup in the local list of ports */ 529f9790aebSLuigi Rizzo for (j = 0; j < b->bdg_active_ports; j++) { 530f9790aebSLuigi Rizzo i = b->bdg_port_index[j]; 531f9790aebSLuigi Rizzo vpna = b->bdg_ports[i]; 532f9790aebSLuigi Rizzo // KASSERT(na != NULL); 533f9790aebSLuigi Rizzo ifp = vpna->up.ifp; 534f9790aebSLuigi Rizzo /* XXX make sure the name only contains one : */ 535f9790aebSLuigi Rizzo if (!strcmp(NM_IFPNAME(ifp), name)) { 536f9790aebSLuigi Rizzo netmap_adapter_get(&vpna->up); 537f9790aebSLuigi Rizzo ND("found existing if %s refs %d", name, 538f9790aebSLuigi Rizzo vpna->na_bdg_refcount); 539f9790aebSLuigi Rizzo *na = (struct netmap_adapter *)vpna; 540f9790aebSLuigi Rizzo return 0; 541f9790aebSLuigi Rizzo } 542f9790aebSLuigi Rizzo } 543f9790aebSLuigi Rizzo /* not found, should we create it? */ 544f9790aebSLuigi Rizzo if (!create) 545f9790aebSLuigi Rizzo return ENXIO; 546f9790aebSLuigi Rizzo /* yes we should, see if we have space to attach entries */ 547f9790aebSLuigi Rizzo needed = 2; /* in some cases we only need 1 */ 548f9790aebSLuigi Rizzo if (b->bdg_active_ports + needed >= NM_BDG_MAXPORTS) { 549f9790aebSLuigi Rizzo D("bridge full %d, cannot create new port", b->bdg_active_ports); 550f9790aebSLuigi Rizzo return EINVAL; 551f9790aebSLuigi Rizzo } 552f9790aebSLuigi Rizzo /* record the next two ports available, but do not allocate yet */ 553f9790aebSLuigi Rizzo cand = b->bdg_port_index[b->bdg_active_ports]; 554f9790aebSLuigi Rizzo cand2 = b->bdg_port_index[b->bdg_active_ports + 1]; 555f9790aebSLuigi Rizzo ND("+++ bridge %s port %s used %d avail %d %d", 556f9790aebSLuigi Rizzo b->bdg_basename, name, b->bdg_active_ports, cand, cand2); 557f9790aebSLuigi Rizzo 558f9790aebSLuigi Rizzo /* 559f9790aebSLuigi Rizzo * try see if there is a matching NIC with this name 560f9790aebSLuigi Rizzo * (after the bridge's name) 561f9790aebSLuigi Rizzo */ 562f9790aebSLuigi Rizzo ifp = ifunit_ref(name + b->bdg_namelen + 1); 563f9790aebSLuigi Rizzo if (!ifp) { /* this is a virtual port */ 564f9790aebSLuigi Rizzo if (nmr->nr_cmd) { 565f9790aebSLuigi Rizzo /* nr_cmd must be 0 for a virtual port */ 566f9790aebSLuigi Rizzo return EINVAL; 567f9790aebSLuigi Rizzo } 568f9790aebSLuigi Rizzo 569f9790aebSLuigi Rizzo /* create a struct ifnet for the new port. 570f9790aebSLuigi Rizzo * need M_NOWAIT as we are under nma_lock 571f9790aebSLuigi Rizzo */ 572f9790aebSLuigi Rizzo ifp = malloc(sizeof(*ifp), M_DEVBUF, M_NOWAIT | M_ZERO); 573f9790aebSLuigi Rizzo if (!ifp) 574f9790aebSLuigi Rizzo return ENOMEM; 575f9790aebSLuigi Rizzo 576f9790aebSLuigi Rizzo strcpy(ifp->if_xname, name); 577f9790aebSLuigi Rizzo /* bdg_netmap_attach creates a struct netmap_adapter */ 578f9790aebSLuigi Rizzo error = bdg_netmap_attach(nmr, ifp); 579f9790aebSLuigi Rizzo if (error) { 580f9790aebSLuigi Rizzo D("error %d", error); 581f9790aebSLuigi Rizzo free(ifp, M_DEVBUF); 582f9790aebSLuigi Rizzo return error; 583f9790aebSLuigi Rizzo } 584f9790aebSLuigi Rizzo ret = NA(ifp); 585f9790aebSLuigi Rizzo cand2 = -1; /* only need one port */ 586f9790aebSLuigi Rizzo } else { /* this is a NIC */ 587f9790aebSLuigi Rizzo struct ifnet *fake_ifp; 588f9790aebSLuigi Rizzo 589f9790aebSLuigi Rizzo error = netmap_get_hw_na(ifp, &ret); 590f9790aebSLuigi Rizzo if (error || ret == NULL) 591f9790aebSLuigi Rizzo goto out; 592f9790aebSLuigi Rizzo 593f9790aebSLuigi Rizzo /* make sure the NIC is not already in use */ 594f9790aebSLuigi Rizzo if (NETMAP_OWNED_BY_ANY(ret)) { 595f9790aebSLuigi Rizzo D("NIC %s busy, cannot attach to bridge", 596f9790aebSLuigi Rizzo NM_IFPNAME(ifp)); 597f9790aebSLuigi Rizzo error = EINVAL; 598f9790aebSLuigi Rizzo goto out; 599f9790aebSLuigi Rizzo } 600f9790aebSLuigi Rizzo /* create a fake interface */ 601f9790aebSLuigi Rizzo fake_ifp = malloc(sizeof(*ifp), M_DEVBUF, M_NOWAIT | M_ZERO); 602f9790aebSLuigi Rizzo if (!fake_ifp) { 603f9790aebSLuigi Rizzo error = ENOMEM; 604f9790aebSLuigi Rizzo goto out; 605f9790aebSLuigi Rizzo } 606f9790aebSLuigi Rizzo strcpy(fake_ifp->if_xname, name); 607f9790aebSLuigi Rizzo error = netmap_bwrap_attach(fake_ifp, ifp); 608f9790aebSLuigi Rizzo if (error) { 609f9790aebSLuigi Rizzo free(fake_ifp, M_DEVBUF); 610f9790aebSLuigi Rizzo goto out; 611f9790aebSLuigi Rizzo } 612f9790aebSLuigi Rizzo ret = NA(fake_ifp); 613f9790aebSLuigi Rizzo if (nmr->nr_arg1 != NETMAP_BDG_HOST) 614f9790aebSLuigi Rizzo cand2 = -1; /* only need one port */ 615f9790aebSLuigi Rizzo if_rele(ifp); 616f9790aebSLuigi Rizzo } 617f9790aebSLuigi Rizzo vpna = (struct netmap_vp_adapter *)ret; 618f9790aebSLuigi Rizzo 619f9790aebSLuigi Rizzo BDG_WLOCK(b); 620f9790aebSLuigi Rizzo vpna->bdg_port = cand; 621f9790aebSLuigi Rizzo ND("NIC %p to bridge port %d", vpna, cand); 622f9790aebSLuigi Rizzo /* bind the port to the bridge (virtual ports are not active) */ 623f9790aebSLuigi Rizzo b->bdg_ports[cand] = vpna; 624f9790aebSLuigi Rizzo vpna->na_bdg = b; 625f9790aebSLuigi Rizzo b->bdg_active_ports++; 626f9790aebSLuigi Rizzo if (cand2 >= 0) { 627f9790aebSLuigi Rizzo struct netmap_vp_adapter *hostna = vpna + 1; 628f9790aebSLuigi Rizzo /* also bind the host stack to the bridge */ 629f9790aebSLuigi Rizzo b->bdg_ports[cand2] = hostna; 630f9790aebSLuigi Rizzo hostna->bdg_port = cand2; 631f9790aebSLuigi Rizzo hostna->na_bdg = b; 632f9790aebSLuigi Rizzo b->bdg_active_ports++; 633f9790aebSLuigi Rizzo ND("host %p to bridge port %d", hostna, cand2); 634f9790aebSLuigi Rizzo } 635f9790aebSLuigi Rizzo ND("if %s refs %d", name, vpna->up.na_refcount); 636f9790aebSLuigi Rizzo BDG_WUNLOCK(b); 637f9790aebSLuigi Rizzo *na = ret; 638f9790aebSLuigi Rizzo netmap_adapter_get(ret); 639f9790aebSLuigi Rizzo return 0; 640f9790aebSLuigi Rizzo 641f9790aebSLuigi Rizzo out: 642f9790aebSLuigi Rizzo if_rele(ifp); 643f9790aebSLuigi Rizzo 644f9790aebSLuigi Rizzo return error; 645f9790aebSLuigi Rizzo } 646f9790aebSLuigi Rizzo 647f9790aebSLuigi Rizzo 648f9790aebSLuigi Rizzo /* Process NETMAP_BDG_ATTACH and NETMAP_BDG_DETACH */ 649f9790aebSLuigi Rizzo static int 650f9790aebSLuigi Rizzo nm_bdg_attach(struct nmreq *nmr) 651f9790aebSLuigi Rizzo { 652f9790aebSLuigi Rizzo struct netmap_adapter *na; 653f9790aebSLuigi Rizzo struct netmap_if *nifp; 654f9790aebSLuigi Rizzo struct netmap_priv_d *npriv; 655f9790aebSLuigi Rizzo struct netmap_bwrap_adapter *bna; 656f9790aebSLuigi Rizzo int error; 657f9790aebSLuigi Rizzo 658f9790aebSLuigi Rizzo npriv = malloc(sizeof(*npriv), M_DEVBUF, M_NOWAIT|M_ZERO); 659f9790aebSLuigi Rizzo if (npriv == NULL) 660f9790aebSLuigi Rizzo return ENOMEM; 661f9790aebSLuigi Rizzo NMG_LOCK(); 662f9790aebSLuigi Rizzo /* XXX probably netmap_get_bdg_na() */ 66317885a7bSLuigi Rizzo error = netmap_get_bdg_na(nmr, &na, 1 /* create if not exists */); 664f9790aebSLuigi Rizzo if (error) /* no device, or another bridge or user owns the device */ 665f9790aebSLuigi Rizzo goto unlock_exit; 66617885a7bSLuigi Rizzo if (na == NULL) { /* VALE prefix missing */ 667f9790aebSLuigi Rizzo error = EINVAL; 66817885a7bSLuigi Rizzo goto unlock_exit; 669f9790aebSLuigi Rizzo } 670f9790aebSLuigi Rizzo 671f9790aebSLuigi Rizzo if (na->active_fds > 0) { /* already registered */ 672f9790aebSLuigi Rizzo error = EBUSY; 673f9790aebSLuigi Rizzo goto unref_exit; 674f9790aebSLuigi Rizzo } 675f9790aebSLuigi Rizzo 676f9790aebSLuigi Rizzo nifp = netmap_do_regif(npriv, na, nmr->nr_ringid, &error); 677f9790aebSLuigi Rizzo if (!nifp) { 678f9790aebSLuigi Rizzo goto unref_exit; 679f9790aebSLuigi Rizzo } 680f9790aebSLuigi Rizzo 681f9790aebSLuigi Rizzo bna = (struct netmap_bwrap_adapter*)na; 682f9790aebSLuigi Rizzo bna->na_kpriv = npriv; 683f9790aebSLuigi Rizzo NMG_UNLOCK(); 684f9790aebSLuigi Rizzo ND("registered %s to netmap-mode", NM_IFPNAME(na->ifp)); 685f9790aebSLuigi Rizzo return 0; 686f9790aebSLuigi Rizzo 687f9790aebSLuigi Rizzo unref_exit: 688f9790aebSLuigi Rizzo netmap_adapter_put(na); 689f9790aebSLuigi Rizzo unlock_exit: 690f9790aebSLuigi Rizzo NMG_UNLOCK(); 691f9790aebSLuigi Rizzo bzero(npriv, sizeof(*npriv)); 692f9790aebSLuigi Rizzo free(npriv, M_DEVBUF); 693f9790aebSLuigi Rizzo return error; 694f9790aebSLuigi Rizzo } 695f9790aebSLuigi Rizzo 69617885a7bSLuigi Rizzo 697f9790aebSLuigi Rizzo static int 698f9790aebSLuigi Rizzo nm_bdg_detach(struct nmreq *nmr) 699f9790aebSLuigi Rizzo { 700f9790aebSLuigi Rizzo struct netmap_adapter *na; 701f9790aebSLuigi Rizzo int error; 702f9790aebSLuigi Rizzo struct netmap_bwrap_adapter *bna; 703f9790aebSLuigi Rizzo int last_instance; 704f9790aebSLuigi Rizzo 705f9790aebSLuigi Rizzo NMG_LOCK(); 70617885a7bSLuigi Rizzo error = netmap_get_bdg_na(nmr, &na, 0 /* don't create */); 707f9790aebSLuigi Rizzo if (error) { /* no device, or another bridge or user owns the device */ 708f9790aebSLuigi Rizzo goto unlock_exit; 709f9790aebSLuigi Rizzo } 71017885a7bSLuigi Rizzo if (na == NULL) { /* VALE prefix missing */ 711f9790aebSLuigi Rizzo error = EINVAL; 71217885a7bSLuigi Rizzo goto unlock_exit; 713f9790aebSLuigi Rizzo } 71417885a7bSLuigi Rizzo 715f9790aebSLuigi Rizzo bna = (struct netmap_bwrap_adapter *)na; 716f9790aebSLuigi Rizzo 717f9790aebSLuigi Rizzo if (na->active_fds == 0) { /* not registered */ 718f9790aebSLuigi Rizzo error = EINVAL; 719f9790aebSLuigi Rizzo goto unref_exit; 720f9790aebSLuigi Rizzo } 721f9790aebSLuigi Rizzo 722f9790aebSLuigi Rizzo last_instance = netmap_dtor_locked(bna->na_kpriv); /* unregister */ 723f9790aebSLuigi Rizzo if (!last_instance) { 724f9790aebSLuigi Rizzo D("--- error, trying to detach an entry with active mmaps"); 725f9790aebSLuigi Rizzo error = EINVAL; 726f9790aebSLuigi Rizzo } else { 727f9790aebSLuigi Rizzo struct netmap_priv_d *npriv = bna->na_kpriv; 728f9790aebSLuigi Rizzo 729f9790aebSLuigi Rizzo bna->na_kpriv = NULL; 730f9790aebSLuigi Rizzo D("deleting priv"); 731f9790aebSLuigi Rizzo 732f9790aebSLuigi Rizzo bzero(npriv, sizeof(*npriv)); 733f9790aebSLuigi Rizzo free(npriv, M_DEVBUF); 734f9790aebSLuigi Rizzo } 735f9790aebSLuigi Rizzo 736f9790aebSLuigi Rizzo unref_exit: 737f9790aebSLuigi Rizzo netmap_adapter_put(na); 738f9790aebSLuigi Rizzo unlock_exit: 739f9790aebSLuigi Rizzo NMG_UNLOCK(); 740f9790aebSLuigi Rizzo return error; 741f9790aebSLuigi Rizzo 742f9790aebSLuigi Rizzo } 743f9790aebSLuigi Rizzo 744f9790aebSLuigi Rizzo 745f9790aebSLuigi Rizzo /* exported to kernel callers, e.g. OVS ? 746f9790aebSLuigi Rizzo * Entry point. 747f9790aebSLuigi Rizzo * Called without NMG_LOCK. 748f9790aebSLuigi Rizzo */ 749f9790aebSLuigi Rizzo int 750f9790aebSLuigi Rizzo netmap_bdg_ctl(struct nmreq *nmr, bdg_lookup_fn_t func) 751f9790aebSLuigi Rizzo { 752f9790aebSLuigi Rizzo struct nm_bridge *b; 753f9790aebSLuigi Rizzo struct netmap_adapter *na; 754f9790aebSLuigi Rizzo struct netmap_vp_adapter *vpna; 755f9790aebSLuigi Rizzo struct ifnet *iter; 756f9790aebSLuigi Rizzo char *name = nmr->nr_name; 757f9790aebSLuigi Rizzo int cmd = nmr->nr_cmd, namelen = strlen(name); 758f9790aebSLuigi Rizzo int error = 0, i, j; 759f9790aebSLuigi Rizzo 760f9790aebSLuigi Rizzo switch (cmd) { 761f9790aebSLuigi Rizzo case NETMAP_BDG_ATTACH: 762f9790aebSLuigi Rizzo error = nm_bdg_attach(nmr); 763f9790aebSLuigi Rizzo break; 764f9790aebSLuigi Rizzo 765f9790aebSLuigi Rizzo case NETMAP_BDG_DETACH: 766f9790aebSLuigi Rizzo error = nm_bdg_detach(nmr); 767f9790aebSLuigi Rizzo break; 768f9790aebSLuigi Rizzo 769f9790aebSLuigi Rizzo case NETMAP_BDG_LIST: 770f9790aebSLuigi Rizzo /* this is used to enumerate bridges and ports */ 771f9790aebSLuigi Rizzo if (namelen) { /* look up indexes of bridge and port */ 772f9790aebSLuigi Rizzo if (strncmp(name, NM_NAME, strlen(NM_NAME))) { 773f9790aebSLuigi Rizzo error = EINVAL; 774f9790aebSLuigi Rizzo break; 775f9790aebSLuigi Rizzo } 776f9790aebSLuigi Rizzo NMG_LOCK(); 777f9790aebSLuigi Rizzo b = nm_find_bridge(name, 0 /* don't create */); 778f9790aebSLuigi Rizzo if (!b) { 779f9790aebSLuigi Rizzo error = ENOENT; 780f9790aebSLuigi Rizzo NMG_UNLOCK(); 781f9790aebSLuigi Rizzo break; 782f9790aebSLuigi Rizzo } 783f9790aebSLuigi Rizzo 784f9790aebSLuigi Rizzo error = ENOENT; 785f9790aebSLuigi Rizzo for (j = 0; j < b->bdg_active_ports; j++) { 786f9790aebSLuigi Rizzo i = b->bdg_port_index[j]; 787f9790aebSLuigi Rizzo vpna = b->bdg_ports[i]; 788f9790aebSLuigi Rizzo if (vpna == NULL) { 789f9790aebSLuigi Rizzo D("---AAAAAAAAARGH-------"); 790f9790aebSLuigi Rizzo continue; 791f9790aebSLuigi Rizzo } 792f9790aebSLuigi Rizzo iter = vpna->up.ifp; 793f9790aebSLuigi Rizzo /* the former and the latter identify a 794f9790aebSLuigi Rizzo * virtual port and a NIC, respectively 795f9790aebSLuigi Rizzo */ 796f9790aebSLuigi Rizzo if (!strcmp(iter->if_xname, name)) { 797f9790aebSLuigi Rizzo /* bridge index */ 798f9790aebSLuigi Rizzo nmr->nr_arg1 = b - nm_bridges; 799f9790aebSLuigi Rizzo nmr->nr_arg2 = i; /* port index */ 800f9790aebSLuigi Rizzo error = 0; 801f9790aebSLuigi Rizzo break; 802f9790aebSLuigi Rizzo } 803f9790aebSLuigi Rizzo } 804f9790aebSLuigi Rizzo NMG_UNLOCK(); 805f9790aebSLuigi Rizzo } else { 806f9790aebSLuigi Rizzo /* return the first non-empty entry starting from 807f9790aebSLuigi Rizzo * bridge nr_arg1 and port nr_arg2. 808f9790aebSLuigi Rizzo * 809f9790aebSLuigi Rizzo * Users can detect the end of the same bridge by 810f9790aebSLuigi Rizzo * seeing the new and old value of nr_arg1, and can 811f9790aebSLuigi Rizzo * detect the end of all the bridge by error != 0 812f9790aebSLuigi Rizzo */ 813f9790aebSLuigi Rizzo i = nmr->nr_arg1; 814f9790aebSLuigi Rizzo j = nmr->nr_arg2; 815f9790aebSLuigi Rizzo 816f9790aebSLuigi Rizzo NMG_LOCK(); 817f9790aebSLuigi Rizzo for (error = ENOENT; i < NM_BRIDGES; i++) { 818f9790aebSLuigi Rizzo b = nm_bridges + i; 819f9790aebSLuigi Rizzo if (j >= b->bdg_active_ports) { 820f9790aebSLuigi Rizzo j = 0; /* following bridges scan from 0 */ 821f9790aebSLuigi Rizzo continue; 822f9790aebSLuigi Rizzo } 823f9790aebSLuigi Rizzo nmr->nr_arg1 = i; 824f9790aebSLuigi Rizzo nmr->nr_arg2 = j; 825f9790aebSLuigi Rizzo j = b->bdg_port_index[j]; 826f9790aebSLuigi Rizzo vpna = b->bdg_ports[j]; 827f9790aebSLuigi Rizzo iter = vpna->up.ifp; 828f9790aebSLuigi Rizzo strncpy(name, iter->if_xname, (size_t)IFNAMSIZ); 829f9790aebSLuigi Rizzo error = 0; 830f9790aebSLuigi Rizzo break; 831f9790aebSLuigi Rizzo } 832f9790aebSLuigi Rizzo NMG_UNLOCK(); 833f9790aebSLuigi Rizzo } 834f9790aebSLuigi Rizzo break; 835f9790aebSLuigi Rizzo 836f9790aebSLuigi Rizzo case NETMAP_BDG_LOOKUP_REG: 837f9790aebSLuigi Rizzo /* register a lookup function to the given bridge. 838f9790aebSLuigi Rizzo * nmr->nr_name may be just bridge's name (including ':' 839f9790aebSLuigi Rizzo * if it is not just NM_NAME). 840f9790aebSLuigi Rizzo */ 841f9790aebSLuigi Rizzo if (!func) { 842f9790aebSLuigi Rizzo error = EINVAL; 843f9790aebSLuigi Rizzo break; 844f9790aebSLuigi Rizzo } 845f9790aebSLuigi Rizzo NMG_LOCK(); 846f9790aebSLuigi Rizzo b = nm_find_bridge(name, 0 /* don't create */); 847f9790aebSLuigi Rizzo if (!b) { 848f9790aebSLuigi Rizzo error = EINVAL; 849f9790aebSLuigi Rizzo } else { 850f9790aebSLuigi Rizzo b->nm_bdg_lookup = func; 851f9790aebSLuigi Rizzo } 852f9790aebSLuigi Rizzo NMG_UNLOCK(); 853f9790aebSLuigi Rizzo break; 854f9790aebSLuigi Rizzo 855f9790aebSLuigi Rizzo case NETMAP_BDG_OFFSET: 856f9790aebSLuigi Rizzo NMG_LOCK(); 857f9790aebSLuigi Rizzo error = netmap_get_bdg_na(nmr, &na, 0); 85817885a7bSLuigi Rizzo if (na && !error) { 859f9790aebSLuigi Rizzo vpna = (struct netmap_vp_adapter *)na; 860f9790aebSLuigi Rizzo if (nmr->nr_arg1 > NETMAP_BDG_MAX_OFFSET) 861f9790aebSLuigi Rizzo nmr->nr_arg1 = NETMAP_BDG_MAX_OFFSET; 862f9790aebSLuigi Rizzo vpna->offset = nmr->nr_arg1; 863f9790aebSLuigi Rizzo D("Using offset %d for %p", vpna->offset, vpna); 86417885a7bSLuigi Rizzo netmap_adapter_put(na); 865f9790aebSLuigi Rizzo } 866f9790aebSLuigi Rizzo NMG_UNLOCK(); 867f9790aebSLuigi Rizzo break; 868f9790aebSLuigi Rizzo 869f9790aebSLuigi Rizzo default: 870f9790aebSLuigi Rizzo D("invalid cmd (nmr->nr_cmd) (0x%x)", cmd); 871f9790aebSLuigi Rizzo error = EINVAL; 872f9790aebSLuigi Rizzo break; 873f9790aebSLuigi Rizzo } 874f9790aebSLuigi Rizzo return error; 875f9790aebSLuigi Rizzo } 876f9790aebSLuigi Rizzo 877f9790aebSLuigi Rizzo 878f9790aebSLuigi Rizzo static int 879f9790aebSLuigi Rizzo netmap_vp_krings_create(struct netmap_adapter *na) 880f9790aebSLuigi Rizzo { 881f9790aebSLuigi Rizzo u_int ntx, nrx, tailroom; 882f9790aebSLuigi Rizzo int error, i; 883f9790aebSLuigi Rizzo uint32_t *leases; 884f9790aebSLuigi Rizzo 885f9790aebSLuigi Rizzo /* XXX vps do not need host rings, 886f9790aebSLuigi Rizzo * but we crash if we don't have one 887f9790aebSLuigi Rizzo */ 888f9790aebSLuigi Rizzo ntx = na->num_tx_rings + 1; 889f9790aebSLuigi Rizzo nrx = na->num_rx_rings + 1; 890f9790aebSLuigi Rizzo 891f9790aebSLuigi Rizzo /* 892f9790aebSLuigi Rizzo * Leases are attached to RX rings on vale ports 893f9790aebSLuigi Rizzo */ 894f9790aebSLuigi Rizzo tailroom = sizeof(uint32_t) * na->num_rx_desc * nrx; 895f9790aebSLuigi Rizzo 896f9790aebSLuigi Rizzo error = netmap_krings_create(na, ntx, nrx, tailroom); 897f9790aebSLuigi Rizzo if (error) 898f9790aebSLuigi Rizzo return error; 899f9790aebSLuigi Rizzo 900f9790aebSLuigi Rizzo leases = na->tailroom; 901f9790aebSLuigi Rizzo 902f9790aebSLuigi Rizzo for (i = 0; i < nrx; i++) { /* Receive rings */ 903f9790aebSLuigi Rizzo na->rx_rings[i].nkr_leases = leases; 904f9790aebSLuigi Rizzo leases += na->num_rx_desc; 905f9790aebSLuigi Rizzo } 906f9790aebSLuigi Rizzo 907f9790aebSLuigi Rizzo error = nm_alloc_bdgfwd(na); 908f9790aebSLuigi Rizzo if (error) { 909f9790aebSLuigi Rizzo netmap_krings_delete(na); 910f9790aebSLuigi Rizzo return error; 911f9790aebSLuigi Rizzo } 912f9790aebSLuigi Rizzo 913f9790aebSLuigi Rizzo return 0; 914f9790aebSLuigi Rizzo } 915f9790aebSLuigi Rizzo 91617885a7bSLuigi Rizzo 917f9790aebSLuigi Rizzo static void 918f9790aebSLuigi Rizzo netmap_vp_krings_delete(struct netmap_adapter *na) 919f9790aebSLuigi Rizzo { 920f9790aebSLuigi Rizzo nm_free_bdgfwd(na); 921f9790aebSLuigi Rizzo netmap_krings_delete(na); 922f9790aebSLuigi Rizzo } 923f9790aebSLuigi Rizzo 924f9790aebSLuigi Rizzo 925f9790aebSLuigi Rizzo static int 926f9790aebSLuigi Rizzo nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, 927f9790aebSLuigi Rizzo struct netmap_vp_adapter *na, u_int ring_nr); 928f9790aebSLuigi Rizzo 929f9790aebSLuigi Rizzo 930f9790aebSLuigi Rizzo /* 931f9790aebSLuigi Rizzo * Grab packets from a kring, move them into the ft structure 932f9790aebSLuigi Rizzo * associated to the tx (input) port. Max one instance per port, 933f9790aebSLuigi Rizzo * filtered on input (ioctl, poll or XXX). 934f9790aebSLuigi Rizzo * Returns the next position in the ring. 935f9790aebSLuigi Rizzo */ 936f9790aebSLuigi Rizzo static int 937f9790aebSLuigi Rizzo nm_bdg_preflush(struct netmap_vp_adapter *na, u_int ring_nr, 938f9790aebSLuigi Rizzo struct netmap_kring *kring, u_int end) 939f9790aebSLuigi Rizzo { 940f9790aebSLuigi Rizzo struct netmap_ring *ring = kring->ring; 941f9790aebSLuigi Rizzo struct nm_bdg_fwd *ft; 942f9790aebSLuigi Rizzo u_int j = kring->nr_hwcur, lim = kring->nkr_num_slots - 1; 943f9790aebSLuigi Rizzo u_int ft_i = 0; /* start from 0 */ 944f9790aebSLuigi Rizzo u_int frags = 1; /* how many frags ? */ 945f9790aebSLuigi Rizzo struct nm_bridge *b = na->na_bdg; 946f9790aebSLuigi Rizzo 947f9790aebSLuigi Rizzo /* To protect against modifications to the bridge we acquire a 948f9790aebSLuigi Rizzo * shared lock, waiting if we can sleep (if the source port is 949f9790aebSLuigi Rizzo * attached to a user process) or with a trylock otherwise (NICs). 950f9790aebSLuigi Rizzo */ 951f9790aebSLuigi Rizzo ND("wait rlock for %d packets", ((j > end ? lim+1 : 0) + end) - j); 952f9790aebSLuigi Rizzo if (na->up.na_flags & NAF_BDG_MAYSLEEP) 953f9790aebSLuigi Rizzo BDG_RLOCK(b); 954f9790aebSLuigi Rizzo else if (!BDG_RTRYLOCK(b)) 955f9790aebSLuigi Rizzo return 0; 956f9790aebSLuigi Rizzo ND(5, "rlock acquired for %d packets", ((j > end ? lim+1 : 0) + end) - j); 957f9790aebSLuigi Rizzo ft = kring->nkr_ft; 958f9790aebSLuigi Rizzo 959f9790aebSLuigi Rizzo for (; likely(j != end); j = nm_next(j, lim)) { 960f9790aebSLuigi Rizzo struct netmap_slot *slot = &ring->slot[j]; 961f9790aebSLuigi Rizzo char *buf; 962f9790aebSLuigi Rizzo 963f9790aebSLuigi Rizzo ft[ft_i].ft_len = slot->len; 964f9790aebSLuigi Rizzo ft[ft_i].ft_flags = slot->flags; 965f9790aebSLuigi Rizzo 966f9790aebSLuigi Rizzo ND("flags is 0x%x", slot->flags); 967f9790aebSLuigi Rizzo /* this slot goes into a list so initialize the link field */ 968f9790aebSLuigi Rizzo ft[ft_i].ft_next = NM_FT_NULL; 969f9790aebSLuigi Rizzo buf = ft[ft_i].ft_buf = (slot->flags & NS_INDIRECT) ? 970f9790aebSLuigi Rizzo (void *)(uintptr_t)slot->ptr : BDG_NMB(&na->up, slot); 9712e159ef0SLuigi Rizzo __builtin_prefetch(buf); 972f9790aebSLuigi Rizzo ++ft_i; 973f9790aebSLuigi Rizzo if (slot->flags & NS_MOREFRAG) { 974f9790aebSLuigi Rizzo frags++; 975f9790aebSLuigi Rizzo continue; 976f9790aebSLuigi Rizzo } 977f9790aebSLuigi Rizzo if (unlikely(netmap_verbose && frags > 1)) 978f9790aebSLuigi Rizzo RD(5, "%d frags at %d", frags, ft_i - frags); 979f9790aebSLuigi Rizzo ft[ft_i - frags].ft_frags = frags; 980f9790aebSLuigi Rizzo frags = 1; 981f9790aebSLuigi Rizzo if (unlikely((int)ft_i >= bridge_batch)) 982f9790aebSLuigi Rizzo ft_i = nm_bdg_flush(ft, ft_i, na, ring_nr); 983f9790aebSLuigi Rizzo } 984f9790aebSLuigi Rizzo if (frags > 1) { 985f9790aebSLuigi Rizzo D("truncate incomplete fragment at %d (%d frags)", ft_i, frags); 986f9790aebSLuigi Rizzo // ft_i > 0, ft[ft_i-1].flags has NS_MOREFRAG 987f9790aebSLuigi Rizzo ft[ft_i - 1].ft_frags &= ~NS_MOREFRAG; 988f9790aebSLuigi Rizzo ft[ft_i - frags].ft_frags = frags - 1; 989f9790aebSLuigi Rizzo } 990f9790aebSLuigi Rizzo if (ft_i) 991f9790aebSLuigi Rizzo ft_i = nm_bdg_flush(ft, ft_i, na, ring_nr); 992f9790aebSLuigi Rizzo BDG_RUNLOCK(b); 993f9790aebSLuigi Rizzo return j; 994f9790aebSLuigi Rizzo } 995f9790aebSLuigi Rizzo 996f9790aebSLuigi Rizzo 997f9790aebSLuigi Rizzo /* ----- FreeBSD if_bridge hash function ------- */ 998f9790aebSLuigi Rizzo 999f9790aebSLuigi Rizzo /* 1000f9790aebSLuigi Rizzo * The following hash function is adapted from "Hash Functions" by Bob Jenkins 1001f9790aebSLuigi Rizzo * ("Algorithm Alley", Dr. Dobbs Journal, September 1997). 1002f9790aebSLuigi Rizzo * 1003f9790aebSLuigi Rizzo * http://www.burtleburtle.net/bob/hash/spooky.html 1004f9790aebSLuigi Rizzo */ 1005f9790aebSLuigi Rizzo #define mix(a, b, c) \ 1006f9790aebSLuigi Rizzo do { \ 1007f9790aebSLuigi Rizzo a -= b; a -= c; a ^= (c >> 13); \ 1008f9790aebSLuigi Rizzo b -= c; b -= a; b ^= (a << 8); \ 1009f9790aebSLuigi Rizzo c -= a; c -= b; c ^= (b >> 13); \ 1010f9790aebSLuigi Rizzo a -= b; a -= c; a ^= (c >> 12); \ 1011f9790aebSLuigi Rizzo b -= c; b -= a; b ^= (a << 16); \ 1012f9790aebSLuigi Rizzo c -= a; c -= b; c ^= (b >> 5); \ 1013f9790aebSLuigi Rizzo a -= b; a -= c; a ^= (c >> 3); \ 1014f9790aebSLuigi Rizzo b -= c; b -= a; b ^= (a << 10); \ 1015f9790aebSLuigi Rizzo c -= a; c -= b; c ^= (b >> 15); \ 1016f9790aebSLuigi Rizzo } while (/*CONSTCOND*/0) 1017f9790aebSLuigi Rizzo 101817885a7bSLuigi Rizzo 1019f9790aebSLuigi Rizzo static __inline uint32_t 1020f9790aebSLuigi Rizzo nm_bridge_rthash(const uint8_t *addr) 1021f9790aebSLuigi Rizzo { 1022f9790aebSLuigi Rizzo uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = 0; // hask key 1023f9790aebSLuigi Rizzo 1024f9790aebSLuigi Rizzo b += addr[5] << 8; 1025f9790aebSLuigi Rizzo b += addr[4]; 1026f9790aebSLuigi Rizzo a += addr[3] << 24; 1027f9790aebSLuigi Rizzo a += addr[2] << 16; 1028f9790aebSLuigi Rizzo a += addr[1] << 8; 1029f9790aebSLuigi Rizzo a += addr[0]; 1030f9790aebSLuigi Rizzo 1031f9790aebSLuigi Rizzo mix(a, b, c); 1032f9790aebSLuigi Rizzo #define BRIDGE_RTHASH_MASK (NM_BDG_HASH-1) 1033f9790aebSLuigi Rizzo return (c & BRIDGE_RTHASH_MASK); 1034f9790aebSLuigi Rizzo } 1035f9790aebSLuigi Rizzo 1036f9790aebSLuigi Rizzo #undef mix 1037f9790aebSLuigi Rizzo 1038f9790aebSLuigi Rizzo 1039f9790aebSLuigi Rizzo static int 1040f9790aebSLuigi Rizzo bdg_netmap_reg(struct netmap_adapter *na, int onoff) 1041f9790aebSLuigi Rizzo { 1042f9790aebSLuigi Rizzo struct netmap_vp_adapter *vpna = 1043f9790aebSLuigi Rizzo (struct netmap_vp_adapter*)na; 1044f9790aebSLuigi Rizzo struct ifnet *ifp = na->ifp; 1045f9790aebSLuigi Rizzo 1046f9790aebSLuigi Rizzo /* the interface is already attached to the bridge, 1047f9790aebSLuigi Rizzo * so we only need to toggle IFCAP_NETMAP. 1048f9790aebSLuigi Rizzo */ 1049f9790aebSLuigi Rizzo BDG_WLOCK(vpna->na_bdg); 1050f9790aebSLuigi Rizzo if (onoff) { 1051f9790aebSLuigi Rizzo ifp->if_capenable |= IFCAP_NETMAP; 1052f9790aebSLuigi Rizzo } else { 1053f9790aebSLuigi Rizzo ifp->if_capenable &= ~IFCAP_NETMAP; 1054f9790aebSLuigi Rizzo } 1055f9790aebSLuigi Rizzo BDG_WUNLOCK(vpna->na_bdg); 1056f9790aebSLuigi Rizzo return 0; 1057f9790aebSLuigi Rizzo } 1058f9790aebSLuigi Rizzo 1059f9790aebSLuigi Rizzo 1060f9790aebSLuigi Rizzo /* 1061f9790aebSLuigi Rizzo * Lookup function for a learning bridge. 1062f9790aebSLuigi Rizzo * Update the hash table with the source address, 1063f9790aebSLuigi Rizzo * and then returns the destination port index, and the 1064f9790aebSLuigi Rizzo * ring in *dst_ring (at the moment, always use ring 0) 1065f9790aebSLuigi Rizzo */ 1066f9790aebSLuigi Rizzo u_int 1067f9790aebSLuigi Rizzo netmap_bdg_learning(char *buf, u_int buf_len, uint8_t *dst_ring, 1068f9790aebSLuigi Rizzo struct netmap_vp_adapter *na) 1069f9790aebSLuigi Rizzo { 1070f9790aebSLuigi Rizzo struct nm_hash_ent *ht = na->na_bdg->ht; 1071f9790aebSLuigi Rizzo uint32_t sh, dh; 1072f9790aebSLuigi Rizzo u_int dst, mysrc = na->bdg_port; 1073f9790aebSLuigi Rizzo uint64_t smac, dmac; 1074f9790aebSLuigi Rizzo 1075f9790aebSLuigi Rizzo if (buf_len < 14) { 1076f9790aebSLuigi Rizzo D("invalid buf length %d", buf_len); 1077f9790aebSLuigi Rizzo return NM_BDG_NOPORT; 1078f9790aebSLuigi Rizzo } 1079f9790aebSLuigi Rizzo dmac = le64toh(*(uint64_t *)(buf)) & 0xffffffffffff; 1080f9790aebSLuigi Rizzo smac = le64toh(*(uint64_t *)(buf + 4)); 1081f9790aebSLuigi Rizzo smac >>= 16; 1082f9790aebSLuigi Rizzo 1083f9790aebSLuigi Rizzo /* 1084f9790aebSLuigi Rizzo * The hash is somewhat expensive, there might be some 1085f9790aebSLuigi Rizzo * worthwhile optimizations here. 1086f9790aebSLuigi Rizzo */ 1087f9790aebSLuigi Rizzo if ((buf[6] & 1) == 0) { /* valid src */ 1088f9790aebSLuigi Rizzo uint8_t *s = buf+6; 1089f9790aebSLuigi Rizzo sh = nm_bridge_rthash(s); // XXX hash of source 1090f9790aebSLuigi Rizzo /* update source port forwarding entry */ 1091f9790aebSLuigi Rizzo ht[sh].mac = smac; /* XXX expire ? */ 1092f9790aebSLuigi Rizzo ht[sh].ports = mysrc; 1093f9790aebSLuigi Rizzo if (netmap_verbose) 1094f9790aebSLuigi Rizzo D("src %02x:%02x:%02x:%02x:%02x:%02x on port %d", 1095f9790aebSLuigi Rizzo s[0], s[1], s[2], s[3], s[4], s[5], mysrc); 1096f9790aebSLuigi Rizzo } 1097f9790aebSLuigi Rizzo dst = NM_BDG_BROADCAST; 1098f9790aebSLuigi Rizzo if ((buf[0] & 1) == 0) { /* unicast */ 1099f9790aebSLuigi Rizzo dh = nm_bridge_rthash(buf); // XXX hash of dst 1100f9790aebSLuigi Rizzo if (ht[dh].mac == dmac) { /* found dst */ 1101f9790aebSLuigi Rizzo dst = ht[dh].ports; 1102f9790aebSLuigi Rizzo } 1103f9790aebSLuigi Rizzo /* XXX otherwise return NM_BDG_UNKNOWN ? */ 1104f9790aebSLuigi Rizzo } 1105f9790aebSLuigi Rizzo *dst_ring = 0; 1106f9790aebSLuigi Rizzo return dst; 1107f9790aebSLuigi Rizzo } 1108f9790aebSLuigi Rizzo 1109f9790aebSLuigi Rizzo 1110f9790aebSLuigi Rizzo /* 111117885a7bSLuigi Rizzo * Available space in the ring. Only used in VALE code 111217885a7bSLuigi Rizzo * and only with is_rx = 1 111317885a7bSLuigi Rizzo */ 111417885a7bSLuigi Rizzo static inline uint32_t 111517885a7bSLuigi Rizzo nm_kr_space(struct netmap_kring *k, int is_rx) 111617885a7bSLuigi Rizzo { 111717885a7bSLuigi Rizzo int space; 111817885a7bSLuigi Rizzo 111917885a7bSLuigi Rizzo if (is_rx) { 112017885a7bSLuigi Rizzo int busy = k->nkr_hwlease - k->nr_hwcur; 112117885a7bSLuigi Rizzo if (busy < 0) 112217885a7bSLuigi Rizzo busy += k->nkr_num_slots; 112317885a7bSLuigi Rizzo space = k->nkr_num_slots - 1 - busy; 112417885a7bSLuigi Rizzo } else { 112517885a7bSLuigi Rizzo /* XXX never used in this branch */ 112617885a7bSLuigi Rizzo space = k->nr_hwtail - k->nkr_hwlease; 112717885a7bSLuigi Rizzo if (space < 0) 112817885a7bSLuigi Rizzo space += k->nkr_num_slots; 112917885a7bSLuigi Rizzo } 113017885a7bSLuigi Rizzo #if 0 113117885a7bSLuigi Rizzo // sanity check 113217885a7bSLuigi Rizzo if (k->nkr_hwlease >= k->nkr_num_slots || 113317885a7bSLuigi Rizzo k->nr_hwcur >= k->nkr_num_slots || 113417885a7bSLuigi Rizzo k->nr_tail >= k->nkr_num_slots || 113517885a7bSLuigi Rizzo busy < 0 || 113617885a7bSLuigi Rizzo busy >= k->nkr_num_slots) { 113717885a7bSLuigi Rizzo D("invalid kring, cur %d tail %d lease %d lease_idx %d lim %d", k->nr_hwcur, k->nr_hwtail, k->nkr_hwlease, 113817885a7bSLuigi Rizzo k->nkr_lease_idx, k->nkr_num_slots); 113917885a7bSLuigi Rizzo } 114017885a7bSLuigi Rizzo #endif 114117885a7bSLuigi Rizzo return space; 114217885a7bSLuigi Rizzo } 114317885a7bSLuigi Rizzo 114417885a7bSLuigi Rizzo 114517885a7bSLuigi Rizzo 114617885a7bSLuigi Rizzo 114717885a7bSLuigi Rizzo /* make a lease on the kring for N positions. return the 114817885a7bSLuigi Rizzo * lease index 114917885a7bSLuigi Rizzo * XXX only used in VALE code and with is_rx = 1 115017885a7bSLuigi Rizzo */ 115117885a7bSLuigi Rizzo static inline uint32_t 115217885a7bSLuigi Rizzo nm_kr_lease(struct netmap_kring *k, u_int n, int is_rx) 115317885a7bSLuigi Rizzo { 115417885a7bSLuigi Rizzo uint32_t lim = k->nkr_num_slots - 1; 115517885a7bSLuigi Rizzo uint32_t lease_idx = k->nkr_lease_idx; 115617885a7bSLuigi Rizzo 115717885a7bSLuigi Rizzo k->nkr_leases[lease_idx] = NR_NOSLOT; 115817885a7bSLuigi Rizzo k->nkr_lease_idx = nm_next(lease_idx, lim); 115917885a7bSLuigi Rizzo 116017885a7bSLuigi Rizzo if (n > nm_kr_space(k, is_rx)) { 116117885a7bSLuigi Rizzo D("invalid request for %d slots", n); 116217885a7bSLuigi Rizzo panic("x"); 116317885a7bSLuigi Rizzo } 116417885a7bSLuigi Rizzo /* XXX verify that there are n slots */ 116517885a7bSLuigi Rizzo k->nkr_hwlease += n; 116617885a7bSLuigi Rizzo if (k->nkr_hwlease > lim) 116717885a7bSLuigi Rizzo k->nkr_hwlease -= lim + 1; 116817885a7bSLuigi Rizzo 116917885a7bSLuigi Rizzo if (k->nkr_hwlease >= k->nkr_num_slots || 117017885a7bSLuigi Rizzo k->nr_hwcur >= k->nkr_num_slots || 117117885a7bSLuigi Rizzo k->nr_hwtail >= k->nkr_num_slots || 117217885a7bSLuigi Rizzo k->nkr_lease_idx >= k->nkr_num_slots) { 117317885a7bSLuigi Rizzo D("invalid kring %s, cur %d tail %d lease %d lease_idx %d lim %d", 117417885a7bSLuigi Rizzo k->na->ifp->if_xname, 117517885a7bSLuigi Rizzo k->nr_hwcur, k->nr_hwtail, k->nkr_hwlease, 117617885a7bSLuigi Rizzo k->nkr_lease_idx, k->nkr_num_slots); 117717885a7bSLuigi Rizzo } 117817885a7bSLuigi Rizzo return lease_idx; 117917885a7bSLuigi Rizzo } 118017885a7bSLuigi Rizzo 118117885a7bSLuigi Rizzo /* 1182f9790aebSLuigi Rizzo * This flush routine supports only unicast and broadcast but a large 1183f9790aebSLuigi Rizzo * number of ports, and lets us replace the learn and dispatch functions. 1184f9790aebSLuigi Rizzo */ 1185f9790aebSLuigi Rizzo int 1186f9790aebSLuigi Rizzo nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na, 1187f9790aebSLuigi Rizzo u_int ring_nr) 1188f9790aebSLuigi Rizzo { 1189f9790aebSLuigi Rizzo struct nm_bdg_q *dst_ents, *brddst; 1190f9790aebSLuigi Rizzo uint16_t num_dsts = 0, *dsts; 1191f9790aebSLuigi Rizzo struct nm_bridge *b = na->na_bdg; 1192f9790aebSLuigi Rizzo u_int i, j, me = na->bdg_port; 1193f9790aebSLuigi Rizzo 1194f9790aebSLuigi Rizzo /* 1195f9790aebSLuigi Rizzo * The work area (pointed by ft) is followed by an array of 1196f9790aebSLuigi Rizzo * pointers to queues , dst_ents; there are NM_BDG_MAXRINGS 1197f9790aebSLuigi Rizzo * queues per port plus one for the broadcast traffic. 1198f9790aebSLuigi Rizzo * Then we have an array of destination indexes. 1199f9790aebSLuigi Rizzo */ 1200f9790aebSLuigi Rizzo dst_ents = (struct nm_bdg_q *)(ft + NM_BDG_BATCH_MAX); 1201f9790aebSLuigi Rizzo dsts = (uint16_t *)(dst_ents + NM_BDG_MAXPORTS * NM_BDG_MAXRINGS + 1); 1202f9790aebSLuigi Rizzo 1203f9790aebSLuigi Rizzo /* first pass: find a destination for each packet in the batch */ 1204f9790aebSLuigi Rizzo for (i = 0; likely(i < n); i += ft[i].ft_frags) { 1205f9790aebSLuigi Rizzo uint8_t dst_ring = ring_nr; /* default, same ring as origin */ 1206f9790aebSLuigi Rizzo uint16_t dst_port, d_i; 1207f9790aebSLuigi Rizzo struct nm_bdg_q *d; 1208f9790aebSLuigi Rizzo uint8_t *buf = ft[i].ft_buf; 1209f9790aebSLuigi Rizzo u_int len = ft[i].ft_len; 1210f9790aebSLuigi Rizzo 1211f9790aebSLuigi Rizzo ND("slot %d frags %d", i, ft[i].ft_frags); 1212f9790aebSLuigi Rizzo /* Drop the packet if the offset is not into the first 1213f9790aebSLuigi Rizzo fragment nor at the very beginning of the second. */ 1214f9790aebSLuigi Rizzo if (unlikely(na->offset > len)) 1215f9790aebSLuigi Rizzo continue; 1216f9790aebSLuigi Rizzo if (len == na->offset) { 1217f9790aebSLuigi Rizzo buf = ft[i+1].ft_buf; 1218f9790aebSLuigi Rizzo len = ft[i+1].ft_len; 1219f9790aebSLuigi Rizzo } else { 1220f9790aebSLuigi Rizzo buf += na->offset; 1221f9790aebSLuigi Rizzo len -= na->offset; 1222f9790aebSLuigi Rizzo } 1223f9790aebSLuigi Rizzo dst_port = b->nm_bdg_lookup(buf, len, &dst_ring, na); 1224f9790aebSLuigi Rizzo if (netmap_verbose > 255) 1225f9790aebSLuigi Rizzo RD(5, "slot %d port %d -> %d", i, me, dst_port); 1226f9790aebSLuigi Rizzo if (dst_port == NM_BDG_NOPORT) 1227f9790aebSLuigi Rizzo continue; /* this packet is identified to be dropped */ 1228f9790aebSLuigi Rizzo else if (unlikely(dst_port > NM_BDG_MAXPORTS)) 1229f9790aebSLuigi Rizzo continue; 1230f9790aebSLuigi Rizzo else if (dst_port == NM_BDG_BROADCAST) 1231f9790aebSLuigi Rizzo dst_ring = 0; /* broadcasts always go to ring 0 */ 1232f9790aebSLuigi Rizzo else if (unlikely(dst_port == me || 1233f9790aebSLuigi Rizzo !b->bdg_ports[dst_port])) 1234f9790aebSLuigi Rizzo continue; 1235f9790aebSLuigi Rizzo 1236f9790aebSLuigi Rizzo /* get a position in the scratch pad */ 1237f9790aebSLuigi Rizzo d_i = dst_port * NM_BDG_MAXRINGS + dst_ring; 1238f9790aebSLuigi Rizzo d = dst_ents + d_i; 1239f9790aebSLuigi Rizzo 1240f9790aebSLuigi Rizzo /* append the first fragment to the list */ 1241f9790aebSLuigi Rizzo if (d->bq_head == NM_FT_NULL) { /* new destination */ 1242f9790aebSLuigi Rizzo d->bq_head = d->bq_tail = i; 1243f9790aebSLuigi Rizzo /* remember this position to be scanned later */ 1244f9790aebSLuigi Rizzo if (dst_port != NM_BDG_BROADCAST) 1245f9790aebSLuigi Rizzo dsts[num_dsts++] = d_i; 1246f9790aebSLuigi Rizzo } else { 1247f9790aebSLuigi Rizzo ft[d->bq_tail].ft_next = i; 1248f9790aebSLuigi Rizzo d->bq_tail = i; 1249f9790aebSLuigi Rizzo } 1250f9790aebSLuigi Rizzo d->bq_len += ft[i].ft_frags; 1251f9790aebSLuigi Rizzo } 1252f9790aebSLuigi Rizzo 1253f9790aebSLuigi Rizzo /* 1254f9790aebSLuigi Rizzo * Broadcast traffic goes to ring 0 on all destinations. 1255f9790aebSLuigi Rizzo * So we need to add these rings to the list of ports to scan. 1256f9790aebSLuigi Rizzo * XXX at the moment we scan all NM_BDG_MAXPORTS ports, which is 1257f9790aebSLuigi Rizzo * expensive. We should keep a compact list of active destinations 1258f9790aebSLuigi Rizzo * so we could shorten this loop. 1259f9790aebSLuigi Rizzo */ 1260f9790aebSLuigi Rizzo brddst = dst_ents + NM_BDG_BROADCAST * NM_BDG_MAXRINGS; 1261f9790aebSLuigi Rizzo if (brddst->bq_head != NM_FT_NULL) { 1262f9790aebSLuigi Rizzo for (j = 0; likely(j < b->bdg_active_ports); j++) { 1263f9790aebSLuigi Rizzo uint16_t d_i; 1264f9790aebSLuigi Rizzo i = b->bdg_port_index[j]; 1265f9790aebSLuigi Rizzo if (unlikely(i == me)) 1266f9790aebSLuigi Rizzo continue; 1267f9790aebSLuigi Rizzo d_i = i * NM_BDG_MAXRINGS; 1268f9790aebSLuigi Rizzo if (dst_ents[d_i].bq_head == NM_FT_NULL) 1269f9790aebSLuigi Rizzo dsts[num_dsts++] = d_i; 1270f9790aebSLuigi Rizzo } 1271f9790aebSLuigi Rizzo } 1272f9790aebSLuigi Rizzo 1273f9790aebSLuigi Rizzo ND(5, "pass 1 done %d pkts %d dsts", n, num_dsts); 1274f9790aebSLuigi Rizzo /* second pass: scan destinations (XXX will be modular somehow) */ 1275f9790aebSLuigi Rizzo for (i = 0; i < num_dsts; i++) { 1276f9790aebSLuigi Rizzo struct ifnet *dst_ifp; 1277f9790aebSLuigi Rizzo struct netmap_vp_adapter *dst_na; 1278f9790aebSLuigi Rizzo struct netmap_kring *kring; 1279f9790aebSLuigi Rizzo struct netmap_ring *ring; 1280f9790aebSLuigi Rizzo u_int dst_nr, lim, j, sent = 0, d_i, next, brd_next; 1281f9790aebSLuigi Rizzo u_int needed, howmany; 1282f9790aebSLuigi Rizzo int retry = netmap_txsync_retry; 1283f9790aebSLuigi Rizzo struct nm_bdg_q *d; 1284f9790aebSLuigi Rizzo uint32_t my_start = 0, lease_idx = 0; 1285f9790aebSLuigi Rizzo int nrings; 1286f9790aebSLuigi Rizzo int offset_mismatch; 1287f9790aebSLuigi Rizzo 1288f9790aebSLuigi Rizzo d_i = dsts[i]; 1289f9790aebSLuigi Rizzo ND("second pass %d port %d", i, d_i); 1290f9790aebSLuigi Rizzo d = dst_ents + d_i; 1291f9790aebSLuigi Rizzo // XXX fix the division 1292f9790aebSLuigi Rizzo dst_na = b->bdg_ports[d_i/NM_BDG_MAXRINGS]; 1293f9790aebSLuigi Rizzo /* protect from the lookup function returning an inactive 1294f9790aebSLuigi Rizzo * destination port 1295f9790aebSLuigi Rizzo */ 1296f9790aebSLuigi Rizzo if (unlikely(dst_na == NULL)) 1297f9790aebSLuigi Rizzo goto cleanup; 1298f9790aebSLuigi Rizzo if (dst_na->up.na_flags & NAF_SW_ONLY) 1299f9790aebSLuigi Rizzo goto cleanup; 1300f9790aebSLuigi Rizzo dst_ifp = dst_na->up.ifp; 1301f9790aebSLuigi Rizzo /* 1302f9790aebSLuigi Rizzo * The interface may be in !netmap mode in two cases: 1303f9790aebSLuigi Rizzo * - when na is attached but not activated yet; 1304f9790aebSLuigi Rizzo * - when na is being deactivated but is still attached. 1305f9790aebSLuigi Rizzo */ 1306f9790aebSLuigi Rizzo if (unlikely(!(dst_ifp->if_capenable & IFCAP_NETMAP))) { 1307f9790aebSLuigi Rizzo ND("not in netmap mode!"); 1308f9790aebSLuigi Rizzo goto cleanup; 1309f9790aebSLuigi Rizzo } 1310f9790aebSLuigi Rizzo 1311f9790aebSLuigi Rizzo offset_mismatch = (dst_na->offset != na->offset); 1312f9790aebSLuigi Rizzo 1313f9790aebSLuigi Rizzo /* there is at least one either unicast or broadcast packet */ 1314f9790aebSLuigi Rizzo brd_next = brddst->bq_head; 1315f9790aebSLuigi Rizzo next = d->bq_head; 1316f9790aebSLuigi Rizzo /* we need to reserve this many slots. If fewer are 1317f9790aebSLuigi Rizzo * available, some packets will be dropped. 1318f9790aebSLuigi Rizzo * Packets may have multiple fragments, so we may not use 1319f9790aebSLuigi Rizzo * there is a chance that we may not use all of the slots 1320f9790aebSLuigi Rizzo * we have claimed, so we will need to handle the leftover 1321f9790aebSLuigi Rizzo * ones when we regain the lock. 1322f9790aebSLuigi Rizzo */ 1323f9790aebSLuigi Rizzo needed = d->bq_len + brddst->bq_len; 1324f9790aebSLuigi Rizzo 1325f9790aebSLuigi Rizzo ND(5, "pass 2 dst %d is %x %s", 1326f9790aebSLuigi Rizzo i, d_i, is_vp ? "virtual" : "nic/host"); 1327f9790aebSLuigi Rizzo dst_nr = d_i & (NM_BDG_MAXRINGS-1); 1328f9790aebSLuigi Rizzo nrings = dst_na->up.num_rx_rings; 1329f9790aebSLuigi Rizzo if (dst_nr >= nrings) 1330f9790aebSLuigi Rizzo dst_nr = dst_nr % nrings; 1331f9790aebSLuigi Rizzo kring = &dst_na->up.rx_rings[dst_nr]; 1332f9790aebSLuigi Rizzo ring = kring->ring; 1333f9790aebSLuigi Rizzo lim = kring->nkr_num_slots - 1; 1334f9790aebSLuigi Rizzo 1335f9790aebSLuigi Rizzo retry: 1336f9790aebSLuigi Rizzo 1337f9790aebSLuigi Rizzo /* reserve the buffers in the queue and an entry 1338f9790aebSLuigi Rizzo * to report completion, and drop lock. 1339f9790aebSLuigi Rizzo * XXX this might become a helper function. 1340f9790aebSLuigi Rizzo */ 1341f9790aebSLuigi Rizzo mtx_lock(&kring->q_lock); 1342f9790aebSLuigi Rizzo if (kring->nkr_stopped) { 1343f9790aebSLuigi Rizzo mtx_unlock(&kring->q_lock); 1344f9790aebSLuigi Rizzo goto cleanup; 1345f9790aebSLuigi Rizzo } 1346f9790aebSLuigi Rizzo if (dst_na->retry) { 1347f9790aebSLuigi Rizzo dst_na->up.nm_notify(&dst_na->up, dst_nr, NR_RX, 0); 1348f9790aebSLuigi Rizzo } 1349f9790aebSLuigi Rizzo my_start = j = kring->nkr_hwlease; 1350f9790aebSLuigi Rizzo howmany = nm_kr_space(kring, 1); 1351f9790aebSLuigi Rizzo if (needed < howmany) 1352f9790aebSLuigi Rizzo howmany = needed; 1353f9790aebSLuigi Rizzo lease_idx = nm_kr_lease(kring, howmany, 1); 1354f9790aebSLuigi Rizzo mtx_unlock(&kring->q_lock); 1355f9790aebSLuigi Rizzo 1356f9790aebSLuigi Rizzo /* only retry if we need more than available slots */ 1357f9790aebSLuigi Rizzo if (retry && needed <= howmany) 1358f9790aebSLuigi Rizzo retry = 0; 1359f9790aebSLuigi Rizzo 1360f9790aebSLuigi Rizzo /* copy to the destination queue */ 1361f9790aebSLuigi Rizzo while (howmany > 0) { 1362f9790aebSLuigi Rizzo struct netmap_slot *slot; 1363f9790aebSLuigi Rizzo struct nm_bdg_fwd *ft_p, *ft_end; 1364f9790aebSLuigi Rizzo u_int cnt; 1365f9790aebSLuigi Rizzo int fix_mismatch = offset_mismatch; 1366f9790aebSLuigi Rizzo 1367f9790aebSLuigi Rizzo /* find the queue from which we pick next packet. 1368f9790aebSLuigi Rizzo * NM_FT_NULL is always higher than valid indexes 1369f9790aebSLuigi Rizzo * so we never dereference it if the other list 1370f9790aebSLuigi Rizzo * has packets (and if both are empty we never 1371f9790aebSLuigi Rizzo * get here). 1372f9790aebSLuigi Rizzo */ 1373f9790aebSLuigi Rizzo if (next < brd_next) { 1374f9790aebSLuigi Rizzo ft_p = ft + next; 1375f9790aebSLuigi Rizzo next = ft_p->ft_next; 1376f9790aebSLuigi Rizzo } else { /* insert broadcast */ 1377f9790aebSLuigi Rizzo ft_p = ft + brd_next; 1378f9790aebSLuigi Rizzo brd_next = ft_p->ft_next; 1379f9790aebSLuigi Rizzo } 1380f9790aebSLuigi Rizzo cnt = ft_p->ft_frags; // cnt > 0 1381f9790aebSLuigi Rizzo if (unlikely(cnt > howmany)) 1382f9790aebSLuigi Rizzo break; /* no more space */ 1383f9790aebSLuigi Rizzo howmany -= cnt; 1384f9790aebSLuigi Rizzo if (netmap_verbose && cnt > 1) 1385f9790aebSLuigi Rizzo RD(5, "rx %d frags to %d", cnt, j); 1386f9790aebSLuigi Rizzo ft_end = ft_p + cnt; 1387f9790aebSLuigi Rizzo do { 1388f9790aebSLuigi Rizzo char *dst, *src = ft_p->ft_buf; 1389f9790aebSLuigi Rizzo size_t copy_len = ft_p->ft_len, dst_len = copy_len; 1390f9790aebSLuigi Rizzo 1391f9790aebSLuigi Rizzo slot = &ring->slot[j]; 1392f9790aebSLuigi Rizzo dst = BDG_NMB(&dst_na->up, slot); 1393f9790aebSLuigi Rizzo 1394f9790aebSLuigi Rizzo if (unlikely(fix_mismatch)) { 139517885a7bSLuigi Rizzo /* We are processing the first fragment 139617885a7bSLuigi Rizzo * and there is a mismatch between source 139717885a7bSLuigi Rizzo * and destination offsets. Create a zeroed 139817885a7bSLuigi Rizzo * header for the destination, independently 139917885a7bSLuigi Rizzo * of the source header length and content. 140017885a7bSLuigi Rizzo */ 140117885a7bSLuigi Rizzo src += na->offset; 140217885a7bSLuigi Rizzo copy_len -= na->offset; 140317885a7bSLuigi Rizzo bzero(dst, dst_na->offset); 140417885a7bSLuigi Rizzo dst += dst_na->offset; 140517885a7bSLuigi Rizzo dst_len = dst_na->offset + copy_len; 1406f9790aebSLuigi Rizzo /* fix the first fragment only */ 1407f9790aebSLuigi Rizzo fix_mismatch = 0; 140817885a7bSLuigi Rizzo /* Here it could be copy_len == dst_len == 0, 140917885a7bSLuigi Rizzo * and so a zero length fragment is passed. 141017885a7bSLuigi Rizzo */ 1411f9790aebSLuigi Rizzo } 141217885a7bSLuigi Rizzo 141317885a7bSLuigi Rizzo ND("send [%d] %d(%d) bytes at %s:%d", 141417885a7bSLuigi Rizzo i, (int)copy_len, (int)dst_len, 141517885a7bSLuigi Rizzo NM_IFPNAME(dst_ifp), j); 1416f9790aebSLuigi Rizzo /* round to a multiple of 64 */ 1417f9790aebSLuigi Rizzo copy_len = (copy_len + 63) & ~63; 1418f9790aebSLuigi Rizzo 1419f9790aebSLuigi Rizzo if (ft_p->ft_flags & NS_INDIRECT) { 1420f9790aebSLuigi Rizzo if (copyin(src, dst, copy_len)) { 1421f9790aebSLuigi Rizzo // invalid user pointer, pretend len is 0 1422f9790aebSLuigi Rizzo dst_len = 0; 1423f9790aebSLuigi Rizzo } 1424f9790aebSLuigi Rizzo } else { 1425f9790aebSLuigi Rizzo //memcpy(dst, src, copy_len); 1426f9790aebSLuigi Rizzo pkt_copy(src, dst, (int)copy_len); 1427f9790aebSLuigi Rizzo } 1428f9790aebSLuigi Rizzo slot->len = dst_len; 1429f9790aebSLuigi Rizzo slot->flags = (cnt << 8)| NS_MOREFRAG; 1430f9790aebSLuigi Rizzo j = nm_next(j, lim); 1431f9790aebSLuigi Rizzo ft_p++; 1432f9790aebSLuigi Rizzo sent++; 1433f9790aebSLuigi Rizzo } while (ft_p != ft_end); 1434f9790aebSLuigi Rizzo slot->flags = (cnt << 8); /* clear flag on last entry */ 1435f9790aebSLuigi Rizzo /* are we done ? */ 1436f9790aebSLuigi Rizzo if (next == NM_FT_NULL && brd_next == NM_FT_NULL) 1437f9790aebSLuigi Rizzo break; 1438f9790aebSLuigi Rizzo } 1439f9790aebSLuigi Rizzo { 1440f9790aebSLuigi Rizzo /* current position */ 1441f9790aebSLuigi Rizzo uint32_t *p = kring->nkr_leases; /* shorthand */ 1442f9790aebSLuigi Rizzo uint32_t update_pos; 1443f9790aebSLuigi Rizzo int still_locked = 1; 1444f9790aebSLuigi Rizzo 1445f9790aebSLuigi Rizzo mtx_lock(&kring->q_lock); 1446f9790aebSLuigi Rizzo if (unlikely(howmany > 0)) { 1447f9790aebSLuigi Rizzo /* not used all bufs. If i am the last one 1448f9790aebSLuigi Rizzo * i can recover the slots, otherwise must 1449f9790aebSLuigi Rizzo * fill them with 0 to mark empty packets. 1450f9790aebSLuigi Rizzo */ 1451f9790aebSLuigi Rizzo ND("leftover %d bufs", howmany); 1452f9790aebSLuigi Rizzo if (nm_next(lease_idx, lim) == kring->nkr_lease_idx) { 1453f9790aebSLuigi Rizzo /* yes i am the last one */ 1454f9790aebSLuigi Rizzo ND("roll back nkr_hwlease to %d", j); 1455f9790aebSLuigi Rizzo kring->nkr_hwlease = j; 1456f9790aebSLuigi Rizzo } else { 1457f9790aebSLuigi Rizzo while (howmany-- > 0) { 1458f9790aebSLuigi Rizzo ring->slot[j].len = 0; 1459f9790aebSLuigi Rizzo ring->slot[j].flags = 0; 1460f9790aebSLuigi Rizzo j = nm_next(j, lim); 1461f9790aebSLuigi Rizzo } 1462f9790aebSLuigi Rizzo } 1463f9790aebSLuigi Rizzo } 1464f9790aebSLuigi Rizzo p[lease_idx] = j; /* report I am done */ 1465f9790aebSLuigi Rizzo 146617885a7bSLuigi Rizzo update_pos = kring->nr_hwtail; 1467f9790aebSLuigi Rizzo 1468f9790aebSLuigi Rizzo if (my_start == update_pos) { 1469f9790aebSLuigi Rizzo /* all slots before my_start have been reported, 1470f9790aebSLuigi Rizzo * so scan subsequent leases to see if other ranges 1471f9790aebSLuigi Rizzo * have been completed, and to a selwakeup or txsync. 1472f9790aebSLuigi Rizzo */ 1473f9790aebSLuigi Rizzo while (lease_idx != kring->nkr_lease_idx && 1474f9790aebSLuigi Rizzo p[lease_idx] != NR_NOSLOT) { 1475f9790aebSLuigi Rizzo j = p[lease_idx]; 1476f9790aebSLuigi Rizzo p[lease_idx] = NR_NOSLOT; 1477f9790aebSLuigi Rizzo lease_idx = nm_next(lease_idx, lim); 1478f9790aebSLuigi Rizzo } 1479f9790aebSLuigi Rizzo /* j is the new 'write' position. j != my_start 1480f9790aebSLuigi Rizzo * means there are new buffers to report 1481f9790aebSLuigi Rizzo */ 1482f9790aebSLuigi Rizzo if (likely(j != my_start)) { 148317885a7bSLuigi Rizzo kring->nr_hwtail = j; 1484f9790aebSLuigi Rizzo dst_na->up.nm_notify(&dst_na->up, dst_nr, NR_RX, 0); 1485f9790aebSLuigi Rizzo still_locked = 0; 1486f9790aebSLuigi Rizzo mtx_unlock(&kring->q_lock); 1487f9790aebSLuigi Rizzo if (dst_na->retry && retry--) 1488f9790aebSLuigi Rizzo goto retry; 1489f9790aebSLuigi Rizzo } 1490f9790aebSLuigi Rizzo } 1491f9790aebSLuigi Rizzo if (still_locked) 1492f9790aebSLuigi Rizzo mtx_unlock(&kring->q_lock); 1493f9790aebSLuigi Rizzo } 1494f9790aebSLuigi Rizzo cleanup: 1495f9790aebSLuigi Rizzo d->bq_head = d->bq_tail = NM_FT_NULL; /* cleanup */ 1496f9790aebSLuigi Rizzo d->bq_len = 0; 1497f9790aebSLuigi Rizzo } 1498f9790aebSLuigi Rizzo brddst->bq_head = brddst->bq_tail = NM_FT_NULL; /* cleanup */ 1499f9790aebSLuigi Rizzo brddst->bq_len = 0; 1500f9790aebSLuigi Rizzo return 0; 1501f9790aebSLuigi Rizzo } 1502f9790aebSLuigi Rizzo 150317885a7bSLuigi Rizzo 1504f9790aebSLuigi Rizzo static int 1505f9790aebSLuigi Rizzo netmap_vp_txsync(struct netmap_vp_adapter *na, u_int ring_nr, int flags) 1506f9790aebSLuigi Rizzo { 1507f9790aebSLuigi Rizzo struct netmap_kring *kring = &na->up.tx_rings[ring_nr]; 150817885a7bSLuigi Rizzo u_int done; 150917885a7bSLuigi Rizzo u_int const lim = kring->nkr_num_slots - 1; 151017885a7bSLuigi Rizzo u_int const cur = kring->rcur; 1511f9790aebSLuigi Rizzo 1512f9790aebSLuigi Rizzo if (bridge_batch <= 0) { /* testing only */ 151317885a7bSLuigi Rizzo done = cur; // used all 1514f9790aebSLuigi Rizzo goto done; 1515f9790aebSLuigi Rizzo } 1516f9790aebSLuigi Rizzo if (bridge_batch > NM_BDG_BATCH) 1517f9790aebSLuigi Rizzo bridge_batch = NM_BDG_BATCH; 1518f9790aebSLuigi Rizzo 151917885a7bSLuigi Rizzo done = nm_bdg_preflush(na, ring_nr, kring, cur); 1520f9790aebSLuigi Rizzo done: 152117885a7bSLuigi Rizzo if (done != cur) 152217885a7bSLuigi Rizzo D("early break at %d/ %d, tail %d", done, cur, kring->nr_hwtail); 152317885a7bSLuigi Rizzo /* 152417885a7bSLuigi Rizzo * packets between 'done' and 'cur' are left unsent. 152517885a7bSLuigi Rizzo */ 152617885a7bSLuigi Rizzo kring->nr_hwcur = done; 152717885a7bSLuigi Rizzo kring->nr_hwtail = nm_prev(done, lim); 152817885a7bSLuigi Rizzo nm_txsync_finalize(kring); 1529f9790aebSLuigi Rizzo if (netmap_verbose) 1530f9790aebSLuigi Rizzo D("%s ring %d flags %d", NM_IFPNAME(na->up.ifp), ring_nr, flags); 1531f9790aebSLuigi Rizzo return 0; 1532f9790aebSLuigi Rizzo } 1533f9790aebSLuigi Rizzo 1534f9790aebSLuigi Rizzo 1535f9790aebSLuigi Rizzo /* 1536f9790aebSLuigi Rizzo * main dispatch routine for the bridge. 1537f9790aebSLuigi Rizzo * We already know that only one thread is running this. 1538f9790aebSLuigi Rizzo * we must run nm_bdg_preflush without lock. 1539f9790aebSLuigi Rizzo */ 1540f9790aebSLuigi Rizzo static int 1541f9790aebSLuigi Rizzo bdg_netmap_txsync(struct netmap_adapter *na, u_int ring_nr, int flags) 1542f9790aebSLuigi Rizzo { 1543f9790aebSLuigi Rizzo struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter*)na; 1544f9790aebSLuigi Rizzo return netmap_vp_txsync(vpna, ring_nr, flags); 1545f9790aebSLuigi Rizzo } 1546f9790aebSLuigi Rizzo 154717885a7bSLuigi Rizzo static int 154817885a7bSLuigi Rizzo netmap_vp_rxsync(struct netmap_adapter *na, u_int ring_nr, int flags) 154917885a7bSLuigi Rizzo { 155017885a7bSLuigi Rizzo struct netmap_kring *kring = &na->rx_rings[ring_nr]; 155117885a7bSLuigi Rizzo struct netmap_ring *ring = kring->ring; 155217885a7bSLuigi Rizzo u_int nm_i, lim = kring->nkr_num_slots - 1; 155317885a7bSLuigi Rizzo u_int head = nm_rxsync_prologue(kring); 155417885a7bSLuigi Rizzo int n; 155517885a7bSLuigi Rizzo 155617885a7bSLuigi Rizzo if (head > lim) { 155717885a7bSLuigi Rizzo D("ouch dangerous reset!!!"); 155817885a7bSLuigi Rizzo n = netmap_ring_reinit(kring); 155917885a7bSLuigi Rizzo goto done; 156017885a7bSLuigi Rizzo } 156117885a7bSLuigi Rizzo 156217885a7bSLuigi Rizzo /* First part, import newly received packets. */ 156317885a7bSLuigi Rizzo /* actually nothing to do here, they are already in the kring */ 156417885a7bSLuigi Rizzo 156517885a7bSLuigi Rizzo /* Second part, skip past packets that userspace has released. */ 156617885a7bSLuigi Rizzo nm_i = kring->nr_hwcur; 156717885a7bSLuigi Rizzo if (nm_i != head) { 156817885a7bSLuigi Rizzo /* consistency check, but nothing really important here */ 156917885a7bSLuigi Rizzo for (n = 0; likely(nm_i != head); n++) { 157017885a7bSLuigi Rizzo struct netmap_slot *slot = &ring->slot[nm_i]; 157117885a7bSLuigi Rizzo void *addr = BDG_NMB(na, slot); 157217885a7bSLuigi Rizzo 157317885a7bSLuigi Rizzo if (addr == netmap_buffer_base) { /* bad buf */ 157417885a7bSLuigi Rizzo D("bad buffer index %d, ignore ?", 157517885a7bSLuigi Rizzo slot->buf_idx); 157617885a7bSLuigi Rizzo } 157717885a7bSLuigi Rizzo slot->flags &= ~NS_BUF_CHANGED; 157817885a7bSLuigi Rizzo nm_i = nm_next(nm_i, lim); 157917885a7bSLuigi Rizzo } 158017885a7bSLuigi Rizzo kring->nr_hwcur = head; 158117885a7bSLuigi Rizzo } 158217885a7bSLuigi Rizzo 158317885a7bSLuigi Rizzo /* tell userspace that there are new packets */ 158417885a7bSLuigi Rizzo nm_rxsync_finalize(kring); 158517885a7bSLuigi Rizzo n = 0; 158617885a7bSLuigi Rizzo done: 158717885a7bSLuigi Rizzo return n; 158817885a7bSLuigi Rizzo } 1589f9790aebSLuigi Rizzo 1590f9790aebSLuigi Rizzo /* 1591f9790aebSLuigi Rizzo * user process reading from a VALE switch. 1592f9790aebSLuigi Rizzo * Already protected against concurrent calls from userspace, 1593f9790aebSLuigi Rizzo * but we must acquire the queue's lock to protect against 1594f9790aebSLuigi Rizzo * writers on the same queue. 1595f9790aebSLuigi Rizzo */ 1596f9790aebSLuigi Rizzo static int 1597f9790aebSLuigi Rizzo bdg_netmap_rxsync(struct netmap_adapter *na, u_int ring_nr, int flags) 1598f9790aebSLuigi Rizzo { 1599f9790aebSLuigi Rizzo struct netmap_kring *kring = &na->rx_rings[ring_nr]; 1600f9790aebSLuigi Rizzo int n; 1601f9790aebSLuigi Rizzo 1602f9790aebSLuigi Rizzo mtx_lock(&kring->q_lock); 160317885a7bSLuigi Rizzo n = netmap_vp_rxsync(na, ring_nr, flags); 1604f9790aebSLuigi Rizzo mtx_unlock(&kring->q_lock); 1605f9790aebSLuigi Rizzo return n; 1606f9790aebSLuigi Rizzo } 1607f9790aebSLuigi Rizzo 160817885a7bSLuigi Rizzo 1609f9790aebSLuigi Rizzo static int 1610f9790aebSLuigi Rizzo bdg_netmap_attach(struct nmreq *nmr, struct ifnet *ifp) 1611f9790aebSLuigi Rizzo { 1612f9790aebSLuigi Rizzo struct netmap_vp_adapter *vpna; 1613f9790aebSLuigi Rizzo struct netmap_adapter *na; 1614f9790aebSLuigi Rizzo int error; 1615f9790aebSLuigi Rizzo 1616f9790aebSLuigi Rizzo vpna = malloc(sizeof(*vpna), M_DEVBUF, M_NOWAIT | M_ZERO); 1617f9790aebSLuigi Rizzo if (vpna == NULL) 1618f9790aebSLuigi Rizzo return ENOMEM; 1619f9790aebSLuigi Rizzo 1620f9790aebSLuigi Rizzo na = &vpna->up; 1621f9790aebSLuigi Rizzo 1622f9790aebSLuigi Rizzo na->ifp = ifp; 1623f9790aebSLuigi Rizzo 1624f9790aebSLuigi Rizzo /* bound checking */ 1625f9790aebSLuigi Rizzo na->num_tx_rings = nmr->nr_tx_rings; 1626f9790aebSLuigi Rizzo nm_bound_var(&na->num_tx_rings, 1, 1, NM_BDG_MAXRINGS, NULL); 1627f9790aebSLuigi Rizzo nmr->nr_tx_rings = na->num_tx_rings; // write back 1628f9790aebSLuigi Rizzo na->num_rx_rings = nmr->nr_rx_rings; 1629f9790aebSLuigi Rizzo nm_bound_var(&na->num_rx_rings, 1, 1, NM_BDG_MAXRINGS, NULL); 1630f9790aebSLuigi Rizzo nmr->nr_rx_rings = na->num_rx_rings; // write back 1631f9790aebSLuigi Rizzo nm_bound_var(&nmr->nr_tx_slots, NM_BRIDGE_RINGSIZE, 1632f9790aebSLuigi Rizzo 1, NM_BDG_MAXSLOTS, NULL); 1633f9790aebSLuigi Rizzo na->num_tx_desc = nmr->nr_tx_slots; 1634f9790aebSLuigi Rizzo nm_bound_var(&nmr->nr_rx_slots, NM_BRIDGE_RINGSIZE, 1635f9790aebSLuigi Rizzo 1, NM_BDG_MAXSLOTS, NULL); 1636f9790aebSLuigi Rizzo na->num_rx_desc = nmr->nr_rx_slots; 1637f9790aebSLuigi Rizzo vpna->offset = 0; 1638f9790aebSLuigi Rizzo 1639f9790aebSLuigi Rizzo na->na_flags |= NAF_BDG_MAYSLEEP | NAF_MEM_OWNER; 1640f9790aebSLuigi Rizzo na->nm_txsync = bdg_netmap_txsync; 1641f9790aebSLuigi Rizzo na->nm_rxsync = bdg_netmap_rxsync; 1642f9790aebSLuigi Rizzo na->nm_register = bdg_netmap_reg; 1643f9790aebSLuigi Rizzo na->nm_dtor = netmap_adapter_vp_dtor; 1644f9790aebSLuigi Rizzo na->nm_krings_create = netmap_vp_krings_create; 1645f9790aebSLuigi Rizzo na->nm_krings_delete = netmap_vp_krings_delete; 1646f9790aebSLuigi Rizzo na->nm_mem = netmap_mem_private_new(NM_IFPNAME(na->ifp), 1647f9790aebSLuigi Rizzo na->num_tx_rings, na->num_tx_desc, 1648f9790aebSLuigi Rizzo na->num_rx_rings, na->num_rx_desc); 1649f9790aebSLuigi Rizzo /* other nmd fields are set in the common routine */ 1650f9790aebSLuigi Rizzo error = netmap_attach_common(na); 1651f9790aebSLuigi Rizzo if (error) { 1652f9790aebSLuigi Rizzo free(vpna, M_DEVBUF); 1653f9790aebSLuigi Rizzo return error; 1654f9790aebSLuigi Rizzo } 1655f9790aebSLuigi Rizzo return 0; 1656f9790aebSLuigi Rizzo } 1657f9790aebSLuigi Rizzo 165817885a7bSLuigi Rizzo 1659f9790aebSLuigi Rizzo static void 1660f9790aebSLuigi Rizzo netmap_bwrap_dtor(struct netmap_adapter *na) 1661f9790aebSLuigi Rizzo { 1662f9790aebSLuigi Rizzo struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter*)na; 1663f9790aebSLuigi Rizzo struct netmap_adapter *hwna = bna->hwna; 1664f9790aebSLuigi Rizzo struct nm_bridge *b = bna->up.na_bdg, 1665f9790aebSLuigi Rizzo *bh = bna->host.na_bdg; 1666f9790aebSLuigi Rizzo struct ifnet *ifp = na->ifp; 1667f9790aebSLuigi Rizzo 1668f9790aebSLuigi Rizzo ND("na %p", na); 1669f9790aebSLuigi Rizzo 1670f9790aebSLuigi Rizzo if (b) { 1671f9790aebSLuigi Rizzo netmap_bdg_detach_common(b, bna->up.bdg_port, 1672f9790aebSLuigi Rizzo (bh ? bna->host.bdg_port : -1)); 1673f9790aebSLuigi Rizzo } 1674f9790aebSLuigi Rizzo 1675f9790aebSLuigi Rizzo hwna->na_private = NULL; 1676f9790aebSLuigi Rizzo netmap_adapter_put(hwna); 1677f9790aebSLuigi Rizzo 1678f9790aebSLuigi Rizzo bzero(ifp, sizeof(*ifp)); 1679f9790aebSLuigi Rizzo free(ifp, M_DEVBUF); 1680f9790aebSLuigi Rizzo na->ifp = NULL; 1681f9790aebSLuigi Rizzo 1682f9790aebSLuigi Rizzo } 1683f9790aebSLuigi Rizzo 168417885a7bSLuigi Rizzo 1685f9790aebSLuigi Rizzo /* 168617885a7bSLuigi Rizzo * Intr callback for NICs connected to a bridge. 168717885a7bSLuigi Rizzo * Simply ignore tx interrupts (maybe we could try to recover space ?) 168817885a7bSLuigi Rizzo * and pass received packets from nic to the bridge. 168917885a7bSLuigi Rizzo * 1690f9790aebSLuigi Rizzo * XXX TODO check locking: this is called from the interrupt 1691f9790aebSLuigi Rizzo * handler so we should make sure that the interface is not 1692f9790aebSLuigi Rizzo * disconnected while passing down an interrupt. 1693f9790aebSLuigi Rizzo * 169417885a7bSLuigi Rizzo * Note, no user process can access this NIC or the host stack. 169517885a7bSLuigi Rizzo * The only part of the ring that is significant are the slots, 169617885a7bSLuigi Rizzo * and head/cur/tail are set from the kring as needed 169717885a7bSLuigi Rizzo * (part as a receive ring, part as a transmit ring). 169817885a7bSLuigi Rizzo * 169917885a7bSLuigi Rizzo * callback that overwrites the hwna notify callback. 1700f9790aebSLuigi Rizzo * Packets come from the outside or from the host stack and are put on an hwna rx ring. 1701f9790aebSLuigi Rizzo * The bridge wrapper then sends the packets through the bridge. 1702f9790aebSLuigi Rizzo */ 1703f9790aebSLuigi Rizzo static int 1704f9790aebSLuigi Rizzo netmap_bwrap_intr_notify(struct netmap_adapter *na, u_int ring_nr, enum txrx tx, int flags) 1705f9790aebSLuigi Rizzo { 1706f9790aebSLuigi Rizzo struct ifnet *ifp = na->ifp; 1707f9790aebSLuigi Rizzo struct netmap_bwrap_adapter *bna = na->na_private; 1708f9790aebSLuigi Rizzo struct netmap_vp_adapter *hostna = &bna->host; 1709f9790aebSLuigi Rizzo struct netmap_kring *kring, *bkring; 1710f9790aebSLuigi Rizzo struct netmap_ring *ring; 1711f9790aebSLuigi Rizzo int is_host_ring = ring_nr == na->num_rx_rings; 1712f9790aebSLuigi Rizzo struct netmap_vp_adapter *vpna = &bna->up; 1713f9790aebSLuigi Rizzo int error = 0; 1714f9790aebSLuigi Rizzo 171517885a7bSLuigi Rizzo if (netmap_verbose) 171617885a7bSLuigi Rizzo D("%s %s%d 0x%x", NM_IFPNAME(ifp), 171717885a7bSLuigi Rizzo (tx == NR_TX ? "TX" : "RX"), ring_nr, flags); 1718f9790aebSLuigi Rizzo 1719f9790aebSLuigi Rizzo if (flags & NAF_DISABLE_NOTIFY) { 1720f9790aebSLuigi Rizzo kring = tx == NR_TX ? na->tx_rings : na->rx_rings; 1721f9790aebSLuigi Rizzo bkring = tx == NR_TX ? vpna->up.rx_rings : vpna->up.tx_rings; 172217885a7bSLuigi Rizzo if (kring[ring_nr].nkr_stopped) 172317885a7bSLuigi Rizzo netmap_disable_ring(&bkring[ring_nr]); 1724f9790aebSLuigi Rizzo else 172517885a7bSLuigi Rizzo bkring[ring_nr].nkr_stopped = 0; 1726f9790aebSLuigi Rizzo return 0; 1727f9790aebSLuigi Rizzo } 1728f9790aebSLuigi Rizzo 1729f9790aebSLuigi Rizzo if (ifp == NULL || !(ifp->if_capenable & IFCAP_NETMAP)) 1730f9790aebSLuigi Rizzo return 0; 1731f9790aebSLuigi Rizzo 173217885a7bSLuigi Rizzo /* we only care about receive interrupts */ 1733f9790aebSLuigi Rizzo if (tx == NR_TX) 1734f9790aebSLuigi Rizzo return 0; 1735f9790aebSLuigi Rizzo 1736f9790aebSLuigi Rizzo kring = &na->rx_rings[ring_nr]; 1737f9790aebSLuigi Rizzo ring = kring->ring; 1738f9790aebSLuigi Rizzo 1739f9790aebSLuigi Rizzo /* make sure the ring is not disabled */ 1740f9790aebSLuigi Rizzo if (nm_kr_tryget(kring)) 1741f9790aebSLuigi Rizzo return 0; 1742f9790aebSLuigi Rizzo 1743f9790aebSLuigi Rizzo if (is_host_ring && hostna->na_bdg == NULL) { 1744f9790aebSLuigi Rizzo error = bna->save_notify(na, ring_nr, tx, flags); 1745f9790aebSLuigi Rizzo goto put_out; 1746f9790aebSLuigi Rizzo } 1747f9790aebSLuigi Rizzo 174817885a7bSLuigi Rizzo /* Here we expect ring->head = ring->cur = ring->tail 174917885a7bSLuigi Rizzo * because everything has been released from the previous round. 175017885a7bSLuigi Rizzo * However the ring is shared and we might have info from 175117885a7bSLuigi Rizzo * the wrong side (the tx ring). Hence we overwrite with 175217885a7bSLuigi Rizzo * the info from the rx kring. 175317885a7bSLuigi Rizzo */ 175417885a7bSLuigi Rizzo if (netmap_verbose) 175517885a7bSLuigi Rizzo D("%s head %d cur %d tail %d (kring %d %d %d)", NM_IFPNAME(ifp), 175617885a7bSLuigi Rizzo ring->head, ring->cur, ring->tail, 175717885a7bSLuigi Rizzo kring->rhead, kring->rcur, kring->rtail); 175817885a7bSLuigi Rizzo 175917885a7bSLuigi Rizzo ring->head = kring->rhead; 176017885a7bSLuigi Rizzo ring->cur = kring->rcur; 176117885a7bSLuigi Rizzo ring->tail = kring->rtail; 176217885a7bSLuigi Rizzo 176317885a7bSLuigi Rizzo /* simulate a user wakeup on the rx ring */ 1764f9790aebSLuigi Rizzo if (is_host_ring) { 176517885a7bSLuigi Rizzo netmap_rxsync_from_host(na, NULL, NULL); 1766f9790aebSLuigi Rizzo vpna = hostna; 1767f9790aebSLuigi Rizzo ring_nr = 0; 1768f9790aebSLuigi Rizzo } else { 1769f9790aebSLuigi Rizzo /* fetch packets that have arrived. 1770f9790aebSLuigi Rizzo * XXX maybe do this in a loop ? 1771f9790aebSLuigi Rizzo */ 1772f9790aebSLuigi Rizzo error = na->nm_rxsync(na, ring_nr, 0); 1773f9790aebSLuigi Rizzo if (error) 1774f9790aebSLuigi Rizzo goto put_out; 1775f9790aebSLuigi Rizzo } 177617885a7bSLuigi Rizzo if (kring->nr_hwcur == kring->nr_hwtail && netmap_verbose) { 1777f9790aebSLuigi Rizzo D("how strange, interrupt with no packets on %s", 1778f9790aebSLuigi Rizzo NM_IFPNAME(ifp)); 1779f9790aebSLuigi Rizzo goto put_out; 1780f9790aebSLuigi Rizzo } 178117885a7bSLuigi Rizzo 178217885a7bSLuigi Rizzo /* new packets are ring->cur to ring->tail, and the bkring 178317885a7bSLuigi Rizzo * had hwcur == ring->cur. So advance ring->cur to ring->tail 178417885a7bSLuigi Rizzo * to push all packets out. 178517885a7bSLuigi Rizzo */ 178617885a7bSLuigi Rizzo ring->head = ring->cur = ring->tail; 178717885a7bSLuigi Rizzo 178817885a7bSLuigi Rizzo /* also set tail to what the bwrap expects */ 178917885a7bSLuigi Rizzo bkring = &vpna->up.tx_rings[ring_nr]; 179017885a7bSLuigi Rizzo ring->tail = bkring->nr_hwtail; // rtail too ? 179117885a7bSLuigi Rizzo 179217885a7bSLuigi Rizzo /* pass packets to the switch */ 179317885a7bSLuigi Rizzo nm_txsync_prologue(bkring); // XXX error checking ? 1794f9790aebSLuigi Rizzo netmap_vp_txsync(vpna, ring_nr, flags); 1795f9790aebSLuigi Rizzo 179617885a7bSLuigi Rizzo /* mark all buffers as released on this ring */ 179717885a7bSLuigi Rizzo ring->head = ring->cur = kring->nr_hwtail; 179817885a7bSLuigi Rizzo ring->tail = kring->rtail; 179917885a7bSLuigi Rizzo /* another call to actually release the buffers */ 180017885a7bSLuigi Rizzo if (!is_host_ring) { 1801f9790aebSLuigi Rizzo error = na->nm_rxsync(na, ring_nr, 0); 180217885a7bSLuigi Rizzo } else { 180317885a7bSLuigi Rizzo /* mark all packets as released, as in the 180417885a7bSLuigi Rizzo * second part of netmap_rxsync_from_host() 180517885a7bSLuigi Rizzo */ 180617885a7bSLuigi Rizzo kring->nr_hwcur = kring->nr_hwtail; 180717885a7bSLuigi Rizzo nm_rxsync_finalize(kring); 180817885a7bSLuigi Rizzo } 1809f9790aebSLuigi Rizzo 1810f9790aebSLuigi Rizzo put_out: 1811f9790aebSLuigi Rizzo nm_kr_put(kring); 1812f9790aebSLuigi Rizzo return error; 1813f9790aebSLuigi Rizzo } 1814f9790aebSLuigi Rizzo 181517885a7bSLuigi Rizzo 1816f9790aebSLuigi Rizzo static int 1817f9790aebSLuigi Rizzo netmap_bwrap_register(struct netmap_adapter *na, int onoff) 1818f9790aebSLuigi Rizzo { 1819f9790aebSLuigi Rizzo struct netmap_bwrap_adapter *bna = 1820f9790aebSLuigi Rizzo (struct netmap_bwrap_adapter *)na; 1821f9790aebSLuigi Rizzo struct netmap_adapter *hwna = bna->hwna; 1822f9790aebSLuigi Rizzo struct netmap_vp_adapter *hostna = &bna->host; 1823f9790aebSLuigi Rizzo int error; 1824f9790aebSLuigi Rizzo 182517885a7bSLuigi Rizzo ND("%s %s", NM_IFPNAME(na->ifp), onoff ? "on" : "off"); 1826f9790aebSLuigi Rizzo 1827f9790aebSLuigi Rizzo if (onoff) { 1828f9790aebSLuigi Rizzo int i; 1829f9790aebSLuigi Rizzo 1830f9790aebSLuigi Rizzo hwna->na_lut = na->na_lut; 1831f9790aebSLuigi Rizzo hwna->na_lut_objtotal = na->na_lut_objtotal; 1832f9790aebSLuigi Rizzo 1833f9790aebSLuigi Rizzo if (hostna->na_bdg) { 1834f9790aebSLuigi Rizzo hostna->up.na_lut = na->na_lut; 1835f9790aebSLuigi Rizzo hostna->up.na_lut_objtotal = na->na_lut_objtotal; 1836f9790aebSLuigi Rizzo } 1837f9790aebSLuigi Rizzo 1838*0c7ba37eSLuigi Rizzo /* cross-link the netmap rings 1839*0c7ba37eSLuigi Rizzo * The original number of rings comes from hwna, 1840*0c7ba37eSLuigi Rizzo * rx rings on one side equals tx rings on the other. 1841*0c7ba37eSLuigi Rizzo */ 1842*0c7ba37eSLuigi Rizzo for (i = 0; i <= na->num_rx_rings; i++) { 1843f9790aebSLuigi Rizzo hwna->tx_rings[i].nkr_num_slots = na->rx_rings[i].nkr_num_slots; 1844f9790aebSLuigi Rizzo hwna->tx_rings[i].ring = na->rx_rings[i].ring; 1845f9790aebSLuigi Rizzo } 1846*0c7ba37eSLuigi Rizzo for (i = 0; i <= na->num_tx_rings; i++) { 1847f9790aebSLuigi Rizzo hwna->rx_rings[i].nkr_num_slots = na->tx_rings[i].nkr_num_slots; 1848f9790aebSLuigi Rizzo hwna->rx_rings[i].ring = na->tx_rings[i].ring; 1849f9790aebSLuigi Rizzo } 1850f9790aebSLuigi Rizzo } 1851f9790aebSLuigi Rizzo 1852f9790aebSLuigi Rizzo if (hwna->ifp) { 1853f9790aebSLuigi Rizzo error = hwna->nm_register(hwna, onoff); 1854f9790aebSLuigi Rizzo if (error) 1855f9790aebSLuigi Rizzo return error; 1856f9790aebSLuigi Rizzo } 1857f9790aebSLuigi Rizzo 1858f9790aebSLuigi Rizzo bdg_netmap_reg(na, onoff); 1859f9790aebSLuigi Rizzo 1860f9790aebSLuigi Rizzo if (onoff) { 1861f9790aebSLuigi Rizzo bna->save_notify = hwna->nm_notify; 1862f9790aebSLuigi Rizzo hwna->nm_notify = netmap_bwrap_intr_notify; 1863f9790aebSLuigi Rizzo } else { 1864f9790aebSLuigi Rizzo hwna->nm_notify = bna->save_notify; 1865f9790aebSLuigi Rizzo hwna->na_lut = NULL; 1866f9790aebSLuigi Rizzo hwna->na_lut_objtotal = 0; 1867f9790aebSLuigi Rizzo } 1868f9790aebSLuigi Rizzo 1869f9790aebSLuigi Rizzo return 0; 1870f9790aebSLuigi Rizzo } 1871f9790aebSLuigi Rizzo 187217885a7bSLuigi Rizzo 1873f9790aebSLuigi Rizzo static int 1874f9790aebSLuigi Rizzo netmap_bwrap_config(struct netmap_adapter *na, u_int *txr, u_int *txd, 1875f9790aebSLuigi Rizzo u_int *rxr, u_int *rxd) 1876f9790aebSLuigi Rizzo { 1877f9790aebSLuigi Rizzo struct netmap_bwrap_adapter *bna = 1878f9790aebSLuigi Rizzo (struct netmap_bwrap_adapter *)na; 1879f9790aebSLuigi Rizzo struct netmap_adapter *hwna = bna->hwna; 1880f9790aebSLuigi Rizzo 1881f9790aebSLuigi Rizzo /* forward the request */ 1882f9790aebSLuigi Rizzo netmap_update_config(hwna); 1883f9790aebSLuigi Rizzo /* swap the results */ 1884f9790aebSLuigi Rizzo *txr = hwna->num_rx_rings; 1885f9790aebSLuigi Rizzo *txd = hwna->num_rx_desc; 1886f9790aebSLuigi Rizzo *rxr = hwna->num_tx_rings; 1887f9790aebSLuigi Rizzo *rxd = hwna->num_rx_desc; 1888f9790aebSLuigi Rizzo 1889f9790aebSLuigi Rizzo return 0; 1890f9790aebSLuigi Rizzo } 1891f9790aebSLuigi Rizzo 189217885a7bSLuigi Rizzo 1893f9790aebSLuigi Rizzo static int 1894f9790aebSLuigi Rizzo netmap_bwrap_krings_create(struct netmap_adapter *na) 1895f9790aebSLuigi Rizzo { 1896f9790aebSLuigi Rizzo struct netmap_bwrap_adapter *bna = 1897f9790aebSLuigi Rizzo (struct netmap_bwrap_adapter *)na; 1898f9790aebSLuigi Rizzo struct netmap_adapter *hwna = bna->hwna; 1899f9790aebSLuigi Rizzo struct netmap_adapter *hostna = &bna->host.up; 1900f9790aebSLuigi Rizzo int error; 1901f9790aebSLuigi Rizzo 1902f9790aebSLuigi Rizzo ND("%s", NM_IFPNAME(na->ifp)); 1903f9790aebSLuigi Rizzo 1904f9790aebSLuigi Rizzo error = netmap_vp_krings_create(na); 1905f9790aebSLuigi Rizzo if (error) 1906f9790aebSLuigi Rizzo return error; 1907f9790aebSLuigi Rizzo 1908f9790aebSLuigi Rizzo error = hwna->nm_krings_create(hwna); 1909f9790aebSLuigi Rizzo if (error) { 1910f9790aebSLuigi Rizzo netmap_vp_krings_delete(na); 1911f9790aebSLuigi Rizzo return error; 1912f9790aebSLuigi Rizzo } 1913f9790aebSLuigi Rizzo 1914f9790aebSLuigi Rizzo hostna->tx_rings = na->tx_rings + na->num_tx_rings; 1915f9790aebSLuigi Rizzo hostna->rx_rings = na->rx_rings + na->num_rx_rings; 1916f9790aebSLuigi Rizzo 1917f9790aebSLuigi Rizzo return 0; 1918f9790aebSLuigi Rizzo } 1919f9790aebSLuigi Rizzo 192017885a7bSLuigi Rizzo 1921f9790aebSLuigi Rizzo static void 1922f9790aebSLuigi Rizzo netmap_bwrap_krings_delete(struct netmap_adapter *na) 1923f9790aebSLuigi Rizzo { 1924f9790aebSLuigi Rizzo struct netmap_bwrap_adapter *bna = 1925f9790aebSLuigi Rizzo (struct netmap_bwrap_adapter *)na; 1926f9790aebSLuigi Rizzo struct netmap_adapter *hwna = bna->hwna; 1927f9790aebSLuigi Rizzo 1928f9790aebSLuigi Rizzo ND("%s", NM_IFPNAME(na->ifp)); 1929f9790aebSLuigi Rizzo 1930f9790aebSLuigi Rizzo hwna->nm_krings_delete(hwna); 1931f9790aebSLuigi Rizzo netmap_vp_krings_delete(na); 1932f9790aebSLuigi Rizzo } 1933f9790aebSLuigi Rizzo 193417885a7bSLuigi Rizzo 1935f9790aebSLuigi Rizzo /* notify method for the bridge-->hwna direction */ 1936f9790aebSLuigi Rizzo static int 1937f9790aebSLuigi Rizzo netmap_bwrap_notify(struct netmap_adapter *na, u_int ring_n, enum txrx tx, int flags) 1938f9790aebSLuigi Rizzo { 1939f9790aebSLuigi Rizzo struct netmap_bwrap_adapter *bna = 1940f9790aebSLuigi Rizzo (struct netmap_bwrap_adapter *)na; 1941f9790aebSLuigi Rizzo struct netmap_adapter *hwna = bna->hwna; 1942f9790aebSLuigi Rizzo struct netmap_kring *kring, *hw_kring; 1943f9790aebSLuigi Rizzo struct netmap_ring *ring; 194417885a7bSLuigi Rizzo u_int lim; 1945f9790aebSLuigi Rizzo int error = 0; 1946f9790aebSLuigi Rizzo 1947f9790aebSLuigi Rizzo if (tx == NR_TX) 1948f9790aebSLuigi Rizzo return ENXIO; 1949f9790aebSLuigi Rizzo 1950f9790aebSLuigi Rizzo kring = &na->rx_rings[ring_n]; 1951f9790aebSLuigi Rizzo hw_kring = &hwna->tx_rings[ring_n]; 1952f9790aebSLuigi Rizzo ring = kring->ring; 1953f9790aebSLuigi Rizzo lim = kring->nkr_num_slots - 1; 1954f9790aebSLuigi Rizzo 1955f9790aebSLuigi Rizzo if (hwna->ifp == NULL || !(hwna->ifp->if_capenable & IFCAP_NETMAP)) 1956f9790aebSLuigi Rizzo return 0; 195717885a7bSLuigi Rizzo /* first step: simulate a user wakeup on the rx ring */ 195817885a7bSLuigi Rizzo netmap_vp_rxsync(na, ring_n, flags); 195917885a7bSLuigi Rizzo ND("%s[%d] PRE rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)", 1960f9790aebSLuigi Rizzo NM_IFPNAME(na->ifp), ring_n, 196117885a7bSLuigi Rizzo kring->nr_hwcur, kring->nr_hwtail, kring->nkr_hwlease, 196217885a7bSLuigi Rizzo ring->head, ring->cur, ring->tail, 196317885a7bSLuigi Rizzo hw_kring->nr_hwcur, hw_kring->nr_hwtail, hw_ring->rtail); 196417885a7bSLuigi Rizzo /* second step: the simulated user consumes all new packets */ 196517885a7bSLuigi Rizzo ring->head = ring->cur = ring->tail; 196617885a7bSLuigi Rizzo 196717885a7bSLuigi Rizzo /* third step: the new packets are sent on the tx ring 196817885a7bSLuigi Rizzo * (which is actually the same ring) 196917885a7bSLuigi Rizzo */ 197017885a7bSLuigi Rizzo /* set tail to what the hw expects */ 197117885a7bSLuigi Rizzo ring->tail = hw_kring->rtail; 1972f9790aebSLuigi Rizzo if (ring_n == na->num_rx_rings) { 1973f9790aebSLuigi Rizzo netmap_txsync_to_host(hwna); 1974f9790aebSLuigi Rizzo } else { 197517885a7bSLuigi Rizzo nm_txsync_prologue(&hwna->tx_rings[ring_n]); // XXX error checking ? 1976f9790aebSLuigi Rizzo error = hwna->nm_txsync(hwna, ring_n, flags); 1977f9790aebSLuigi Rizzo } 197817885a7bSLuigi Rizzo 197917885a7bSLuigi Rizzo /* fourth step: now we are back the rx ring */ 198017885a7bSLuigi Rizzo /* claim ownership on all hw owned bufs */ 198117885a7bSLuigi Rizzo ring->head = nm_next(ring->tail, lim); /* skip past reserved slot */ 198217885a7bSLuigi Rizzo ring->tail = kring->rtail; /* restore saved value of tail, for safety */ 198317885a7bSLuigi Rizzo 198417885a7bSLuigi Rizzo /* fifth step: the user goes to sleep again, causing another rxsync */ 198517885a7bSLuigi Rizzo netmap_vp_rxsync(na, ring_n, flags); 198617885a7bSLuigi Rizzo ND("%s[%d] PST rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)", 1987f9790aebSLuigi Rizzo NM_IFPNAME(na->ifp), ring_n, 198817885a7bSLuigi Rizzo kring->nr_hwcur, kring->nr_hwtail, kring->nkr_hwlease, 198917885a7bSLuigi Rizzo ring->head, ring->cur, ring->tail, 199017885a7bSLuigi Rizzo hw_kring->nr_hwcur, hw_kring->nr_hwtail, hw_kring->rtail); 1991f9790aebSLuigi Rizzo 1992f9790aebSLuigi Rizzo return error; 1993f9790aebSLuigi Rizzo } 1994f9790aebSLuigi Rizzo 199517885a7bSLuigi Rizzo 1996f9790aebSLuigi Rizzo static int 1997f9790aebSLuigi Rizzo netmap_bwrap_host_notify(struct netmap_adapter *na, u_int ring_n, enum txrx tx, int flags) 1998f9790aebSLuigi Rizzo { 1999f9790aebSLuigi Rizzo struct netmap_bwrap_adapter *bna = na->na_private; 2000f9790aebSLuigi Rizzo struct netmap_adapter *port_na = &bna->up.up; 2001f9790aebSLuigi Rizzo if (tx == NR_TX || ring_n != 0) 2002f9790aebSLuigi Rizzo return ENXIO; 2003f9790aebSLuigi Rizzo return netmap_bwrap_notify(port_na, port_na->num_rx_rings, NR_RX, flags); 2004f9790aebSLuigi Rizzo } 2005f9790aebSLuigi Rizzo 200617885a7bSLuigi Rizzo 2007f9790aebSLuigi Rizzo /* attach a bridge wrapper to the 'real' device */ 2008f9790aebSLuigi Rizzo static int 2009f9790aebSLuigi Rizzo netmap_bwrap_attach(struct ifnet *fake, struct ifnet *real) 2010f9790aebSLuigi Rizzo { 2011f9790aebSLuigi Rizzo struct netmap_bwrap_adapter *bna; 2012f9790aebSLuigi Rizzo struct netmap_adapter *na; 2013f9790aebSLuigi Rizzo struct netmap_adapter *hwna = NA(real); 2014f9790aebSLuigi Rizzo struct netmap_adapter *hostna; 2015f9790aebSLuigi Rizzo int error; 2016f9790aebSLuigi Rizzo 2017f9790aebSLuigi Rizzo 2018f9790aebSLuigi Rizzo bna = malloc(sizeof(*bna), M_DEVBUF, M_NOWAIT | M_ZERO); 2019f9790aebSLuigi Rizzo if (bna == NULL) 2020f9790aebSLuigi Rizzo return ENOMEM; 2021f9790aebSLuigi Rizzo 2022f9790aebSLuigi Rizzo na = &bna->up.up; 2023f9790aebSLuigi Rizzo na->ifp = fake; 2024f9790aebSLuigi Rizzo /* fill the ring data for the bwrap adapter with rx/tx meanings 2025f9790aebSLuigi Rizzo * swapped. The real cross-linking will be done during register, 2026f9790aebSLuigi Rizzo * when all the krings will have been created. 2027f9790aebSLuigi Rizzo */ 2028f9790aebSLuigi Rizzo na->num_rx_rings = hwna->num_tx_rings; 2029f9790aebSLuigi Rizzo na->num_tx_rings = hwna->num_rx_rings; 2030f9790aebSLuigi Rizzo na->num_tx_desc = hwna->num_rx_desc; 2031f9790aebSLuigi Rizzo na->num_rx_desc = hwna->num_tx_desc; 2032f9790aebSLuigi Rizzo na->nm_dtor = netmap_bwrap_dtor; 2033f9790aebSLuigi Rizzo na->nm_register = netmap_bwrap_register; 2034f9790aebSLuigi Rizzo // na->nm_txsync = netmap_bwrap_txsync; 2035f9790aebSLuigi Rizzo // na->nm_rxsync = netmap_bwrap_rxsync; 2036f9790aebSLuigi Rizzo na->nm_config = netmap_bwrap_config; 2037f9790aebSLuigi Rizzo na->nm_krings_create = netmap_bwrap_krings_create; 2038f9790aebSLuigi Rizzo na->nm_krings_delete = netmap_bwrap_krings_delete; 2039f9790aebSLuigi Rizzo na->nm_notify = netmap_bwrap_notify; 2040f9790aebSLuigi Rizzo na->nm_mem = hwna->nm_mem; 2041f9790aebSLuigi Rizzo na->na_private = na; /* prevent NIOCREGIF */ 2042f9790aebSLuigi Rizzo bna->up.retry = 1; /* XXX maybe this should depend on the hwna */ 2043f9790aebSLuigi Rizzo 2044f9790aebSLuigi Rizzo bna->hwna = hwna; 2045f9790aebSLuigi Rizzo netmap_adapter_get(hwna); 2046f9790aebSLuigi Rizzo hwna->na_private = bna; /* weak reference */ 2047f9790aebSLuigi Rizzo 2048f9790aebSLuigi Rizzo hostna = &bna->host.up; 2049f9790aebSLuigi Rizzo hostna->ifp = hwna->ifp; 2050f9790aebSLuigi Rizzo hostna->num_tx_rings = 1; 2051f9790aebSLuigi Rizzo hostna->num_tx_desc = hwna->num_rx_desc; 2052f9790aebSLuigi Rizzo hostna->num_rx_rings = 1; 2053f9790aebSLuigi Rizzo hostna->num_rx_desc = hwna->num_tx_desc; 2054f9790aebSLuigi Rizzo // hostna->nm_txsync = netmap_bwrap_host_txsync; 2055f9790aebSLuigi Rizzo // hostna->nm_rxsync = netmap_bwrap_host_rxsync; 2056f9790aebSLuigi Rizzo hostna->nm_notify = netmap_bwrap_host_notify; 2057f9790aebSLuigi Rizzo hostna->nm_mem = na->nm_mem; 2058f9790aebSLuigi Rizzo hostna->na_private = bna; 2059f9790aebSLuigi Rizzo 206017885a7bSLuigi Rizzo ND("%s<->%s txr %d txd %d rxr %d rxd %d", 206117885a7bSLuigi Rizzo fake->if_xname, real->if_xname, 2062f9790aebSLuigi Rizzo na->num_tx_rings, na->num_tx_desc, 2063f9790aebSLuigi Rizzo na->num_rx_rings, na->num_rx_desc); 2064f9790aebSLuigi Rizzo 2065f9790aebSLuigi Rizzo error = netmap_attach_common(na); 2066f9790aebSLuigi Rizzo if (error) { 2067f9790aebSLuigi Rizzo netmap_adapter_put(hwna); 2068f9790aebSLuigi Rizzo free(bna, M_DEVBUF); 2069f9790aebSLuigi Rizzo return error; 2070f9790aebSLuigi Rizzo } 2071f9790aebSLuigi Rizzo return 0; 2072f9790aebSLuigi Rizzo } 2073f9790aebSLuigi Rizzo 207417885a7bSLuigi Rizzo 2075f9790aebSLuigi Rizzo void 2076f9790aebSLuigi Rizzo netmap_init_bridges(void) 2077f9790aebSLuigi Rizzo { 2078f9790aebSLuigi Rizzo int i; 2079f9790aebSLuigi Rizzo bzero(nm_bridges, sizeof(struct nm_bridge) * NM_BRIDGES); /* safety */ 2080f9790aebSLuigi Rizzo for (i = 0; i < NM_BRIDGES; i++) 2081f9790aebSLuigi Rizzo BDG_RWINIT(&nm_bridges[i]); 2082f9790aebSLuigi Rizzo } 2083f9790aebSLuigi Rizzo #endif /* WITH_VALE */ 2084