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