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