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