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*
netmap_bdg_name(struct netmap_vp_adapter * vp)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
nm_is_id_char(const char c)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
nm_bdg_name_validate(const char * name,size_t prefixlen)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 *
nm_find_bridge(const char * name,int create,struct netmap_bdg_ops * ops)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) {
206*01e8e2c2SVincenzo Maffione nm_prdis("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 */
213*01e8e2c2SVincenzo Maffione nm_prdis("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
netmap_bdg_free(struct nm_bridge * b)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
242*01e8e2c2SVincenzo Maffione nm_prdis("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
netmap_bdg_update_private_data(const char * name,bdg_update_private_data_fn_t callback,void * callback_data,void * auth_token)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
netmap_bdg_detach_common(struct nm_bridge * b,int hw,int sw)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) {
315*01e8e2c2SVincenzo Maffione nm_prdis("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) {
321*01e8e2c2SVincenzo Maffione nm_prdis("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
345*01e8e2c2SVincenzo Maffione nm_prdis("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
netmap_vp_bdg_ctl(struct nmreq_header * hdr,struct netmap_adapter * na)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
netmap_default_bdg_attach(const char * name,struct netmap_adapter * na,struct nm_bridge * b)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
netmap_get_bdg_na(struct nmreq_header * hdr,struct netmap_adapter ** na,struct netmap_mem_d * nmd,int create,struct netmap_bdg_ops * ops)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) {
411*01e8e2c2SVincenzo Maffione nm_prdis("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];
428*01e8e2c2SVincenzo Maffione nm_prdis("checking %s", vpna->up.name);
429d740f837SVincenzo Maffione if (!strcmp(vpna->up.name, nr_name)) {
430d740f837SVincenzo Maffione netmap_adapter_get(&vpna->up);
431*01e8e2c2SVincenzo Maffione nm_prdis("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];
448*01e8e2c2SVincenzo Maffione nm_prdis("+++ 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;
518*01e8e2c2SVincenzo Maffione nm_prdis("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++;
529*01e8e2c2SVincenzo Maffione nm_prdis("host %p to bridge port %d", hostna, cand2);
530d740f837SVincenzo Maffione }
531*01e8e2c2SVincenzo Maffione nm_prdis("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
nm_is_bwrap(struct netmap_adapter * na)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
netmap_bwrap_polling(void * data)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
nm_bdg_create_kthreads(struct nm_bdg_polling_state * bps)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
nm_bdg_polling_start_kthreads(struct nm_bdg_polling_state * bps)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
nm_bdg_polling_stop_delete_kthreads(struct nm_bdg_polling_state * bps)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
get_polling_cfg(struct nmreq_vale_polling * req,struct netmap_adapter * na,struct nm_bdg_polling_state * bps)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
nm_bdg_ctl_polling_start(struct nmreq_vale_polling * req,struct netmap_adapter * na)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
nm_bdg_ctl_polling_stop(struct netmap_adapter * na)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
nm_bdg_polling(struct nmreq_header * hdr)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
netmap_bdg_regops(const char * name,struct netmap_bdg_ops * bdg_ops,void * private_data,void * auth_token)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
netmap_bdg_config(struct nm_ifreq * nr)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
netmap_vp_reg(struct netmap_adapter * na,int onoff)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
924d740f837SVincenzo Maffione /* persistent ports may be put in netmap mode
925d740f837SVincenzo Maffione * before being attached to a bridge
926d740f837SVincenzo Maffione */
927d740f837SVincenzo Maffione if (vpna->na_bdg)
928d740f837SVincenzo Maffione BDG_WLOCK(vpna->na_bdg);
929d740f837SVincenzo Maffione if (onoff) {
930*01e8e2c2SVincenzo Maffione netmap_krings_mode_commit(na, onoff);
931d740f837SVincenzo Maffione if (na->active_fds == 0)
932d740f837SVincenzo Maffione na->na_flags |= NAF_NETMAP_ON;
933d740f837SVincenzo Maffione /* XXX on FreeBSD, persistent VALE ports should also
934d740f837SVincenzo Maffione * toggle IFCAP_NETMAP in na->ifp (2014-03-16)
935d740f837SVincenzo Maffione */
936d740f837SVincenzo Maffione } else {
937d740f837SVincenzo Maffione if (na->active_fds == 0)
938d740f837SVincenzo Maffione na->na_flags &= ~NAF_NETMAP_ON;
939*01e8e2c2SVincenzo Maffione netmap_krings_mode_commit(na, onoff);
940d740f837SVincenzo Maffione }
941d740f837SVincenzo Maffione if (vpna->na_bdg)
942d740f837SVincenzo Maffione BDG_WUNLOCK(vpna->na_bdg);
943d740f837SVincenzo Maffione return 0;
944d740f837SVincenzo Maffione }
945d740f837SVincenzo Maffione
946d740f837SVincenzo Maffione
947d740f837SVincenzo Maffione /* rxsync code used by VALE ports nm_rxsync callback and also
948d740f837SVincenzo Maffione * internally by the brwap
949d740f837SVincenzo Maffione */
950d740f837SVincenzo Maffione static int
netmap_vp_rxsync_locked(struct netmap_kring * kring,int flags)951d740f837SVincenzo Maffione netmap_vp_rxsync_locked(struct netmap_kring *kring, int flags)
952d740f837SVincenzo Maffione {
953d740f837SVincenzo Maffione struct netmap_adapter *na = kring->na;
954d740f837SVincenzo Maffione struct netmap_ring *ring = kring->ring;
955d740f837SVincenzo Maffione u_int nm_i, lim = kring->nkr_num_slots - 1;
956d740f837SVincenzo Maffione u_int head = kring->rhead;
957d740f837SVincenzo Maffione int n;
958d740f837SVincenzo Maffione
959d740f837SVincenzo Maffione if (head > lim) {
960b321acabSVincenzo Maffione nm_prerr("ouch dangerous reset!!!");
961d740f837SVincenzo Maffione n = netmap_ring_reinit(kring);
962d740f837SVincenzo Maffione goto done;
963d740f837SVincenzo Maffione }
964d740f837SVincenzo Maffione
965d740f837SVincenzo Maffione /* First part, import newly received packets. */
966d740f837SVincenzo Maffione /* actually nothing to do here, they are already in the kring */
967d740f837SVincenzo Maffione
968d740f837SVincenzo Maffione /* Second part, skip past packets that userspace has released. */
969d740f837SVincenzo Maffione nm_i = kring->nr_hwcur;
970d740f837SVincenzo Maffione if (nm_i != head) {
971d740f837SVincenzo Maffione /* consistency check, but nothing really important here */
972d740f837SVincenzo Maffione for (n = 0; likely(nm_i != head); n++) {
973d740f837SVincenzo Maffione struct netmap_slot *slot = &ring->slot[nm_i];
974d740f837SVincenzo Maffione void *addr = NMB(na, slot);
975d740f837SVincenzo Maffione
976d740f837SVincenzo Maffione if (addr == NETMAP_BUF_BASE(kring->na)) { /* bad buf */
977b321acabSVincenzo Maffione nm_prerr("bad buffer index %d, ignore ?",
978d740f837SVincenzo Maffione slot->buf_idx);
979d740f837SVincenzo Maffione }
980d740f837SVincenzo Maffione slot->flags &= ~NS_BUF_CHANGED;
981d740f837SVincenzo Maffione nm_i = nm_next(nm_i, lim);
982d740f837SVincenzo Maffione }
983d740f837SVincenzo Maffione kring->nr_hwcur = head;
984d740f837SVincenzo Maffione }
985d740f837SVincenzo Maffione
986d740f837SVincenzo Maffione n = 0;
987d740f837SVincenzo Maffione done:
988d740f837SVincenzo Maffione return n;
989d740f837SVincenzo Maffione }
990d740f837SVincenzo Maffione
991d740f837SVincenzo Maffione /*
992d740f837SVincenzo Maffione * nm_rxsync callback for VALE ports
993d740f837SVincenzo Maffione * user process reading from a VALE switch.
994d740f837SVincenzo Maffione * Already protected against concurrent calls from userspace,
995d740f837SVincenzo Maffione * but we must acquire the queue's lock to protect against
996d740f837SVincenzo Maffione * writers on the same queue.
997d740f837SVincenzo Maffione */
998d740f837SVincenzo Maffione int
netmap_vp_rxsync(struct netmap_kring * kring,int flags)999d740f837SVincenzo Maffione netmap_vp_rxsync(struct netmap_kring *kring, int flags)
1000d740f837SVincenzo Maffione {
1001d740f837SVincenzo Maffione int n;
1002d740f837SVincenzo Maffione
1003d740f837SVincenzo Maffione mtx_lock(&kring->q_lock);
1004d740f837SVincenzo Maffione n = netmap_vp_rxsync_locked(kring, flags);
1005d740f837SVincenzo Maffione mtx_unlock(&kring->q_lock);
1006d740f837SVincenzo Maffione return n;
1007d740f837SVincenzo Maffione }
1008d740f837SVincenzo Maffione
1009d740f837SVincenzo Maffione int
netmap_bwrap_attach(const char * nr_name,struct netmap_adapter * hwna,struct netmap_bdg_ops * ops)1010d740f837SVincenzo Maffione netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna,
1011d740f837SVincenzo Maffione struct netmap_bdg_ops *ops)
1012d740f837SVincenzo Maffione {
1013d740f837SVincenzo Maffione return ops->bwrap_attach(nr_name, hwna);
1014d740f837SVincenzo Maffione }
1015d740f837SVincenzo Maffione
1016d740f837SVincenzo Maffione
1017d740f837SVincenzo Maffione /* Bridge wrapper code (bwrap).
1018d740f837SVincenzo Maffione * This is used to connect a non-VALE-port netmap_adapter (hwna) to a
1019d740f837SVincenzo Maffione * VALE switch.
1020d740f837SVincenzo Maffione * The main task is to swap the meaning of tx and rx rings to match the
1021d740f837SVincenzo Maffione * expectations of the VALE switch code (see nm_bdg_flush).
1022d740f837SVincenzo Maffione *
1023d740f837SVincenzo Maffione * The bwrap works by interposing a netmap_bwrap_adapter between the
1024d740f837SVincenzo Maffione * rest of the system and the hwna. The netmap_bwrap_adapter looks like
1025d740f837SVincenzo Maffione * a netmap_vp_adapter to the rest the system, but, internally, it
1026d740f837SVincenzo Maffione * translates all callbacks to what the hwna expects.
1027d740f837SVincenzo Maffione *
1028d740f837SVincenzo Maffione * Note that we have to intercept callbacks coming from two sides:
1029d740f837SVincenzo Maffione *
1030d740f837SVincenzo Maffione * - callbacks coming from the netmap module are intercepted by
1031d740f837SVincenzo Maffione * passing around the netmap_bwrap_adapter instead of the hwna
1032d740f837SVincenzo Maffione *
1033d740f837SVincenzo Maffione * - callbacks coming from outside of the netmap module only know
1034d740f837SVincenzo Maffione * about the hwna. This, however, only happens in interrupt
1035d740f837SVincenzo Maffione * handlers, where only the hwna->nm_notify callback is called.
1036d740f837SVincenzo Maffione * What the bwrap does is to overwrite the hwna->nm_notify callback
1037d740f837SVincenzo Maffione * with its own netmap_bwrap_intr_notify.
1038d740f837SVincenzo Maffione * XXX This assumes that the hwna->nm_notify callback was the
1039d740f837SVincenzo Maffione * standard netmap_notify(), as it is the case for nic adapters.
1040d740f837SVincenzo Maffione * Any additional action performed by hwna->nm_notify will not be
1041d740f837SVincenzo Maffione * performed by netmap_bwrap_intr_notify.
1042d740f837SVincenzo Maffione *
1043d740f837SVincenzo Maffione * Additionally, the bwrap can optionally attach the host rings pair
1044d740f837SVincenzo Maffione * of the wrapped adapter to a different port of the switch.
1045d740f837SVincenzo Maffione */
1046d740f837SVincenzo Maffione
1047d740f837SVincenzo Maffione
1048d740f837SVincenzo Maffione static void
netmap_bwrap_dtor(struct netmap_adapter * na)1049d740f837SVincenzo Maffione netmap_bwrap_dtor(struct netmap_adapter *na)
1050d740f837SVincenzo Maffione {
1051d740f837SVincenzo Maffione struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter*)na;
1052d740f837SVincenzo Maffione struct netmap_adapter *hwna = bna->hwna;
1053d740f837SVincenzo Maffione struct nm_bridge *b = bna->up.na_bdg,
1054d740f837SVincenzo Maffione *bh = bna->host.na_bdg;
1055d740f837SVincenzo Maffione
1056d740f837SVincenzo Maffione if (bna->host.up.nm_mem)
1057d740f837SVincenzo Maffione netmap_mem_put(bna->host.up.nm_mem);
1058d740f837SVincenzo Maffione
1059d740f837SVincenzo Maffione if (b) {
1060d740f837SVincenzo Maffione netmap_bdg_detach_common(b, bna->up.bdg_port,
1061d740f837SVincenzo Maffione (bh ? bna->host.bdg_port : -1));
1062d740f837SVincenzo Maffione }
1063d740f837SVincenzo Maffione
1064*01e8e2c2SVincenzo Maffione nm_prdis("na %p", na);
1065d740f837SVincenzo Maffione na->ifp = NULL;
1066d740f837SVincenzo Maffione bna->host.up.ifp = NULL;
1067d740f837SVincenzo Maffione hwna->na_vp = bna->saved_na_vp;
1068d740f837SVincenzo Maffione hwna->na_hostvp = NULL;
1069d740f837SVincenzo Maffione hwna->na_private = NULL;
1070d740f837SVincenzo Maffione hwna->na_flags &= ~NAF_BUSY;
1071d740f837SVincenzo Maffione netmap_adapter_put(hwna);
1072d740f837SVincenzo Maffione
1073d740f837SVincenzo Maffione }
1074d740f837SVincenzo Maffione
1075d740f837SVincenzo Maffione
1076d740f837SVincenzo Maffione /*
1077d740f837SVincenzo Maffione * Intr callback for NICs connected to a bridge.
1078d740f837SVincenzo Maffione * Simply ignore tx interrupts (maybe we could try to recover space ?)
1079d740f837SVincenzo Maffione * and pass received packets from nic to the bridge.
1080d740f837SVincenzo Maffione *
1081d740f837SVincenzo Maffione * XXX TODO check locking: this is called from the interrupt
1082d740f837SVincenzo Maffione * handler so we should make sure that the interface is not
1083d740f837SVincenzo Maffione * disconnected while passing down an interrupt.
1084d740f837SVincenzo Maffione *
1085d740f837SVincenzo Maffione * Note, no user process can access this NIC or the host stack.
1086d740f837SVincenzo Maffione * The only part of the ring that is significant are the slots,
1087d740f837SVincenzo Maffione * and head/cur/tail are set from the kring as needed
1088d740f837SVincenzo Maffione * (part as a receive ring, part as a transmit ring).
1089d740f837SVincenzo Maffione *
1090d740f837SVincenzo Maffione * callback that overwrites the hwna notify callback.
1091d740f837SVincenzo Maffione * Packets come from the outside or from the host stack and are put on an
1092d740f837SVincenzo Maffione * hwna rx ring.
1093d740f837SVincenzo Maffione * The bridge wrapper then sends the packets through the bridge.
1094d740f837SVincenzo Maffione */
1095d740f837SVincenzo Maffione static int
netmap_bwrap_intr_notify(struct netmap_kring * kring,int flags)1096d740f837SVincenzo Maffione netmap_bwrap_intr_notify(struct netmap_kring *kring, int flags)
1097d740f837SVincenzo Maffione {
1098d740f837SVincenzo Maffione struct netmap_adapter *na = kring->na;
1099d740f837SVincenzo Maffione struct netmap_bwrap_adapter *bna = na->na_private;
1100d740f837SVincenzo Maffione struct netmap_kring *bkring;
1101d740f837SVincenzo Maffione struct netmap_vp_adapter *vpna = &bna->up;
1102d740f837SVincenzo Maffione u_int ring_nr = kring->ring_id;
1103d740f837SVincenzo Maffione int ret = NM_IRQ_COMPLETED;
1104d740f837SVincenzo Maffione int error;
1105d740f837SVincenzo Maffione
1106b321acabSVincenzo Maffione if (netmap_debug & NM_DEBUG_RXINTR)
1107b321acabSVincenzo Maffione nm_prinf("%s %s 0x%x", na->name, kring->name, flags);
1108d740f837SVincenzo Maffione
1109d740f837SVincenzo Maffione bkring = vpna->up.tx_rings[ring_nr];
1110d740f837SVincenzo Maffione
1111d740f837SVincenzo Maffione /* make sure the ring is not disabled */
1112d740f837SVincenzo Maffione if (nm_kr_tryget(kring, 0 /* can't sleep */, NULL)) {
1113d740f837SVincenzo Maffione return EIO;
1114d740f837SVincenzo Maffione }
1115d740f837SVincenzo Maffione
1116b321acabSVincenzo Maffione if (netmap_debug & NM_DEBUG_RXINTR)
1117b321acabSVincenzo Maffione nm_prinf("%s head %d cur %d tail %d", na->name,
1118d740f837SVincenzo Maffione kring->rhead, kring->rcur, kring->rtail);
1119d740f837SVincenzo Maffione
1120d740f837SVincenzo Maffione /* simulate a user wakeup on the rx ring
1121d740f837SVincenzo Maffione * fetch packets that have arrived.
1122d740f837SVincenzo Maffione */
1123d740f837SVincenzo Maffione error = kring->nm_sync(kring, 0);
1124d740f837SVincenzo Maffione if (error)
1125d740f837SVincenzo Maffione goto put_out;
1126d740f837SVincenzo Maffione if (kring->nr_hwcur == kring->nr_hwtail) {
1127d740f837SVincenzo Maffione if (netmap_verbose)
1128e2e0ef76SVincenzo Maffione nm_prlim(1, "interrupt with no packets on %s",
1129e2e0ef76SVincenzo Maffione kring->name);
1130d740f837SVincenzo Maffione goto put_out;
1131d740f837SVincenzo Maffione }
1132d740f837SVincenzo Maffione
1133d740f837SVincenzo Maffione /* new packets are kring->rcur to kring->nr_hwtail, and the bkring
1134d740f837SVincenzo Maffione * had hwcur == bkring->rhead. So advance bkring->rhead to kring->nr_hwtail
1135d740f837SVincenzo Maffione * to push all packets out.
1136d740f837SVincenzo Maffione */
1137d740f837SVincenzo Maffione bkring->rhead = bkring->rcur = kring->nr_hwtail;
1138d740f837SVincenzo Maffione
1139d740f837SVincenzo Maffione bkring->nm_sync(bkring, flags);
1140d740f837SVincenzo Maffione
1141d740f837SVincenzo Maffione /* mark all buffers as released on this ring */
1142d740f837SVincenzo Maffione kring->rhead = kring->rcur = kring->rtail = kring->nr_hwtail;
1143d740f837SVincenzo Maffione /* another call to actually release the buffers */
1144d740f837SVincenzo Maffione error = kring->nm_sync(kring, 0);
1145d740f837SVincenzo Maffione
1146d740f837SVincenzo Maffione /* The second rxsync may have further advanced hwtail. If this happens,
1147d740f837SVincenzo Maffione * return NM_IRQ_RESCHED, otherwise just return NM_IRQ_COMPLETED. */
1148d740f837SVincenzo Maffione if (kring->rcur != kring->nr_hwtail) {
1149d740f837SVincenzo Maffione ret = NM_IRQ_RESCHED;
1150d740f837SVincenzo Maffione }
1151d740f837SVincenzo Maffione put_out:
1152d740f837SVincenzo Maffione nm_kr_put(kring);
1153d740f837SVincenzo Maffione
1154d740f837SVincenzo Maffione return error ? error : ret;
1155d740f837SVincenzo Maffione }
1156d740f837SVincenzo Maffione
1157d740f837SVincenzo Maffione
1158d740f837SVincenzo Maffione /* nm_register callback for bwrap */
1159d740f837SVincenzo Maffione int
netmap_bwrap_reg(struct netmap_adapter * na,int onoff)1160d740f837SVincenzo Maffione netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
1161d740f837SVincenzo Maffione {
1162d740f837SVincenzo Maffione struct netmap_bwrap_adapter *bna =
1163d740f837SVincenzo Maffione (struct netmap_bwrap_adapter *)na;
1164d740f837SVincenzo Maffione struct netmap_adapter *hwna = bna->hwna;
1165d740f837SVincenzo Maffione struct netmap_vp_adapter *hostna = &bna->host;
1166d740f837SVincenzo Maffione int error, i;
1167d740f837SVincenzo Maffione enum txrx t;
1168d740f837SVincenzo Maffione
1169*01e8e2c2SVincenzo Maffione nm_prdis("%s %s", na->name, onoff ? "on" : "off");
1170d740f837SVincenzo Maffione
1171d740f837SVincenzo Maffione if (onoff) {
1172d740f837SVincenzo Maffione /* netmap_do_regif has been called on the bwrap na.
1173d740f837SVincenzo Maffione * We need to pass the information about the
1174d740f837SVincenzo Maffione * memory allocator down to the hwna before
1175d740f837SVincenzo Maffione * putting it in netmap mode
1176d740f837SVincenzo Maffione */
1177d740f837SVincenzo Maffione hwna->na_lut = na->na_lut;
1178d740f837SVincenzo Maffione
1179d740f837SVincenzo Maffione if (hostna->na_bdg) {
1180d740f837SVincenzo Maffione /* if the host rings have been attached to switch,
1181d740f837SVincenzo Maffione * we need to copy the memory allocator information
1182d740f837SVincenzo Maffione * in the hostna also
1183d740f837SVincenzo Maffione */
1184d740f837SVincenzo Maffione hostna->up.na_lut = na->na_lut;
1185d740f837SVincenzo Maffione }
1186d740f837SVincenzo Maffione
1187d740f837SVincenzo Maffione }
1188d740f837SVincenzo Maffione
1189d740f837SVincenzo Maffione /* pass down the pending ring state information */
1190d740f837SVincenzo Maffione for_rx_tx(t) {
1191d740f837SVincenzo Maffione for (i = 0; i < netmap_all_rings(na, t); i++) {
1192d740f837SVincenzo Maffione NMR(hwna, nm_txrx_swap(t))[i]->nr_pending_mode =
1193d740f837SVincenzo Maffione NMR(na, t)[i]->nr_pending_mode;
1194d740f837SVincenzo Maffione }
1195d740f837SVincenzo Maffione }
1196d740f837SVincenzo Maffione
1197d740f837SVincenzo Maffione /* forward the request to the hwna */
1198d740f837SVincenzo Maffione error = hwna->nm_register(hwna, onoff);
1199d740f837SVincenzo Maffione if (error)
1200d740f837SVincenzo Maffione return error;
1201d740f837SVincenzo Maffione
1202d740f837SVincenzo Maffione /* copy up the current ring state information */
1203d740f837SVincenzo Maffione for_rx_tx(t) {
1204d740f837SVincenzo Maffione for (i = 0; i < netmap_all_rings(na, t); i++) {
1205d740f837SVincenzo Maffione struct netmap_kring *kring = NMR(hwna, nm_txrx_swap(t))[i];
1206d740f837SVincenzo Maffione NMR(na, t)[i]->nr_mode = kring->nr_mode;
1207d740f837SVincenzo Maffione }
1208d740f837SVincenzo Maffione }
1209d740f837SVincenzo Maffione
1210d740f837SVincenzo Maffione /* impersonate a netmap_vp_adapter */
1211d740f837SVincenzo Maffione netmap_vp_reg(na, onoff);
1212d740f837SVincenzo Maffione if (hostna->na_bdg)
1213d740f837SVincenzo Maffione netmap_vp_reg(&hostna->up, onoff);
1214d740f837SVincenzo Maffione
1215d740f837SVincenzo Maffione if (onoff) {
1216d740f837SVincenzo Maffione u_int i;
1217d740f837SVincenzo Maffione /* intercept the hwna nm_nofify callback on the hw rings */
1218d740f837SVincenzo Maffione for (i = 0; i < hwna->num_rx_rings; i++) {
1219d740f837SVincenzo Maffione hwna->rx_rings[i]->save_notify = hwna->rx_rings[i]->nm_notify;
1220d740f837SVincenzo Maffione hwna->rx_rings[i]->nm_notify = netmap_bwrap_intr_notify;
1221d740f837SVincenzo Maffione }
1222d740f837SVincenzo Maffione i = hwna->num_rx_rings; /* for safety */
1223d740f837SVincenzo Maffione /* save the host ring notify unconditionally */
1224d740f837SVincenzo Maffione for (; i < netmap_real_rings(hwna, NR_RX); i++) {
1225d740f837SVincenzo Maffione hwna->rx_rings[i]->save_notify =
1226d740f837SVincenzo Maffione hwna->rx_rings[i]->nm_notify;
1227d740f837SVincenzo Maffione if (hostna->na_bdg) {
1228d740f837SVincenzo Maffione /* also intercept the host ring notify */
1229d740f837SVincenzo Maffione hwna->rx_rings[i]->nm_notify =
1230d740f837SVincenzo Maffione netmap_bwrap_intr_notify;
1231d740f837SVincenzo Maffione na->tx_rings[i]->nm_sync = na->nm_txsync;
1232d740f837SVincenzo Maffione }
1233d740f837SVincenzo Maffione }
1234d740f837SVincenzo Maffione if (na->active_fds == 0)
1235d740f837SVincenzo Maffione na->na_flags |= NAF_NETMAP_ON;
1236d740f837SVincenzo Maffione } else {
1237d740f837SVincenzo Maffione u_int i;
1238d740f837SVincenzo Maffione
1239d740f837SVincenzo Maffione if (na->active_fds == 0)
1240d740f837SVincenzo Maffione na->na_flags &= ~NAF_NETMAP_ON;
1241d740f837SVincenzo Maffione
1242d740f837SVincenzo Maffione /* reset all notify callbacks (including host ring) */
1243d740f837SVincenzo Maffione for (i = 0; i < netmap_all_rings(hwna, NR_RX); i++) {
1244d740f837SVincenzo Maffione hwna->rx_rings[i]->nm_notify =
1245d740f837SVincenzo Maffione hwna->rx_rings[i]->save_notify;
1246d740f837SVincenzo Maffione hwna->rx_rings[i]->save_notify = NULL;
1247d740f837SVincenzo Maffione }
1248d740f837SVincenzo Maffione hwna->na_lut.lut = NULL;
1249d740f837SVincenzo Maffione hwna->na_lut.plut = NULL;
1250d740f837SVincenzo Maffione hwna->na_lut.objtotal = 0;
1251d740f837SVincenzo Maffione hwna->na_lut.objsize = 0;
1252d740f837SVincenzo Maffione
1253d740f837SVincenzo Maffione /* pass ownership of the netmap rings to the hwna */
1254d740f837SVincenzo Maffione for_rx_tx(t) {
1255d740f837SVincenzo Maffione for (i = 0; i < netmap_all_rings(na, t); i++) {
1256d740f837SVincenzo Maffione NMR(na, t)[i]->ring = NULL;
1257d740f837SVincenzo Maffione }
1258d740f837SVincenzo Maffione }
1259d740f837SVincenzo Maffione /* reset the number of host rings to default */
1260d740f837SVincenzo Maffione for_rx_tx(t) {
1261d740f837SVincenzo Maffione nma_set_host_nrings(hwna, t, 1);
1262d740f837SVincenzo Maffione }
1263d740f837SVincenzo Maffione
1264d740f837SVincenzo Maffione }
1265d740f837SVincenzo Maffione
1266d740f837SVincenzo Maffione return 0;
1267d740f837SVincenzo Maffione }
1268d740f837SVincenzo Maffione
1269d740f837SVincenzo Maffione /* nm_config callback for bwrap */
1270d740f837SVincenzo Maffione static int
netmap_bwrap_config(struct netmap_adapter * na,struct nm_config_info * info)1271d740f837SVincenzo Maffione netmap_bwrap_config(struct netmap_adapter *na, struct nm_config_info *info)
1272d740f837SVincenzo Maffione {
1273d740f837SVincenzo Maffione struct netmap_bwrap_adapter *bna =
1274d740f837SVincenzo Maffione (struct netmap_bwrap_adapter *)na;
1275d740f837SVincenzo Maffione struct netmap_adapter *hwna = bna->hwna;
1276d740f837SVincenzo Maffione int error;
1277d740f837SVincenzo Maffione
1278d740f837SVincenzo Maffione /* Forward the request to the hwna. It may happen that nobody
1279d740f837SVincenzo Maffione * registered hwna yet, so netmap_mem_get_lut() may have not
1280d740f837SVincenzo Maffione * been called yet. */
1281d740f837SVincenzo Maffione error = netmap_mem_get_lut(hwna->nm_mem, &hwna->na_lut);
1282d740f837SVincenzo Maffione if (error)
1283d740f837SVincenzo Maffione return error;
1284d740f837SVincenzo Maffione netmap_update_config(hwna);
1285d740f837SVincenzo Maffione /* swap the results and propagate */
1286d740f837SVincenzo Maffione info->num_tx_rings = hwna->num_rx_rings;
1287d740f837SVincenzo Maffione info->num_tx_descs = hwna->num_rx_desc;
1288d740f837SVincenzo Maffione info->num_rx_rings = hwna->num_tx_rings;
1289d740f837SVincenzo Maffione info->num_rx_descs = hwna->num_tx_desc;
1290d740f837SVincenzo Maffione info->rx_buf_maxsize = hwna->rx_buf_maxsize;
1291d740f837SVincenzo Maffione
1292d740f837SVincenzo Maffione return 0;
1293d740f837SVincenzo Maffione }
1294d740f837SVincenzo Maffione
1295d740f837SVincenzo Maffione
1296d740f837SVincenzo Maffione /* nm_krings_create callback for bwrap */
1297d740f837SVincenzo Maffione int
netmap_bwrap_krings_create_common(struct netmap_adapter * na)1298d740f837SVincenzo Maffione netmap_bwrap_krings_create_common(struct netmap_adapter *na)
1299d740f837SVincenzo Maffione {
1300d740f837SVincenzo Maffione struct netmap_bwrap_adapter *bna =
1301d740f837SVincenzo Maffione (struct netmap_bwrap_adapter *)na;
1302d740f837SVincenzo Maffione struct netmap_adapter *hwna = bna->hwna;
1303d740f837SVincenzo Maffione struct netmap_adapter *hostna = &bna->host.up;
1304d740f837SVincenzo Maffione int i, error = 0;
1305d740f837SVincenzo Maffione enum txrx t;
1306d740f837SVincenzo Maffione
1307d740f837SVincenzo Maffione /* also create the hwna krings */
1308d740f837SVincenzo Maffione error = hwna->nm_krings_create(hwna);
1309d740f837SVincenzo Maffione if (error) {
1310d740f837SVincenzo Maffione return error;
1311d740f837SVincenzo Maffione }
1312d740f837SVincenzo Maffione
1313d740f837SVincenzo Maffione /* increment the usage counter for all the hwna krings */
1314d740f837SVincenzo Maffione for_rx_tx(t) {
1315d740f837SVincenzo Maffione for (i = 0; i < netmap_all_rings(hwna, t); i++) {
1316d740f837SVincenzo Maffione NMR(hwna, t)[i]->users++;
1317d740f837SVincenzo Maffione }
1318d740f837SVincenzo Maffione }
1319d740f837SVincenzo Maffione
1320d740f837SVincenzo Maffione /* now create the actual rings */
1321d740f837SVincenzo Maffione error = netmap_mem_rings_create(hwna);
1322d740f837SVincenzo Maffione if (error) {
1323d740f837SVincenzo Maffione goto err_dec_users;
1324d740f837SVincenzo Maffione }
1325d740f837SVincenzo Maffione
1326d740f837SVincenzo Maffione /* cross-link the netmap rings
1327d740f837SVincenzo Maffione * The original number of rings comes from hwna,
1328d740f837SVincenzo Maffione * rx rings on one side equals tx rings on the other.
1329d740f837SVincenzo Maffione */
1330d740f837SVincenzo Maffione for_rx_tx(t) {
1331d740f837SVincenzo Maffione enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
1332d740f837SVincenzo Maffione for (i = 0; i < netmap_all_rings(hwna, r); i++) {
1333d740f837SVincenzo Maffione NMR(na, t)[i]->nkr_num_slots = NMR(hwna, r)[i]->nkr_num_slots;
1334d740f837SVincenzo Maffione NMR(na, t)[i]->ring = NMR(hwna, r)[i]->ring;
1335d740f837SVincenzo Maffione }
1336d740f837SVincenzo Maffione }
1337d740f837SVincenzo Maffione
1338d740f837SVincenzo Maffione if (na->na_flags & NAF_HOST_RINGS) {
1339d740f837SVincenzo Maffione /* the hostna rings are the host rings of the bwrap.
1340d740f837SVincenzo Maffione * The corresponding krings must point back to the
1341d740f837SVincenzo Maffione * hostna
1342d740f837SVincenzo Maffione */
1343d740f837SVincenzo Maffione hostna->tx_rings = &na->tx_rings[na->num_tx_rings];
1344d740f837SVincenzo Maffione hostna->rx_rings = &na->rx_rings[na->num_rx_rings];
1345d740f837SVincenzo Maffione for_rx_tx(t) {
1346d740f837SVincenzo Maffione for (i = 0; i < nma_get_nrings(hostna, t); i++) {
1347d740f837SVincenzo Maffione NMR(hostna, t)[i]->na = hostna;
1348d740f837SVincenzo Maffione }
1349d740f837SVincenzo Maffione }
1350d740f837SVincenzo Maffione }
1351d740f837SVincenzo Maffione
1352d740f837SVincenzo Maffione return 0;
1353d740f837SVincenzo Maffione
1354d740f837SVincenzo Maffione err_dec_users:
1355d740f837SVincenzo Maffione for_rx_tx(t) {
1356d740f837SVincenzo Maffione for (i = 0; i < netmap_all_rings(hwna, t); i++) {
1357d740f837SVincenzo Maffione NMR(hwna, t)[i]->users--;
1358d740f837SVincenzo Maffione }
1359d740f837SVincenzo Maffione }
1360d740f837SVincenzo Maffione hwna->nm_krings_delete(hwna);
1361d740f837SVincenzo Maffione return error;
1362d740f837SVincenzo Maffione }
1363d740f837SVincenzo Maffione
1364d740f837SVincenzo Maffione
1365d740f837SVincenzo Maffione void
netmap_bwrap_krings_delete_common(struct netmap_adapter * na)1366d740f837SVincenzo Maffione netmap_bwrap_krings_delete_common(struct netmap_adapter *na)
1367d740f837SVincenzo Maffione {
1368d740f837SVincenzo Maffione struct netmap_bwrap_adapter *bna =
1369d740f837SVincenzo Maffione (struct netmap_bwrap_adapter *)na;
1370d740f837SVincenzo Maffione struct netmap_adapter *hwna = bna->hwna;
1371d740f837SVincenzo Maffione enum txrx t;
1372d740f837SVincenzo Maffione int i;
1373d740f837SVincenzo Maffione
1374*01e8e2c2SVincenzo Maffione nm_prdis("%s", na->name);
1375d740f837SVincenzo Maffione
1376d740f837SVincenzo Maffione /* decrement the usage counter for all the hwna krings */
1377d740f837SVincenzo Maffione for_rx_tx(t) {
1378d740f837SVincenzo Maffione for (i = 0; i < netmap_all_rings(hwna, t); i++) {
1379d740f837SVincenzo Maffione NMR(hwna, t)[i]->users--;
1380d740f837SVincenzo Maffione }
1381d740f837SVincenzo Maffione }
1382d740f837SVincenzo Maffione
1383d740f837SVincenzo Maffione /* delete any netmap rings that are no longer needed */
1384d740f837SVincenzo Maffione netmap_mem_rings_delete(hwna);
1385d740f837SVincenzo Maffione hwna->nm_krings_delete(hwna);
1386d740f837SVincenzo Maffione }
1387d740f837SVincenzo Maffione
1388d740f837SVincenzo Maffione
1389d740f837SVincenzo Maffione /* notify method for the bridge-->hwna direction */
1390d740f837SVincenzo Maffione int
netmap_bwrap_notify(struct netmap_kring * kring,int flags)1391d740f837SVincenzo Maffione netmap_bwrap_notify(struct netmap_kring *kring, int flags)
1392d740f837SVincenzo Maffione {
1393d740f837SVincenzo Maffione struct netmap_adapter *na = kring->na;
1394d740f837SVincenzo Maffione struct netmap_bwrap_adapter *bna = na->na_private;
1395d740f837SVincenzo Maffione struct netmap_adapter *hwna = bna->hwna;
1396d740f837SVincenzo Maffione u_int ring_n = kring->ring_id;
1397d740f837SVincenzo Maffione u_int lim = kring->nkr_num_slots - 1;
1398d740f837SVincenzo Maffione struct netmap_kring *hw_kring;
1399d740f837SVincenzo Maffione int error;
1400d740f837SVincenzo Maffione
1401*01e8e2c2SVincenzo Maffione nm_prdis("%s: na %s hwna %s",
1402d740f837SVincenzo Maffione (kring ? kring->name : "NULL!"),
1403d740f837SVincenzo Maffione (na ? na->name : "NULL!"),
1404d740f837SVincenzo Maffione (hwna ? hwna->name : "NULL!"));
1405d740f837SVincenzo Maffione hw_kring = hwna->tx_rings[ring_n];
1406d740f837SVincenzo Maffione
1407d740f837SVincenzo Maffione if (nm_kr_tryget(hw_kring, 0, NULL)) {
1408d740f837SVincenzo Maffione return ENXIO;
1409d740f837SVincenzo Maffione }
1410d740f837SVincenzo Maffione
1411d740f837SVincenzo Maffione /* first step: simulate a user wakeup on the rx ring */
1412d740f837SVincenzo Maffione netmap_vp_rxsync(kring, flags);
1413*01e8e2c2SVincenzo Maffione nm_prdis("%s[%d] PRE rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)",
1414d740f837SVincenzo Maffione na->name, ring_n,
1415d740f837SVincenzo Maffione kring->nr_hwcur, kring->nr_hwtail, kring->nkr_hwlease,
1416b321acabSVincenzo Maffione kring->rhead, kring->rcur, kring->rtail,
1417b321acabSVincenzo Maffione hw_kring->nr_hwcur, hw_kring->nr_hwtail, hw_kring->rtail);
1418d740f837SVincenzo Maffione /* second step: the new packets are sent on the tx ring
1419d740f837SVincenzo Maffione * (which is actually the same ring)
1420d740f837SVincenzo Maffione */
1421d740f837SVincenzo Maffione hw_kring->rhead = hw_kring->rcur = kring->nr_hwtail;
1422d740f837SVincenzo Maffione error = hw_kring->nm_sync(hw_kring, flags);
1423d740f837SVincenzo Maffione if (error)
1424d740f837SVincenzo Maffione goto put_out;
1425d740f837SVincenzo Maffione
1426d740f837SVincenzo Maffione /* third step: now we are back the rx ring */
1427d740f837SVincenzo Maffione /* claim ownership on all hw owned bufs */
1428d740f837SVincenzo Maffione kring->rhead = kring->rcur = nm_next(hw_kring->nr_hwtail, lim); /* skip past reserved slot */
1429d740f837SVincenzo Maffione
1430d740f837SVincenzo Maffione /* fourth step: the user goes to sleep again, causing another rxsync */
1431d740f837SVincenzo Maffione netmap_vp_rxsync(kring, flags);
1432*01e8e2c2SVincenzo Maffione nm_prdis("%s[%d] PST rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)",
1433d740f837SVincenzo Maffione na->name, ring_n,
1434d740f837SVincenzo Maffione kring->nr_hwcur, kring->nr_hwtail, kring->nkr_hwlease,
1435b321acabSVincenzo Maffione kring->rhead, kring->rcur, kring->rtail,
1436d740f837SVincenzo Maffione hw_kring->nr_hwcur, hw_kring->nr_hwtail, hw_kring->rtail);
1437d740f837SVincenzo Maffione put_out:
1438d740f837SVincenzo Maffione nm_kr_put(hw_kring);
1439d740f837SVincenzo Maffione
1440d740f837SVincenzo Maffione return error ? error : NM_IRQ_COMPLETED;
1441d740f837SVincenzo Maffione }
1442d740f837SVincenzo Maffione
1443d740f837SVincenzo Maffione
1444d740f837SVincenzo Maffione /* nm_bdg_ctl callback for the bwrap.
1445d740f837SVincenzo Maffione * Called on bridge-attach and detach, as an effect of vale-ctl -[ahd].
1446d740f837SVincenzo Maffione * On attach, it needs to provide a fake netmap_priv_d structure and
1447d740f837SVincenzo Maffione * perform a netmap_do_regif() on the bwrap. This will put both the
1448d740f837SVincenzo Maffione * bwrap and the hwna in netmap mode, with the netmap rings shared
1449d740f837SVincenzo Maffione * and cross linked. Moroever, it will start intercepting interrupts
1450d740f837SVincenzo Maffione * directed to hwna.
1451d740f837SVincenzo Maffione */
1452d740f837SVincenzo Maffione static int
netmap_bwrap_bdg_ctl(struct nmreq_header * hdr,struct netmap_adapter * na)1453d740f837SVincenzo Maffione netmap_bwrap_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
1454d740f837SVincenzo Maffione {
1455d740f837SVincenzo Maffione struct netmap_priv_d *npriv;
1456d740f837SVincenzo Maffione struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter*)na;
1457d740f837SVincenzo Maffione int error = 0;
1458d740f837SVincenzo Maffione
1459d740f837SVincenzo Maffione if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
1460d740f837SVincenzo Maffione struct nmreq_vale_attach *req =
1461d740f837SVincenzo Maffione (struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body;
1462d740f837SVincenzo Maffione if (req->reg.nr_ringid != 0 ||
1463d740f837SVincenzo Maffione (req->reg.nr_mode != NR_REG_ALL_NIC &&
1464d740f837SVincenzo Maffione req->reg.nr_mode != NR_REG_NIC_SW)) {
1465d740f837SVincenzo Maffione /* We only support attaching all the NIC rings
1466d740f837SVincenzo Maffione * and/or the host stack. */
1467d740f837SVincenzo Maffione return EINVAL;
1468d740f837SVincenzo Maffione }
1469d740f837SVincenzo Maffione if (NETMAP_OWNED_BY_ANY(na)) {
1470d740f837SVincenzo Maffione return EBUSY;
1471d740f837SVincenzo Maffione }
1472d740f837SVincenzo Maffione if (bna->na_kpriv) {
1473d740f837SVincenzo Maffione /* nothing to do */
1474d740f837SVincenzo Maffione return 0;
1475d740f837SVincenzo Maffione }
1476d740f837SVincenzo Maffione npriv = netmap_priv_new();
1477d740f837SVincenzo Maffione if (npriv == NULL)
1478d740f837SVincenzo Maffione return ENOMEM;
1479d740f837SVincenzo Maffione npriv->np_ifp = na->ifp; /* let the priv destructor release the ref */
1480d740f837SVincenzo Maffione error = netmap_do_regif(npriv, na, req->reg.nr_mode,
1481d740f837SVincenzo Maffione req->reg.nr_ringid, req->reg.nr_flags);
1482d740f837SVincenzo Maffione if (error) {
1483d740f837SVincenzo Maffione netmap_priv_delete(npriv);
1484d740f837SVincenzo Maffione return error;
1485d740f837SVincenzo Maffione }
1486d740f837SVincenzo Maffione bna->na_kpriv = npriv;
1487d740f837SVincenzo Maffione na->na_flags |= NAF_BUSY;
1488d740f837SVincenzo Maffione } else {
1489d740f837SVincenzo Maffione if (na->active_fds == 0) /* not registered */
1490d740f837SVincenzo Maffione return EINVAL;
1491d740f837SVincenzo Maffione netmap_priv_delete(bna->na_kpriv);
1492d740f837SVincenzo Maffione bna->na_kpriv = NULL;
1493d740f837SVincenzo Maffione na->na_flags &= ~NAF_BUSY;
1494d740f837SVincenzo Maffione }
1495d740f837SVincenzo Maffione
1496d740f837SVincenzo Maffione return error;
1497d740f837SVincenzo Maffione }
1498d740f837SVincenzo Maffione
1499d740f837SVincenzo Maffione /* attach a bridge wrapper to the 'real' device */
1500d740f837SVincenzo Maffione int
netmap_bwrap_attach_common(struct netmap_adapter * na,struct netmap_adapter * hwna)1501d740f837SVincenzo Maffione netmap_bwrap_attach_common(struct netmap_adapter *na,
1502d740f837SVincenzo Maffione struct netmap_adapter *hwna)
1503d740f837SVincenzo Maffione {
1504d740f837SVincenzo Maffione struct netmap_bwrap_adapter *bna;
1505d740f837SVincenzo Maffione struct netmap_adapter *hostna = NULL;
1506d740f837SVincenzo Maffione int error = 0;
1507d740f837SVincenzo Maffione enum txrx t;
1508d740f837SVincenzo Maffione
1509d740f837SVincenzo Maffione /* make sure the NIC is not already in use */
1510d740f837SVincenzo Maffione if (NETMAP_OWNED_BY_ANY(hwna)) {
1511b321acabSVincenzo Maffione nm_prerr("NIC %s busy, cannot attach to bridge", hwna->name);
1512d740f837SVincenzo Maffione return EBUSY;
1513d740f837SVincenzo Maffione }
1514d740f837SVincenzo Maffione
1515d740f837SVincenzo Maffione bna = (struct netmap_bwrap_adapter *)na;
1516d740f837SVincenzo Maffione /* make bwrap ifp point to the real ifp */
1517d740f837SVincenzo Maffione na->ifp = hwna->ifp;
1518d740f837SVincenzo Maffione if_ref(na->ifp);
1519d740f837SVincenzo Maffione na->na_private = bna;
1520d740f837SVincenzo Maffione /* fill the ring data for the bwrap adapter with rx/tx meanings
1521d740f837SVincenzo Maffione * swapped. The real cross-linking will be done during register,
1522d740f837SVincenzo Maffione * when all the krings will have been created.
1523d740f837SVincenzo Maffione */
1524d740f837SVincenzo Maffione for_rx_tx(t) {
1525d740f837SVincenzo Maffione enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
1526d740f837SVincenzo Maffione nma_set_nrings(na, t, nma_get_nrings(hwna, r));
1527d740f837SVincenzo Maffione nma_set_ndesc(na, t, nma_get_ndesc(hwna, r));
1528d740f837SVincenzo Maffione }
1529d740f837SVincenzo Maffione na->nm_dtor = netmap_bwrap_dtor;
1530d740f837SVincenzo Maffione na->nm_config = netmap_bwrap_config;
1531d740f837SVincenzo Maffione na->nm_bdg_ctl = netmap_bwrap_bdg_ctl;
1532d740f837SVincenzo Maffione na->pdev = hwna->pdev;
1533d740f837SVincenzo Maffione na->nm_mem = netmap_mem_get(hwna->nm_mem);
1534d740f837SVincenzo Maffione na->virt_hdr_len = hwna->virt_hdr_len;
1535d740f837SVincenzo Maffione na->rx_buf_maxsize = hwna->rx_buf_maxsize;
1536d740f837SVincenzo Maffione
1537d740f837SVincenzo Maffione bna->hwna = hwna;
1538d740f837SVincenzo Maffione netmap_adapter_get(hwna);
1539d740f837SVincenzo Maffione hwna->na_private = bna; /* weak reference */
1540d740f837SVincenzo Maffione bna->saved_na_vp = hwna->na_vp;
1541d740f837SVincenzo Maffione hwna->na_vp = &bna->up;
1542d740f837SVincenzo Maffione bna->up.up.na_vp = &(bna->up);
1543d740f837SVincenzo Maffione
1544d740f837SVincenzo Maffione if (hwna->na_flags & NAF_HOST_RINGS) {
1545d740f837SVincenzo Maffione if (hwna->na_flags & NAF_SW_ONLY)
1546d740f837SVincenzo Maffione na->na_flags |= NAF_SW_ONLY;
1547d740f837SVincenzo Maffione na->na_flags |= NAF_HOST_RINGS;
1548d740f837SVincenzo Maffione hostna = &bna->host.up;
1549d740f837SVincenzo Maffione
1550d740f837SVincenzo Maffione /* limit the number of host rings to that of hw */
1551d740f837SVincenzo Maffione nm_bound_var(&hostna->num_tx_rings, 1, 1,
1552d740f837SVincenzo Maffione nma_get_nrings(hwna, NR_TX), NULL);
1553d740f837SVincenzo Maffione nm_bound_var(&hostna->num_rx_rings, 1, 1,
1554d740f837SVincenzo Maffione nma_get_nrings(hwna, NR_RX), NULL);
1555d740f837SVincenzo Maffione
1556d740f837SVincenzo Maffione snprintf(hostna->name, sizeof(hostna->name), "%s^", na->name);
1557d740f837SVincenzo Maffione hostna->ifp = hwna->ifp;
1558d740f837SVincenzo Maffione for_rx_tx(t) {
1559d740f837SVincenzo Maffione enum txrx r = nm_txrx_swap(t);
1560d740f837SVincenzo Maffione u_int nr = nma_get_nrings(hostna, t);
1561d740f837SVincenzo Maffione
1562d740f837SVincenzo Maffione nma_set_nrings(hostna, t, nr);
1563d740f837SVincenzo Maffione nma_set_host_nrings(na, t, nr);
1564d740f837SVincenzo Maffione if (nma_get_host_nrings(hwna, t) < nr) {
1565d740f837SVincenzo Maffione nma_set_host_nrings(hwna, t, nr);
1566d740f837SVincenzo Maffione }
1567d740f837SVincenzo Maffione nma_set_ndesc(hostna, t, nma_get_ndesc(hwna, r));
1568d740f837SVincenzo Maffione }
1569d740f837SVincenzo Maffione // hostna->nm_txsync = netmap_bwrap_host_txsync;
1570d740f837SVincenzo Maffione // hostna->nm_rxsync = netmap_bwrap_host_rxsync;
1571d740f837SVincenzo Maffione hostna->nm_mem = netmap_mem_get(na->nm_mem);
1572d740f837SVincenzo Maffione hostna->na_private = bna;
1573d740f837SVincenzo Maffione hostna->na_vp = &bna->up;
1574d740f837SVincenzo Maffione na->na_hostvp = hwna->na_hostvp =
1575d740f837SVincenzo Maffione hostna->na_hostvp = &bna->host;
1576d740f837SVincenzo Maffione hostna->na_flags = NAF_BUSY; /* prevent NIOCREGIF */
1577d740f837SVincenzo Maffione hostna->rx_buf_maxsize = hwna->rx_buf_maxsize;
1578d740f837SVincenzo Maffione }
1579b321acabSVincenzo Maffione if (hwna->na_flags & NAF_MOREFRAG)
1580b321acabSVincenzo Maffione na->na_flags |= NAF_MOREFRAG;
1581d740f837SVincenzo Maffione
1582*01e8e2c2SVincenzo Maffione nm_prdis("%s<->%s txr %d txd %d rxr %d rxd %d",
1583d740f837SVincenzo Maffione na->name, ifp->if_xname,
1584d740f837SVincenzo Maffione na->num_tx_rings, na->num_tx_desc,
1585d740f837SVincenzo Maffione na->num_rx_rings, na->num_rx_desc);
1586d740f837SVincenzo Maffione
1587d740f837SVincenzo Maffione error = netmap_attach_common(na);
1588d740f837SVincenzo Maffione if (error) {
1589d740f837SVincenzo Maffione goto err_put;
1590d740f837SVincenzo Maffione }
1591d740f837SVincenzo Maffione hwna->na_flags |= NAF_BUSY;
1592d740f837SVincenzo Maffione return 0;
1593d740f837SVincenzo Maffione
1594d740f837SVincenzo Maffione err_put:
1595d740f837SVincenzo Maffione hwna->na_vp = hwna->na_hostvp = NULL;
1596d740f837SVincenzo Maffione netmap_adapter_put(hwna);
1597d740f837SVincenzo Maffione return error;
1598d740f837SVincenzo Maffione
1599d740f837SVincenzo Maffione }
1600d740f837SVincenzo Maffione
1601d740f837SVincenzo Maffione struct nm_bridge *
netmap_init_bridges2(u_int n)1602d740f837SVincenzo Maffione netmap_init_bridges2(u_int n)
1603d740f837SVincenzo Maffione {
1604d740f837SVincenzo Maffione int i;
1605d740f837SVincenzo Maffione struct nm_bridge *b;
1606d740f837SVincenzo Maffione
1607d740f837SVincenzo Maffione b = nm_os_malloc(sizeof(struct nm_bridge) * n);
1608d740f837SVincenzo Maffione if (b == NULL)
1609d740f837SVincenzo Maffione return NULL;
1610d740f837SVincenzo Maffione for (i = 0; i < n; i++)
1611d740f837SVincenzo Maffione BDG_RWINIT(&b[i]);
1612d740f837SVincenzo Maffione return b;
1613d740f837SVincenzo Maffione }
1614d740f837SVincenzo Maffione
1615d740f837SVincenzo Maffione void
netmap_uninit_bridges2(struct nm_bridge * b,u_int n)1616d740f837SVincenzo Maffione netmap_uninit_bridges2(struct nm_bridge *b, u_int n)
1617d740f837SVincenzo Maffione {
1618d740f837SVincenzo Maffione int i;
1619d740f837SVincenzo Maffione
1620d740f837SVincenzo Maffione if (b == NULL)
1621d740f837SVincenzo Maffione return;
1622d740f837SVincenzo Maffione
1623d740f837SVincenzo Maffione for (i = 0; i < n; i++)
1624d740f837SVincenzo Maffione BDG_RWDESTROY(&b[i]);
1625d740f837SVincenzo Maffione nm_os_free(b);
1626d740f837SVincenzo Maffione }
1627d740f837SVincenzo Maffione
1628d740f837SVincenzo Maffione int
netmap_init_bridges(void)1629d740f837SVincenzo Maffione netmap_init_bridges(void)
1630d740f837SVincenzo Maffione {
1631d740f837SVincenzo Maffione #ifdef CONFIG_NET_NS
1632d740f837SVincenzo Maffione return netmap_bns_register();
1633d740f837SVincenzo Maffione #else
1634d740f837SVincenzo Maffione nm_bridges = netmap_init_bridges2(NM_BRIDGES);
1635d740f837SVincenzo Maffione if (nm_bridges == NULL)
1636d740f837SVincenzo Maffione return ENOMEM;
1637d740f837SVincenzo Maffione return 0;
1638d740f837SVincenzo Maffione #endif
1639d740f837SVincenzo Maffione }
1640d740f837SVincenzo Maffione
1641d740f837SVincenzo Maffione void
netmap_uninit_bridges(void)1642d740f837SVincenzo Maffione netmap_uninit_bridges(void)
1643d740f837SVincenzo Maffione {
1644d740f837SVincenzo Maffione #ifdef CONFIG_NET_NS
1645d740f837SVincenzo Maffione netmap_bns_unregister();
1646d740f837SVincenzo Maffione #else
1647d740f837SVincenzo Maffione netmap_uninit_bridges2(nm_bridges, NM_BRIDGES);
1648d740f837SVincenzo Maffione #endif
1649d740f837SVincenzo Maffione }
1650