xref: /freebsd/sys/dev/netmap/netmap_bdg.c (revision b6e66be22bdce2aadcf52ee6230faa1e6cd3f805)
12a7db7a6SVincenzo Maffione /*
22a7db7a6SVincenzo Maffione  * Copyright (C) 2013-2016 Universita` di Pisa
32a7db7a6SVincenzo Maffione  * All rights reserved.
42a7db7a6SVincenzo Maffione  *
52a7db7a6SVincenzo Maffione  * Redistribution and use in source and binary forms, with or without
62a7db7a6SVincenzo Maffione  * modification, are permitted provided that the following conditions
72a7db7a6SVincenzo Maffione  * are met:
82a7db7a6SVincenzo Maffione  *   1. Redistributions of source code must retain the above copyright
92a7db7a6SVincenzo Maffione  *      notice, this list of conditions and the following disclaimer.
102a7db7a6SVincenzo Maffione  *   2. Redistributions in binary form must reproduce the above copyright
112a7db7a6SVincenzo Maffione  *      notice, this list of conditions and the following disclaimer in the
122a7db7a6SVincenzo Maffione  *      documentation and/or other materials provided with the distribution.
132a7db7a6SVincenzo Maffione  *
142a7db7a6SVincenzo Maffione  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
152a7db7a6SVincenzo Maffione  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
162a7db7a6SVincenzo Maffione  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
172a7db7a6SVincenzo Maffione  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
182a7db7a6SVincenzo Maffione  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
192a7db7a6SVincenzo Maffione  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
202a7db7a6SVincenzo Maffione  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
212a7db7a6SVincenzo Maffione  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
222a7db7a6SVincenzo Maffione  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
232a7db7a6SVincenzo Maffione  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
242a7db7a6SVincenzo Maffione  * SUCH DAMAGE.
252a7db7a6SVincenzo Maffione  */
262a7db7a6SVincenzo Maffione 
272a7db7a6SVincenzo Maffione 
282a7db7a6SVincenzo Maffione /*
292a7db7a6SVincenzo Maffione  * This module implements the VALE switch for netmap
302a7db7a6SVincenzo Maffione 
312a7db7a6SVincenzo Maffione --- VALE SWITCH ---
322a7db7a6SVincenzo Maffione 
332a7db7a6SVincenzo Maffione NMG_LOCK() serializes all modifications to switches and ports.
342a7db7a6SVincenzo Maffione A switch cannot be deleted until all ports are gone.
352a7db7a6SVincenzo Maffione 
362a7db7a6SVincenzo Maffione For each switch, an SX lock (RWlock on linux) protects
372a7db7a6SVincenzo Maffione deletion of ports. When configuring or deleting a new port, the
382a7db7a6SVincenzo Maffione lock is acquired in exclusive mode (after holding NMG_LOCK).
392a7db7a6SVincenzo Maffione When forwarding, the lock is acquired in shared mode (without NMG_LOCK).
402a7db7a6SVincenzo Maffione The lock is held throughout the entire forwarding cycle,
412a7db7a6SVincenzo Maffione during which the thread may incur in a page fault.
422a7db7a6SVincenzo Maffione Hence it is important that sleepable shared locks are used.
432a7db7a6SVincenzo Maffione 
442a7db7a6SVincenzo Maffione On the rx ring, the per-port lock is grabbed initially to reserve
452a7db7a6SVincenzo Maffione a number of slot in the ring, then the lock is released,
462a7db7a6SVincenzo Maffione packets are copied from source to destination, and then
472a7db7a6SVincenzo Maffione the lock is acquired again and the receive ring is updated.
482a7db7a6SVincenzo Maffione (A similar thing is done on the tx ring for NIC and host stack
492a7db7a6SVincenzo Maffione ports attached to the switch)
502a7db7a6SVincenzo Maffione 
512a7db7a6SVincenzo Maffione  */
522a7db7a6SVincenzo Maffione 
532a7db7a6SVincenzo Maffione /*
542a7db7a6SVincenzo Maffione  * OS-specific code that is used only within this file.
552a7db7a6SVincenzo Maffione  * Other OS-specific code that must be accessed by drivers
562a7db7a6SVincenzo Maffione  * is present in netmap_kern.h
572a7db7a6SVincenzo Maffione  */
582a7db7a6SVincenzo Maffione 
592a7db7a6SVincenzo Maffione #if defined(__FreeBSD__)
602a7db7a6SVincenzo Maffione #include <sys/cdefs.h> /* prerequisite */
612a7db7a6SVincenzo Maffione __FBSDID("$FreeBSD$");
622a7db7a6SVincenzo Maffione 
632a7db7a6SVincenzo Maffione #include <sys/types.h>
642a7db7a6SVincenzo Maffione #include <sys/errno.h>
652a7db7a6SVincenzo Maffione #include <sys/param.h>	/* defines used in kernel.h */
662a7db7a6SVincenzo Maffione #include <sys/kernel.h>	/* types used in module initialization */
672a7db7a6SVincenzo Maffione #include <sys/conf.h>	/* cdevsw struct, UID, GID */
682a7db7a6SVincenzo Maffione #include <sys/sockio.h>
692a7db7a6SVincenzo Maffione #include <sys/socketvar.h>	/* struct socket */
702a7db7a6SVincenzo Maffione #include <sys/malloc.h>
712a7db7a6SVincenzo Maffione #include <sys/poll.h>
722a7db7a6SVincenzo Maffione #include <sys/rwlock.h>
732a7db7a6SVincenzo Maffione #include <sys/socket.h> /* sockaddrs */
742a7db7a6SVincenzo Maffione #include <sys/selinfo.h>
752a7db7a6SVincenzo Maffione #include <sys/sysctl.h>
762a7db7a6SVincenzo Maffione #include <net/if.h>
772a7db7a6SVincenzo Maffione #include <net/if_var.h>
782a7db7a6SVincenzo Maffione #include <net/bpf.h>		/* BIOCIMMEDIATE */
792a7db7a6SVincenzo Maffione #include <machine/bus.h>	/* bus_dmamap_* */
802a7db7a6SVincenzo Maffione #include <sys/endian.h>
812a7db7a6SVincenzo Maffione #include <sys/refcount.h>
822a7db7a6SVincenzo Maffione #include <sys/smp.h>
832a7db7a6SVincenzo Maffione 
842a7db7a6SVincenzo Maffione 
852a7db7a6SVincenzo Maffione #elif defined(linux)
862a7db7a6SVincenzo Maffione 
872a7db7a6SVincenzo Maffione #include "bsd_glue.h"
882a7db7a6SVincenzo Maffione 
892a7db7a6SVincenzo Maffione #elif defined(__APPLE__)
902a7db7a6SVincenzo Maffione 
912a7db7a6SVincenzo Maffione #warning OSX support is only partial
922a7db7a6SVincenzo Maffione #include "osx_glue.h"
932a7db7a6SVincenzo Maffione 
942a7db7a6SVincenzo Maffione #elif defined(_WIN32)
952a7db7a6SVincenzo Maffione #include "win_glue.h"
962a7db7a6SVincenzo Maffione 
972a7db7a6SVincenzo Maffione #else
982a7db7a6SVincenzo Maffione 
992a7db7a6SVincenzo Maffione #error	Unsupported platform
1002a7db7a6SVincenzo Maffione 
1012a7db7a6SVincenzo Maffione #endif /* unsupported */
1022a7db7a6SVincenzo Maffione 
1032a7db7a6SVincenzo Maffione /*
1042a7db7a6SVincenzo Maffione  * common headers
1052a7db7a6SVincenzo Maffione  */
1062a7db7a6SVincenzo Maffione 
1072a7db7a6SVincenzo Maffione #include <net/netmap.h>
1082a7db7a6SVincenzo Maffione #include <dev/netmap/netmap_kern.h>
1092a7db7a6SVincenzo Maffione #include <dev/netmap/netmap_mem2.h>
1102a7db7a6SVincenzo Maffione 
1112a7db7a6SVincenzo Maffione #include <dev/netmap/netmap_bdg.h>
1122a7db7a6SVincenzo Maffione 
1132a7db7a6SVincenzo Maffione const char*
1142a7db7a6SVincenzo Maffione netmap_bdg_name(struct netmap_vp_adapter *vp)
1152a7db7a6SVincenzo Maffione {
1162a7db7a6SVincenzo Maffione 	struct nm_bridge *b = vp->na_bdg;
1172a7db7a6SVincenzo Maffione 	if (b == NULL)
1182a7db7a6SVincenzo Maffione 		return NULL;
1192a7db7a6SVincenzo Maffione 	return b->bdg_basename;
1202a7db7a6SVincenzo Maffione }
1212a7db7a6SVincenzo Maffione 
1222a7db7a6SVincenzo Maffione 
1232a7db7a6SVincenzo Maffione #ifndef CONFIG_NET_NS
1242a7db7a6SVincenzo Maffione /*
1252a7db7a6SVincenzo Maffione  * XXX in principle nm_bridges could be created dynamically
1262a7db7a6SVincenzo Maffione  * Right now we have a static array and deletions are protected
1272a7db7a6SVincenzo Maffione  * by an exclusive lock.
1282a7db7a6SVincenzo Maffione  */
129*b6e66be2SVincenzo Maffione struct nm_bridge *nm_bridges;
1302a7db7a6SVincenzo Maffione #endif /* !CONFIG_NET_NS */
1312a7db7a6SVincenzo Maffione 
1322a7db7a6SVincenzo Maffione 
1332a7db7a6SVincenzo Maffione static int
1342a7db7a6SVincenzo Maffione nm_is_id_char(const char c)
1352a7db7a6SVincenzo Maffione {
1362a7db7a6SVincenzo Maffione 	return (c >= 'a' && c <= 'z') ||
1372a7db7a6SVincenzo Maffione 	       (c >= 'A' && c <= 'Z') ||
1382a7db7a6SVincenzo Maffione 	       (c >= '0' && c <= '9') ||
1392a7db7a6SVincenzo Maffione 	       (c == '_');
1402a7db7a6SVincenzo Maffione }
1412a7db7a6SVincenzo Maffione 
142*b6e66be2SVincenzo Maffione /* Validate the name of a bdg port and return the
1432a7db7a6SVincenzo Maffione  * position of the ":" character. */
1442a7db7a6SVincenzo Maffione static int
145*b6e66be2SVincenzo Maffione nm_bdg_name_validate(const char *name, size_t prefixlen)
1462a7db7a6SVincenzo Maffione {
1472a7db7a6SVincenzo Maffione 	int colon_pos = -1;
1482a7db7a6SVincenzo Maffione 	int i;
1492a7db7a6SVincenzo Maffione 
150*b6e66be2SVincenzo Maffione 	if (!name || strlen(name) < prefixlen) {
1512a7db7a6SVincenzo Maffione 		return -1;
1522a7db7a6SVincenzo Maffione 	}
1532a7db7a6SVincenzo Maffione 
1542a7db7a6SVincenzo Maffione 	for (i = 0; i < NM_BDG_IFNAMSIZ && name[i]; i++) {
1552a7db7a6SVincenzo Maffione 		if (name[i] == ':') {
1562a7db7a6SVincenzo Maffione 			colon_pos = i;
1572a7db7a6SVincenzo Maffione 			break;
1582a7db7a6SVincenzo Maffione 		} else if (!nm_is_id_char(name[i])) {
1592a7db7a6SVincenzo Maffione 			return -1;
1602a7db7a6SVincenzo Maffione 		}
1612a7db7a6SVincenzo Maffione 	}
1622a7db7a6SVincenzo Maffione 
1632a7db7a6SVincenzo Maffione 	if (strlen(name) - colon_pos > IFNAMSIZ) {
1642a7db7a6SVincenzo Maffione 		/* interface name too long */
1652a7db7a6SVincenzo Maffione 		return -1;
1662a7db7a6SVincenzo Maffione 	}
1672a7db7a6SVincenzo Maffione 
1682a7db7a6SVincenzo Maffione 	return colon_pos;
1692a7db7a6SVincenzo Maffione }
1702a7db7a6SVincenzo Maffione 
1712a7db7a6SVincenzo Maffione /*
1722a7db7a6SVincenzo Maffione  * locate a bridge among the existing ones.
1732a7db7a6SVincenzo Maffione  * MUST BE CALLED WITH NMG_LOCK()
1742a7db7a6SVincenzo Maffione  *
1752a7db7a6SVincenzo Maffione  * a ':' in the name terminates the bridge name. Otherwise, just NM_NAME.
1762a7db7a6SVincenzo Maffione  * We assume that this is called with a name of at least NM_NAME chars.
1772a7db7a6SVincenzo Maffione  */
1782a7db7a6SVincenzo Maffione struct nm_bridge *
1792a7db7a6SVincenzo Maffione nm_find_bridge(const char *name, int create, struct netmap_bdg_ops *ops)
1802a7db7a6SVincenzo Maffione {
1812a7db7a6SVincenzo Maffione 	int i, namelen;
1822a7db7a6SVincenzo Maffione 	struct nm_bridge *b = NULL, *bridges;
1832a7db7a6SVincenzo Maffione 	u_int num_bridges;
1842a7db7a6SVincenzo Maffione 
1852a7db7a6SVincenzo Maffione 	NMG_LOCK_ASSERT();
1862a7db7a6SVincenzo Maffione 
1872a7db7a6SVincenzo Maffione 	netmap_bns_getbridges(&bridges, &num_bridges);
1882a7db7a6SVincenzo Maffione 
189*b6e66be2SVincenzo Maffione 	namelen = nm_bdg_name_validate(name,
190*b6e66be2SVincenzo Maffione 			(ops != NULL ? strlen(ops->name) : 0));
1912a7db7a6SVincenzo Maffione 	if (namelen < 0) {
192*b6e66be2SVincenzo Maffione 		nm_prerr("invalid bridge name %s", name ? name : NULL);
1932a7db7a6SVincenzo Maffione 		return NULL;
1942a7db7a6SVincenzo Maffione 	}
1952a7db7a6SVincenzo Maffione 
1962a7db7a6SVincenzo Maffione 	/* lookup the name, remember empty slot if there is one */
1972a7db7a6SVincenzo Maffione 	for (i = 0; i < num_bridges; i++) {
1982a7db7a6SVincenzo Maffione 		struct nm_bridge *x = bridges + i;
1992a7db7a6SVincenzo Maffione 
2002a7db7a6SVincenzo Maffione 		if ((x->bdg_flags & NM_BDG_ACTIVE) + x->bdg_active_ports == 0) {
2012a7db7a6SVincenzo Maffione 			if (create && b == NULL)
2022a7db7a6SVincenzo Maffione 				b = x;	/* record empty slot */
2032a7db7a6SVincenzo Maffione 		} else if (x->bdg_namelen != namelen) {
2042a7db7a6SVincenzo Maffione 			continue;
2052a7db7a6SVincenzo Maffione 		} else if (strncmp(name, x->bdg_basename, namelen) == 0) {
2062a7db7a6SVincenzo Maffione 			ND("found '%.*s' at %d", namelen, name, i);
2072a7db7a6SVincenzo Maffione 			b = x;
2082a7db7a6SVincenzo Maffione 			break;
2092a7db7a6SVincenzo Maffione 		}
2102a7db7a6SVincenzo Maffione 	}
2112a7db7a6SVincenzo Maffione 	if (i == num_bridges && b) { /* name not found, can create entry */
2122a7db7a6SVincenzo Maffione 		/* initialize the bridge */
2132a7db7a6SVincenzo Maffione 		ND("create new bridge %s with ports %d", b->bdg_basename,
2142a7db7a6SVincenzo Maffione 			b->bdg_active_ports);
2152a7db7a6SVincenzo Maffione 		b->ht = nm_os_malloc(sizeof(struct nm_hash_ent) * NM_BDG_HASH);
2162a7db7a6SVincenzo Maffione 		if (b->ht == NULL) {
217*b6e66be2SVincenzo Maffione 			nm_prerr("failed to allocate hash table");
2182a7db7a6SVincenzo Maffione 			return NULL;
2192a7db7a6SVincenzo Maffione 		}
2202a7db7a6SVincenzo Maffione 		strncpy(b->bdg_basename, name, namelen);
2212a7db7a6SVincenzo Maffione 		b->bdg_namelen = namelen;
2222a7db7a6SVincenzo Maffione 		b->bdg_active_ports = 0;
2232a7db7a6SVincenzo Maffione 		for (i = 0; i < NM_BDG_MAXPORTS; i++)
2242a7db7a6SVincenzo Maffione 			b->bdg_port_index[i] = i;
2252a7db7a6SVincenzo Maffione 		/* set the default function */
226*b6e66be2SVincenzo Maffione 		b->bdg_ops = b->bdg_saved_ops = *ops;
2272a7db7a6SVincenzo Maffione 		b->private_data = b->ht;
2282a7db7a6SVincenzo Maffione 		b->bdg_flags = 0;
2292a7db7a6SVincenzo Maffione 		NM_BNS_GET(b);
2302a7db7a6SVincenzo Maffione 	}
2312a7db7a6SVincenzo Maffione 	return b;
2322a7db7a6SVincenzo Maffione }
2332a7db7a6SVincenzo Maffione 
2342a7db7a6SVincenzo Maffione 
2352a7db7a6SVincenzo Maffione int
2362a7db7a6SVincenzo Maffione netmap_bdg_free(struct nm_bridge *b)
2372a7db7a6SVincenzo Maffione {
2382a7db7a6SVincenzo Maffione 	if ((b->bdg_flags & NM_BDG_ACTIVE) + b->bdg_active_ports != 0) {
2392a7db7a6SVincenzo Maffione 		return EBUSY;
2402a7db7a6SVincenzo Maffione 	}
2412a7db7a6SVincenzo Maffione 
2422a7db7a6SVincenzo Maffione 	ND("marking bridge %s as free", b->bdg_basename);
2432a7db7a6SVincenzo Maffione 	nm_os_free(b->ht);
244*b6e66be2SVincenzo Maffione 	memset(&b->bdg_ops, 0, sizeof(b->bdg_ops));
245*b6e66be2SVincenzo Maffione 	memset(&b->bdg_saved_ops, 0, sizeof(b->bdg_saved_ops));
2462a7db7a6SVincenzo Maffione 	b->bdg_flags = 0;
2472a7db7a6SVincenzo Maffione 	NM_BNS_PUT(b);
2482a7db7a6SVincenzo Maffione 	return 0;
2492a7db7a6SVincenzo Maffione }
2502a7db7a6SVincenzo Maffione 
251*b6e66be2SVincenzo Maffione /* Called by external kernel modules (e.g., Openvswitch).
252*b6e66be2SVincenzo Maffione  * to modify the private data previously given to regops().
253*b6e66be2SVincenzo Maffione  * 'name' may be just bridge's name (including ':' if it
254*b6e66be2SVincenzo Maffione  * is not just NM_BDG_NAME).
255*b6e66be2SVincenzo Maffione  * Called without NMG_LOCK.
256*b6e66be2SVincenzo Maffione  */
257*b6e66be2SVincenzo Maffione int
258*b6e66be2SVincenzo Maffione netmap_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callback,
259*b6e66be2SVincenzo Maffione 	void *callback_data, void *auth_token)
260*b6e66be2SVincenzo Maffione {
261*b6e66be2SVincenzo Maffione 	void *private_data = NULL;
262*b6e66be2SVincenzo Maffione 	struct nm_bridge *b;
263*b6e66be2SVincenzo Maffione 	int error = 0;
264*b6e66be2SVincenzo Maffione 
265*b6e66be2SVincenzo Maffione 	NMG_LOCK();
266*b6e66be2SVincenzo Maffione 	b = nm_find_bridge(name, 0 /* don't create */, NULL);
267*b6e66be2SVincenzo Maffione 	if (!b) {
268*b6e66be2SVincenzo Maffione 		error = EINVAL;
269*b6e66be2SVincenzo Maffione 		goto unlock_update_priv;
270*b6e66be2SVincenzo Maffione 	}
271*b6e66be2SVincenzo Maffione 	if (!nm_bdg_valid_auth_token(b, auth_token)) {
272*b6e66be2SVincenzo Maffione 		error = EACCES;
273*b6e66be2SVincenzo Maffione 		goto unlock_update_priv;
274*b6e66be2SVincenzo Maffione 	}
275*b6e66be2SVincenzo Maffione 	BDG_WLOCK(b);
276*b6e66be2SVincenzo Maffione 	private_data = callback(b->private_data, callback_data, &error);
277*b6e66be2SVincenzo Maffione 	b->private_data = private_data;
278*b6e66be2SVincenzo Maffione 	BDG_WUNLOCK(b);
279*b6e66be2SVincenzo Maffione 
280*b6e66be2SVincenzo Maffione unlock_update_priv:
281*b6e66be2SVincenzo Maffione 	NMG_UNLOCK();
282*b6e66be2SVincenzo Maffione 	return error;
283*b6e66be2SVincenzo Maffione }
284*b6e66be2SVincenzo Maffione 
285*b6e66be2SVincenzo Maffione 
2862a7db7a6SVincenzo Maffione 
2872a7db7a6SVincenzo Maffione /* remove from bridge b the ports in slots hw and sw
2882a7db7a6SVincenzo Maffione  * (sw can be -1 if not needed)
2892a7db7a6SVincenzo Maffione  */
2902a7db7a6SVincenzo Maffione void
2912a7db7a6SVincenzo Maffione netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
2922a7db7a6SVincenzo Maffione {
2932a7db7a6SVincenzo Maffione 	int s_hw = hw, s_sw = sw;
2942a7db7a6SVincenzo Maffione 	int i, lim =b->bdg_active_ports;
2952a7db7a6SVincenzo Maffione 	uint32_t *tmp = b->tmp_bdg_port_index;
2962a7db7a6SVincenzo Maffione 
2972a7db7a6SVincenzo Maffione 	/*
2982a7db7a6SVincenzo Maffione 	New algorithm:
2992a7db7a6SVincenzo Maffione 	make a copy of bdg_port_index;
3002a7db7a6SVincenzo Maffione 	lookup NA(ifp)->bdg_port and SWNA(ifp)->bdg_port
3012a7db7a6SVincenzo Maffione 	in the array of bdg_port_index, replacing them with
3022a7db7a6SVincenzo Maffione 	entries from the bottom of the array;
3032a7db7a6SVincenzo Maffione 	decrement bdg_active_ports;
3042a7db7a6SVincenzo Maffione 	acquire BDG_WLOCK() and copy back the array.
3052a7db7a6SVincenzo Maffione 	 */
3062a7db7a6SVincenzo Maffione 
307*b6e66be2SVincenzo Maffione 	if (netmap_debug & NM_DEBUG_BDG)
308*b6e66be2SVincenzo Maffione 		nm_prinf("detach %d and %d (lim %d)", hw, sw, lim);
3092a7db7a6SVincenzo Maffione 	/* make a copy of the list of active ports, update it,
3102a7db7a6SVincenzo Maffione 	 * and then copy back within BDG_WLOCK().
3112a7db7a6SVincenzo Maffione 	 */
3122a7db7a6SVincenzo Maffione 	memcpy(b->tmp_bdg_port_index, b->bdg_port_index, sizeof(b->tmp_bdg_port_index));
3132a7db7a6SVincenzo Maffione 	for (i = 0; (hw >= 0 || sw >= 0) && i < lim; ) {
3142a7db7a6SVincenzo Maffione 		if (hw >= 0 && tmp[i] == hw) {
3152a7db7a6SVincenzo Maffione 			ND("detach hw %d at %d", hw, i);
3162a7db7a6SVincenzo Maffione 			lim--; /* point to last active port */
3172a7db7a6SVincenzo Maffione 			tmp[i] = tmp[lim]; /* swap with i */
3182a7db7a6SVincenzo Maffione 			tmp[lim] = hw;	/* now this is inactive */
3192a7db7a6SVincenzo Maffione 			hw = -1;
3202a7db7a6SVincenzo Maffione 		} else if (sw >= 0 && tmp[i] == sw) {
3212a7db7a6SVincenzo Maffione 			ND("detach sw %d at %d", sw, i);
3222a7db7a6SVincenzo Maffione 			lim--;
3232a7db7a6SVincenzo Maffione 			tmp[i] = tmp[lim];
3242a7db7a6SVincenzo Maffione 			tmp[lim] = sw;
3252a7db7a6SVincenzo Maffione 			sw = -1;
3262a7db7a6SVincenzo Maffione 		} else {
3272a7db7a6SVincenzo Maffione 			i++;
3282a7db7a6SVincenzo Maffione 		}
3292a7db7a6SVincenzo Maffione 	}
3302a7db7a6SVincenzo Maffione 	if (hw >= 0 || sw >= 0) {
331*b6e66be2SVincenzo Maffione 		nm_prerr("delete failed hw %d sw %d, should panic...", hw, sw);
3322a7db7a6SVincenzo Maffione 	}
3332a7db7a6SVincenzo Maffione 
3342a7db7a6SVincenzo Maffione 	BDG_WLOCK(b);
335*b6e66be2SVincenzo Maffione 	if (b->bdg_ops.dtor)
336*b6e66be2SVincenzo Maffione 		b->bdg_ops.dtor(b->bdg_ports[s_hw]);
3372a7db7a6SVincenzo Maffione 	b->bdg_ports[s_hw] = NULL;
3382a7db7a6SVincenzo Maffione 	if (s_sw >= 0) {
3392a7db7a6SVincenzo Maffione 		b->bdg_ports[s_sw] = NULL;
3402a7db7a6SVincenzo Maffione 	}
3412a7db7a6SVincenzo Maffione 	memcpy(b->bdg_port_index, b->tmp_bdg_port_index, sizeof(b->tmp_bdg_port_index));
3422a7db7a6SVincenzo Maffione 	b->bdg_active_ports = lim;
3432a7db7a6SVincenzo Maffione 	BDG_WUNLOCK(b);
3442a7db7a6SVincenzo Maffione 
3452a7db7a6SVincenzo Maffione 	ND("now %d active ports", lim);
3462a7db7a6SVincenzo Maffione 	netmap_bdg_free(b);
3472a7db7a6SVincenzo Maffione }
3482a7db7a6SVincenzo Maffione 
3492a7db7a6SVincenzo Maffione 
3502a7db7a6SVincenzo Maffione /* nm_bdg_ctl callback for VALE ports */
3512a7db7a6SVincenzo Maffione int
3522a7db7a6SVincenzo Maffione netmap_vp_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
3532a7db7a6SVincenzo Maffione {
3542a7db7a6SVincenzo Maffione 	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter *)na;
3552a7db7a6SVincenzo Maffione 	struct nm_bridge *b = vpna->na_bdg;
3562a7db7a6SVincenzo Maffione 
3572a7db7a6SVincenzo Maffione 	if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
3582a7db7a6SVincenzo Maffione 		return 0; /* nothing to do */
3592a7db7a6SVincenzo Maffione 	}
3602a7db7a6SVincenzo Maffione 	if (b) {
3612a7db7a6SVincenzo Maffione 		netmap_set_all_rings(na, 0 /* disable */);
3622a7db7a6SVincenzo Maffione 		netmap_bdg_detach_common(b, vpna->bdg_port, -1);
3632a7db7a6SVincenzo Maffione 		vpna->na_bdg = NULL;
3642a7db7a6SVincenzo Maffione 		netmap_set_all_rings(na, 1 /* enable */);
3652a7db7a6SVincenzo Maffione 	}
3662a7db7a6SVincenzo Maffione 	/* I have took reference just for attach */
3672a7db7a6SVincenzo Maffione 	netmap_adapter_put(na);
3682a7db7a6SVincenzo Maffione 	return 0;
3692a7db7a6SVincenzo Maffione }
3702a7db7a6SVincenzo Maffione 
3712a7db7a6SVincenzo Maffione int
3722a7db7a6SVincenzo Maffione netmap_default_bdg_attach(const char *name, struct netmap_adapter *na,
3732a7db7a6SVincenzo Maffione 		struct nm_bridge *b)
3742a7db7a6SVincenzo Maffione {
3752a7db7a6SVincenzo Maffione 	return NM_NEED_BWRAP;
3762a7db7a6SVincenzo Maffione }
3772a7db7a6SVincenzo Maffione 
3782a7db7a6SVincenzo Maffione /* Try to get a reference to a netmap adapter attached to a VALE switch.
3792a7db7a6SVincenzo Maffione  * If the adapter is found (or is created), this function returns 0, a
3802a7db7a6SVincenzo Maffione  * non NULL pointer is returned into *na, and the caller holds a
3812a7db7a6SVincenzo Maffione  * reference to the adapter.
3822a7db7a6SVincenzo Maffione  * If an adapter is not found, then no reference is grabbed and the
3832a7db7a6SVincenzo Maffione  * function returns an error code, or 0 if there is just a VALE prefix
3842a7db7a6SVincenzo Maffione  * mismatch. Therefore the caller holds a reference when
3852a7db7a6SVincenzo Maffione  * (*na != NULL && return == 0).
3862a7db7a6SVincenzo Maffione  */
3872a7db7a6SVincenzo Maffione int
3882a7db7a6SVincenzo Maffione netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
3892a7db7a6SVincenzo Maffione 	struct netmap_mem_d *nmd, int create, struct netmap_bdg_ops *ops)
3902a7db7a6SVincenzo Maffione {
3912a7db7a6SVincenzo Maffione 	char *nr_name = hdr->nr_name;
3922a7db7a6SVincenzo Maffione 	const char *ifname;
3932a7db7a6SVincenzo Maffione 	struct ifnet *ifp = NULL;
3942a7db7a6SVincenzo Maffione 	int error = 0;
3952a7db7a6SVincenzo Maffione 	struct netmap_vp_adapter *vpna, *hostna = NULL;
3962a7db7a6SVincenzo Maffione 	struct nm_bridge *b;
3972a7db7a6SVincenzo Maffione 	uint32_t i, j;
3982a7db7a6SVincenzo Maffione 	uint32_t cand = NM_BDG_NOPORT, cand2 = NM_BDG_NOPORT;
3992a7db7a6SVincenzo Maffione 	int needed;
4002a7db7a6SVincenzo Maffione 
4012a7db7a6SVincenzo Maffione 	*na = NULL;     /* default return value */
4022a7db7a6SVincenzo Maffione 
4032a7db7a6SVincenzo Maffione 	/* first try to see if this is a bridge port. */
4042a7db7a6SVincenzo Maffione 	NMG_LOCK_ASSERT();
4052a7db7a6SVincenzo Maffione 	if (strncmp(nr_name, ops->name, strlen(ops->name) - 1)) {
4062a7db7a6SVincenzo Maffione 		return 0;  /* no error, but no VALE prefix */
4072a7db7a6SVincenzo Maffione 	}
4082a7db7a6SVincenzo Maffione 
4092a7db7a6SVincenzo Maffione 	b = nm_find_bridge(nr_name, create, ops);
4102a7db7a6SVincenzo Maffione 	if (b == NULL) {
4112a7db7a6SVincenzo Maffione 		ND("no bridges available for '%s'", nr_name);
4122a7db7a6SVincenzo Maffione 		return (create ? ENOMEM : ENXIO);
4132a7db7a6SVincenzo Maffione 	}
4142a7db7a6SVincenzo Maffione 	if (strlen(nr_name) < b->bdg_namelen) /* impossible */
4152a7db7a6SVincenzo Maffione 		panic("x");
4162a7db7a6SVincenzo Maffione 
4172a7db7a6SVincenzo Maffione 	/* Now we are sure that name starts with the bridge's name,
4182a7db7a6SVincenzo Maffione 	 * lookup the port in the bridge. We need to scan the entire
4192a7db7a6SVincenzo Maffione 	 * list. It is not important to hold a WLOCK on the bridge
4202a7db7a6SVincenzo Maffione 	 * during the search because NMG_LOCK already guarantees
4212a7db7a6SVincenzo Maffione 	 * that there are no other possible writers.
4222a7db7a6SVincenzo Maffione 	 */
4232a7db7a6SVincenzo Maffione 
4242a7db7a6SVincenzo Maffione 	/* lookup in the local list of ports */
4252a7db7a6SVincenzo Maffione 	for (j = 0; j < b->bdg_active_ports; j++) {
4262a7db7a6SVincenzo Maffione 		i = b->bdg_port_index[j];
4272a7db7a6SVincenzo Maffione 		vpna = b->bdg_ports[i];
4282a7db7a6SVincenzo Maffione 		ND("checking %s", vpna->up.name);
4292a7db7a6SVincenzo Maffione 		if (!strcmp(vpna->up.name, nr_name)) {
4302a7db7a6SVincenzo Maffione 			netmap_adapter_get(&vpna->up);
4312a7db7a6SVincenzo Maffione 			ND("found existing if %s refs %d", nr_name)
4322a7db7a6SVincenzo Maffione 			*na = &vpna->up;
4332a7db7a6SVincenzo Maffione 			return 0;
4342a7db7a6SVincenzo Maffione 		}
4352a7db7a6SVincenzo Maffione 	}
4362a7db7a6SVincenzo Maffione 	/* not found, should we create it? */
4372a7db7a6SVincenzo Maffione 	if (!create)
4382a7db7a6SVincenzo Maffione 		return ENXIO;
4392a7db7a6SVincenzo Maffione 	/* yes we should, see if we have space to attach entries */
4402a7db7a6SVincenzo Maffione 	needed = 2; /* in some cases we only need 1 */
4412a7db7a6SVincenzo Maffione 	if (b->bdg_active_ports + needed >= NM_BDG_MAXPORTS) {
442*b6e66be2SVincenzo Maffione 		nm_prerr("bridge full %d, cannot create new port", b->bdg_active_ports);
4432a7db7a6SVincenzo Maffione 		return ENOMEM;
4442a7db7a6SVincenzo Maffione 	}
4452a7db7a6SVincenzo Maffione 	/* record the next two ports available, but do not allocate yet */
4462a7db7a6SVincenzo Maffione 	cand = b->bdg_port_index[b->bdg_active_ports];
4472a7db7a6SVincenzo Maffione 	cand2 = b->bdg_port_index[b->bdg_active_ports + 1];
4482a7db7a6SVincenzo Maffione 	ND("+++ bridge %s port %s used %d avail %d %d",
4492a7db7a6SVincenzo Maffione 		b->bdg_basename, ifname, b->bdg_active_ports, cand, cand2);
4502a7db7a6SVincenzo Maffione 
4512a7db7a6SVincenzo Maffione 	/*
4522a7db7a6SVincenzo Maffione 	 * try see if there is a matching NIC with this name
4532a7db7a6SVincenzo Maffione 	 * (after the bridge's name)
4542a7db7a6SVincenzo Maffione 	 */
4552a7db7a6SVincenzo Maffione 	ifname = nr_name + b->bdg_namelen + 1;
4562a7db7a6SVincenzo Maffione 	ifp = ifunit_ref(ifname);
4572a7db7a6SVincenzo Maffione 	if (!ifp) {
4582a7db7a6SVincenzo Maffione 		/* Create an ephemeral virtual port.
4592a7db7a6SVincenzo Maffione 		 * This block contains all the ephemeral-specific logic.
4602a7db7a6SVincenzo Maffione 		 */
4612a7db7a6SVincenzo Maffione 
4622a7db7a6SVincenzo Maffione 		if (hdr->nr_reqtype != NETMAP_REQ_REGISTER) {
4632a7db7a6SVincenzo Maffione 			error = EINVAL;
4642a7db7a6SVincenzo Maffione 			goto out;
4652a7db7a6SVincenzo Maffione 		}
4662a7db7a6SVincenzo Maffione 
4672a7db7a6SVincenzo Maffione 		/* bdg_netmap_attach creates a struct netmap_adapter */
468*b6e66be2SVincenzo Maffione 		error = b->bdg_ops.vp_create(hdr, NULL, nmd, &vpna);
4692a7db7a6SVincenzo Maffione 		if (error) {
470*b6e66be2SVincenzo Maffione 			if (netmap_debug & NM_DEBUG_BDG)
471*b6e66be2SVincenzo Maffione 				nm_prerr("error %d", error);
4722a7db7a6SVincenzo Maffione 			goto out;
4732a7db7a6SVincenzo Maffione 		}
4742a7db7a6SVincenzo Maffione 		/* shortcut - we can skip get_hw_na(),
4752a7db7a6SVincenzo Maffione 		 * ownership check and nm_bdg_attach()
4762a7db7a6SVincenzo Maffione 		 */
4772a7db7a6SVincenzo Maffione 
4782a7db7a6SVincenzo Maffione 	} else {
4792a7db7a6SVincenzo Maffione 		struct netmap_adapter *hw;
4802a7db7a6SVincenzo Maffione 
4812a7db7a6SVincenzo Maffione 		/* the vale:nic syntax is only valid for some commands */
4822a7db7a6SVincenzo Maffione 		switch (hdr->nr_reqtype) {
4832a7db7a6SVincenzo Maffione 		case NETMAP_REQ_VALE_ATTACH:
4842a7db7a6SVincenzo Maffione 		case NETMAP_REQ_VALE_DETACH:
4852a7db7a6SVincenzo Maffione 		case NETMAP_REQ_VALE_POLLING_ENABLE:
4862a7db7a6SVincenzo Maffione 		case NETMAP_REQ_VALE_POLLING_DISABLE:
4872a7db7a6SVincenzo Maffione 			break; /* ok */
4882a7db7a6SVincenzo Maffione 		default:
4892a7db7a6SVincenzo Maffione 			error = EINVAL;
4902a7db7a6SVincenzo Maffione 			goto out;
4912a7db7a6SVincenzo Maffione 		}
4922a7db7a6SVincenzo Maffione 
4932a7db7a6SVincenzo Maffione 		error = netmap_get_hw_na(ifp, nmd, &hw);
4942a7db7a6SVincenzo Maffione 		if (error || hw == NULL)
4952a7db7a6SVincenzo Maffione 			goto out;
4962a7db7a6SVincenzo Maffione 
4972a7db7a6SVincenzo Maffione 		/* host adapter might not be created */
4982a7db7a6SVincenzo Maffione 		error = hw->nm_bdg_attach(nr_name, hw, b);
4992a7db7a6SVincenzo Maffione 		if (error == NM_NEED_BWRAP) {
500*b6e66be2SVincenzo Maffione 			error = b->bdg_ops.bwrap_attach(nr_name, hw);
5012a7db7a6SVincenzo Maffione 		}
5022a7db7a6SVincenzo Maffione 		if (error)
5032a7db7a6SVincenzo Maffione 			goto out;
5042a7db7a6SVincenzo Maffione 		vpna = hw->na_vp;
5052a7db7a6SVincenzo Maffione 		hostna = hw->na_hostvp;
5062a7db7a6SVincenzo Maffione 		if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
5072a7db7a6SVincenzo Maffione 			/* Check if we need to skip the host rings. */
5082a7db7a6SVincenzo Maffione 			struct nmreq_vale_attach *areq =
5092a7db7a6SVincenzo Maffione 				(struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body;
5102a7db7a6SVincenzo Maffione 			if (areq->reg.nr_mode != NR_REG_NIC_SW) {
5112a7db7a6SVincenzo Maffione 				hostna = NULL;
5122a7db7a6SVincenzo Maffione 			}
5132a7db7a6SVincenzo Maffione 		}
5142a7db7a6SVincenzo Maffione 	}
5152a7db7a6SVincenzo Maffione 
5162a7db7a6SVincenzo Maffione 	BDG_WLOCK(b);
5172a7db7a6SVincenzo Maffione 	vpna->bdg_port = cand;
5182a7db7a6SVincenzo Maffione 	ND("NIC  %p to bridge port %d", vpna, cand);
5192a7db7a6SVincenzo Maffione 	/* bind the port to the bridge (virtual ports are not active) */
5202a7db7a6SVincenzo Maffione 	b->bdg_ports[cand] = vpna;
5212a7db7a6SVincenzo Maffione 	vpna->na_bdg = b;
5222a7db7a6SVincenzo Maffione 	b->bdg_active_ports++;
5232a7db7a6SVincenzo Maffione 	if (hostna != NULL) {
5242a7db7a6SVincenzo Maffione 		/* also bind the host stack to the bridge */
5252a7db7a6SVincenzo Maffione 		b->bdg_ports[cand2] = hostna;
5262a7db7a6SVincenzo Maffione 		hostna->bdg_port = cand2;
5272a7db7a6SVincenzo Maffione 		hostna->na_bdg = b;
5282a7db7a6SVincenzo Maffione 		b->bdg_active_ports++;
5292a7db7a6SVincenzo Maffione 		ND("host %p to bridge port %d", hostna, cand2);
5302a7db7a6SVincenzo Maffione 	}
5312a7db7a6SVincenzo Maffione 	ND("if %s refs %d", ifname, vpna->up.na_refcount);
5322a7db7a6SVincenzo Maffione 	BDG_WUNLOCK(b);
5332a7db7a6SVincenzo Maffione 	*na = &vpna->up;
5342a7db7a6SVincenzo Maffione 	netmap_adapter_get(*na);
5352a7db7a6SVincenzo Maffione 
5362a7db7a6SVincenzo Maffione out:
5372a7db7a6SVincenzo Maffione 	if (ifp)
5382a7db7a6SVincenzo Maffione 		if_rele(ifp);
5392a7db7a6SVincenzo Maffione 
5402a7db7a6SVincenzo Maffione 	return error;
5412a7db7a6SVincenzo Maffione }
5422a7db7a6SVincenzo Maffione 
543*b6e66be2SVincenzo Maffione 
5442a7db7a6SVincenzo Maffione int
5452a7db7a6SVincenzo Maffione nm_is_bwrap(struct netmap_adapter *na)
5462a7db7a6SVincenzo Maffione {
5472a7db7a6SVincenzo Maffione 	return na->nm_register == netmap_bwrap_reg;
5482a7db7a6SVincenzo Maffione }
5492a7db7a6SVincenzo Maffione 
5502a7db7a6SVincenzo Maffione 
5512a7db7a6SVincenzo Maffione struct nm_bdg_polling_state;
5522a7db7a6SVincenzo Maffione struct
5532a7db7a6SVincenzo Maffione nm_bdg_kthread {
5542a7db7a6SVincenzo Maffione 	struct nm_kctx *nmk;
5552a7db7a6SVincenzo Maffione 	u_int qfirst;
5562a7db7a6SVincenzo Maffione 	u_int qlast;
5572a7db7a6SVincenzo Maffione 	struct nm_bdg_polling_state *bps;
5582a7db7a6SVincenzo Maffione };
5592a7db7a6SVincenzo Maffione 
5602a7db7a6SVincenzo Maffione struct nm_bdg_polling_state {
5612a7db7a6SVincenzo Maffione 	bool configured;
5622a7db7a6SVincenzo Maffione 	bool stopped;
5632a7db7a6SVincenzo Maffione 	struct netmap_bwrap_adapter *bna;
5642a7db7a6SVincenzo Maffione 	uint32_t mode;
5652a7db7a6SVincenzo Maffione 	u_int qfirst;
5662a7db7a6SVincenzo Maffione 	u_int qlast;
5672a7db7a6SVincenzo Maffione 	u_int cpu_from;
5682a7db7a6SVincenzo Maffione 	u_int ncpus;
5692a7db7a6SVincenzo Maffione 	struct nm_bdg_kthread *kthreads;
5702a7db7a6SVincenzo Maffione };
5712a7db7a6SVincenzo Maffione 
5722a7db7a6SVincenzo Maffione static void
573*b6e66be2SVincenzo Maffione netmap_bwrap_polling(void *data)
5742a7db7a6SVincenzo Maffione {
5752a7db7a6SVincenzo Maffione 	struct nm_bdg_kthread *nbk = data;
5762a7db7a6SVincenzo Maffione 	struct netmap_bwrap_adapter *bna;
5772a7db7a6SVincenzo Maffione 	u_int qfirst, qlast, i;
5782a7db7a6SVincenzo Maffione 	struct netmap_kring **kring0, *kring;
5792a7db7a6SVincenzo Maffione 
5802a7db7a6SVincenzo Maffione 	if (!nbk)
5812a7db7a6SVincenzo Maffione 		return;
5822a7db7a6SVincenzo Maffione 	qfirst = nbk->qfirst;
5832a7db7a6SVincenzo Maffione 	qlast = nbk->qlast;
5842a7db7a6SVincenzo Maffione 	bna = nbk->bps->bna;
5852a7db7a6SVincenzo Maffione 	kring0 = NMR(bna->hwna, NR_RX);
5862a7db7a6SVincenzo Maffione 
5872a7db7a6SVincenzo Maffione 	for (i = qfirst; i < qlast; i++) {
5882a7db7a6SVincenzo Maffione 		kring = kring0[i];
5892a7db7a6SVincenzo Maffione 		kring->nm_notify(kring, 0);
5902a7db7a6SVincenzo Maffione 	}
5912a7db7a6SVincenzo Maffione }
5922a7db7a6SVincenzo Maffione 
5932a7db7a6SVincenzo Maffione static int
5942a7db7a6SVincenzo Maffione nm_bdg_create_kthreads(struct nm_bdg_polling_state *bps)
5952a7db7a6SVincenzo Maffione {
5962a7db7a6SVincenzo Maffione 	struct nm_kctx_cfg kcfg;
5972a7db7a6SVincenzo Maffione 	int i, j;
5982a7db7a6SVincenzo Maffione 
5992a7db7a6SVincenzo Maffione 	bps->kthreads = nm_os_malloc(sizeof(struct nm_bdg_kthread) * bps->ncpus);
6002a7db7a6SVincenzo Maffione 	if (bps->kthreads == NULL)
6012a7db7a6SVincenzo Maffione 		return ENOMEM;
6022a7db7a6SVincenzo Maffione 
6032a7db7a6SVincenzo Maffione 	bzero(&kcfg, sizeof(kcfg));
6042a7db7a6SVincenzo Maffione 	kcfg.worker_fn = netmap_bwrap_polling;
6052a7db7a6SVincenzo Maffione 	for (i = 0; i < bps->ncpus; i++) {
6062a7db7a6SVincenzo Maffione 		struct nm_bdg_kthread *t = bps->kthreads + i;
6072a7db7a6SVincenzo Maffione 		int all = (bps->ncpus == 1 &&
6082a7db7a6SVincenzo Maffione 			bps->mode == NETMAP_POLLING_MODE_SINGLE_CPU);
6092a7db7a6SVincenzo Maffione 		int affinity = bps->cpu_from + i;
6102a7db7a6SVincenzo Maffione 
6112a7db7a6SVincenzo Maffione 		t->bps = bps;
6122a7db7a6SVincenzo Maffione 		t->qfirst = all ? bps->qfirst /* must be 0 */: affinity;
6132a7db7a6SVincenzo Maffione 		t->qlast = all ? bps->qlast : t->qfirst + 1;
614*b6e66be2SVincenzo Maffione 		if (netmap_verbose)
615*b6e66be2SVincenzo Maffione 			nm_prinf("kthread %d a:%u qf:%u ql:%u", i, affinity, t->qfirst,
6162a7db7a6SVincenzo Maffione 				t->qlast);
6172a7db7a6SVincenzo Maffione 
6182a7db7a6SVincenzo Maffione 		kcfg.type = i;
6192a7db7a6SVincenzo Maffione 		kcfg.worker_private = t;
6202a7db7a6SVincenzo Maffione 		t->nmk = nm_os_kctx_create(&kcfg, NULL);
6212a7db7a6SVincenzo Maffione 		if (t->nmk == NULL) {
6222a7db7a6SVincenzo Maffione 			goto cleanup;
6232a7db7a6SVincenzo Maffione 		}
6242a7db7a6SVincenzo Maffione 		nm_os_kctx_worker_setaff(t->nmk, affinity);
6252a7db7a6SVincenzo Maffione 	}
6262a7db7a6SVincenzo Maffione 	return 0;
6272a7db7a6SVincenzo Maffione 
6282a7db7a6SVincenzo Maffione cleanup:
6292a7db7a6SVincenzo Maffione 	for (j = 0; j < i; j++) {
6302a7db7a6SVincenzo Maffione 		struct nm_bdg_kthread *t = bps->kthreads + i;
6312a7db7a6SVincenzo Maffione 		nm_os_kctx_destroy(t->nmk);
6322a7db7a6SVincenzo Maffione 	}
6332a7db7a6SVincenzo Maffione 	nm_os_free(bps->kthreads);
6342a7db7a6SVincenzo Maffione 	return EFAULT;
6352a7db7a6SVincenzo Maffione }
6362a7db7a6SVincenzo Maffione 
6372a7db7a6SVincenzo Maffione /* A variant of ptnetmap_start_kthreads() */
6382a7db7a6SVincenzo Maffione static int
6392a7db7a6SVincenzo Maffione nm_bdg_polling_start_kthreads(struct nm_bdg_polling_state *bps)
6402a7db7a6SVincenzo Maffione {
6412a7db7a6SVincenzo Maffione 	int error, i, j;
6422a7db7a6SVincenzo Maffione 
6432a7db7a6SVincenzo Maffione 	if (!bps) {
644*b6e66be2SVincenzo Maffione 		nm_prerr("polling is not configured");
6452a7db7a6SVincenzo Maffione 		return EFAULT;
6462a7db7a6SVincenzo Maffione 	}
6472a7db7a6SVincenzo Maffione 	bps->stopped = false;
6482a7db7a6SVincenzo Maffione 
6492a7db7a6SVincenzo Maffione 	for (i = 0; i < bps->ncpus; i++) {
6502a7db7a6SVincenzo Maffione 		struct nm_bdg_kthread *t = bps->kthreads + i;
6512a7db7a6SVincenzo Maffione 		error = nm_os_kctx_worker_start(t->nmk);
6522a7db7a6SVincenzo Maffione 		if (error) {
653*b6e66be2SVincenzo Maffione 			nm_prerr("error in nm_kthread_start(): %d", error);
6542a7db7a6SVincenzo Maffione 			goto cleanup;
6552a7db7a6SVincenzo Maffione 		}
6562a7db7a6SVincenzo Maffione 	}
6572a7db7a6SVincenzo Maffione 	return 0;
6582a7db7a6SVincenzo Maffione 
6592a7db7a6SVincenzo Maffione cleanup:
6602a7db7a6SVincenzo Maffione 	for (j = 0; j < i; j++) {
6612a7db7a6SVincenzo Maffione 		struct nm_bdg_kthread *t = bps->kthreads + i;
6622a7db7a6SVincenzo Maffione 		nm_os_kctx_worker_stop(t->nmk);
6632a7db7a6SVincenzo Maffione 	}
6642a7db7a6SVincenzo Maffione 	bps->stopped = true;
6652a7db7a6SVincenzo Maffione 	return error;
6662a7db7a6SVincenzo Maffione }
6672a7db7a6SVincenzo Maffione 
6682a7db7a6SVincenzo Maffione static void
6692a7db7a6SVincenzo Maffione nm_bdg_polling_stop_delete_kthreads(struct nm_bdg_polling_state *bps)
6702a7db7a6SVincenzo Maffione {
6712a7db7a6SVincenzo Maffione 	int i;
6722a7db7a6SVincenzo Maffione 
6732a7db7a6SVincenzo Maffione 	if (!bps)
6742a7db7a6SVincenzo Maffione 		return;
6752a7db7a6SVincenzo Maffione 
6762a7db7a6SVincenzo Maffione 	for (i = 0; i < bps->ncpus; i++) {
6772a7db7a6SVincenzo Maffione 		struct nm_bdg_kthread *t = bps->kthreads + i;
6782a7db7a6SVincenzo Maffione 		nm_os_kctx_worker_stop(t->nmk);
6792a7db7a6SVincenzo Maffione 		nm_os_kctx_destroy(t->nmk);
6802a7db7a6SVincenzo Maffione 	}
6812a7db7a6SVincenzo Maffione 	bps->stopped = true;
6822a7db7a6SVincenzo Maffione }
6832a7db7a6SVincenzo Maffione 
6842a7db7a6SVincenzo Maffione static int
6852a7db7a6SVincenzo Maffione get_polling_cfg(struct nmreq_vale_polling *req, struct netmap_adapter *na,
6862a7db7a6SVincenzo Maffione 		struct nm_bdg_polling_state *bps)
6872a7db7a6SVincenzo Maffione {
6882a7db7a6SVincenzo Maffione 	unsigned int avail_cpus, core_from;
6892a7db7a6SVincenzo Maffione 	unsigned int qfirst, qlast;
6902a7db7a6SVincenzo Maffione 	uint32_t i = req->nr_first_cpu_id;
6912a7db7a6SVincenzo Maffione 	uint32_t req_cpus = req->nr_num_polling_cpus;
6922a7db7a6SVincenzo Maffione 
6932a7db7a6SVincenzo Maffione 	avail_cpus = nm_os_ncpus();
6942a7db7a6SVincenzo Maffione 
6952a7db7a6SVincenzo Maffione 	if (req_cpus == 0) {
696*b6e66be2SVincenzo Maffione 		nm_prerr("req_cpus must be > 0");
6972a7db7a6SVincenzo Maffione 		return EINVAL;
6982a7db7a6SVincenzo Maffione 	} else if (req_cpus >= avail_cpus) {
699*b6e66be2SVincenzo Maffione 		nm_prerr("Cannot use all the CPUs in the system");
7002a7db7a6SVincenzo Maffione 		return EINVAL;
7012a7db7a6SVincenzo Maffione 	}
7022a7db7a6SVincenzo Maffione 
7032a7db7a6SVincenzo Maffione 	if (req->nr_mode == NETMAP_POLLING_MODE_MULTI_CPU) {
7042a7db7a6SVincenzo Maffione 		/* Use a separate core for each ring. If nr_num_polling_cpus>1
7052a7db7a6SVincenzo Maffione 		 * more consecutive rings are polled.
7062a7db7a6SVincenzo Maffione 		 * For example, if nr_first_cpu_id=2 and nr_num_polling_cpus=2,
7072a7db7a6SVincenzo Maffione 		 * ring 2 and 3 are polled by core 2 and 3, respectively. */
7082a7db7a6SVincenzo Maffione 		if (i + req_cpus > nma_get_nrings(na, NR_RX)) {
709*b6e66be2SVincenzo Maffione 			nm_prerr("Rings %u-%u not in range (have %d rings)",
7102a7db7a6SVincenzo Maffione 				i, i + req_cpus, nma_get_nrings(na, NR_RX));
7112a7db7a6SVincenzo Maffione 			return EINVAL;
7122a7db7a6SVincenzo Maffione 		}
7132a7db7a6SVincenzo Maffione 		qfirst = i;
7142a7db7a6SVincenzo Maffione 		qlast = qfirst + req_cpus;
7152a7db7a6SVincenzo Maffione 		core_from = qfirst;
7162a7db7a6SVincenzo Maffione 
7172a7db7a6SVincenzo Maffione 	} else if (req->nr_mode == NETMAP_POLLING_MODE_SINGLE_CPU) {
7182a7db7a6SVincenzo Maffione 		/* Poll all the rings using a core specified by nr_first_cpu_id.
7192a7db7a6SVincenzo Maffione 		 * the number of cores must be 1. */
7202a7db7a6SVincenzo Maffione 		if (req_cpus != 1) {
721*b6e66be2SVincenzo Maffione 			nm_prerr("ncpus must be 1 for NETMAP_POLLING_MODE_SINGLE_CPU "
7222a7db7a6SVincenzo Maffione 				"(was %d)", req_cpus);
7232a7db7a6SVincenzo Maffione 			return EINVAL;
7242a7db7a6SVincenzo Maffione 		}
7252a7db7a6SVincenzo Maffione 		qfirst = 0;
7262a7db7a6SVincenzo Maffione 		qlast = nma_get_nrings(na, NR_RX);
7272a7db7a6SVincenzo Maffione 		core_from = i;
7282a7db7a6SVincenzo Maffione 	} else {
729*b6e66be2SVincenzo Maffione 		nm_prerr("Invalid polling mode");
7302a7db7a6SVincenzo Maffione 		return EINVAL;
7312a7db7a6SVincenzo Maffione 	}
7322a7db7a6SVincenzo Maffione 
7332a7db7a6SVincenzo Maffione 	bps->mode = req->nr_mode;
7342a7db7a6SVincenzo Maffione 	bps->qfirst = qfirst;
7352a7db7a6SVincenzo Maffione 	bps->qlast = qlast;
7362a7db7a6SVincenzo Maffione 	bps->cpu_from = core_from;
7372a7db7a6SVincenzo Maffione 	bps->ncpus = req_cpus;
738*b6e66be2SVincenzo Maffione 	nm_prinf("%s qfirst %u qlast %u cpu_from %u ncpus %u",
7392a7db7a6SVincenzo Maffione 		req->nr_mode == NETMAP_POLLING_MODE_MULTI_CPU ?
7402a7db7a6SVincenzo Maffione 		"MULTI" : "SINGLE",
7412a7db7a6SVincenzo Maffione 		qfirst, qlast, core_from, req_cpus);
7422a7db7a6SVincenzo Maffione 	return 0;
7432a7db7a6SVincenzo Maffione }
7442a7db7a6SVincenzo Maffione 
7452a7db7a6SVincenzo Maffione static int
7462a7db7a6SVincenzo Maffione nm_bdg_ctl_polling_start(struct nmreq_vale_polling *req, struct netmap_adapter *na)
7472a7db7a6SVincenzo Maffione {
7482a7db7a6SVincenzo Maffione 	struct nm_bdg_polling_state *bps;
7492a7db7a6SVincenzo Maffione 	struct netmap_bwrap_adapter *bna;
7502a7db7a6SVincenzo Maffione 	int error;
7512a7db7a6SVincenzo Maffione 
7522a7db7a6SVincenzo Maffione 	bna = (struct netmap_bwrap_adapter *)na;
7532a7db7a6SVincenzo Maffione 	if (bna->na_polling_state) {
754*b6e66be2SVincenzo Maffione 		nm_prerr("ERROR adapter already in polling mode");
7552a7db7a6SVincenzo Maffione 		return EFAULT;
7562a7db7a6SVincenzo Maffione 	}
7572a7db7a6SVincenzo Maffione 
7582a7db7a6SVincenzo Maffione 	bps = nm_os_malloc(sizeof(*bps));
7592a7db7a6SVincenzo Maffione 	if (!bps)
7602a7db7a6SVincenzo Maffione 		return ENOMEM;
7612a7db7a6SVincenzo Maffione 	bps->configured = false;
7622a7db7a6SVincenzo Maffione 	bps->stopped = true;
7632a7db7a6SVincenzo Maffione 
7642a7db7a6SVincenzo Maffione 	if (get_polling_cfg(req, na, bps)) {
7652a7db7a6SVincenzo Maffione 		nm_os_free(bps);
7662a7db7a6SVincenzo Maffione 		return EINVAL;
7672a7db7a6SVincenzo Maffione 	}
7682a7db7a6SVincenzo Maffione 
7692a7db7a6SVincenzo Maffione 	if (nm_bdg_create_kthreads(bps)) {
7702a7db7a6SVincenzo Maffione 		nm_os_free(bps);
7712a7db7a6SVincenzo Maffione 		return EFAULT;
7722a7db7a6SVincenzo Maffione 	}
7732a7db7a6SVincenzo Maffione 
7742a7db7a6SVincenzo Maffione 	bps->configured = true;
7752a7db7a6SVincenzo Maffione 	bna->na_polling_state = bps;
7762a7db7a6SVincenzo Maffione 	bps->bna = bna;
7772a7db7a6SVincenzo Maffione 
7782a7db7a6SVincenzo Maffione 	/* disable interrupts if possible */
7792a7db7a6SVincenzo Maffione 	nma_intr_enable(bna->hwna, 0);
7802a7db7a6SVincenzo Maffione 	/* start kthread now */
7812a7db7a6SVincenzo Maffione 	error = nm_bdg_polling_start_kthreads(bps);
7822a7db7a6SVincenzo Maffione 	if (error) {
783*b6e66be2SVincenzo Maffione 		nm_prerr("ERROR nm_bdg_polling_start_kthread()");
7842a7db7a6SVincenzo Maffione 		nm_os_free(bps->kthreads);
7852a7db7a6SVincenzo Maffione 		nm_os_free(bps);
7862a7db7a6SVincenzo Maffione 		bna->na_polling_state = NULL;
7872a7db7a6SVincenzo Maffione 		nma_intr_enable(bna->hwna, 1);
7882a7db7a6SVincenzo Maffione 	}
7892a7db7a6SVincenzo Maffione 	return error;
7902a7db7a6SVincenzo Maffione }
7912a7db7a6SVincenzo Maffione 
7922a7db7a6SVincenzo Maffione static int
7932a7db7a6SVincenzo Maffione nm_bdg_ctl_polling_stop(struct netmap_adapter *na)
7942a7db7a6SVincenzo Maffione {
7952a7db7a6SVincenzo Maffione 	struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter *)na;
7962a7db7a6SVincenzo Maffione 	struct nm_bdg_polling_state *bps;
7972a7db7a6SVincenzo Maffione 
7982a7db7a6SVincenzo Maffione 	if (!bna->na_polling_state) {
799*b6e66be2SVincenzo Maffione 		nm_prerr("ERROR adapter is not in polling mode");
8002a7db7a6SVincenzo Maffione 		return EFAULT;
8012a7db7a6SVincenzo Maffione 	}
8022a7db7a6SVincenzo Maffione 	bps = bna->na_polling_state;
8032a7db7a6SVincenzo Maffione 	nm_bdg_polling_stop_delete_kthreads(bna->na_polling_state);
8042a7db7a6SVincenzo Maffione 	bps->configured = false;
8052a7db7a6SVincenzo Maffione 	nm_os_free(bps);
8062a7db7a6SVincenzo Maffione 	bna->na_polling_state = NULL;
8072a7db7a6SVincenzo Maffione 	/* reenable interrupts */
8082a7db7a6SVincenzo Maffione 	nma_intr_enable(bna->hwna, 1);
8092a7db7a6SVincenzo Maffione 	return 0;
8102a7db7a6SVincenzo Maffione }
8112a7db7a6SVincenzo Maffione 
8122a7db7a6SVincenzo Maffione int
8132a7db7a6SVincenzo Maffione nm_bdg_polling(struct nmreq_header *hdr)
8142a7db7a6SVincenzo Maffione {
8152a7db7a6SVincenzo Maffione 	struct nmreq_vale_polling *req =
8162a7db7a6SVincenzo Maffione 		(struct nmreq_vale_polling *)(uintptr_t)hdr->nr_body;
8172a7db7a6SVincenzo Maffione 	struct netmap_adapter *na = NULL;
8182a7db7a6SVincenzo Maffione 	int error = 0;
8192a7db7a6SVincenzo Maffione 
8202a7db7a6SVincenzo Maffione 	NMG_LOCK();
8212a7db7a6SVincenzo Maffione 	error = netmap_get_vale_na(hdr, &na, NULL, /*create=*/0);
8222a7db7a6SVincenzo Maffione 	if (na && !error) {
8232a7db7a6SVincenzo Maffione 		if (!nm_is_bwrap(na)) {
8242a7db7a6SVincenzo Maffione 			error = EOPNOTSUPP;
8252a7db7a6SVincenzo Maffione 		} else if (hdr->nr_reqtype == NETMAP_BDG_POLLING_ON) {
8262a7db7a6SVincenzo Maffione 			error = nm_bdg_ctl_polling_start(req, na);
8272a7db7a6SVincenzo Maffione 			if (!error)
8282a7db7a6SVincenzo Maffione 				netmap_adapter_get(na);
8292a7db7a6SVincenzo Maffione 		} else {
8302a7db7a6SVincenzo Maffione 			error = nm_bdg_ctl_polling_stop(na);
8312a7db7a6SVincenzo Maffione 			if (!error)
8322a7db7a6SVincenzo Maffione 				netmap_adapter_put(na);
8332a7db7a6SVincenzo Maffione 		}
8342a7db7a6SVincenzo Maffione 		netmap_adapter_put(na);
8352a7db7a6SVincenzo Maffione 	} else if (!na && !error) {
8362a7db7a6SVincenzo Maffione 		/* Not VALE port. */
8372a7db7a6SVincenzo Maffione 		error = EINVAL;
8382a7db7a6SVincenzo Maffione 	}
8392a7db7a6SVincenzo Maffione 	NMG_UNLOCK();
8402a7db7a6SVincenzo Maffione 
8412a7db7a6SVincenzo Maffione 	return error;
8422a7db7a6SVincenzo Maffione }
8432a7db7a6SVincenzo Maffione 
8442a7db7a6SVincenzo Maffione /* Called by external kernel modules (e.g., Openvswitch).
8452a7db7a6SVincenzo Maffione  * to set configure/lookup/dtor functions of a VALE instance.
8462a7db7a6SVincenzo Maffione  * Register callbacks to the given bridge. 'name' may be just
8472a7db7a6SVincenzo Maffione  * bridge's name (including ':' if it is not just NM_BDG_NAME).
8482a7db7a6SVincenzo Maffione  *
8492a7db7a6SVincenzo Maffione  * Called without NMG_LOCK.
8502a7db7a6SVincenzo Maffione  */
8512a7db7a6SVincenzo Maffione 
8522a7db7a6SVincenzo Maffione int
8532a7db7a6SVincenzo Maffione netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data, void *auth_token)
8542a7db7a6SVincenzo Maffione {
8552a7db7a6SVincenzo Maffione 	struct nm_bridge *b;
8562a7db7a6SVincenzo Maffione 	int error = 0;
8572a7db7a6SVincenzo Maffione 
8582a7db7a6SVincenzo Maffione 	NMG_LOCK();
8592a7db7a6SVincenzo Maffione 	b = nm_find_bridge(name, 0 /* don't create */, NULL);
8602a7db7a6SVincenzo Maffione 	if (!b) {
8612a7db7a6SVincenzo Maffione 		error = ENXIO;
8622a7db7a6SVincenzo Maffione 		goto unlock_regops;
8632a7db7a6SVincenzo Maffione 	}
8642a7db7a6SVincenzo Maffione 	if (!nm_bdg_valid_auth_token(b, auth_token)) {
8652a7db7a6SVincenzo Maffione 		error = EACCES;
8662a7db7a6SVincenzo Maffione 		goto unlock_regops;
8672a7db7a6SVincenzo Maffione 	}
8682a7db7a6SVincenzo Maffione 
8692a7db7a6SVincenzo Maffione 	BDG_WLOCK(b);
8702a7db7a6SVincenzo Maffione 	if (!bdg_ops) {
8712a7db7a6SVincenzo Maffione 		/* resetting the bridge */
8722a7db7a6SVincenzo Maffione 		bzero(b->ht, sizeof(struct nm_hash_ent) * NM_BDG_HASH);
873*b6e66be2SVincenzo Maffione 		b->bdg_ops = b->bdg_saved_ops;
8742a7db7a6SVincenzo Maffione 		b->private_data = b->ht;
8752a7db7a6SVincenzo Maffione 	} else {
8762a7db7a6SVincenzo Maffione 		/* modifying the bridge */
8772a7db7a6SVincenzo Maffione 		b->private_data = private_data;
878*b6e66be2SVincenzo Maffione #define nm_bdg_override(m) if (bdg_ops->m) b->bdg_ops.m = bdg_ops->m
879*b6e66be2SVincenzo Maffione 		nm_bdg_override(lookup);
880*b6e66be2SVincenzo Maffione 		nm_bdg_override(config);
881*b6e66be2SVincenzo Maffione 		nm_bdg_override(dtor);
882*b6e66be2SVincenzo Maffione 		nm_bdg_override(vp_create);
883*b6e66be2SVincenzo Maffione 		nm_bdg_override(bwrap_attach);
884*b6e66be2SVincenzo Maffione #undef nm_bdg_override
885*b6e66be2SVincenzo Maffione 
8862a7db7a6SVincenzo Maffione 	}
8872a7db7a6SVincenzo Maffione 	BDG_WUNLOCK(b);
8882a7db7a6SVincenzo Maffione 
8892a7db7a6SVincenzo Maffione unlock_regops:
8902a7db7a6SVincenzo Maffione 	NMG_UNLOCK();
8912a7db7a6SVincenzo Maffione 	return error;
8922a7db7a6SVincenzo Maffione }
8932a7db7a6SVincenzo Maffione 
8942a7db7a6SVincenzo Maffione 
8952a7db7a6SVincenzo Maffione int
8962a7db7a6SVincenzo Maffione netmap_bdg_config(struct nm_ifreq *nr)
8972a7db7a6SVincenzo Maffione {
8982a7db7a6SVincenzo Maffione 	struct nm_bridge *b;
8992a7db7a6SVincenzo Maffione 	int error = EINVAL;
9002a7db7a6SVincenzo Maffione 
9012a7db7a6SVincenzo Maffione 	NMG_LOCK();
9022a7db7a6SVincenzo Maffione 	b = nm_find_bridge(nr->nifr_name, 0, NULL);
9032a7db7a6SVincenzo Maffione 	if (!b) {
9042a7db7a6SVincenzo Maffione 		NMG_UNLOCK();
9052a7db7a6SVincenzo Maffione 		return error;
9062a7db7a6SVincenzo Maffione 	}
9072a7db7a6SVincenzo Maffione 	NMG_UNLOCK();
9082a7db7a6SVincenzo Maffione 	/* Don't call config() with NMG_LOCK() held */
9092a7db7a6SVincenzo Maffione 	BDG_RLOCK(b);
910*b6e66be2SVincenzo Maffione 	if (b->bdg_ops.config != NULL)
911*b6e66be2SVincenzo Maffione 		error = b->bdg_ops.config(nr);
9122a7db7a6SVincenzo Maffione 	BDG_RUNLOCK(b);
9132a7db7a6SVincenzo Maffione 	return error;
9142a7db7a6SVincenzo Maffione }
9152a7db7a6SVincenzo Maffione 
9162a7db7a6SVincenzo Maffione 
9172a7db7a6SVincenzo Maffione /* nm_register callback for VALE ports */
9182a7db7a6SVincenzo Maffione int
9192a7db7a6SVincenzo Maffione netmap_vp_reg(struct netmap_adapter *na, int onoff)
9202a7db7a6SVincenzo Maffione {
9212a7db7a6SVincenzo Maffione 	struct netmap_vp_adapter *vpna =
9222a7db7a6SVincenzo Maffione 		(struct netmap_vp_adapter*)na;
9232a7db7a6SVincenzo Maffione 	enum txrx t;
9242a7db7a6SVincenzo Maffione 	int i;
9252a7db7a6SVincenzo Maffione 
9262a7db7a6SVincenzo Maffione 	/* persistent ports may be put in netmap mode
9272a7db7a6SVincenzo Maffione 	 * before being attached to a bridge
9282a7db7a6SVincenzo Maffione 	 */
9292a7db7a6SVincenzo Maffione 	if (vpna->na_bdg)
9302a7db7a6SVincenzo Maffione 		BDG_WLOCK(vpna->na_bdg);
9312a7db7a6SVincenzo Maffione 	if (onoff) {
9322a7db7a6SVincenzo Maffione 		for_rx_tx(t) {
9332a7db7a6SVincenzo Maffione 			for (i = 0; i < netmap_real_rings(na, t); i++) {
9342a7db7a6SVincenzo Maffione 				struct netmap_kring *kring = NMR(na, t)[i];
9352a7db7a6SVincenzo Maffione 
9362a7db7a6SVincenzo Maffione 				if (nm_kring_pending_on(kring))
9372a7db7a6SVincenzo Maffione 					kring->nr_mode = NKR_NETMAP_ON;
9382a7db7a6SVincenzo Maffione 			}
9392a7db7a6SVincenzo Maffione 		}
9402a7db7a6SVincenzo Maffione 		if (na->active_fds == 0)
9412a7db7a6SVincenzo Maffione 			na->na_flags |= NAF_NETMAP_ON;
9422a7db7a6SVincenzo Maffione 		 /* XXX on FreeBSD, persistent VALE ports should also
9432a7db7a6SVincenzo Maffione 		 * toggle IFCAP_NETMAP in na->ifp (2014-03-16)
9442a7db7a6SVincenzo Maffione 		 */
9452a7db7a6SVincenzo Maffione 	} else {
9462a7db7a6SVincenzo Maffione 		if (na->active_fds == 0)
9472a7db7a6SVincenzo Maffione 			na->na_flags &= ~NAF_NETMAP_ON;
9482a7db7a6SVincenzo Maffione 		for_rx_tx(t) {
9492a7db7a6SVincenzo Maffione 			for (i = 0; i < netmap_real_rings(na, t); i++) {
9502a7db7a6SVincenzo Maffione 				struct netmap_kring *kring = NMR(na, t)[i];
9512a7db7a6SVincenzo Maffione 
9522a7db7a6SVincenzo Maffione 				if (nm_kring_pending_off(kring))
9532a7db7a6SVincenzo Maffione 					kring->nr_mode = NKR_NETMAP_OFF;
9542a7db7a6SVincenzo Maffione 			}
9552a7db7a6SVincenzo Maffione 		}
9562a7db7a6SVincenzo Maffione 	}
9572a7db7a6SVincenzo Maffione 	if (vpna->na_bdg)
9582a7db7a6SVincenzo Maffione 		BDG_WUNLOCK(vpna->na_bdg);
9592a7db7a6SVincenzo Maffione 	return 0;
9602a7db7a6SVincenzo Maffione }
9612a7db7a6SVincenzo Maffione 
9622a7db7a6SVincenzo Maffione 
9632a7db7a6SVincenzo Maffione /* rxsync code used by VALE ports nm_rxsync callback and also
9642a7db7a6SVincenzo Maffione  * internally by the brwap
9652a7db7a6SVincenzo Maffione  */
9662a7db7a6SVincenzo Maffione static int
9672a7db7a6SVincenzo Maffione netmap_vp_rxsync_locked(struct netmap_kring *kring, int flags)
9682a7db7a6SVincenzo Maffione {
9692a7db7a6SVincenzo Maffione 	struct netmap_adapter *na = kring->na;
9702a7db7a6SVincenzo Maffione 	struct netmap_ring *ring = kring->ring;
9712a7db7a6SVincenzo Maffione 	u_int nm_i, lim = kring->nkr_num_slots - 1;
9722a7db7a6SVincenzo Maffione 	u_int head = kring->rhead;
9732a7db7a6SVincenzo Maffione 	int n;
9742a7db7a6SVincenzo Maffione 
9752a7db7a6SVincenzo Maffione 	if (head > lim) {
976*b6e66be2SVincenzo Maffione 		nm_prerr("ouch dangerous reset!!!");
9772a7db7a6SVincenzo Maffione 		n = netmap_ring_reinit(kring);
9782a7db7a6SVincenzo Maffione 		goto done;
9792a7db7a6SVincenzo Maffione 	}
9802a7db7a6SVincenzo Maffione 
9812a7db7a6SVincenzo Maffione 	/* First part, import newly received packets. */
9822a7db7a6SVincenzo Maffione 	/* actually nothing to do here, they are already in the kring */
9832a7db7a6SVincenzo Maffione 
9842a7db7a6SVincenzo Maffione 	/* Second part, skip past packets that userspace has released. */
9852a7db7a6SVincenzo Maffione 	nm_i = kring->nr_hwcur;
9862a7db7a6SVincenzo Maffione 	if (nm_i != head) {
9872a7db7a6SVincenzo Maffione 		/* consistency check, but nothing really important here */
9882a7db7a6SVincenzo Maffione 		for (n = 0; likely(nm_i != head); n++) {
9892a7db7a6SVincenzo Maffione 			struct netmap_slot *slot = &ring->slot[nm_i];
9902a7db7a6SVincenzo Maffione 			void *addr = NMB(na, slot);
9912a7db7a6SVincenzo Maffione 
9922a7db7a6SVincenzo Maffione 			if (addr == NETMAP_BUF_BASE(kring->na)) { /* bad buf */
993*b6e66be2SVincenzo Maffione 				nm_prerr("bad buffer index %d, ignore ?",
9942a7db7a6SVincenzo Maffione 					slot->buf_idx);
9952a7db7a6SVincenzo Maffione 			}
9962a7db7a6SVincenzo Maffione 			slot->flags &= ~NS_BUF_CHANGED;
9972a7db7a6SVincenzo Maffione 			nm_i = nm_next(nm_i, lim);
9982a7db7a6SVincenzo Maffione 		}
9992a7db7a6SVincenzo Maffione 		kring->nr_hwcur = head;
10002a7db7a6SVincenzo Maffione 	}
10012a7db7a6SVincenzo Maffione 
10022a7db7a6SVincenzo Maffione 	n = 0;
10032a7db7a6SVincenzo Maffione done:
10042a7db7a6SVincenzo Maffione 	return n;
10052a7db7a6SVincenzo Maffione }
10062a7db7a6SVincenzo Maffione 
10072a7db7a6SVincenzo Maffione /*
10082a7db7a6SVincenzo Maffione  * nm_rxsync callback for VALE ports
10092a7db7a6SVincenzo Maffione  * user process reading from a VALE switch.
10102a7db7a6SVincenzo Maffione  * Already protected against concurrent calls from userspace,
10112a7db7a6SVincenzo Maffione  * but we must acquire the queue's lock to protect against
10122a7db7a6SVincenzo Maffione  * writers on the same queue.
10132a7db7a6SVincenzo Maffione  */
10142a7db7a6SVincenzo Maffione int
10152a7db7a6SVincenzo Maffione netmap_vp_rxsync(struct netmap_kring *kring, int flags)
10162a7db7a6SVincenzo Maffione {
10172a7db7a6SVincenzo Maffione 	int n;
10182a7db7a6SVincenzo Maffione 
10192a7db7a6SVincenzo Maffione 	mtx_lock(&kring->q_lock);
10202a7db7a6SVincenzo Maffione 	n = netmap_vp_rxsync_locked(kring, flags);
10212a7db7a6SVincenzo Maffione 	mtx_unlock(&kring->q_lock);
10222a7db7a6SVincenzo Maffione 	return n;
10232a7db7a6SVincenzo Maffione }
10242a7db7a6SVincenzo Maffione 
10252a7db7a6SVincenzo Maffione int
10262a7db7a6SVincenzo Maffione netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna,
10272a7db7a6SVincenzo Maffione 		struct netmap_bdg_ops *ops)
10282a7db7a6SVincenzo Maffione {
10292a7db7a6SVincenzo Maffione 	return ops->bwrap_attach(nr_name, hwna);
10302a7db7a6SVincenzo Maffione }
10312a7db7a6SVincenzo Maffione 
10322a7db7a6SVincenzo Maffione 
10332a7db7a6SVincenzo Maffione /* Bridge wrapper code (bwrap).
10342a7db7a6SVincenzo Maffione  * This is used to connect a non-VALE-port netmap_adapter (hwna) to a
10352a7db7a6SVincenzo Maffione  * VALE switch.
10362a7db7a6SVincenzo Maffione  * The main task is to swap the meaning of tx and rx rings to match the
10372a7db7a6SVincenzo Maffione  * expectations of the VALE switch code (see nm_bdg_flush).
10382a7db7a6SVincenzo Maffione  *
10392a7db7a6SVincenzo Maffione  * The bwrap works by interposing a netmap_bwrap_adapter between the
10402a7db7a6SVincenzo Maffione  * rest of the system and the hwna. The netmap_bwrap_adapter looks like
10412a7db7a6SVincenzo Maffione  * a netmap_vp_adapter to the rest the system, but, internally, it
10422a7db7a6SVincenzo Maffione  * translates all callbacks to what the hwna expects.
10432a7db7a6SVincenzo Maffione  *
10442a7db7a6SVincenzo Maffione  * Note that we have to intercept callbacks coming from two sides:
10452a7db7a6SVincenzo Maffione  *
10462a7db7a6SVincenzo Maffione  *  - callbacks coming from the netmap module are intercepted by
10472a7db7a6SVincenzo Maffione  *    passing around the netmap_bwrap_adapter instead of the hwna
10482a7db7a6SVincenzo Maffione  *
10492a7db7a6SVincenzo Maffione  *  - callbacks coming from outside of the netmap module only know
10502a7db7a6SVincenzo Maffione  *    about the hwna. This, however, only happens in interrupt
10512a7db7a6SVincenzo Maffione  *    handlers, where only the hwna->nm_notify callback is called.
10522a7db7a6SVincenzo Maffione  *    What the bwrap does is to overwrite the hwna->nm_notify callback
10532a7db7a6SVincenzo Maffione  *    with its own netmap_bwrap_intr_notify.
10542a7db7a6SVincenzo Maffione  *    XXX This assumes that the hwna->nm_notify callback was the
10552a7db7a6SVincenzo Maffione  *    standard netmap_notify(), as it is the case for nic adapters.
10562a7db7a6SVincenzo Maffione  *    Any additional action performed by hwna->nm_notify will not be
10572a7db7a6SVincenzo Maffione  *    performed by netmap_bwrap_intr_notify.
10582a7db7a6SVincenzo Maffione  *
10592a7db7a6SVincenzo Maffione  * Additionally, the bwrap can optionally attach the host rings pair
10602a7db7a6SVincenzo Maffione  * of the wrapped adapter to a different port of the switch.
10612a7db7a6SVincenzo Maffione  */
10622a7db7a6SVincenzo Maffione 
10632a7db7a6SVincenzo Maffione 
10642a7db7a6SVincenzo Maffione static void
10652a7db7a6SVincenzo Maffione netmap_bwrap_dtor(struct netmap_adapter *na)
10662a7db7a6SVincenzo Maffione {
10672a7db7a6SVincenzo Maffione 	struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter*)na;
10682a7db7a6SVincenzo Maffione 	struct netmap_adapter *hwna = bna->hwna;
10692a7db7a6SVincenzo Maffione 	struct nm_bridge *b = bna->up.na_bdg,
10702a7db7a6SVincenzo Maffione 		*bh = bna->host.na_bdg;
10712a7db7a6SVincenzo Maffione 
10722a7db7a6SVincenzo Maffione 	if (bna->host.up.nm_mem)
10732a7db7a6SVincenzo Maffione 		netmap_mem_put(bna->host.up.nm_mem);
10742a7db7a6SVincenzo Maffione 
10752a7db7a6SVincenzo Maffione 	if (b) {
10762a7db7a6SVincenzo Maffione 		netmap_bdg_detach_common(b, bna->up.bdg_port,
10772a7db7a6SVincenzo Maffione 			    (bh ? bna->host.bdg_port : -1));
10782a7db7a6SVincenzo Maffione 	}
10792a7db7a6SVincenzo Maffione 
10802a7db7a6SVincenzo Maffione 	ND("na %p", na);
10812a7db7a6SVincenzo Maffione 	na->ifp = NULL;
10822a7db7a6SVincenzo Maffione 	bna->host.up.ifp = NULL;
10832a7db7a6SVincenzo Maffione 	hwna->na_vp = bna->saved_na_vp;
10842a7db7a6SVincenzo Maffione 	hwna->na_hostvp = NULL;
10852a7db7a6SVincenzo Maffione 	hwna->na_private = NULL;
10862a7db7a6SVincenzo Maffione 	hwna->na_flags &= ~NAF_BUSY;
10872a7db7a6SVincenzo Maffione 	netmap_adapter_put(hwna);
10882a7db7a6SVincenzo Maffione 
10892a7db7a6SVincenzo Maffione }
10902a7db7a6SVincenzo Maffione 
10912a7db7a6SVincenzo Maffione 
10922a7db7a6SVincenzo Maffione /*
10932a7db7a6SVincenzo Maffione  * Intr callback for NICs connected to a bridge.
10942a7db7a6SVincenzo Maffione  * Simply ignore tx interrupts (maybe we could try to recover space ?)
10952a7db7a6SVincenzo Maffione  * and pass received packets from nic to the bridge.
10962a7db7a6SVincenzo Maffione  *
10972a7db7a6SVincenzo Maffione  * XXX TODO check locking: this is called from the interrupt
10982a7db7a6SVincenzo Maffione  * handler so we should make sure that the interface is not
10992a7db7a6SVincenzo Maffione  * disconnected while passing down an interrupt.
11002a7db7a6SVincenzo Maffione  *
11012a7db7a6SVincenzo Maffione  * Note, no user process can access this NIC or the host stack.
11022a7db7a6SVincenzo Maffione  * The only part of the ring that is significant are the slots,
11032a7db7a6SVincenzo Maffione  * and head/cur/tail are set from the kring as needed
11042a7db7a6SVincenzo Maffione  * (part as a receive ring, part as a transmit ring).
11052a7db7a6SVincenzo Maffione  *
11062a7db7a6SVincenzo Maffione  * callback that overwrites the hwna notify callback.
11072a7db7a6SVincenzo Maffione  * Packets come from the outside or from the host stack and are put on an
11082a7db7a6SVincenzo Maffione  * hwna rx ring.
11092a7db7a6SVincenzo Maffione  * The bridge wrapper then sends the packets through the bridge.
11102a7db7a6SVincenzo Maffione  */
11112a7db7a6SVincenzo Maffione static int
11122a7db7a6SVincenzo Maffione netmap_bwrap_intr_notify(struct netmap_kring *kring, int flags)
11132a7db7a6SVincenzo Maffione {
11142a7db7a6SVincenzo Maffione 	struct netmap_adapter *na = kring->na;
11152a7db7a6SVincenzo Maffione 	struct netmap_bwrap_adapter *bna = na->na_private;
11162a7db7a6SVincenzo Maffione 	struct netmap_kring *bkring;
11172a7db7a6SVincenzo Maffione 	struct netmap_vp_adapter *vpna = &bna->up;
11182a7db7a6SVincenzo Maffione 	u_int ring_nr = kring->ring_id;
11192a7db7a6SVincenzo Maffione 	int ret = NM_IRQ_COMPLETED;
11202a7db7a6SVincenzo Maffione 	int error;
11212a7db7a6SVincenzo Maffione 
1122*b6e66be2SVincenzo Maffione 	if (netmap_debug & NM_DEBUG_RXINTR)
1123*b6e66be2SVincenzo Maffione 	    nm_prinf("%s %s 0x%x", na->name, kring->name, flags);
11242a7db7a6SVincenzo Maffione 
11252a7db7a6SVincenzo Maffione 	bkring = vpna->up.tx_rings[ring_nr];
11262a7db7a6SVincenzo Maffione 
11272a7db7a6SVincenzo Maffione 	/* make sure the ring is not disabled */
11282a7db7a6SVincenzo Maffione 	if (nm_kr_tryget(kring, 0 /* can't sleep */, NULL)) {
11292a7db7a6SVincenzo Maffione 		return EIO;
11302a7db7a6SVincenzo Maffione 	}
11312a7db7a6SVincenzo Maffione 
1132*b6e66be2SVincenzo Maffione 	if (netmap_debug & NM_DEBUG_RXINTR)
1133*b6e66be2SVincenzo Maffione 	    nm_prinf("%s head %d cur %d tail %d",  na->name,
11342a7db7a6SVincenzo Maffione 		kring->rhead, kring->rcur, kring->rtail);
11352a7db7a6SVincenzo Maffione 
11362a7db7a6SVincenzo Maffione 	/* simulate a user wakeup on the rx ring
11372a7db7a6SVincenzo Maffione 	 * fetch packets that have arrived.
11382a7db7a6SVincenzo Maffione 	 */
11392a7db7a6SVincenzo Maffione 	error = kring->nm_sync(kring, 0);
11402a7db7a6SVincenzo Maffione 	if (error)
11412a7db7a6SVincenzo Maffione 		goto put_out;
11422a7db7a6SVincenzo Maffione 	if (kring->nr_hwcur == kring->nr_hwtail) {
11432a7db7a6SVincenzo Maffione 		if (netmap_verbose)
1144*b6e66be2SVincenzo Maffione 			nm_prerr("how strange, interrupt with no packets on %s",
11452a7db7a6SVincenzo Maffione 			    na->name);
11462a7db7a6SVincenzo Maffione 		goto put_out;
11472a7db7a6SVincenzo Maffione 	}
11482a7db7a6SVincenzo Maffione 
11492a7db7a6SVincenzo Maffione 	/* new packets are kring->rcur to kring->nr_hwtail, and the bkring
11502a7db7a6SVincenzo Maffione 	 * had hwcur == bkring->rhead. So advance bkring->rhead to kring->nr_hwtail
11512a7db7a6SVincenzo Maffione 	 * to push all packets out.
11522a7db7a6SVincenzo Maffione 	 */
11532a7db7a6SVincenzo Maffione 	bkring->rhead = bkring->rcur = kring->nr_hwtail;
11542a7db7a6SVincenzo Maffione 
11552a7db7a6SVincenzo Maffione 	bkring->nm_sync(bkring, flags);
11562a7db7a6SVincenzo Maffione 
11572a7db7a6SVincenzo Maffione 	/* mark all buffers as released on this ring */
11582a7db7a6SVincenzo Maffione 	kring->rhead = kring->rcur = kring->rtail = kring->nr_hwtail;
11592a7db7a6SVincenzo Maffione 	/* another call to actually release the buffers */
11602a7db7a6SVincenzo Maffione 	error = kring->nm_sync(kring, 0);
11612a7db7a6SVincenzo Maffione 
11622a7db7a6SVincenzo Maffione 	/* The second rxsync may have further advanced hwtail. If this happens,
11632a7db7a6SVincenzo Maffione 	 *  return NM_IRQ_RESCHED, otherwise just return NM_IRQ_COMPLETED. */
11642a7db7a6SVincenzo Maffione 	if (kring->rcur != kring->nr_hwtail) {
11652a7db7a6SVincenzo Maffione 		ret = NM_IRQ_RESCHED;
11662a7db7a6SVincenzo Maffione 	}
11672a7db7a6SVincenzo Maffione put_out:
11682a7db7a6SVincenzo Maffione 	nm_kr_put(kring);
11692a7db7a6SVincenzo Maffione 
11702a7db7a6SVincenzo Maffione 	return error ? error : ret;
11712a7db7a6SVincenzo Maffione }
11722a7db7a6SVincenzo Maffione 
11732a7db7a6SVincenzo Maffione 
11742a7db7a6SVincenzo Maffione /* nm_register callback for bwrap */
11752a7db7a6SVincenzo Maffione int
11762a7db7a6SVincenzo Maffione netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
11772a7db7a6SVincenzo Maffione {
11782a7db7a6SVincenzo Maffione 	struct netmap_bwrap_adapter *bna =
11792a7db7a6SVincenzo Maffione 		(struct netmap_bwrap_adapter *)na;
11802a7db7a6SVincenzo Maffione 	struct netmap_adapter *hwna = bna->hwna;
11812a7db7a6SVincenzo Maffione 	struct netmap_vp_adapter *hostna = &bna->host;
11822a7db7a6SVincenzo Maffione 	int error, i;
11832a7db7a6SVincenzo Maffione 	enum txrx t;
11842a7db7a6SVincenzo Maffione 
11852a7db7a6SVincenzo Maffione 	ND("%s %s", na->name, onoff ? "on" : "off");
11862a7db7a6SVincenzo Maffione 
11872a7db7a6SVincenzo Maffione 	if (onoff) {
11882a7db7a6SVincenzo Maffione 		/* netmap_do_regif has been called on the bwrap na.
11892a7db7a6SVincenzo Maffione 		 * We need to pass the information about the
11902a7db7a6SVincenzo Maffione 		 * memory allocator down to the hwna before
11912a7db7a6SVincenzo Maffione 		 * putting it in netmap mode
11922a7db7a6SVincenzo Maffione 		 */
11932a7db7a6SVincenzo Maffione 		hwna->na_lut = na->na_lut;
11942a7db7a6SVincenzo Maffione 
11952a7db7a6SVincenzo Maffione 		if (hostna->na_bdg) {
11962a7db7a6SVincenzo Maffione 			/* if the host rings have been attached to switch,
11972a7db7a6SVincenzo Maffione 			 * we need to copy the memory allocator information
11982a7db7a6SVincenzo Maffione 			 * in the hostna also
11992a7db7a6SVincenzo Maffione 			 */
12002a7db7a6SVincenzo Maffione 			hostna->up.na_lut = na->na_lut;
12012a7db7a6SVincenzo Maffione 		}
12022a7db7a6SVincenzo Maffione 
12032a7db7a6SVincenzo Maffione 	}
12042a7db7a6SVincenzo Maffione 
12052a7db7a6SVincenzo Maffione 	/* pass down the pending ring state information */
12062a7db7a6SVincenzo Maffione 	for_rx_tx(t) {
12072a7db7a6SVincenzo Maffione 		for (i = 0; i < netmap_all_rings(na, t); i++) {
12082a7db7a6SVincenzo Maffione 			NMR(hwna, nm_txrx_swap(t))[i]->nr_pending_mode =
12092a7db7a6SVincenzo Maffione 				NMR(na, t)[i]->nr_pending_mode;
12102a7db7a6SVincenzo Maffione 		}
12112a7db7a6SVincenzo Maffione 	}
12122a7db7a6SVincenzo Maffione 
12132a7db7a6SVincenzo Maffione 	/* forward the request to the hwna */
12142a7db7a6SVincenzo Maffione 	error = hwna->nm_register(hwna, onoff);
12152a7db7a6SVincenzo Maffione 	if (error)
12162a7db7a6SVincenzo Maffione 		return error;
12172a7db7a6SVincenzo Maffione 
12182a7db7a6SVincenzo Maffione 	/* copy up the current ring state information */
12192a7db7a6SVincenzo Maffione 	for_rx_tx(t) {
12202a7db7a6SVincenzo Maffione 		for (i = 0; i < netmap_all_rings(na, t); i++) {
12212a7db7a6SVincenzo Maffione 			struct netmap_kring *kring = NMR(hwna, nm_txrx_swap(t))[i];
12222a7db7a6SVincenzo Maffione 			NMR(na, t)[i]->nr_mode = kring->nr_mode;
12232a7db7a6SVincenzo Maffione 		}
12242a7db7a6SVincenzo Maffione 	}
12252a7db7a6SVincenzo Maffione 
12262a7db7a6SVincenzo Maffione 	/* impersonate a netmap_vp_adapter */
12272a7db7a6SVincenzo Maffione 	netmap_vp_reg(na, onoff);
12282a7db7a6SVincenzo Maffione 	if (hostna->na_bdg)
12292a7db7a6SVincenzo Maffione 		netmap_vp_reg(&hostna->up, onoff);
12302a7db7a6SVincenzo Maffione 
12312a7db7a6SVincenzo Maffione 	if (onoff) {
12322a7db7a6SVincenzo Maffione 		u_int i;
12332a7db7a6SVincenzo Maffione 		/* intercept the hwna nm_nofify callback on the hw rings */
12342a7db7a6SVincenzo Maffione 		for (i = 0; i < hwna->num_rx_rings; i++) {
12352a7db7a6SVincenzo Maffione 			hwna->rx_rings[i]->save_notify = hwna->rx_rings[i]->nm_notify;
12362a7db7a6SVincenzo Maffione 			hwna->rx_rings[i]->nm_notify = netmap_bwrap_intr_notify;
12372a7db7a6SVincenzo Maffione 		}
12382a7db7a6SVincenzo Maffione 		i = hwna->num_rx_rings; /* for safety */
12392a7db7a6SVincenzo Maffione 		/* save the host ring notify unconditionally */
12402a7db7a6SVincenzo Maffione 		for (; i < netmap_real_rings(hwna, NR_RX); i++) {
12412a7db7a6SVincenzo Maffione 			hwna->rx_rings[i]->save_notify =
12422a7db7a6SVincenzo Maffione 				hwna->rx_rings[i]->nm_notify;
12432a7db7a6SVincenzo Maffione 			if (hostna->na_bdg) {
12442a7db7a6SVincenzo Maffione 				/* also intercept the host ring notify */
12452a7db7a6SVincenzo Maffione 				hwna->rx_rings[i]->nm_notify =
12462a7db7a6SVincenzo Maffione 					netmap_bwrap_intr_notify;
12472a7db7a6SVincenzo Maffione 				na->tx_rings[i]->nm_sync = na->nm_txsync;
12482a7db7a6SVincenzo Maffione 			}
12492a7db7a6SVincenzo Maffione 		}
12502a7db7a6SVincenzo Maffione 		if (na->active_fds == 0)
12512a7db7a6SVincenzo Maffione 			na->na_flags |= NAF_NETMAP_ON;
12522a7db7a6SVincenzo Maffione 	} else {
12532a7db7a6SVincenzo Maffione 		u_int i;
12542a7db7a6SVincenzo Maffione 
12552a7db7a6SVincenzo Maffione 		if (na->active_fds == 0)
12562a7db7a6SVincenzo Maffione 			na->na_flags &= ~NAF_NETMAP_ON;
12572a7db7a6SVincenzo Maffione 
12582a7db7a6SVincenzo Maffione 		/* reset all notify callbacks (including host ring) */
12592a7db7a6SVincenzo Maffione 		for (i = 0; i < netmap_all_rings(hwna, NR_RX); i++) {
12602a7db7a6SVincenzo Maffione 			hwna->rx_rings[i]->nm_notify =
12612a7db7a6SVincenzo Maffione 				hwna->rx_rings[i]->save_notify;
12622a7db7a6SVincenzo Maffione 			hwna->rx_rings[i]->save_notify = NULL;
12632a7db7a6SVincenzo Maffione 		}
12642a7db7a6SVincenzo Maffione 		hwna->na_lut.lut = NULL;
12652a7db7a6SVincenzo Maffione 		hwna->na_lut.plut = NULL;
12662a7db7a6SVincenzo Maffione 		hwna->na_lut.objtotal = 0;
12672a7db7a6SVincenzo Maffione 		hwna->na_lut.objsize = 0;
12682a7db7a6SVincenzo Maffione 
12692a7db7a6SVincenzo Maffione 		/* pass ownership of the netmap rings to the hwna */
12702a7db7a6SVincenzo Maffione 		for_rx_tx(t) {
12712a7db7a6SVincenzo Maffione 			for (i = 0; i < netmap_all_rings(na, t); i++) {
12722a7db7a6SVincenzo Maffione 				NMR(na, t)[i]->ring = NULL;
12732a7db7a6SVincenzo Maffione 			}
12742a7db7a6SVincenzo Maffione 		}
12752a7db7a6SVincenzo Maffione 		/* reset the number of host rings to default */
12762a7db7a6SVincenzo Maffione 		for_rx_tx(t) {
12772a7db7a6SVincenzo Maffione 			nma_set_host_nrings(hwna, t, 1);
12782a7db7a6SVincenzo Maffione 		}
12792a7db7a6SVincenzo Maffione 
12802a7db7a6SVincenzo Maffione 	}
12812a7db7a6SVincenzo Maffione 
12822a7db7a6SVincenzo Maffione 	return 0;
12832a7db7a6SVincenzo Maffione }
12842a7db7a6SVincenzo Maffione 
12852a7db7a6SVincenzo Maffione /* nm_config callback for bwrap */
12862a7db7a6SVincenzo Maffione static int
12872a7db7a6SVincenzo Maffione netmap_bwrap_config(struct netmap_adapter *na, struct nm_config_info *info)
12882a7db7a6SVincenzo Maffione {
12892a7db7a6SVincenzo Maffione 	struct netmap_bwrap_adapter *bna =
12902a7db7a6SVincenzo Maffione 		(struct netmap_bwrap_adapter *)na;
12912a7db7a6SVincenzo Maffione 	struct netmap_adapter *hwna = bna->hwna;
12922a7db7a6SVincenzo Maffione 	int error;
12932a7db7a6SVincenzo Maffione 
12942a7db7a6SVincenzo Maffione 	/* Forward the request to the hwna. It may happen that nobody
12952a7db7a6SVincenzo Maffione 	 * registered hwna yet, so netmap_mem_get_lut() may have not
12962a7db7a6SVincenzo Maffione 	 * been called yet. */
12972a7db7a6SVincenzo Maffione 	error = netmap_mem_get_lut(hwna->nm_mem, &hwna->na_lut);
12982a7db7a6SVincenzo Maffione 	if (error)
12992a7db7a6SVincenzo Maffione 		return error;
13002a7db7a6SVincenzo Maffione 	netmap_update_config(hwna);
13012a7db7a6SVincenzo Maffione 	/* swap the results and propagate */
13022a7db7a6SVincenzo Maffione 	info->num_tx_rings = hwna->num_rx_rings;
13032a7db7a6SVincenzo Maffione 	info->num_tx_descs = hwna->num_rx_desc;
13042a7db7a6SVincenzo Maffione 	info->num_rx_rings = hwna->num_tx_rings;
13052a7db7a6SVincenzo Maffione 	info->num_rx_descs = hwna->num_tx_desc;
13062a7db7a6SVincenzo Maffione 	info->rx_buf_maxsize = hwna->rx_buf_maxsize;
13072a7db7a6SVincenzo Maffione 
13082a7db7a6SVincenzo Maffione 	return 0;
13092a7db7a6SVincenzo Maffione }
13102a7db7a6SVincenzo Maffione 
13112a7db7a6SVincenzo Maffione 
13122a7db7a6SVincenzo Maffione /* nm_krings_create callback for bwrap */
13132a7db7a6SVincenzo Maffione int
13142a7db7a6SVincenzo Maffione netmap_bwrap_krings_create_common(struct netmap_adapter *na)
13152a7db7a6SVincenzo Maffione {
13162a7db7a6SVincenzo Maffione 	struct netmap_bwrap_adapter *bna =
13172a7db7a6SVincenzo Maffione 		(struct netmap_bwrap_adapter *)na;
13182a7db7a6SVincenzo Maffione 	struct netmap_adapter *hwna = bna->hwna;
13192a7db7a6SVincenzo Maffione 	struct netmap_adapter *hostna = &bna->host.up;
13202a7db7a6SVincenzo Maffione 	int i, error = 0;
13212a7db7a6SVincenzo Maffione 	enum txrx t;
13222a7db7a6SVincenzo Maffione 
13232a7db7a6SVincenzo Maffione 	/* also create the hwna krings */
13242a7db7a6SVincenzo Maffione 	error = hwna->nm_krings_create(hwna);
13252a7db7a6SVincenzo Maffione 	if (error) {
13262a7db7a6SVincenzo Maffione 		return error;
13272a7db7a6SVincenzo Maffione 	}
13282a7db7a6SVincenzo Maffione 
13292a7db7a6SVincenzo Maffione 	/* increment the usage counter for all the hwna krings */
13302a7db7a6SVincenzo Maffione 	for_rx_tx(t) {
13312a7db7a6SVincenzo Maffione 		for (i = 0; i < netmap_all_rings(hwna, t); i++) {
13322a7db7a6SVincenzo Maffione 			NMR(hwna, t)[i]->users++;
13332a7db7a6SVincenzo Maffione 		}
13342a7db7a6SVincenzo Maffione 	}
13352a7db7a6SVincenzo Maffione 
13362a7db7a6SVincenzo Maffione 	/* now create the actual rings */
13372a7db7a6SVincenzo Maffione 	error = netmap_mem_rings_create(hwna);
13382a7db7a6SVincenzo Maffione 	if (error) {
13392a7db7a6SVincenzo Maffione 		goto err_dec_users;
13402a7db7a6SVincenzo Maffione 	}
13412a7db7a6SVincenzo Maffione 
13422a7db7a6SVincenzo Maffione 	/* cross-link the netmap rings
13432a7db7a6SVincenzo Maffione 	 * The original number of rings comes from hwna,
13442a7db7a6SVincenzo Maffione 	 * rx rings on one side equals tx rings on the other.
13452a7db7a6SVincenzo Maffione 	 */
13462a7db7a6SVincenzo Maffione 	for_rx_tx(t) {
13472a7db7a6SVincenzo Maffione 		enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
13482a7db7a6SVincenzo Maffione 		for (i = 0; i < netmap_all_rings(hwna, r); i++) {
13492a7db7a6SVincenzo Maffione 			NMR(na, t)[i]->nkr_num_slots = NMR(hwna, r)[i]->nkr_num_slots;
13502a7db7a6SVincenzo Maffione 			NMR(na, t)[i]->ring = NMR(hwna, r)[i]->ring;
13512a7db7a6SVincenzo Maffione 		}
13522a7db7a6SVincenzo Maffione 	}
13532a7db7a6SVincenzo Maffione 
13542a7db7a6SVincenzo Maffione 	if (na->na_flags & NAF_HOST_RINGS) {
13552a7db7a6SVincenzo Maffione 		/* the hostna rings are the host rings of the bwrap.
13562a7db7a6SVincenzo Maffione 		 * The corresponding krings must point back to the
13572a7db7a6SVincenzo Maffione 		 * hostna
13582a7db7a6SVincenzo Maffione 		 */
13592a7db7a6SVincenzo Maffione 		hostna->tx_rings = &na->tx_rings[na->num_tx_rings];
13602a7db7a6SVincenzo Maffione 		hostna->rx_rings = &na->rx_rings[na->num_rx_rings];
13612a7db7a6SVincenzo Maffione 		for_rx_tx(t) {
13622a7db7a6SVincenzo Maffione 			for (i = 0; i < nma_get_nrings(hostna, t); i++) {
13632a7db7a6SVincenzo Maffione 				NMR(hostna, t)[i]->na = hostna;
13642a7db7a6SVincenzo Maffione 			}
13652a7db7a6SVincenzo Maffione 		}
13662a7db7a6SVincenzo Maffione 	}
13672a7db7a6SVincenzo Maffione 
13682a7db7a6SVincenzo Maffione 	return 0;
13692a7db7a6SVincenzo Maffione 
13702a7db7a6SVincenzo Maffione err_dec_users:
13712a7db7a6SVincenzo Maffione 	for_rx_tx(t) {
13722a7db7a6SVincenzo Maffione 		for (i = 0; i < netmap_all_rings(hwna, t); i++) {
13732a7db7a6SVincenzo Maffione 			NMR(hwna, t)[i]->users--;
13742a7db7a6SVincenzo Maffione 		}
13752a7db7a6SVincenzo Maffione 	}
13762a7db7a6SVincenzo Maffione 	hwna->nm_krings_delete(hwna);
13772a7db7a6SVincenzo Maffione 	return error;
13782a7db7a6SVincenzo Maffione }
13792a7db7a6SVincenzo Maffione 
13802a7db7a6SVincenzo Maffione 
13812a7db7a6SVincenzo Maffione void
13822a7db7a6SVincenzo Maffione netmap_bwrap_krings_delete_common(struct netmap_adapter *na)
13832a7db7a6SVincenzo Maffione {
13842a7db7a6SVincenzo Maffione 	struct netmap_bwrap_adapter *bna =
13852a7db7a6SVincenzo Maffione 		(struct netmap_bwrap_adapter *)na;
13862a7db7a6SVincenzo Maffione 	struct netmap_adapter *hwna = bna->hwna;
13872a7db7a6SVincenzo Maffione 	enum txrx t;
13882a7db7a6SVincenzo Maffione 	int i;
13892a7db7a6SVincenzo Maffione 
13902a7db7a6SVincenzo Maffione 	ND("%s", na->name);
13912a7db7a6SVincenzo Maffione 
13922a7db7a6SVincenzo Maffione 	/* decrement the usage counter for all the hwna krings */
13932a7db7a6SVincenzo Maffione 	for_rx_tx(t) {
13942a7db7a6SVincenzo Maffione 		for (i = 0; i < netmap_all_rings(hwna, t); i++) {
13952a7db7a6SVincenzo Maffione 			NMR(hwna, t)[i]->users--;
13962a7db7a6SVincenzo Maffione 		}
13972a7db7a6SVincenzo Maffione 	}
13982a7db7a6SVincenzo Maffione 
13992a7db7a6SVincenzo Maffione 	/* delete any netmap rings that are no longer needed */
14002a7db7a6SVincenzo Maffione 	netmap_mem_rings_delete(hwna);
14012a7db7a6SVincenzo Maffione 	hwna->nm_krings_delete(hwna);
14022a7db7a6SVincenzo Maffione }
14032a7db7a6SVincenzo Maffione 
14042a7db7a6SVincenzo Maffione 
14052a7db7a6SVincenzo Maffione /* notify method for the bridge-->hwna direction */
14062a7db7a6SVincenzo Maffione int
14072a7db7a6SVincenzo Maffione netmap_bwrap_notify(struct netmap_kring *kring, int flags)
14082a7db7a6SVincenzo Maffione {
14092a7db7a6SVincenzo Maffione 	struct netmap_adapter *na = kring->na;
14102a7db7a6SVincenzo Maffione 	struct netmap_bwrap_adapter *bna = na->na_private;
14112a7db7a6SVincenzo Maffione 	struct netmap_adapter *hwna = bna->hwna;
14122a7db7a6SVincenzo Maffione 	u_int ring_n = kring->ring_id;
14132a7db7a6SVincenzo Maffione 	u_int lim = kring->nkr_num_slots - 1;
14142a7db7a6SVincenzo Maffione 	struct netmap_kring *hw_kring;
14152a7db7a6SVincenzo Maffione 	int error;
14162a7db7a6SVincenzo Maffione 
14172a7db7a6SVincenzo Maffione 	ND("%s: na %s hwna %s",
14182a7db7a6SVincenzo Maffione 			(kring ? kring->name : "NULL!"),
14192a7db7a6SVincenzo Maffione 			(na ? na->name : "NULL!"),
14202a7db7a6SVincenzo Maffione 			(hwna ? hwna->name : "NULL!"));
14212a7db7a6SVincenzo Maffione 	hw_kring = hwna->tx_rings[ring_n];
14222a7db7a6SVincenzo Maffione 
14232a7db7a6SVincenzo Maffione 	if (nm_kr_tryget(hw_kring, 0, NULL)) {
14242a7db7a6SVincenzo Maffione 		return ENXIO;
14252a7db7a6SVincenzo Maffione 	}
14262a7db7a6SVincenzo Maffione 
14272a7db7a6SVincenzo Maffione 	/* first step: simulate a user wakeup on the rx ring */
14282a7db7a6SVincenzo Maffione 	netmap_vp_rxsync(kring, flags);
14292a7db7a6SVincenzo Maffione 	ND("%s[%d] PRE rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)",
14302a7db7a6SVincenzo Maffione 		na->name, ring_n,
14312a7db7a6SVincenzo Maffione 		kring->nr_hwcur, kring->nr_hwtail, kring->nkr_hwlease,
1432*b6e66be2SVincenzo Maffione 		kring->rhead, kring->rcur, kring->rtail,
1433*b6e66be2SVincenzo Maffione 		hw_kring->nr_hwcur, hw_kring->nr_hwtail, hw_kring->rtail);
14342a7db7a6SVincenzo Maffione 	/* second step: the new packets are sent on the tx ring
14352a7db7a6SVincenzo Maffione 	 * (which is actually the same ring)
14362a7db7a6SVincenzo Maffione 	 */
14372a7db7a6SVincenzo Maffione 	hw_kring->rhead = hw_kring->rcur = kring->nr_hwtail;
14382a7db7a6SVincenzo Maffione 	error = hw_kring->nm_sync(hw_kring, flags);
14392a7db7a6SVincenzo Maffione 	if (error)
14402a7db7a6SVincenzo Maffione 		goto put_out;
14412a7db7a6SVincenzo Maffione 
14422a7db7a6SVincenzo Maffione 	/* third step: now we are back the rx ring */
14432a7db7a6SVincenzo Maffione 	/* claim ownership on all hw owned bufs */
14442a7db7a6SVincenzo Maffione 	kring->rhead = kring->rcur = nm_next(hw_kring->nr_hwtail, lim); /* skip past reserved slot */
14452a7db7a6SVincenzo Maffione 
14462a7db7a6SVincenzo Maffione 	/* fourth step: the user goes to sleep again, causing another rxsync */
14472a7db7a6SVincenzo Maffione 	netmap_vp_rxsync(kring, flags);
14482a7db7a6SVincenzo Maffione 	ND("%s[%d] PST rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)",
14492a7db7a6SVincenzo Maffione 		na->name, ring_n,
14502a7db7a6SVincenzo Maffione 		kring->nr_hwcur, kring->nr_hwtail, kring->nkr_hwlease,
1451*b6e66be2SVincenzo Maffione 		kring->rhead, kring->rcur, kring->rtail,
14522a7db7a6SVincenzo Maffione 		hw_kring->nr_hwcur, hw_kring->nr_hwtail, hw_kring->rtail);
14532a7db7a6SVincenzo Maffione put_out:
14542a7db7a6SVincenzo Maffione 	nm_kr_put(hw_kring);
14552a7db7a6SVincenzo Maffione 
14562a7db7a6SVincenzo Maffione 	return error ? error : NM_IRQ_COMPLETED;
14572a7db7a6SVincenzo Maffione }
14582a7db7a6SVincenzo Maffione 
14592a7db7a6SVincenzo Maffione 
14602a7db7a6SVincenzo Maffione /* nm_bdg_ctl callback for the bwrap.
14612a7db7a6SVincenzo Maffione  * Called on bridge-attach and detach, as an effect of vale-ctl -[ahd].
14622a7db7a6SVincenzo Maffione  * On attach, it needs to provide a fake netmap_priv_d structure and
14632a7db7a6SVincenzo Maffione  * perform a netmap_do_regif() on the bwrap. This will put both the
14642a7db7a6SVincenzo Maffione  * bwrap and the hwna in netmap mode, with the netmap rings shared
14652a7db7a6SVincenzo Maffione  * and cross linked. Moroever, it will start intercepting interrupts
14662a7db7a6SVincenzo Maffione  * directed to hwna.
14672a7db7a6SVincenzo Maffione  */
14682a7db7a6SVincenzo Maffione static int
14692a7db7a6SVincenzo Maffione netmap_bwrap_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
14702a7db7a6SVincenzo Maffione {
14712a7db7a6SVincenzo Maffione 	struct netmap_priv_d *npriv;
14722a7db7a6SVincenzo Maffione 	struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter*)na;
14732a7db7a6SVincenzo Maffione 	int error = 0;
14742a7db7a6SVincenzo Maffione 
14752a7db7a6SVincenzo Maffione 	if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
14762a7db7a6SVincenzo Maffione 		struct nmreq_vale_attach *req =
14772a7db7a6SVincenzo Maffione 			(struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body;
14782a7db7a6SVincenzo Maffione 		if (req->reg.nr_ringid != 0 ||
14792a7db7a6SVincenzo Maffione 			(req->reg.nr_mode != NR_REG_ALL_NIC &&
14802a7db7a6SVincenzo Maffione 				req->reg.nr_mode != NR_REG_NIC_SW)) {
14812a7db7a6SVincenzo Maffione 			/* We only support attaching all the NIC rings
14822a7db7a6SVincenzo Maffione 			 * and/or the host stack. */
14832a7db7a6SVincenzo Maffione 			return EINVAL;
14842a7db7a6SVincenzo Maffione 		}
14852a7db7a6SVincenzo Maffione 		if (NETMAP_OWNED_BY_ANY(na)) {
14862a7db7a6SVincenzo Maffione 			return EBUSY;
14872a7db7a6SVincenzo Maffione 		}
14882a7db7a6SVincenzo Maffione 		if (bna->na_kpriv) {
14892a7db7a6SVincenzo Maffione 			/* nothing to do */
14902a7db7a6SVincenzo Maffione 			return 0;
14912a7db7a6SVincenzo Maffione 		}
14922a7db7a6SVincenzo Maffione 		npriv = netmap_priv_new();
14932a7db7a6SVincenzo Maffione 		if (npriv == NULL)
14942a7db7a6SVincenzo Maffione 			return ENOMEM;
14952a7db7a6SVincenzo Maffione 		npriv->np_ifp = na->ifp; /* let the priv destructor release the ref */
14962a7db7a6SVincenzo Maffione 		error = netmap_do_regif(npriv, na, req->reg.nr_mode,
14972a7db7a6SVincenzo Maffione 					req->reg.nr_ringid, req->reg.nr_flags);
14982a7db7a6SVincenzo Maffione 		if (error) {
14992a7db7a6SVincenzo Maffione 			netmap_priv_delete(npriv);
15002a7db7a6SVincenzo Maffione 			return error;
15012a7db7a6SVincenzo Maffione 		}
15022a7db7a6SVincenzo Maffione 		bna->na_kpriv = npriv;
15032a7db7a6SVincenzo Maffione 		na->na_flags |= NAF_BUSY;
15042a7db7a6SVincenzo Maffione 	} else {
15052a7db7a6SVincenzo Maffione 		if (na->active_fds == 0) /* not registered */
15062a7db7a6SVincenzo Maffione 			return EINVAL;
15072a7db7a6SVincenzo Maffione 		netmap_priv_delete(bna->na_kpriv);
15082a7db7a6SVincenzo Maffione 		bna->na_kpriv = NULL;
15092a7db7a6SVincenzo Maffione 		na->na_flags &= ~NAF_BUSY;
15102a7db7a6SVincenzo Maffione 	}
15112a7db7a6SVincenzo Maffione 
15122a7db7a6SVincenzo Maffione 	return error;
15132a7db7a6SVincenzo Maffione }
15142a7db7a6SVincenzo Maffione 
15152a7db7a6SVincenzo Maffione /* attach a bridge wrapper to the 'real' device */
15162a7db7a6SVincenzo Maffione int
15172a7db7a6SVincenzo Maffione netmap_bwrap_attach_common(struct netmap_adapter *na,
15182a7db7a6SVincenzo Maffione 		struct netmap_adapter *hwna)
15192a7db7a6SVincenzo Maffione {
15202a7db7a6SVincenzo Maffione 	struct netmap_bwrap_adapter *bna;
15212a7db7a6SVincenzo Maffione 	struct netmap_adapter *hostna = NULL;
15222a7db7a6SVincenzo Maffione 	int error = 0;
15232a7db7a6SVincenzo Maffione 	enum txrx t;
15242a7db7a6SVincenzo Maffione 
15252a7db7a6SVincenzo Maffione 	/* make sure the NIC is not already in use */
15262a7db7a6SVincenzo Maffione 	if (NETMAP_OWNED_BY_ANY(hwna)) {
1527*b6e66be2SVincenzo Maffione 		nm_prerr("NIC %s busy, cannot attach to bridge", hwna->name);
15282a7db7a6SVincenzo Maffione 		return EBUSY;
15292a7db7a6SVincenzo Maffione 	}
15302a7db7a6SVincenzo Maffione 
15312a7db7a6SVincenzo Maffione 	bna = (struct netmap_bwrap_adapter *)na;
15322a7db7a6SVincenzo Maffione 	/* make bwrap ifp point to the real ifp */
15332a7db7a6SVincenzo Maffione 	na->ifp = hwna->ifp;
15342a7db7a6SVincenzo Maffione 	if_ref(na->ifp);
15352a7db7a6SVincenzo Maffione 	na->na_private = bna;
15362a7db7a6SVincenzo Maffione 	/* fill the ring data for the bwrap adapter with rx/tx meanings
15372a7db7a6SVincenzo Maffione 	 * swapped. The real cross-linking will be done during register,
15382a7db7a6SVincenzo Maffione 	 * when all the krings will have been created.
15392a7db7a6SVincenzo Maffione 	 */
15402a7db7a6SVincenzo Maffione 	for_rx_tx(t) {
15412a7db7a6SVincenzo Maffione 		enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
15422a7db7a6SVincenzo Maffione 		nma_set_nrings(na, t, nma_get_nrings(hwna, r));
15432a7db7a6SVincenzo Maffione 		nma_set_ndesc(na, t, nma_get_ndesc(hwna, r));
15442a7db7a6SVincenzo Maffione 	}
15452a7db7a6SVincenzo Maffione 	na->nm_dtor = netmap_bwrap_dtor;
15462a7db7a6SVincenzo Maffione 	na->nm_config = netmap_bwrap_config;
15472a7db7a6SVincenzo Maffione 	na->nm_bdg_ctl = netmap_bwrap_bdg_ctl;
15482a7db7a6SVincenzo Maffione 	na->pdev = hwna->pdev;
15492a7db7a6SVincenzo Maffione 	na->nm_mem = netmap_mem_get(hwna->nm_mem);
15502a7db7a6SVincenzo Maffione 	na->virt_hdr_len = hwna->virt_hdr_len;
15512a7db7a6SVincenzo Maffione 	na->rx_buf_maxsize = hwna->rx_buf_maxsize;
15522a7db7a6SVincenzo Maffione 
15532a7db7a6SVincenzo Maffione 	bna->hwna = hwna;
15542a7db7a6SVincenzo Maffione 	netmap_adapter_get(hwna);
15552a7db7a6SVincenzo Maffione 	hwna->na_private = bna; /* weak reference */
15562a7db7a6SVincenzo Maffione 	bna->saved_na_vp = hwna->na_vp;
15572a7db7a6SVincenzo Maffione 	hwna->na_vp = &bna->up;
15582a7db7a6SVincenzo Maffione 	bna->up.up.na_vp = &(bna->up);
15592a7db7a6SVincenzo Maffione 
15602a7db7a6SVincenzo Maffione 	if (hwna->na_flags & NAF_HOST_RINGS) {
15612a7db7a6SVincenzo Maffione 		if (hwna->na_flags & NAF_SW_ONLY)
15622a7db7a6SVincenzo Maffione 			na->na_flags |= NAF_SW_ONLY;
15632a7db7a6SVincenzo Maffione 		na->na_flags |= NAF_HOST_RINGS;
15642a7db7a6SVincenzo Maffione 		hostna = &bna->host.up;
15652a7db7a6SVincenzo Maffione 
15662a7db7a6SVincenzo Maffione 		/* limit the number of host rings to that of hw */
15672a7db7a6SVincenzo Maffione 		nm_bound_var(&hostna->num_tx_rings, 1, 1,
15682a7db7a6SVincenzo Maffione 				nma_get_nrings(hwna, NR_TX), NULL);
15692a7db7a6SVincenzo Maffione 		nm_bound_var(&hostna->num_rx_rings, 1, 1,
15702a7db7a6SVincenzo Maffione 				nma_get_nrings(hwna, NR_RX), NULL);
15712a7db7a6SVincenzo Maffione 
15722a7db7a6SVincenzo Maffione 		snprintf(hostna->name, sizeof(hostna->name), "%s^", na->name);
15732a7db7a6SVincenzo Maffione 		hostna->ifp = hwna->ifp;
15742a7db7a6SVincenzo Maffione 		for_rx_tx(t) {
15752a7db7a6SVincenzo Maffione 			enum txrx r = nm_txrx_swap(t);
15762a7db7a6SVincenzo Maffione 			u_int nr = nma_get_nrings(hostna, t);
15772a7db7a6SVincenzo Maffione 
15782a7db7a6SVincenzo Maffione 			nma_set_nrings(hostna, t, nr);
15792a7db7a6SVincenzo Maffione 			nma_set_host_nrings(na, t, nr);
15802a7db7a6SVincenzo Maffione 			if (nma_get_host_nrings(hwna, t) < nr) {
15812a7db7a6SVincenzo Maffione 				nma_set_host_nrings(hwna, t, nr);
15822a7db7a6SVincenzo Maffione 			}
15832a7db7a6SVincenzo Maffione 			nma_set_ndesc(hostna, t, nma_get_ndesc(hwna, r));
15842a7db7a6SVincenzo Maffione 		}
15852a7db7a6SVincenzo Maffione 		// hostna->nm_txsync = netmap_bwrap_host_txsync;
15862a7db7a6SVincenzo Maffione 		// hostna->nm_rxsync = netmap_bwrap_host_rxsync;
15872a7db7a6SVincenzo Maffione 		hostna->nm_mem = netmap_mem_get(na->nm_mem);
15882a7db7a6SVincenzo Maffione 		hostna->na_private = bna;
15892a7db7a6SVincenzo Maffione 		hostna->na_vp = &bna->up;
15902a7db7a6SVincenzo Maffione 		na->na_hostvp = hwna->na_hostvp =
15912a7db7a6SVincenzo Maffione 			hostna->na_hostvp = &bna->host;
15922a7db7a6SVincenzo Maffione 		hostna->na_flags = NAF_BUSY; /* prevent NIOCREGIF */
15932a7db7a6SVincenzo Maffione 		hostna->rx_buf_maxsize = hwna->rx_buf_maxsize;
15942a7db7a6SVincenzo Maffione 	}
1595*b6e66be2SVincenzo Maffione 	if (hwna->na_flags & NAF_MOREFRAG)
1596*b6e66be2SVincenzo Maffione 		na->na_flags |= NAF_MOREFRAG;
15972a7db7a6SVincenzo Maffione 
15982a7db7a6SVincenzo Maffione 	ND("%s<->%s txr %d txd %d rxr %d rxd %d",
15992a7db7a6SVincenzo Maffione 		na->name, ifp->if_xname,
16002a7db7a6SVincenzo Maffione 		na->num_tx_rings, na->num_tx_desc,
16012a7db7a6SVincenzo Maffione 		na->num_rx_rings, na->num_rx_desc);
16022a7db7a6SVincenzo Maffione 
16032a7db7a6SVincenzo Maffione 	error = netmap_attach_common(na);
16042a7db7a6SVincenzo Maffione 	if (error) {
16052a7db7a6SVincenzo Maffione 		goto err_put;
16062a7db7a6SVincenzo Maffione 	}
16072a7db7a6SVincenzo Maffione 	hwna->na_flags |= NAF_BUSY;
16082a7db7a6SVincenzo Maffione 	return 0;
16092a7db7a6SVincenzo Maffione 
16102a7db7a6SVincenzo Maffione err_put:
16112a7db7a6SVincenzo Maffione 	hwna->na_vp = hwna->na_hostvp = NULL;
16122a7db7a6SVincenzo Maffione 	netmap_adapter_put(hwna);
16132a7db7a6SVincenzo Maffione 	return error;
16142a7db7a6SVincenzo Maffione 
16152a7db7a6SVincenzo Maffione }
16162a7db7a6SVincenzo Maffione 
16172a7db7a6SVincenzo Maffione struct nm_bridge *
16182a7db7a6SVincenzo Maffione netmap_init_bridges2(u_int n)
16192a7db7a6SVincenzo Maffione {
16202a7db7a6SVincenzo Maffione 	int i;
16212a7db7a6SVincenzo Maffione 	struct nm_bridge *b;
16222a7db7a6SVincenzo Maffione 
16232a7db7a6SVincenzo Maffione 	b = nm_os_malloc(sizeof(struct nm_bridge) * n);
16242a7db7a6SVincenzo Maffione 	if (b == NULL)
16252a7db7a6SVincenzo Maffione 		return NULL;
16262a7db7a6SVincenzo Maffione 	for (i = 0; i < n; i++)
16272a7db7a6SVincenzo Maffione 		BDG_RWINIT(&b[i]);
16282a7db7a6SVincenzo Maffione 	return b;
16292a7db7a6SVincenzo Maffione }
16302a7db7a6SVincenzo Maffione 
16312a7db7a6SVincenzo Maffione void
16322a7db7a6SVincenzo Maffione netmap_uninit_bridges2(struct nm_bridge *b, u_int n)
16332a7db7a6SVincenzo Maffione {
16342a7db7a6SVincenzo Maffione 	int i;
16352a7db7a6SVincenzo Maffione 
16362a7db7a6SVincenzo Maffione 	if (b == NULL)
16372a7db7a6SVincenzo Maffione 		return;
16382a7db7a6SVincenzo Maffione 
16392a7db7a6SVincenzo Maffione 	for (i = 0; i < n; i++)
16402a7db7a6SVincenzo Maffione 		BDG_RWDESTROY(&b[i]);
16412a7db7a6SVincenzo Maffione 	nm_os_free(b);
16422a7db7a6SVincenzo Maffione }
16432a7db7a6SVincenzo Maffione 
16442a7db7a6SVincenzo Maffione int
16452a7db7a6SVincenzo Maffione netmap_init_bridges(void)
16462a7db7a6SVincenzo Maffione {
16472a7db7a6SVincenzo Maffione #ifdef CONFIG_NET_NS
16482a7db7a6SVincenzo Maffione 	return netmap_bns_register();
16492a7db7a6SVincenzo Maffione #else
16502a7db7a6SVincenzo Maffione 	nm_bridges = netmap_init_bridges2(NM_BRIDGES);
16512a7db7a6SVincenzo Maffione 	if (nm_bridges == NULL)
16522a7db7a6SVincenzo Maffione 		return ENOMEM;
16532a7db7a6SVincenzo Maffione 	return 0;
16542a7db7a6SVincenzo Maffione #endif
16552a7db7a6SVincenzo Maffione }
16562a7db7a6SVincenzo Maffione 
16572a7db7a6SVincenzo Maffione void
16582a7db7a6SVincenzo Maffione netmap_uninit_bridges(void)
16592a7db7a6SVincenzo Maffione {
16602a7db7a6SVincenzo Maffione #ifdef CONFIG_NET_NS
16612a7db7a6SVincenzo Maffione 	netmap_bns_unregister();
16622a7db7a6SVincenzo Maffione #else
16632a7db7a6SVincenzo Maffione 	netmap_uninit_bridges2(nm_bridges, NM_BRIDGES);
16642a7db7a6SVincenzo Maffione #endif
16652a7db7a6SVincenzo Maffione }
1666