xref: /dflybsd-src/sys/net/netmap/netmap_vale.c (revision f933b737dabc806a2f1680f0afea2fb42a345b92)
1fb578518SFranco Fichtner /*
2fb578518SFranco Fichtner  * Copyright (C) 2013 Universita` di Pisa. All rights reserved.
3fb578518SFranco Fichtner  *
4fb578518SFranco Fichtner  * Redistribution and use in source and binary forms, with or without
5fb578518SFranco Fichtner  * modification, are permitted provided that the following conditions
6fb578518SFranco Fichtner  * are met:
7fb578518SFranco Fichtner  *   1. Redistributions of source code must retain the above copyright
8fb578518SFranco Fichtner  *      notice, this list of conditions and the following disclaimer.
9fb578518SFranco Fichtner  *   2. Redistributions in binary form must reproduce the above copyright
10fb578518SFranco Fichtner  *      notice, this list of conditions and the following disclaimer in the
11fb578518SFranco Fichtner  *      documentation and/or other materials provided with the distribution.
12fb578518SFranco Fichtner  *
13fb578518SFranco Fichtner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14fb578518SFranco Fichtner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15fb578518SFranco Fichtner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16fb578518SFranco Fichtner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17fb578518SFranco Fichtner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18fb578518SFranco Fichtner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19fb578518SFranco Fichtner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20fb578518SFranco Fichtner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21fb578518SFranco Fichtner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22fb578518SFranco Fichtner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23fb578518SFranco Fichtner  * SUCH DAMAGE.
24fb578518SFranco Fichtner  */
25fb578518SFranco Fichtner 
26fb578518SFranco Fichtner 
27fb578518SFranco Fichtner /*
28fb578518SFranco Fichtner  * This module implements the VALE switch for netmap
29fb578518SFranco Fichtner 
30fb578518SFranco Fichtner --- VALE SWITCH ---
31fb578518SFranco Fichtner 
32fb578518SFranco Fichtner NMG_LOCK() serializes all modifications to switches and ports.
33fb578518SFranco Fichtner A switch cannot be deleted until all ports are gone.
34fb578518SFranco Fichtner 
35fb578518SFranco Fichtner For each switch, an SX lock (RWlock on linux) protects
36fb578518SFranco Fichtner deletion of ports. When configuring or deleting a new port, the
37fb578518SFranco Fichtner lock is acquired in exclusive mode (after holding NMG_LOCK).
38fb578518SFranco Fichtner When forwarding, the lock is acquired in shared mode (without NMG_LOCK).
39fb578518SFranco Fichtner The lock is held throughout the entire forwarding cycle,
40fb578518SFranco Fichtner during which the thread may incur in a page fault.
41fb578518SFranco Fichtner Hence it is important that sleepable shared locks are used.
42fb578518SFranco Fichtner 
43fb578518SFranco Fichtner On the rx ring, the per-port lock is grabbed initially to reserve
44fb578518SFranco Fichtner a number of slot in the ring, then the lock is released,
45fb578518SFranco Fichtner packets are copied from source to destination, and then
46fb578518SFranco Fichtner the lock is acquired again and the receive ring is updated.
47fb578518SFranco Fichtner (A similar thing is done on the tx ring for NIC and host stack
48fb578518SFranco Fichtner ports attached to the switch)
49fb578518SFranco Fichtner 
50fb578518SFranco Fichtner  */
51fb578518SFranco Fichtner 
52fb578518SFranco Fichtner /*
53fb578518SFranco Fichtner  * OS-specific code that is used only within this file.
54fb578518SFranco Fichtner  * Other OS-specific code that must be accessed by drivers
55fb578518SFranco Fichtner  * is present in netmap_kern.h
56fb578518SFranco Fichtner  */
57fb578518SFranco Fichtner 
58785c7ee6SFranco Fichtner #include <sys/cdefs.h> /* prerequisite */
59785c7ee6SFranco Fichtner __FBSDID("$FreeBSD: head/sys/dev/netmap/netmap.c 257176 2013-10-26 17:58:36Z glebius $");
60fb578518SFranco Fichtner 
61fb578518SFranco Fichtner #include <sys/types.h>
62fb578518SFranco Fichtner #include <sys/errno.h>
63fb578518SFranco Fichtner #include <sys/param.h>	/* defines used in kernel.h */
64fb578518SFranco Fichtner #include <sys/kernel.h>	/* types used in module initialization */
65fb578518SFranco Fichtner #include <sys/conf.h>	/* cdevsw struct, UID, GID */
66fb578518SFranco Fichtner #include <sys/sockio.h>
67fb578518SFranco Fichtner #include <sys/socketvar.h>	/* struct socket */
68fb578518SFranco Fichtner #include <sys/malloc.h>
69fb578518SFranco Fichtner #include <sys/poll.h>
70bf9f7c16SFranco Fichtner #include <sys/lock.h>
71fb578518SFranco Fichtner #include <sys/socket.h> /* sockaddrs */
72fb578518SFranco Fichtner #include <sys/sysctl.h>
73fb578518SFranco Fichtner #include <net/if.h>
74fb578518SFranco Fichtner #include <net/if_var.h>
75fb578518SFranco Fichtner #include <net/bpf.h>		/* BIOCIMMEDIATE */
76bf9f7c16SFranco Fichtner #include <sys/bus.h>	/* bus_dmamap_* */
77fb578518SFranco Fichtner #include <sys/endian.h>
78fb578518SFranco Fichtner #include <sys/refcount.h>
79fb578518SFranco Fichtner 
80fb578518SFranco Fichtner 
81bf9f7c16SFranco Fichtner #define BDG_RWLOCK_T		struct lock
82fb578518SFranco Fichtner 
83fb578518SFranco Fichtner #define	BDG_RWINIT(b)		\
84bf9f7c16SFranco Fichtner 	lockinit(&(b)->bdg_lock, "bdg lock", 0, LK_CANRECURSE)
85bf9f7c16SFranco Fichtner #define BDG_WLOCK(b)		lockmgr(&(b)->bdg_lock, LK_EXCLUSIVE)
86bf9f7c16SFranco Fichtner #define BDG_WUNLOCK(b)		lockmgr(&(b)->bdg_lock, LK_RELEASE)
87bf9f7c16SFranco Fichtner #define BDG_RLOCK(b)		lockmgr(&(b)->bdg_lock, LK_SHARED)
88bf9f7c16SFranco Fichtner #define BDG_RTRYLOCK(b)		lockmgr(&(b)->bdg_lock, LK_SHARED|LK_NOWAIT)
89bf9f7c16SFranco Fichtner #define BDG_RUNLOCK(b)		lockmgr(&(b)->bdg_lock, LK_RELEASE)
90bf9f7c16SFranco Fichtner #define BDG_RWDESTROY(b)	lockuninit(&(b)->bdg_lock)
91fb578518SFranco Fichtner 
92fb578518SFranco Fichtner /*
93fb578518SFranco Fichtner  * common headers
94fb578518SFranco Fichtner  */
95fb578518SFranco Fichtner 
96*f933b737SSascha Wildner #include <net/netmap/netmap.h>
97b3f97fadSFranco Fichtner #include <net/netmap/netmap_kern.h>
98b3f97fadSFranco Fichtner #include <net/netmap/netmap_mem2.h>
99fb578518SFranco Fichtner 
100fb578518SFranco Fichtner #ifdef WITH_VALE
101fb578518SFranco Fichtner 
102fb578518SFranco Fichtner /*
103fb578518SFranco Fichtner  * system parameters (most of them in netmap_kern.h)
104fb578518SFranco Fichtner  * NM_NAME	prefix for switch port names, default "vale"
105fb578518SFranco Fichtner  * NM_BDG_MAXPORTS	number of ports
106fb578518SFranco Fichtner  * NM_BRIDGES	max number of switches in the system.
107fb578518SFranco Fichtner  *	XXX should become a sysctl or tunable
108fb578518SFranco Fichtner  *
109fb578518SFranco Fichtner  * Switch ports are named valeX:Y where X is the switch name and Y
110fb578518SFranco Fichtner  * is the port. If Y matches a physical interface name, the port is
111fb578518SFranco Fichtner  * connected to a physical device.
112fb578518SFranco Fichtner  *
113fb578518SFranco Fichtner  * Unlike physical interfaces, switch ports use their own memory region
114fb578518SFranco Fichtner  * for rings and buffers.
115fb578518SFranco Fichtner  * The virtual interfaces use per-queue lock instead of core lock.
116fb578518SFranco Fichtner  * In the tx loop, we aggregate traffic in batches to make all operations
117fb578518SFranco Fichtner  * faster. The batch size is bridge_batch.
118fb578518SFranco Fichtner  */
119fb578518SFranco Fichtner #define NM_BDG_MAXRINGS		16	/* XXX unclear how many. */
120fb578518SFranco Fichtner #define NM_BDG_MAXSLOTS		4096	/* XXX same as above */
121fb578518SFranco Fichtner #define NM_BRIDGE_RINGSIZE	1024	/* in the device */
122fb578518SFranco Fichtner #define NM_BDG_HASH		1024	/* forwarding table entries */
123fb578518SFranco Fichtner #define NM_BDG_BATCH		1024	/* entries in the forwarding buffer */
124fb578518SFranco Fichtner #define NM_MULTISEG		64	/* max size of a chain of bufs */
125fb578518SFranco Fichtner /* actual size of the tables */
126fb578518SFranco Fichtner #define NM_BDG_BATCH_MAX	(NM_BDG_BATCH + NM_MULTISEG)
127fb578518SFranco Fichtner /* NM_FT_NULL terminates a list of slots in the ft */
128fb578518SFranco Fichtner #define NM_FT_NULL		NM_BDG_BATCH_MAX
129fb578518SFranco Fichtner #define	NM_BRIDGES		8	/* number of bridges */
130fb578518SFranco Fichtner 
131fb578518SFranco Fichtner 
132fb578518SFranco Fichtner /*
133fb578518SFranco Fichtner  * bridge_batch is set via sysctl to the max batch size to be
134fb578518SFranco Fichtner  * used in the bridge. The actual value may be larger as the
135fb578518SFranco Fichtner  * last packet in the block may overflow the size.
136fb578518SFranco Fichtner  */
137fb578518SFranco Fichtner int bridge_batch = NM_BDG_BATCH; /* bridge batch size */
138fb578518SFranco Fichtner SYSCTL_DECL(_dev_netmap);
139fb578518SFranco Fichtner SYSCTL_INT(_dev_netmap, OID_AUTO, bridge_batch, CTLFLAG_RW, &bridge_batch, 0 , "");
140fb578518SFranco Fichtner 
141fb578518SFranco Fichtner 
142fb578518SFranco Fichtner static int bdg_netmap_attach(struct netmap_adapter *);
143fb578518SFranco Fichtner static int bdg_netmap_reg(struct netmap_adapter *na, int onoff);
144fb578518SFranco Fichtner static int netmap_bwrap_attach(struct ifnet *, struct ifnet *);
145fb578518SFranco Fichtner static int netmap_bwrap_register(struct netmap_adapter *, int onoff);
146fb578518SFranco Fichtner int kern_netmap_regif(struct nmreq *nmr);
147fb578518SFranco Fichtner 
148fb578518SFranco Fichtner /*
149fb578518SFranco Fichtner  * Each transmit queue accumulates a batch of packets into
150fb578518SFranco Fichtner  * a structure before forwarding. Packets to the same
151fb578518SFranco Fichtner  * destination are put in a list using ft_next as a link field.
152fb578518SFranco Fichtner  * ft_frags and ft_next are valid only on the first fragment.
153fb578518SFranco Fichtner  */
154fb578518SFranco Fichtner struct nm_bdg_fwd {	/* forwarding entry for a bridge */
155fb578518SFranco Fichtner 	void *ft_buf;		/* netmap or indirect buffer */
156fb578518SFranco Fichtner 	uint8_t ft_frags;	/* how many fragments (only on 1st frag) */
157fb578518SFranco Fichtner 	uint8_t _ft_port;	/* dst port (unused) */
158fb578518SFranco Fichtner 	uint16_t ft_flags;	/* flags, e.g. indirect */
159fb578518SFranco Fichtner 	uint16_t ft_len;	/* src fragment len */
160fb578518SFranco Fichtner 	uint16_t ft_next;	/* next packet to same destination */
161fb578518SFranco Fichtner };
162fb578518SFranco Fichtner 
163fb578518SFranco Fichtner /*
164fb578518SFranco Fichtner  * For each output interface, nm_bdg_q is used to construct a list.
165fb578518SFranco Fichtner  * bq_len is the number of output buffers (we can have coalescing
166fb578518SFranco Fichtner  * during the copy).
167fb578518SFranco Fichtner  */
168fb578518SFranco Fichtner struct nm_bdg_q {
169fb578518SFranco Fichtner 	uint16_t bq_head;
170fb578518SFranco Fichtner 	uint16_t bq_tail;
171fb578518SFranco Fichtner 	uint32_t bq_len;	/* number of buffers */
172fb578518SFranco Fichtner };
173fb578518SFranco Fichtner 
174fb578518SFranco Fichtner /* XXX revise this */
175fb578518SFranco Fichtner struct nm_hash_ent {
176fb578518SFranco Fichtner 	uint64_t	mac;	/* the top 2 bytes are the epoch */
177fb578518SFranco Fichtner 	uint64_t	ports;
178fb578518SFranco Fichtner };
179fb578518SFranco Fichtner 
180fb578518SFranco Fichtner /*
181fb578518SFranco Fichtner  * nm_bridge is a descriptor for a VALE switch.
182fb578518SFranco Fichtner  * Interfaces for a bridge are all in bdg_ports[].
183fb578518SFranco Fichtner  * The array has fixed size, an empty entry does not terminate
184fb578518SFranco Fichtner  * the search, but lookups only occur on attach/detach so we
185fb578518SFranco Fichtner  * don't mind if they are slow.
186fb578518SFranco Fichtner  *
187fb578518SFranco Fichtner  * The bridge is non blocking on the transmit ports: excess
188fb578518SFranco Fichtner  * packets are dropped if there is no room on the output port.
189fb578518SFranco Fichtner  *
190fb578518SFranco Fichtner  * bdg_lock protects accesses to the bdg_ports array.
191fb578518SFranco Fichtner  * This is a rw lock (or equivalent).
192fb578518SFranco Fichtner  */
193fb578518SFranco Fichtner struct nm_bridge {
194fb578518SFranco Fichtner 	/* XXX what is the proper alignment/layout ? */
195fb578518SFranco Fichtner 	BDG_RWLOCK_T	bdg_lock;	/* protects bdg_ports */
196fb578518SFranco Fichtner 	int		bdg_namelen;
197fb578518SFranco Fichtner 	uint32_t	bdg_active_ports; /* 0 means free */
198fb578518SFranco Fichtner 	char		bdg_basename[IFNAMSIZ];
199fb578518SFranco Fichtner 
200fb578518SFranco Fichtner 	/* Indexes of active ports (up to active_ports)
201fb578518SFranco Fichtner 	 * and all other remaining ports.
202fb578518SFranco Fichtner 	 */
203fb578518SFranco Fichtner 	uint8_t		bdg_port_index[NM_BDG_MAXPORTS];
204fb578518SFranco Fichtner 
205fb578518SFranco Fichtner 	struct netmap_vp_adapter *bdg_ports[NM_BDG_MAXPORTS];
206fb578518SFranco Fichtner 
207fb578518SFranco Fichtner 
208fb578518SFranco Fichtner 	/*
209fb578518SFranco Fichtner 	 * The function to decide the destination port.
210fb578518SFranco Fichtner 	 * It returns either of an index of the destination port,
211fb578518SFranco Fichtner 	 * NM_BDG_BROADCAST to broadcast this packet, or NM_BDG_NOPORT not to
212fb578518SFranco Fichtner 	 * forward this packet.  ring_nr is the source ring index, and the
213fb578518SFranco Fichtner 	 * function may overwrite this value to forward this packet to a
214fb578518SFranco Fichtner 	 * different ring index.
215fb578518SFranco Fichtner 	 * This function must be set by netmap_bdgctl().
216fb578518SFranco Fichtner 	 */
217fb578518SFranco Fichtner 	bdg_lookup_fn_t nm_bdg_lookup;
218fb578518SFranco Fichtner 
219fb578518SFranco Fichtner 	/* the forwarding table, MAC+ports.
220fb578518SFranco Fichtner 	 * XXX should be changed to an argument to be passed to
221fb578518SFranco Fichtner 	 * the lookup function, and allocated on attach
222fb578518SFranco Fichtner 	 */
223fb578518SFranco Fichtner 	struct nm_hash_ent ht[NM_BDG_HASH];
224fb578518SFranco Fichtner };
225fb578518SFranco Fichtner 
226fb578518SFranco Fichtner 
227fb578518SFranco Fichtner /*
228fb578518SFranco Fichtner  * XXX in principle nm_bridges could be created dynamically
229fb578518SFranco Fichtner  * Right now we have a static array and deletions are protected
230fb578518SFranco Fichtner  * by an exclusive lock.
231fb578518SFranco Fichtner  */
232fb578518SFranco Fichtner struct nm_bridge nm_bridges[NM_BRIDGES];
233fb578518SFranco Fichtner 
234fb578518SFranco Fichtner 
235fb578518SFranco Fichtner /*
236fb578518SFranco Fichtner  * A few function to tell which kind of port are we using.
237fb578518SFranco Fichtner  * XXX should we hold a lock ?
238fb578518SFranco Fichtner  *
239fb578518SFranco Fichtner  * nma_is_vp()		virtual port
240fb578518SFranco Fichtner  * nma_is_host()	port connected to the host stack
241fb578518SFranco Fichtner  * nma_is_hw()		port connected to a NIC
242fb578518SFranco Fichtner  * nma_is_generic()	generic netmap adapter XXX stop this madness
243fb578518SFranco Fichtner  */
244fb578518SFranco Fichtner static __inline int
nma_is_vp(struct netmap_adapter * na)245fb578518SFranco Fichtner nma_is_vp(struct netmap_adapter *na)
246fb578518SFranco Fichtner {
247fb578518SFranco Fichtner 	return na->nm_register == bdg_netmap_reg;
248fb578518SFranco Fichtner }
249fb578518SFranco Fichtner 
250fb578518SFranco Fichtner 
251fb578518SFranco Fichtner static __inline int
nma_is_host(struct netmap_adapter * na)252fb578518SFranco Fichtner nma_is_host(struct netmap_adapter *na)
253fb578518SFranco Fichtner {
254fb578518SFranco Fichtner 	return na->nm_register == NULL;
255fb578518SFranco Fichtner }
256fb578518SFranco Fichtner 
257fb578518SFranco Fichtner 
258fb578518SFranco Fichtner static __inline int
nma_is_hw(struct netmap_adapter * na)259fb578518SFranco Fichtner nma_is_hw(struct netmap_adapter *na)
260fb578518SFranco Fichtner {
261fb578518SFranco Fichtner 	/* In case of sw adapter, nm_register is NULL */
262fb578518SFranco Fichtner 	return !nma_is_vp(na) && !nma_is_host(na) && !nma_is_generic(na);
263fb578518SFranco Fichtner }
264fb578518SFranco Fichtner 
265fb578518SFranco Fichtner static __inline int
nma_is_bwrap(struct netmap_adapter * na)266fb578518SFranco Fichtner nma_is_bwrap(struct netmap_adapter *na)
267fb578518SFranco Fichtner {
268fb578518SFranco Fichtner 	return na->nm_register == netmap_bwrap_register;
269fb578518SFranco Fichtner }
270fb578518SFranco Fichtner 
271fb578518SFranco Fichtner 
272fb578518SFranco Fichtner 
273fb578518SFranco Fichtner /*
274fb578518SFranco Fichtner  * this is a slightly optimized copy routine which rounds
275fb578518SFranco Fichtner  * to multiple of 64 bytes and is often faster than dealing
276fb578518SFranco Fichtner  * with other odd sizes. We assume there is enough room
277fb578518SFranco Fichtner  * in the source and destination buffers.
278fb578518SFranco Fichtner  *
279fb578518SFranco Fichtner  * XXX only for multiples of 64 bytes, non overlapped.
280fb578518SFranco Fichtner  */
281fb578518SFranco Fichtner static inline void
pkt_copy(void * _src,void * _dst,int l)282fb578518SFranco Fichtner pkt_copy(void *_src, void *_dst, int l)
283fb578518SFranco Fichtner {
284fb578518SFranco Fichtner         uint64_t *src = _src;
285fb578518SFranco Fichtner         uint64_t *dst = _dst;
286fb578518SFranco Fichtner         if (unlikely(l >= 1024)) {
287fb578518SFranco Fichtner                 memcpy(dst, src, l);
288fb578518SFranco Fichtner                 return;
289fb578518SFranco Fichtner         }
290fb578518SFranco Fichtner         for (; likely(l > 0); l-=64) {
291fb578518SFranco Fichtner                 *dst++ = *src++;
292fb578518SFranco Fichtner                 *dst++ = *src++;
293fb578518SFranco Fichtner                 *dst++ = *src++;
294fb578518SFranco Fichtner                 *dst++ = *src++;
295fb578518SFranco Fichtner                 *dst++ = *src++;
296fb578518SFranco Fichtner                 *dst++ = *src++;
297fb578518SFranco Fichtner                 *dst++ = *src++;
298fb578518SFranco Fichtner                 *dst++ = *src++;
299fb578518SFranco Fichtner         }
300fb578518SFranco Fichtner }
301fb578518SFranco Fichtner 
302fb578518SFranco Fichtner 
303fb578518SFranco Fichtner 
304fb578518SFranco Fichtner /*
305fb578518SFranco Fichtner  * locate a bridge among the existing ones.
306fb578518SFranco Fichtner  * MUST BE CALLED WITH NMG_LOCK()
307fb578518SFranco Fichtner  *
308fb578518SFranco Fichtner  * a ':' in the name terminates the bridge name. Otherwise, just NM_NAME.
309fb578518SFranco Fichtner  * We assume that this is called with a name of at least NM_NAME chars.
310fb578518SFranco Fichtner  */
311fb578518SFranco Fichtner static struct nm_bridge *
nm_find_bridge(const char * name,int create)312fb578518SFranco Fichtner nm_find_bridge(const char *name, int create)
313fb578518SFranco Fichtner {
314fb578518SFranco Fichtner 	int i, l, namelen;
315fb578518SFranco Fichtner 	struct nm_bridge *b = NULL;
316fb578518SFranco Fichtner 
317fb578518SFranco Fichtner 	NMG_LOCK_ASSERT();
318fb578518SFranco Fichtner 
319fb578518SFranco Fichtner 	namelen = strlen(NM_NAME);	/* base length */
320fb578518SFranco Fichtner 	l = name ? strlen(name) : 0;		/* actual length */
321fb578518SFranco Fichtner 	if (l < namelen) {
322fb578518SFranco Fichtner 		D("invalid bridge name %s", name ? name : NULL);
323fb578518SFranco Fichtner 		return NULL;
324fb578518SFranco Fichtner 	}
325fb578518SFranco Fichtner 	for (i = namelen + 1; i < l; i++) {
326fb578518SFranco Fichtner 		if (name[i] == ':') {
327fb578518SFranco Fichtner 			namelen = i;
328fb578518SFranco Fichtner 			break;
329fb578518SFranco Fichtner 		}
330fb578518SFranco Fichtner 	}
331fb578518SFranco Fichtner 	if (namelen >= IFNAMSIZ)
332fb578518SFranco Fichtner 		namelen = IFNAMSIZ;
333fb578518SFranco Fichtner 	ND("--- prefix is '%.*s' ---", namelen, name);
334fb578518SFranco Fichtner 
335fb578518SFranco Fichtner 	/* lookup the name, remember empty slot if there is one */
336fb578518SFranco Fichtner 	for (i = 0; i < NM_BRIDGES; i++) {
337fb578518SFranco Fichtner 		struct nm_bridge *x = nm_bridges + i;
338fb578518SFranco Fichtner 
339fb578518SFranco Fichtner 		if (x->bdg_active_ports == 0) {
340fb578518SFranco Fichtner 			if (create && b == NULL)
341fb578518SFranco Fichtner 				b = x;	/* record empty slot */
342fb578518SFranco Fichtner 		} else if (x->bdg_namelen != namelen) {
343fb578518SFranco Fichtner 			continue;
344fb578518SFranco Fichtner 		} else if (strncmp(name, x->bdg_basename, namelen) == 0) {
345fb578518SFranco Fichtner 			ND("found '%.*s' at %d", namelen, name, i);
346fb578518SFranco Fichtner 			b = x;
347fb578518SFranco Fichtner 			break;
348fb578518SFranco Fichtner 		}
349fb578518SFranco Fichtner 	}
350fb578518SFranco Fichtner 	if (i == NM_BRIDGES && b) { /* name not found, can create entry */
351fb578518SFranco Fichtner 		/* initialize the bridge */
352fb578518SFranco Fichtner 		strncpy(b->bdg_basename, name, namelen);
353fb578518SFranco Fichtner 		ND("create new bridge %s with ports %d", b->bdg_basename,
354fb578518SFranco Fichtner 			b->bdg_active_ports);
355fb578518SFranco Fichtner 		b->bdg_namelen = namelen;
356fb578518SFranco Fichtner 		b->bdg_active_ports = 0;
357fb578518SFranco Fichtner 		for (i = 0; i < NM_BDG_MAXPORTS; i++)
358fb578518SFranco Fichtner 			b->bdg_port_index[i] = i;
359fb578518SFranco Fichtner 		/* set the default function */
360fb578518SFranco Fichtner 		b->nm_bdg_lookup = netmap_bdg_learning;
361fb578518SFranco Fichtner 		/* reset the MAC address table */
362fb578518SFranco Fichtner 		bzero(b->ht, sizeof(struct nm_hash_ent) * NM_BDG_HASH);
363fb578518SFranco Fichtner 	}
364fb578518SFranco Fichtner 	return b;
365fb578518SFranco Fichtner }
366fb578518SFranco Fichtner 
367fb578518SFranco Fichtner 
368fb578518SFranco Fichtner /*
369fb578518SFranco Fichtner  * Free the forwarding tables for rings attached to switch ports.
370fb578518SFranco Fichtner  */
371fb578518SFranco Fichtner static void
nm_free_bdgfwd(struct netmap_adapter * na)372fb578518SFranco Fichtner nm_free_bdgfwd(struct netmap_adapter *na)
373fb578518SFranco Fichtner {
374fb578518SFranco Fichtner 	int nrings, i;
375fb578518SFranco Fichtner 	struct netmap_kring *kring;
376fb578518SFranco Fichtner 
377fb578518SFranco Fichtner 	NMG_LOCK_ASSERT();
378fb578518SFranco Fichtner 	nrings = nma_is_vp(na) ? na->num_tx_rings : na->num_rx_rings;
379fb578518SFranco Fichtner 	kring = nma_is_vp(na) ? na->tx_rings : na->rx_rings;
380fb578518SFranco Fichtner 	for (i = 0; i < nrings; i++) {
381fb578518SFranco Fichtner 		if (kring[i].nkr_ft) {
382ed9bd855SFranco Fichtner 			kfree(kring[i].nkr_ft, M_DEVBUF);
383fb578518SFranco Fichtner 			kring[i].nkr_ft = NULL; /* protect from freeing twice */
384fb578518SFranco Fichtner 		}
385fb578518SFranco Fichtner 	}
386fb578518SFranco Fichtner }
387fb578518SFranco Fichtner 
388fb578518SFranco Fichtner 
389fb578518SFranco Fichtner /*
390fb578518SFranco Fichtner  * Allocate the forwarding tables for the rings attached to the bridge ports.
391fb578518SFranco Fichtner  */
392fb578518SFranco Fichtner static int
nm_alloc_bdgfwd(struct netmap_adapter * na)393fb578518SFranco Fichtner nm_alloc_bdgfwd(struct netmap_adapter *na)
394fb578518SFranco Fichtner {
395fb578518SFranco Fichtner 	int nrings, l, i, num_dstq;
396fb578518SFranco Fichtner 	struct netmap_kring *kring;
397fb578518SFranco Fichtner 
398fb578518SFranco Fichtner 	NMG_LOCK_ASSERT();
399fb578518SFranco Fichtner 	/* all port:rings + broadcast */
400fb578518SFranco Fichtner 	num_dstq = NM_BDG_MAXPORTS * NM_BDG_MAXRINGS + 1;
401fb578518SFranco Fichtner 	l = sizeof(struct nm_bdg_fwd) * NM_BDG_BATCH_MAX;
402fb578518SFranco Fichtner 	l += sizeof(struct nm_bdg_q) * num_dstq;
403fb578518SFranco Fichtner 	l += sizeof(uint16_t) * NM_BDG_BATCH_MAX;
404fb578518SFranco Fichtner 
405fb578518SFranco Fichtner 	nrings = na->num_tx_rings + 1;
406fb578518SFranco Fichtner 	kring = na->tx_rings;
407fb578518SFranco Fichtner 	for (i = 0; i < nrings; i++) {
408fb578518SFranco Fichtner 		struct nm_bdg_fwd *ft;
409fb578518SFranco Fichtner 		struct nm_bdg_q *dstq;
410fb578518SFranco Fichtner 		int j;
411fb578518SFranco Fichtner 
412ed9bd855SFranco Fichtner 		ft = kmalloc(l, M_DEVBUF, M_NOWAIT | M_ZERO);
413fb578518SFranco Fichtner 		if (!ft) {
414fb578518SFranco Fichtner 			nm_free_bdgfwd(na);
415fb578518SFranco Fichtner 			return ENOMEM;
416fb578518SFranco Fichtner 		}
417fb578518SFranco Fichtner 		dstq = (struct nm_bdg_q *)(ft + NM_BDG_BATCH_MAX);
418fb578518SFranco Fichtner 		for (j = 0; j < num_dstq; j++) {
419fb578518SFranco Fichtner 			dstq[j].bq_head = dstq[j].bq_tail = NM_FT_NULL;
420fb578518SFranco Fichtner 			dstq[j].bq_len = 0;
421fb578518SFranco Fichtner 		}
422fb578518SFranco Fichtner 		kring[i].nkr_ft = ft;
423fb578518SFranco Fichtner 	}
424fb578518SFranco Fichtner 	return 0;
425fb578518SFranco Fichtner }
426fb578518SFranco Fichtner 
427fb578518SFranco Fichtner 
428fb578518SFranco Fichtner static void
netmap_bdg_detach_common(struct nm_bridge * b,int hw,int sw)429fb578518SFranco Fichtner netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
430fb578518SFranco Fichtner {
431fb578518SFranco Fichtner 	int s_hw = hw, s_sw = sw;
432fb578518SFranco Fichtner 	int i, lim =b->bdg_active_ports;
433fb578518SFranco Fichtner 	uint8_t tmp[NM_BDG_MAXPORTS];
434fb578518SFranco Fichtner 
435fb578518SFranco Fichtner 	/*
436fb578518SFranco Fichtner 	New algorithm:
437fb578518SFranco Fichtner 	make a copy of bdg_port_index;
438fb578518SFranco Fichtner 	lookup NA(ifp)->bdg_port and SWNA(ifp)->bdg_port
439fb578518SFranco Fichtner 	in the array of bdg_port_index, replacing them with
440fb578518SFranco Fichtner 	entries from the bottom of the array;
441fb578518SFranco Fichtner 	decrement bdg_active_ports;
442fb578518SFranco Fichtner 	acquire BDG_WLOCK() and copy back the array.
443fb578518SFranco Fichtner 	 */
444fb578518SFranco Fichtner 
445fb578518SFranco Fichtner 	D("detach %d and %d (lim %d)", hw, sw, lim);
446fb578518SFranco Fichtner 	/* make a copy of the list of active ports, update it,
447fb578518SFranco Fichtner 	 * and then copy back within BDG_WLOCK().
448fb578518SFranco Fichtner 	 */
449fb578518SFranco Fichtner 	memcpy(tmp, b->bdg_port_index, sizeof(tmp));
450fb578518SFranco Fichtner 	for (i = 0; (hw >= 0 || sw >= 0) && i < lim; ) {
451fb578518SFranco Fichtner 		if (hw >= 0 && tmp[i] == hw) {
452fb578518SFranco Fichtner 			ND("detach hw %d at %d", hw, i);
453fb578518SFranco Fichtner 			lim--; /* point to last active port */
454fb578518SFranco Fichtner 			tmp[i] = tmp[lim]; /* swap with i */
455fb578518SFranco Fichtner 			tmp[lim] = hw;	/* now this is inactive */
456fb578518SFranco Fichtner 			hw = -1;
457fb578518SFranco Fichtner 		} else if (sw >= 0 && tmp[i] == sw) {
458fb578518SFranco Fichtner 			ND("detach sw %d at %d", sw, i);
459fb578518SFranco Fichtner 			lim--;
460fb578518SFranco Fichtner 			tmp[i] = tmp[lim];
461fb578518SFranco Fichtner 			tmp[lim] = sw;
462fb578518SFranco Fichtner 			sw = -1;
463fb578518SFranco Fichtner 		} else {
464fb578518SFranco Fichtner 			i++;
465fb578518SFranco Fichtner 		}
466fb578518SFranco Fichtner 	}
467fb578518SFranco Fichtner 	if (hw >= 0 || sw >= 0) {
468fb578518SFranco Fichtner 		D("XXX delete failed hw %d sw %d, should panic...", hw, sw);
469fb578518SFranco Fichtner 	}
470fb578518SFranco Fichtner 
471fb578518SFranco Fichtner 	BDG_WLOCK(b);
472fb578518SFranco Fichtner 	b->bdg_ports[s_hw] = NULL;
473fb578518SFranco Fichtner 	if (s_sw >= 0) {
474fb578518SFranco Fichtner 		b->bdg_ports[s_sw] = NULL;
475fb578518SFranco Fichtner 	}
476fb578518SFranco Fichtner 	memcpy(b->bdg_port_index, tmp, sizeof(tmp));
477fb578518SFranco Fichtner 	b->bdg_active_ports = lim;
478fb578518SFranco Fichtner 	BDG_WUNLOCK(b);
479fb578518SFranco Fichtner 
480fb578518SFranco Fichtner 	ND("now %d active ports", lim);
481fb578518SFranco Fichtner 	if (lim == 0) {
482fb578518SFranco Fichtner 		ND("marking bridge %s as free", b->bdg_basename);
483fb578518SFranco Fichtner 		b->nm_bdg_lookup = NULL;
484fb578518SFranco Fichtner 	}
485fb578518SFranco Fichtner }
486fb578518SFranco Fichtner 
487fb578518SFranco Fichtner static void
netmap_adapter_vp_dtor(struct netmap_adapter * na)488fb578518SFranco Fichtner netmap_adapter_vp_dtor(struct netmap_adapter *na)
489fb578518SFranco Fichtner {
490fb578518SFranco Fichtner 	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter*)na;
491fb578518SFranco Fichtner 	struct nm_bridge *b = vpna->na_bdg;
492fb578518SFranco Fichtner 	struct ifnet *ifp = na->ifp;
493fb578518SFranco Fichtner 
494fb578518SFranco Fichtner 	ND("%s has %d references", NM_IFPNAME(ifp), na->na_refcount);
495fb578518SFranco Fichtner 
496fb578518SFranco Fichtner 	if (b) {
497fb578518SFranco Fichtner 		netmap_bdg_detach_common(b, vpna->bdg_port, -1);
498fb578518SFranco Fichtner 	}
499fb578518SFranco Fichtner 
500fb578518SFranco Fichtner 	bzero(ifp, sizeof(*ifp));
501ed9bd855SFranco Fichtner 	kfree(ifp, M_DEVBUF);
502fb578518SFranco Fichtner 	na->ifp = NULL;
503fb578518SFranco Fichtner }
504fb578518SFranco Fichtner 
505fb578518SFranco Fichtner int
netmap_get_bdg_na(struct nmreq * nmr,struct netmap_adapter ** na,int create)506fb578518SFranco Fichtner netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na, int create)
507fb578518SFranco Fichtner {
508fb578518SFranco Fichtner 	const char *name = nmr->nr_name;
509fb578518SFranco Fichtner 	struct ifnet *ifp;
510fb578518SFranco Fichtner 	int error = 0;
511fb578518SFranco Fichtner 	struct netmap_adapter *ret;
512fb578518SFranco Fichtner 	struct netmap_vp_adapter *vpna;
513fb578518SFranco Fichtner 	struct nm_bridge *b;
514fb578518SFranco Fichtner 	int i, j, cand = -1, cand2 = -1;
515fb578518SFranco Fichtner 	int needed;
516fb578518SFranco Fichtner 
517fb578518SFranco Fichtner 	*na = NULL;     /* default return value */
518fb578518SFranco Fichtner 
519fb578518SFranco Fichtner 	/* first try to see if this is a bridge port. */
520fb578518SFranco Fichtner 	NMG_LOCK_ASSERT();
521fb578518SFranco Fichtner 	if (strncmp(name, NM_NAME, sizeof(NM_NAME) - 1)) {
522fb578518SFranco Fichtner 		return 0;  /* no error, but no VALE prefix */
523fb578518SFranco Fichtner 	}
524fb578518SFranco Fichtner 
525fb578518SFranco Fichtner 	b = nm_find_bridge(name, create);
526fb578518SFranco Fichtner 	if (b == NULL) {
527fb578518SFranco Fichtner 		D("no bridges available for '%s'", name);
528fb578518SFranco Fichtner 		return (ENXIO);
529fb578518SFranco Fichtner 	}
530fb578518SFranco Fichtner 
531fb578518SFranco Fichtner 	/* Now we are sure that name starts with the bridge's name,
532fb578518SFranco Fichtner 	 * lookup the port in the bridge. We need to scan the entire
533fb578518SFranco Fichtner 	 * list. It is not important to hold a WLOCK on the bridge
534fb578518SFranco Fichtner 	 * during the search because NMG_LOCK already guarantees
535fb578518SFranco Fichtner 	 * that there are no other possible writers.
536fb578518SFranco Fichtner 	 */
537fb578518SFranco Fichtner 
538fb578518SFranco Fichtner 	/* lookup in the local list of ports */
539fb578518SFranco Fichtner 	for (j = 0; j < b->bdg_active_ports; j++) {
540fb578518SFranco Fichtner 		i = b->bdg_port_index[j];
541fb578518SFranco Fichtner 		vpna = b->bdg_ports[i];
542fb578518SFranco Fichtner 		// KASSERT(na != NULL);
543fb578518SFranco Fichtner 		ifp = vpna->up.ifp;
544fb578518SFranco Fichtner 		/* XXX make sure the name only contains one : */
545fb578518SFranco Fichtner 		if (!strcmp(NM_IFPNAME(ifp), name)) {
546fb578518SFranco Fichtner 			netmap_adapter_get(&vpna->up);
547fb578518SFranco Fichtner 			ND("found existing if %s refs %d", name,
548fb578518SFranco Fichtner 				vpna->na_bdg_refcount);
549fb578518SFranco Fichtner 			*na = (struct netmap_adapter *)vpna;
550fb578518SFranco Fichtner 			return 0;
551fb578518SFranco Fichtner 		}
552fb578518SFranco Fichtner 	}
553fb578518SFranco Fichtner 	/* not found, should we create it? */
554fb578518SFranco Fichtner 	if (!create)
555fb578518SFranco Fichtner 		return ENXIO;
556fb578518SFranco Fichtner 	/* yes we should, see if we have space to attach entries */
557fb578518SFranco Fichtner 	needed = 2; /* in some cases we only need 1 */
558fb578518SFranco Fichtner 	if (b->bdg_active_ports + needed >= NM_BDG_MAXPORTS) {
559fb578518SFranco Fichtner 		D("bridge full %d, cannot create new port", b->bdg_active_ports);
560fb578518SFranco Fichtner 		return EINVAL;
561fb578518SFranco Fichtner 	}
562fb578518SFranco Fichtner 	/* record the next two ports available, but do not allocate yet */
563fb578518SFranco Fichtner 	cand = b->bdg_port_index[b->bdg_active_ports];
564fb578518SFranco Fichtner 	cand2 = b->bdg_port_index[b->bdg_active_ports + 1];
565fb578518SFranco Fichtner 	ND("+++ bridge %s port %s used %d avail %d %d",
566fb578518SFranco Fichtner 		b->bdg_basename, name, b->bdg_active_ports, cand, cand2);
567fb578518SFranco Fichtner 
568fb578518SFranco Fichtner 	/*
569fb578518SFranco Fichtner 	 * try see if there is a matching NIC with this name
570fb578518SFranco Fichtner 	 * (after the bridge's name)
571fb578518SFranco Fichtner 	 */
572b4051e25SSepherosa Ziehau 	ifnet_lock();
573bf9f7c16SFranco Fichtner 	ifp = ifunit(name + b->bdg_namelen + 1);
574fb578518SFranco Fichtner 	if (!ifp) { /* this is a virtual port */
575fb578518SFranco Fichtner 		/* Create a temporary NA with arguments, then
576fb578518SFranco Fichtner 		 * bdg_netmap_attach() will allocate the real one
577fb578518SFranco Fichtner 		 * and attach it to the ifp
578fb578518SFranco Fichtner 		 */
579fb578518SFranco Fichtner 		struct netmap_adapter tmp_na;
580fb578518SFranco Fichtner 
581b4051e25SSepherosa Ziehau 		ifnet_unlock();
582b4051e25SSepherosa Ziehau 
583fb578518SFranco Fichtner 		if (nmr->nr_cmd) {
584fb578518SFranco Fichtner 			/* nr_cmd must be 0 for a virtual port */
585fb578518SFranco Fichtner 			return EINVAL;
586fb578518SFranco Fichtner 		}
587fb578518SFranco Fichtner 		bzero(&tmp_na, sizeof(tmp_na));
588fb578518SFranco Fichtner 		/* bound checking */
589fb578518SFranco Fichtner 		tmp_na.num_tx_rings = nmr->nr_tx_rings;
590fb578518SFranco Fichtner 		nm_bound_var(&tmp_na.num_tx_rings, 1, 1, NM_BDG_MAXRINGS, NULL);
591fb578518SFranco Fichtner 		nmr->nr_tx_rings = tmp_na.num_tx_rings; // write back
592fb578518SFranco Fichtner 		tmp_na.num_rx_rings = nmr->nr_rx_rings;
593fb578518SFranco Fichtner 		nm_bound_var(&tmp_na.num_rx_rings, 1, 1, NM_BDG_MAXRINGS, NULL);
594fb578518SFranco Fichtner 		nmr->nr_rx_rings = tmp_na.num_rx_rings; // write back
595fb578518SFranco Fichtner 		nm_bound_var(&nmr->nr_tx_slots, NM_BRIDGE_RINGSIZE,
596fb578518SFranco Fichtner 				1, NM_BDG_MAXSLOTS, NULL);
597fb578518SFranco Fichtner 		tmp_na.num_tx_desc = nmr->nr_tx_slots;
598fb578518SFranco Fichtner 		nm_bound_var(&nmr->nr_rx_slots, NM_BRIDGE_RINGSIZE,
599fb578518SFranco Fichtner 				1, NM_BDG_MAXSLOTS, NULL);
600fb578518SFranco Fichtner 		tmp_na.num_rx_desc = nmr->nr_rx_slots;
601fb578518SFranco Fichtner 
602fb578518SFranco Fichtner 	 	/* create a struct ifnet for the new port.
603fb578518SFranco Fichtner 		 * need M_NOWAIT as we are under nma_lock
604fb578518SFranco Fichtner 		 */
605ed9bd855SFranco Fichtner 		ifp = kmalloc(sizeof(*ifp), M_DEVBUF, M_NOWAIT | M_ZERO);
606fb578518SFranco Fichtner 		if (!ifp)
607fb578518SFranco Fichtner 			return ENOMEM;
608fb578518SFranco Fichtner 
609fb578518SFranco Fichtner 		strcpy(ifp->if_xname, name);
610fb578518SFranco Fichtner 		tmp_na.ifp = ifp;
611fb578518SFranco Fichtner 		/* bdg_netmap_attach creates a struct netmap_adapter */
612fb578518SFranco Fichtner 		error = bdg_netmap_attach(&tmp_na);
613fb578518SFranco Fichtner 		if (error) {
614fb578518SFranco Fichtner 			D("error %d", error);
615ed9bd855SFranco Fichtner 			kfree(ifp, M_DEVBUF);
616fb578518SFranco Fichtner 			return error;
617fb578518SFranco Fichtner 		}
618fb578518SFranco Fichtner 		ret = NA(ifp);
619fb578518SFranco Fichtner 		cand2 = -1;	/* only need one port */
620fb578518SFranco Fichtner 	} else {  /* this is a NIC */
621fb578518SFranco Fichtner 		struct ifnet *fake_ifp;
622fb578518SFranco Fichtner 
623fb578518SFranco Fichtner 		error = netmap_get_hw_na(ifp, &ret);
624fb578518SFranco Fichtner 		if (error || ret == NULL)
625fb578518SFranco Fichtner 			goto out;
626fb578518SFranco Fichtner 
627fb578518SFranco Fichtner 		/* make sure the NIC is not already in use */
628fb578518SFranco Fichtner 		if (NETMAP_OWNED_BY_ANY(ret)) {
629fb578518SFranco Fichtner 			D("NIC %s busy, cannot attach to bridge",
630fb578518SFranco Fichtner 				NM_IFPNAME(ifp));
631fb578518SFranco Fichtner 			error = EINVAL;
632fb578518SFranco Fichtner 			goto out;
633fb578518SFranco Fichtner 		}
634fb578518SFranco Fichtner 		/* create a fake interface */
635ed9bd855SFranco Fichtner 		fake_ifp = kmalloc(sizeof(*ifp), M_DEVBUF, M_NOWAIT | M_ZERO);
636fb578518SFranco Fichtner 		if (!fake_ifp) {
637fb578518SFranco Fichtner 			error = ENOMEM;
638fb578518SFranco Fichtner 			goto out;
639fb578518SFranco Fichtner 		}
640fb578518SFranco Fichtner 		strcpy(fake_ifp->if_xname, name);
641fb578518SFranco Fichtner 		error = netmap_bwrap_attach(fake_ifp, ifp);
642fb578518SFranco Fichtner 		if (error) {
643ed9bd855SFranco Fichtner 			kfree(fake_ifp, M_DEVBUF);
644fb578518SFranco Fichtner 			goto out;
645fb578518SFranco Fichtner 		}
646fb578518SFranco Fichtner 		ret = NA(fake_ifp);
647fb578518SFranco Fichtner 		if (nmr->nr_arg1 != NETMAP_BDG_HOST)
648fb578518SFranco Fichtner 			cand2 = -1; /* only need one port */
649b4051e25SSepherosa Ziehau 
650b4051e25SSepherosa Ziehau 		ifnet_unlock();
651fb578518SFranco Fichtner 	}
652fb578518SFranco Fichtner 	vpna = (struct netmap_vp_adapter *)ret;
653fb578518SFranco Fichtner 
654fb578518SFranco Fichtner 	BDG_WLOCK(b);
655fb578518SFranco Fichtner 	vpna->bdg_port = cand;
656fb578518SFranco Fichtner 	ND("NIC  %p to bridge port %d", vpna, cand);
657fb578518SFranco Fichtner 	/* bind the port to the bridge (virtual ports are not active) */
658fb578518SFranco Fichtner 	b->bdg_ports[cand] = vpna;
659fb578518SFranco Fichtner 	vpna->na_bdg = b;
660fb578518SFranco Fichtner 	b->bdg_active_ports++;
661fb578518SFranco Fichtner 	if (cand2 >= 0) {
662fb578518SFranco Fichtner 		struct netmap_vp_adapter *hostna = vpna + 1;
663fb578518SFranco Fichtner 		/* also bind the host stack to the bridge */
664fb578518SFranco Fichtner 		b->bdg_ports[cand2] = hostna;
665fb578518SFranco Fichtner 		hostna->bdg_port = cand2;
666fb578518SFranco Fichtner 		hostna->na_bdg = b;
667fb578518SFranco Fichtner 		b->bdg_active_ports++;
668fb578518SFranco Fichtner 		ND("host %p to bridge port %d", hostna, cand2);
669fb578518SFranco Fichtner 	}
670fb578518SFranco Fichtner 	ND("if %s refs %d", name, vpna->up.na_refcount);
671fb578518SFranco Fichtner 	BDG_WUNLOCK(b);
672fb578518SFranco Fichtner 	*na = ret;
673fb578518SFranco Fichtner 	netmap_adapter_get(ret);
674fb578518SFranco Fichtner 	return 0;
675fb578518SFranco Fichtner 
676fb578518SFranco Fichtner out:
677b4051e25SSepherosa Ziehau 	ifnet_unlock();
678fb578518SFranco Fichtner 	return error;
679fb578518SFranco Fichtner }
680fb578518SFranco Fichtner 
681fb578518SFranco Fichtner 
682fb578518SFranco Fichtner /* Process NETMAP_BDG_ATTACH and NETMAP_BDG_DETACH */
683fb578518SFranco Fichtner static int
nm_bdg_attach(struct nmreq * nmr)684fb578518SFranco Fichtner nm_bdg_attach(struct nmreq *nmr)
685fb578518SFranco Fichtner {
686fb578518SFranco Fichtner 	struct netmap_adapter *na;
687fb578518SFranco Fichtner 	struct netmap_if *nifp;
688fb578518SFranco Fichtner 	struct netmap_priv_d *npriv;
689fb578518SFranco Fichtner 	struct netmap_bwrap_adapter *bna;
690fb578518SFranco Fichtner 	int error;
691fb578518SFranco Fichtner 
692ed9bd855SFranco Fichtner 	npriv = kmalloc(sizeof(*npriv), M_DEVBUF, M_NOWAIT|M_ZERO);
693fb578518SFranco Fichtner 	if (npriv == NULL)
694fb578518SFranco Fichtner 		return ENOMEM;
695fb578518SFranco Fichtner 	NMG_LOCK();
696fb578518SFranco Fichtner 	/* XXX probably netmap_get_bdg_na() */
697fb578518SFranco Fichtner 	error = netmap_get_na(nmr, &na, 1 /* create if not exists */);
698fb578518SFranco Fichtner 	if (error) /* no device, or another bridge or user owns the device */
699fb578518SFranco Fichtner 		goto unlock_exit;
700fb578518SFranco Fichtner 	/* netmap_get_na() sets na_bdg if this is a physical interface
701fb578518SFranco Fichtner 	 * that we can attach to a switch.
702fb578518SFranco Fichtner 	 */
703fb578518SFranco Fichtner 	if (!nma_is_bwrap(na)) {
704fb578518SFranco Fichtner 		/* got reference to a virtual port or direct access to a NIC.
705fb578518SFranco Fichtner 		 * perhaps specified no bridge prefix or wrong NIC name
706fb578518SFranco Fichtner 		 */
707fb578518SFranco Fichtner 		error = EINVAL;
708fb578518SFranco Fichtner 		goto unref_exit;
709fb578518SFranco Fichtner 	}
710fb578518SFranco Fichtner 
711fb578518SFranco Fichtner 	if (na->active_fds > 0) { /* already registered */
712fb578518SFranco Fichtner 		error = EBUSY;
713fb578518SFranco Fichtner 		goto unref_exit;
714fb578518SFranco Fichtner 	}
715fb578518SFranco Fichtner 
716fb578518SFranco Fichtner 	nifp = netmap_do_regif(npriv, na, nmr->nr_ringid, &error);
717fb578518SFranco Fichtner 	if (!nifp) {
718fb578518SFranco Fichtner 		goto unref_exit;
719fb578518SFranco Fichtner 	}
720fb578518SFranco Fichtner 
721fb578518SFranco Fichtner 	bna = (struct netmap_bwrap_adapter*)na;
722fb578518SFranco Fichtner 	bna->na_kpriv = npriv;
723fb578518SFranco Fichtner 	NMG_UNLOCK();
724fb578518SFranco Fichtner 	ND("registered %s to netmap-mode", NM_IFPNAME(na->ifp));
725fb578518SFranco Fichtner 	return 0;
726fb578518SFranco Fichtner 
727fb578518SFranco Fichtner unref_exit:
728fb578518SFranco Fichtner 	netmap_adapter_put(na);
729fb578518SFranco Fichtner unlock_exit:
730fb578518SFranco Fichtner 	NMG_UNLOCK();
731fb578518SFranco Fichtner 	bzero(npriv, sizeof(*npriv));
732ed9bd855SFranco Fichtner 	kfree(npriv, M_DEVBUF);
733fb578518SFranco Fichtner 	return error;
734fb578518SFranco Fichtner }
735fb578518SFranco Fichtner 
736fb578518SFranco Fichtner static int
nm_bdg_detach(struct nmreq * nmr)737fb578518SFranco Fichtner nm_bdg_detach(struct nmreq *nmr)
738fb578518SFranco Fichtner {
739fb578518SFranco Fichtner 	struct netmap_adapter *na;
740fb578518SFranco Fichtner 	int error;
741fb578518SFranco Fichtner 	struct netmap_bwrap_adapter *bna;
742fb578518SFranco Fichtner 	int last_instance;
743fb578518SFranco Fichtner 
744fb578518SFranco Fichtner 	NMG_LOCK();
745fb578518SFranco Fichtner 	error = netmap_get_na(nmr, &na, 0 /* don't create */);
746fb578518SFranco Fichtner 	if (error) { /* no device, or another bridge or user owns the device */
747fb578518SFranco Fichtner 		goto unlock_exit;
748fb578518SFranco Fichtner 	}
749fb578518SFranco Fichtner 	if (!nma_is_bwrap(na)) {
750fb578518SFranco Fichtner 		/* got reference to a virtual port or direct access to a NIC.
751fb578518SFranco Fichtner 		 * perhaps specified no bridge's prefix or wrong NIC's name
752fb578518SFranco Fichtner 		 */
753fb578518SFranco Fichtner 		error = EINVAL;
754fb578518SFranco Fichtner 		goto unref_exit;
755fb578518SFranco Fichtner 	}
756fb578518SFranco Fichtner 	bna = (struct netmap_bwrap_adapter *)na;
757fb578518SFranco Fichtner 
758fb578518SFranco Fichtner 	if (na->active_fds == 0) { /* not registered */
759fb578518SFranco Fichtner 		error = EINVAL;
760fb578518SFranco Fichtner 		goto unref_exit;
761fb578518SFranco Fichtner 	}
762fb578518SFranco Fichtner 
763fb578518SFranco Fichtner 	last_instance = netmap_dtor_locked(bna->na_kpriv); /* unregister */
764fb578518SFranco Fichtner 	if (!last_instance) {
765fb578518SFranco Fichtner 		D("--- error, trying to detach an entry with active mmaps");
766fb578518SFranco Fichtner 		error = EINVAL;
767fb578518SFranco Fichtner 	} else {
768fb578518SFranco Fichtner 		struct netmap_priv_d *npriv = bna->na_kpriv;
769fb578518SFranco Fichtner 
770fb578518SFranco Fichtner 		bna->na_kpriv = NULL;
771fb578518SFranco Fichtner 		D("deleting priv");
772fb578518SFranco Fichtner 
773fb578518SFranco Fichtner 		bzero(npriv, sizeof(*npriv));
774ed9bd855SFranco Fichtner 		kfree(npriv, M_DEVBUF);
775fb578518SFranco Fichtner 	}
776fb578518SFranco Fichtner 
777fb578518SFranco Fichtner unref_exit:
778fb578518SFranco Fichtner 	netmap_adapter_put(na);
779fb578518SFranco Fichtner unlock_exit:
780fb578518SFranco Fichtner 	NMG_UNLOCK();
781fb578518SFranco Fichtner 	return error;
782fb578518SFranco Fichtner 
783fb578518SFranco Fichtner }
784fb578518SFranco Fichtner 
785fb578518SFranco Fichtner 
786fb578518SFranco Fichtner /* exported to kernel callers, e.g. OVS ?
787fb578518SFranco Fichtner  * Entry point.
788fb578518SFranco Fichtner  * Called without NMG_LOCK.
789fb578518SFranco Fichtner  */
790fb578518SFranco Fichtner int
netmap_bdg_ctl(struct nmreq * nmr,bdg_lookup_fn_t func)791fb578518SFranco Fichtner netmap_bdg_ctl(struct nmreq *nmr, bdg_lookup_fn_t func)
792fb578518SFranco Fichtner {
793fb578518SFranco Fichtner 	struct nm_bridge *b;
794fb578518SFranco Fichtner 	struct netmap_vp_adapter *na;
795fb578518SFranco Fichtner 	struct ifnet *iter;
796fb578518SFranco Fichtner 	char *name = nmr->nr_name;
797fb578518SFranco Fichtner 	int cmd = nmr->nr_cmd, namelen = strlen(name);
798fb578518SFranco Fichtner 	int error = 0, i, j;
799fb578518SFranco Fichtner 
800fb578518SFranco Fichtner 	switch (cmd) {
801fb578518SFranco Fichtner 	case NETMAP_BDG_ATTACH:
802fb578518SFranco Fichtner 		error = nm_bdg_attach(nmr);
803fb578518SFranco Fichtner 		break;
804fb578518SFranco Fichtner 
805fb578518SFranco Fichtner 	case NETMAP_BDG_DETACH:
806fb578518SFranco Fichtner 		error = nm_bdg_detach(nmr);
807fb578518SFranco Fichtner 		break;
808fb578518SFranco Fichtner 
809fb578518SFranco Fichtner 	case NETMAP_BDG_LIST:
810fb578518SFranco Fichtner 		/* this is used to enumerate bridges and ports */
811fb578518SFranco Fichtner 		if (namelen) { /* look up indexes of bridge and port */
812fb578518SFranco Fichtner 			if (strncmp(name, NM_NAME, strlen(NM_NAME))) {
813fb578518SFranco Fichtner 				error = EINVAL;
814fb578518SFranco Fichtner 				break;
815fb578518SFranco Fichtner 			}
816fb578518SFranco Fichtner 			NMG_LOCK();
817fb578518SFranco Fichtner 			b = nm_find_bridge(name, 0 /* don't create */);
818fb578518SFranco Fichtner 			if (!b) {
819fb578518SFranco Fichtner 				error = ENOENT;
820fb578518SFranco Fichtner 				NMG_UNLOCK();
821fb578518SFranco Fichtner 				break;
822fb578518SFranco Fichtner 			}
823fb578518SFranco Fichtner 
824fb578518SFranco Fichtner 			error = ENOENT;
825fb578518SFranco Fichtner 			for (j = 0; j < b->bdg_active_ports; j++) {
826fb578518SFranco Fichtner 				i = b->bdg_port_index[j];
827fb578518SFranco Fichtner 				na = b->bdg_ports[i];
828fb578518SFranco Fichtner 				if (na == NULL) {
829fb578518SFranco Fichtner 					D("---AAAAAAAAARGH-------");
830fb578518SFranco Fichtner 					continue;
831fb578518SFranco Fichtner 				}
832fb578518SFranco Fichtner 				iter = na->up.ifp;
833fb578518SFranco Fichtner 				/* the former and the latter identify a
834fb578518SFranco Fichtner 				 * virtual port and a NIC, respectively
835fb578518SFranco Fichtner 				 */
836fb578518SFranco Fichtner 				if (!strcmp(iter->if_xname, name)) {
837fb578518SFranco Fichtner 					/* bridge index */
838fb578518SFranco Fichtner 					nmr->nr_arg1 = b - nm_bridges;
839fb578518SFranco Fichtner 					nmr->nr_arg2 = i; /* port index */
840fb578518SFranco Fichtner 					error = 0;
841fb578518SFranco Fichtner 					break;
842fb578518SFranco Fichtner 				}
843fb578518SFranco Fichtner 			}
844fb578518SFranco Fichtner 			NMG_UNLOCK();
845fb578518SFranco Fichtner 		} else {
846fb578518SFranco Fichtner 			/* return the first non-empty entry starting from
847fb578518SFranco Fichtner 			 * bridge nr_arg1 and port nr_arg2.
848fb578518SFranco Fichtner 			 *
849fb578518SFranco Fichtner 			 * Users can detect the end of the same bridge by
850fb578518SFranco Fichtner 			 * seeing the new and old value of nr_arg1, and can
851fb578518SFranco Fichtner 			 * detect the end of all the bridge by error != 0
852fb578518SFranco Fichtner 			 */
853fb578518SFranco Fichtner 			i = nmr->nr_arg1;
854fb578518SFranco Fichtner 			j = nmr->nr_arg2;
855fb578518SFranco Fichtner 
856fb578518SFranco Fichtner 			NMG_LOCK();
857fb578518SFranco Fichtner 			for (error = ENOENT; i < NM_BRIDGES; i++) {
858fb578518SFranco Fichtner 				b = nm_bridges + i;
859fb578518SFranco Fichtner 				if (j >= b->bdg_active_ports) {
860fb578518SFranco Fichtner 					j = 0; /* following bridges scan from 0 */
861fb578518SFranco Fichtner 					continue;
862fb578518SFranco Fichtner 				}
863fb578518SFranco Fichtner 				nmr->nr_arg1 = i;
864fb578518SFranco Fichtner 				nmr->nr_arg2 = j;
865fb578518SFranco Fichtner 				j = b->bdg_port_index[j];
866fb578518SFranco Fichtner 				na = b->bdg_ports[j];
867fb578518SFranco Fichtner 				iter = na->up.ifp;
868fb578518SFranco Fichtner 				strncpy(name, iter->if_xname, (size_t)IFNAMSIZ);
869fb578518SFranco Fichtner 				error = 0;
870fb578518SFranco Fichtner 				break;
871fb578518SFranco Fichtner 			}
872fb578518SFranco Fichtner 			NMG_UNLOCK();
873fb578518SFranco Fichtner 		}
874fb578518SFranco Fichtner 		break;
875fb578518SFranco Fichtner 
876fb578518SFranco Fichtner 	case NETMAP_BDG_LOOKUP_REG:
877fb578518SFranco Fichtner 		/* register a lookup function to the given bridge.
878fb578518SFranco Fichtner 		 * nmr->nr_name may be just bridge's name (including ':'
879fb578518SFranco Fichtner 		 * if it is not just NM_NAME).
880fb578518SFranco Fichtner 		 */
881fb578518SFranco Fichtner 		if (!func) {
882fb578518SFranco Fichtner 			error = EINVAL;
883fb578518SFranco Fichtner 			break;
884fb578518SFranco Fichtner 		}
885fb578518SFranco Fichtner 		NMG_LOCK();
886fb578518SFranco Fichtner 		b = nm_find_bridge(name, 0 /* don't create */);
887fb578518SFranco Fichtner 		if (!b) {
888fb578518SFranco Fichtner 			error = EINVAL;
889fb578518SFranco Fichtner 		} else {
890fb578518SFranco Fichtner 			b->nm_bdg_lookup = func;
891fb578518SFranco Fichtner 		}
892fb578518SFranco Fichtner 		NMG_UNLOCK();
893fb578518SFranco Fichtner 		break;
894fb578518SFranco Fichtner 
895fb578518SFranco Fichtner 	default:
896fb578518SFranco Fichtner 		D("invalid cmd (nmr->nr_cmd) (0x%x)", cmd);
897fb578518SFranco Fichtner 		error = EINVAL;
898fb578518SFranco Fichtner 		break;
899fb578518SFranco Fichtner 	}
900fb578518SFranco Fichtner 	return error;
901fb578518SFranco Fichtner }
902fb578518SFranco Fichtner 
903fb578518SFranco Fichtner 
904fb578518SFranco Fichtner static int
netmap_vp_krings_create(struct netmap_adapter * na)905fb578518SFranco Fichtner netmap_vp_krings_create(struct netmap_adapter *na)
906fb578518SFranco Fichtner {
907fb578518SFranco Fichtner 	u_int ntx, nrx, tailroom;
908fb578518SFranco Fichtner 	int error, i;
909fb578518SFranco Fichtner 	uint32_t *leases;
910fb578518SFranco Fichtner 
911fb578518SFranco Fichtner 	/* XXX vps do not need host rings,
912fb578518SFranco Fichtner 	 * but we crash if we don't have one
913fb578518SFranco Fichtner 	 */
914fb578518SFranco Fichtner 	ntx = na->num_tx_rings + 1;
915fb578518SFranco Fichtner 	nrx = na->num_rx_rings + 1;
916fb578518SFranco Fichtner 
917fb578518SFranco Fichtner 	/*
918fb578518SFranco Fichtner 	 * Leases are attached to RX rings on vale ports
919fb578518SFranco Fichtner 	 */
920fb578518SFranco Fichtner 	tailroom = sizeof(uint32_t) * na->num_rx_desc * nrx;
921fb578518SFranco Fichtner 
922fb578518SFranco Fichtner 	error = netmap_krings_create(na, ntx, nrx, tailroom);
923fb578518SFranco Fichtner 	if (error)
924fb578518SFranco Fichtner 		return error;
925fb578518SFranco Fichtner 
926fb578518SFranco Fichtner 	leases = na->tailroom;
927fb578518SFranco Fichtner 
928fb578518SFranco Fichtner 	for (i = 0; i < nrx; i++) { /* Receive rings */
929fb578518SFranco Fichtner 		na->rx_rings[i].nkr_leases = leases;
930fb578518SFranco Fichtner 		leases += na->num_rx_desc;
931fb578518SFranco Fichtner 	}
932fb578518SFranco Fichtner 
933fb578518SFranco Fichtner 	error = nm_alloc_bdgfwd(na);
934fb578518SFranco Fichtner 	if (error) {
935fb578518SFranco Fichtner 		netmap_krings_delete(na);
936fb578518SFranco Fichtner 		return error;
937fb578518SFranco Fichtner 	}
938fb578518SFranco Fichtner 
939fb578518SFranco Fichtner 	return 0;
940fb578518SFranco Fichtner }
941fb578518SFranco Fichtner 
942fb578518SFranco Fichtner static void
netmap_vp_krings_delete(struct netmap_adapter * na)943fb578518SFranco Fichtner netmap_vp_krings_delete(struct netmap_adapter *na)
944fb578518SFranco Fichtner {
945fb578518SFranco Fichtner 	nm_free_bdgfwd(na);
946fb578518SFranco Fichtner 	netmap_krings_delete(na);
947fb578518SFranco Fichtner }
948fb578518SFranco Fichtner 
949fb578518SFranco Fichtner 
950fb578518SFranco Fichtner static int
951fb578518SFranco Fichtner nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n,
952fb578518SFranco Fichtner 	struct netmap_vp_adapter *na, u_int ring_nr);
953fb578518SFranco Fichtner 
954fb578518SFranco Fichtner 
955fb578518SFranco Fichtner /*
956fb578518SFranco Fichtner  * Grab packets from a kring, move them into the ft structure
957fb578518SFranco Fichtner  * associated to the tx (input) port. Max one instance per port,
958fb578518SFranco Fichtner  * filtered on input (ioctl, poll or XXX).
959fb578518SFranco Fichtner  * Returns the next position in the ring.
960fb578518SFranco Fichtner  */
961fb578518SFranco Fichtner static int
nm_bdg_preflush(struct netmap_vp_adapter * na,u_int ring_nr,struct netmap_kring * kring,u_int end)962fb578518SFranco Fichtner nm_bdg_preflush(struct netmap_vp_adapter *na, u_int ring_nr,
963fb578518SFranco Fichtner 	struct netmap_kring *kring, u_int end)
964fb578518SFranco Fichtner {
965fb578518SFranco Fichtner 	struct netmap_ring *ring = kring->ring;
966fb578518SFranco Fichtner 	struct nm_bdg_fwd *ft;
967fb578518SFranco Fichtner 	u_int j = kring->nr_hwcur, lim = kring->nkr_num_slots - 1;
968fb578518SFranco Fichtner 	u_int ft_i = 0;	/* start from 0 */
969fb578518SFranco Fichtner 	u_int frags = 1; /* how many frags ? */
970fb578518SFranco Fichtner 	struct nm_bridge *b = na->na_bdg;
971fb578518SFranco Fichtner 
972fb578518SFranco Fichtner 	/* To protect against modifications to the bridge we acquire a
973fb578518SFranco Fichtner 	 * shared lock, waiting if we can sleep (if the source port is
974fb578518SFranco Fichtner 	 * attached to a user process) or with a trylock otherwise (NICs).
975fb578518SFranco Fichtner 	 */
976fb578518SFranco Fichtner 	ND("wait rlock for %d packets", ((j > end ? lim+1 : 0) + end) - j);
977fb578518SFranco Fichtner 	if (na->up.na_flags & NAF_BDG_MAYSLEEP)
978fb578518SFranco Fichtner 		BDG_RLOCK(b);
979fb578518SFranco Fichtner 	else if (!BDG_RTRYLOCK(b))
980fb578518SFranco Fichtner 		return 0;
981fb578518SFranco Fichtner 	ND(5, "rlock acquired for %d packets", ((j > end ? lim+1 : 0) + end) - j);
982fb578518SFranco Fichtner 	ft = kring->nkr_ft;
983fb578518SFranco Fichtner 
984fb578518SFranco Fichtner 	for (; likely(j != end); j = nm_next(j, lim)) {
985fb578518SFranco Fichtner 		struct netmap_slot *slot = &ring->slot[j];
986fb578518SFranco Fichtner 		char *buf;
987fb578518SFranco Fichtner 
988fb578518SFranco Fichtner 		ft[ft_i].ft_len = slot->len;
989fb578518SFranco Fichtner 		ft[ft_i].ft_flags = slot->flags;
990fb578518SFranco Fichtner 
991fb578518SFranco Fichtner 		ND("flags is 0x%x", slot->flags);
992fb578518SFranco Fichtner 		/* this slot goes into a list so initialize the link field */
993fb578518SFranco Fichtner 		ft[ft_i].ft_next = NM_FT_NULL;
994fb578518SFranco Fichtner 		buf = ft[ft_i].ft_buf = (slot->flags & NS_INDIRECT) ?
995fb578518SFranco Fichtner 			(void *)(uintptr_t)slot->ptr : BDG_NMB(&na->up, slot);
996fb578518SFranco Fichtner 		prefetch(buf);
997fb578518SFranco Fichtner 		++ft_i;
998fb578518SFranco Fichtner 		if (slot->flags & NS_MOREFRAG) {
999fb578518SFranco Fichtner 			frags++;
1000fb578518SFranco Fichtner 			continue;
1001fb578518SFranco Fichtner 		}
1002fb578518SFranco Fichtner 		if (unlikely(netmap_verbose && frags > 1))
1003fb578518SFranco Fichtner 			RD(5, "%d frags at %d", frags, ft_i - frags);
1004fb578518SFranco Fichtner 		ft[ft_i - frags].ft_frags = frags;
1005fb578518SFranco Fichtner 		frags = 1;
1006fb578518SFranco Fichtner 		if (unlikely((int)ft_i >= bridge_batch))
1007fb578518SFranco Fichtner 			ft_i = nm_bdg_flush(ft, ft_i, na, ring_nr);
1008fb578518SFranco Fichtner 	}
1009fb578518SFranco Fichtner 	if (frags > 1) {
1010fb578518SFranco Fichtner 		D("truncate incomplete fragment at %d (%d frags)", ft_i, frags);
1011fb578518SFranco Fichtner 		// ft_i > 0, ft[ft_i-1].flags has NS_MOREFRAG
1012fb578518SFranco Fichtner 		ft[ft_i - 1].ft_frags &= ~NS_MOREFRAG;
1013fb578518SFranco Fichtner 		ft[ft_i - frags].ft_frags = frags - 1;
1014fb578518SFranco Fichtner 	}
1015fb578518SFranco Fichtner 	if (ft_i)
1016fb578518SFranco Fichtner 		ft_i = nm_bdg_flush(ft, ft_i, na, ring_nr);
1017fb578518SFranco Fichtner 	BDG_RUNLOCK(b);
1018fb578518SFranco Fichtner 	return j;
1019fb578518SFranco Fichtner }
1020fb578518SFranco Fichtner 
1021fb578518SFranco Fichtner 
1022fb578518SFranco Fichtner /*
1023fb578518SFranco Fichtner  *---- support for virtual bridge -----
1024fb578518SFranco Fichtner  */
1025fb578518SFranco Fichtner 
1026fb578518SFranco Fichtner /* ----- FreeBSD if_bridge hash function ------- */
1027fb578518SFranco Fichtner 
1028fb578518SFranco Fichtner /*
1029fb578518SFranco Fichtner  * The following hash function is adapted from "Hash Functions" by Bob Jenkins
1030fb578518SFranco Fichtner  * ("Algorithm Alley", Dr. Dobbs Journal, September 1997).
1031fb578518SFranco Fichtner  *
1032fb578518SFranco Fichtner  * http://www.burtleburtle.net/bob/hash/spooky.html
1033fb578518SFranco Fichtner  */
1034fb578518SFranco Fichtner #define mix(a, b, c)                                                    \
1035fb578518SFranco Fichtner do {                                                                    \
1036fb578518SFranco Fichtner         a -= b; a -= c; a ^= (c >> 13);                                 \
1037fb578518SFranco Fichtner         b -= c; b -= a; b ^= (a << 8);                                  \
1038fb578518SFranco Fichtner         c -= a; c -= b; c ^= (b >> 13);                                 \
1039fb578518SFranco Fichtner         a -= b; a -= c; a ^= (c >> 12);                                 \
1040fb578518SFranco Fichtner         b -= c; b -= a; b ^= (a << 16);                                 \
1041fb578518SFranco Fichtner         c -= a; c -= b; c ^= (b >> 5);                                  \
1042fb578518SFranco Fichtner         a -= b; a -= c; a ^= (c >> 3);                                  \
1043fb578518SFranco Fichtner         b -= c; b -= a; b ^= (a << 10);                                 \
1044fb578518SFranco Fichtner         c -= a; c -= b; c ^= (b >> 15);                                 \
1045fb578518SFranco Fichtner } while (/*CONSTCOND*/0)
1046fb578518SFranco Fichtner 
1047fb578518SFranco Fichtner static __inline uint32_t
nm_bridge_rthash(const uint8_t * addr)1048fb578518SFranco Fichtner nm_bridge_rthash(const uint8_t *addr)
1049fb578518SFranco Fichtner {
1050fb578518SFranco Fichtner         uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = 0; // hask key
1051fb578518SFranco Fichtner 
1052fb578518SFranco Fichtner         b += addr[5] << 8;
1053fb578518SFranco Fichtner         b += addr[4];
1054fb578518SFranco Fichtner         a += addr[3] << 24;
1055fb578518SFranco Fichtner         a += addr[2] << 16;
1056fb578518SFranco Fichtner         a += addr[1] << 8;
1057fb578518SFranco Fichtner         a += addr[0];
1058fb578518SFranco Fichtner 
1059fb578518SFranco Fichtner         mix(a, b, c);
1060fb578518SFranco Fichtner #define BRIDGE_RTHASH_MASK	(NM_BDG_HASH-1)
1061fb578518SFranco Fichtner         return (c & BRIDGE_RTHASH_MASK);
1062fb578518SFranco Fichtner }
1063fb578518SFranco Fichtner 
1064fb578518SFranco Fichtner #undef mix
1065fb578518SFranco Fichtner 
1066fb578518SFranco Fichtner 
1067fb578518SFranco Fichtner static int
bdg_netmap_reg(struct netmap_adapter * na,int onoff)1068fb578518SFranco Fichtner bdg_netmap_reg(struct netmap_adapter *na, int onoff)
1069fb578518SFranco Fichtner {
1070fb578518SFranco Fichtner 	struct netmap_vp_adapter *vpna =
1071fb578518SFranco Fichtner 		(struct netmap_vp_adapter*)na;
1072fb578518SFranco Fichtner 	struct ifnet *ifp = na->ifp;
1073fb578518SFranco Fichtner 
1074fb578518SFranco Fichtner 	/* the interface is already attached to the bridge,
1075fb578518SFranco Fichtner 	 * so we only need to toggle IFCAP_NETMAP.
1076fb578518SFranco Fichtner 	 */
1077fb578518SFranco Fichtner 	BDG_WLOCK(vpna->na_bdg);
1078fb578518SFranco Fichtner 	if (onoff) {
1079fb578518SFranco Fichtner 		ifp->if_capenable |= IFCAP_NETMAP;
1080fb578518SFranco Fichtner 	} else {
1081fb578518SFranco Fichtner 		ifp->if_capenable &= ~IFCAP_NETMAP;
1082fb578518SFranco Fichtner 	}
1083fb578518SFranco Fichtner 	BDG_WUNLOCK(vpna->na_bdg);
1084fb578518SFranco Fichtner 	return 0;
1085fb578518SFranco Fichtner }
1086fb578518SFranco Fichtner 
1087fb578518SFranco Fichtner 
1088fb578518SFranco Fichtner /*
1089fb578518SFranco Fichtner  * Lookup function for a learning bridge.
1090fb578518SFranco Fichtner  * Update the hash table with the source address,
1091fb578518SFranco Fichtner  * and then returns the destination port index, and the
1092fb578518SFranco Fichtner  * ring in *dst_ring (at the moment, always use ring 0)
1093fb578518SFranco Fichtner  */
1094fb578518SFranco Fichtner u_int
netmap_bdg_learning(char * buf,u_int buf_len,uint8_t * dst_ring,struct netmap_vp_adapter * na)1095fb578518SFranco Fichtner netmap_bdg_learning(char *buf, u_int buf_len, uint8_t *dst_ring,
1096fb578518SFranco Fichtner 		struct netmap_vp_adapter *na)
1097fb578518SFranco Fichtner {
1098fb578518SFranco Fichtner 	struct nm_hash_ent *ht = na->na_bdg->ht;
1099fb578518SFranco Fichtner 	uint32_t sh, dh;
1100fb578518SFranco Fichtner 	u_int dst, mysrc = na->bdg_port;
1101fb578518SFranco Fichtner 	uint64_t smac, dmac;
1102fb578518SFranco Fichtner 
1103fb578518SFranco Fichtner 	if (buf_len < 14) {
1104fb578518SFranco Fichtner 		D("invalid buf length %d", buf_len);
1105fb578518SFranco Fichtner 		return NM_BDG_NOPORT;
1106fb578518SFranco Fichtner 	}
1107fb578518SFranco Fichtner 	dmac = le64toh(*(uint64_t *)(buf)) & 0xffffffffffff;
1108fb578518SFranco Fichtner 	smac = le64toh(*(uint64_t *)(buf + 4));
1109fb578518SFranco Fichtner 	smac >>= 16;
1110fb578518SFranco Fichtner 
1111fb578518SFranco Fichtner 	/*
1112fb578518SFranco Fichtner 	 * The hash is somewhat expensive, there might be some
1113fb578518SFranco Fichtner 	 * worthwhile optimizations here.
1114fb578518SFranco Fichtner 	 */
1115fb578518SFranco Fichtner 	if ((buf[6] & 1) == 0) { /* valid src */
1116fb578518SFranco Fichtner 		uint8_t *s = buf+6;
1117fb578518SFranco Fichtner 		sh = nm_bridge_rthash(s); // XXX hash of source
1118fb578518SFranco Fichtner 		/* update source port forwarding entry */
1119fb578518SFranco Fichtner 		ht[sh].mac = smac;	/* XXX expire ? */
1120fb578518SFranco Fichtner 		ht[sh].ports = mysrc;
1121fb578518SFranco Fichtner 		if (netmap_verbose)
1122fb578518SFranco Fichtner 		    D("src %02x:%02x:%02x:%02x:%02x:%02x on port %d",
1123fb578518SFranco Fichtner 			s[0], s[1], s[2], s[3], s[4], s[5], mysrc);
1124fb578518SFranco Fichtner 	}
1125fb578518SFranco Fichtner 	dst = NM_BDG_BROADCAST;
1126fb578518SFranco Fichtner 	if ((buf[0] & 1) == 0) { /* unicast */
1127fb578518SFranco Fichtner 		dh = nm_bridge_rthash(buf); // XXX hash of dst
1128fb578518SFranco Fichtner 		if (ht[dh].mac == dmac) {	/* found dst */
1129fb578518SFranco Fichtner 			dst = ht[dh].ports;
1130fb578518SFranco Fichtner 		}
1131fb578518SFranco Fichtner 		/* XXX otherwise return NM_BDG_UNKNOWN ? */
1132fb578518SFranco Fichtner 	}
1133fb578518SFranco Fichtner 	*dst_ring = 0;
1134fb578518SFranco Fichtner 	return dst;
1135fb578518SFranco Fichtner }
1136fb578518SFranco Fichtner 
1137fb578518SFranco Fichtner 
1138fb578518SFranco Fichtner /*
1139fb578518SFranco Fichtner  * This flush routine supports only unicast and broadcast but a large
1140fb578518SFranco Fichtner  * number of ports, and lets us replace the learn and dispatch functions.
1141fb578518SFranco Fichtner  */
1142fb578518SFranco Fichtner int
nm_bdg_flush(struct nm_bdg_fwd * ft,u_int n,struct netmap_vp_adapter * na,u_int ring_nr)1143fb578518SFranco Fichtner nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
1144fb578518SFranco Fichtner 		u_int ring_nr)
1145fb578518SFranco Fichtner {
1146fb578518SFranco Fichtner 	struct nm_bdg_q *dst_ents, *brddst;
1147fb578518SFranco Fichtner 	uint16_t num_dsts = 0, *dsts;
1148fb578518SFranco Fichtner 	struct nm_bridge *b = na->na_bdg;
1149fb578518SFranco Fichtner 	u_int i, j, me = na->bdg_port;
1150fb578518SFranco Fichtner 
1151fb578518SFranco Fichtner 	/*
1152fb578518SFranco Fichtner 	 * The work area (pointed by ft) is followed by an array of
1153fb578518SFranco Fichtner 	 * pointers to queues , dst_ents; there are NM_BDG_MAXRINGS
1154fb578518SFranco Fichtner 	 * queues per port plus one for the broadcast traffic.
1155fb578518SFranco Fichtner 	 * Then we have an array of destination indexes.
1156fb578518SFranco Fichtner 	 */
1157fb578518SFranco Fichtner 	dst_ents = (struct nm_bdg_q *)(ft + NM_BDG_BATCH_MAX);
1158fb578518SFranco Fichtner 	dsts = (uint16_t *)(dst_ents + NM_BDG_MAXPORTS * NM_BDG_MAXRINGS + 1);
1159fb578518SFranco Fichtner 
1160fb578518SFranco Fichtner 	/* first pass: find a destination for each packet in the batch */
1161fb578518SFranco Fichtner 	for (i = 0; likely(i < n); i += ft[i].ft_frags) {
1162fb578518SFranco Fichtner 		uint8_t dst_ring = ring_nr; /* default, same ring as origin */
1163fb578518SFranco Fichtner 		uint16_t dst_port, d_i;
1164fb578518SFranco Fichtner 		struct nm_bdg_q *d;
1165fb578518SFranco Fichtner 
1166fb578518SFranco Fichtner 		ND("slot %d frags %d", i, ft[i].ft_frags);
1167fb578518SFranco Fichtner 		dst_port = b->nm_bdg_lookup(ft[i].ft_buf, ft[i].ft_len,
1168fb578518SFranco Fichtner 			&dst_ring, na);
1169fb578518SFranco Fichtner 		if (netmap_verbose > 255)
1170fb578518SFranco Fichtner 			RD(5, "slot %d port %d -> %d", i, me, dst_port);
1171fb578518SFranco Fichtner 		if (dst_port == NM_BDG_NOPORT)
1172fb578518SFranco Fichtner 			continue; /* this packet is identified to be dropped */
1173fb578518SFranco Fichtner 		else if (unlikely(dst_port > NM_BDG_MAXPORTS))
1174fb578518SFranco Fichtner 			continue;
1175fb578518SFranco Fichtner 		else if (dst_port == NM_BDG_BROADCAST)
1176fb578518SFranco Fichtner 			dst_ring = 0; /* broadcasts always go to ring 0 */
1177fb578518SFranco Fichtner 		else if (unlikely(dst_port == me ||
1178fb578518SFranco Fichtner 		    !b->bdg_ports[dst_port]))
1179fb578518SFranco Fichtner 			continue;
1180fb578518SFranco Fichtner 
1181fb578518SFranco Fichtner 		/* get a position in the scratch pad */
1182fb578518SFranco Fichtner 		d_i = dst_port * NM_BDG_MAXRINGS + dst_ring;
1183fb578518SFranco Fichtner 		d = dst_ents + d_i;
1184fb578518SFranco Fichtner 
1185fb578518SFranco Fichtner 		/* append the first fragment to the list */
1186fb578518SFranco Fichtner 		if (d->bq_head == NM_FT_NULL) { /* new destination */
1187fb578518SFranco Fichtner 			d->bq_head = d->bq_tail = i;
1188fb578518SFranco Fichtner 			/* remember this position to be scanned later */
1189fb578518SFranco Fichtner 			if (dst_port != NM_BDG_BROADCAST)
1190fb578518SFranco Fichtner 				dsts[num_dsts++] = d_i;
1191fb578518SFranco Fichtner 		} else {
1192fb578518SFranco Fichtner 			ft[d->bq_tail].ft_next = i;
1193fb578518SFranco Fichtner 			d->bq_tail = i;
1194fb578518SFranco Fichtner 		}
1195fb578518SFranco Fichtner 		d->bq_len += ft[i].ft_frags;
1196fb578518SFranco Fichtner 	}
1197fb578518SFranco Fichtner 
1198fb578518SFranco Fichtner 	/*
1199fb578518SFranco Fichtner 	 * Broadcast traffic goes to ring 0 on all destinations.
1200fb578518SFranco Fichtner 	 * So we need to add these rings to the list of ports to scan.
1201fb578518SFranco Fichtner 	 * XXX at the moment we scan all NM_BDG_MAXPORTS ports, which is
1202fb578518SFranco Fichtner 	 * expensive. We should keep a compact list of active destinations
1203fb578518SFranco Fichtner 	 * so we could shorten this loop.
1204fb578518SFranco Fichtner 	 */
1205fb578518SFranco Fichtner 	brddst = dst_ents + NM_BDG_BROADCAST * NM_BDG_MAXRINGS;
1206fb578518SFranco Fichtner 	if (brddst->bq_head != NM_FT_NULL) {
1207fb578518SFranco Fichtner 		for (j = 0; likely(j < b->bdg_active_ports); j++) {
1208fb578518SFranco Fichtner 			uint16_t d_i;
1209fb578518SFranco Fichtner 			i = b->bdg_port_index[j];
1210fb578518SFranco Fichtner 			if (unlikely(i == me))
1211fb578518SFranco Fichtner 				continue;
1212fb578518SFranco Fichtner 			d_i = i * NM_BDG_MAXRINGS;
1213fb578518SFranco Fichtner 			if (dst_ents[d_i].bq_head == NM_FT_NULL)
1214fb578518SFranco Fichtner 				dsts[num_dsts++] = d_i;
1215fb578518SFranco Fichtner 		}
1216fb578518SFranco Fichtner 	}
1217fb578518SFranco Fichtner 
1218fb578518SFranco Fichtner 	ND(5, "pass 1 done %d pkts %d dsts", n, num_dsts);
1219fb578518SFranco Fichtner 	/* second pass: scan destinations (XXX will be modular somehow) */
1220fb578518SFranco Fichtner 	for (i = 0; i < num_dsts; i++) {
1221fb578518SFranco Fichtner 		struct ifnet *dst_ifp;
1222fb578518SFranco Fichtner 		struct netmap_vp_adapter *dst_na;
1223fb578518SFranco Fichtner 		struct netmap_kring *kring;
1224fb578518SFranco Fichtner 		struct netmap_ring *ring;
1225fb578518SFranco Fichtner 		u_int dst_nr, lim, j, sent = 0, d_i, next, brd_next;
1226fb578518SFranco Fichtner 		u_int needed, howmany;
1227fb578518SFranco Fichtner 		int retry = netmap_txsync_retry;
1228fb578518SFranco Fichtner 		struct nm_bdg_q *d;
1229fb578518SFranco Fichtner 		uint32_t my_start = 0, lease_idx = 0;
1230fb578518SFranco Fichtner 		int nrings;
1231fb578518SFranco Fichtner 
1232fb578518SFranco Fichtner 		d_i = dsts[i];
1233fb578518SFranco Fichtner 		ND("second pass %d port %d", i, d_i);
1234fb578518SFranco Fichtner 		d = dst_ents + d_i;
1235fb578518SFranco Fichtner 		// XXX fix the division
1236fb578518SFranco Fichtner 		dst_na = b->bdg_ports[d_i/NM_BDG_MAXRINGS];
1237fb578518SFranco Fichtner 		/* protect from the lookup function returning an inactive
1238fb578518SFranco Fichtner 		 * destination port
1239fb578518SFranco Fichtner 		 */
1240fb578518SFranco Fichtner 		if (unlikely(dst_na == NULL))
1241fb578518SFranco Fichtner 			goto cleanup;
1242fb578518SFranco Fichtner 		if (dst_na->up.na_flags & NAF_SW_ONLY)
1243fb578518SFranco Fichtner 			goto cleanup;
1244fb578518SFranco Fichtner 		dst_ifp = dst_na->up.ifp;
1245fb578518SFranco Fichtner 		/*
1246fb578518SFranco Fichtner 		 * The interface may be in !netmap mode in two cases:
1247fb578518SFranco Fichtner 		 * - when na is attached but not activated yet;
1248fb578518SFranco Fichtner 		 * - when na is being deactivated but is still attached.
1249fb578518SFranco Fichtner 		 */
1250fb578518SFranco Fichtner 		if (unlikely(!(dst_ifp->if_capenable & IFCAP_NETMAP))) {
1251fb578518SFranco Fichtner 			ND("not in netmap mode!");
1252fb578518SFranco Fichtner 			goto cleanup;
1253fb578518SFranco Fichtner 		}
1254fb578518SFranco Fichtner 
1255fb578518SFranco Fichtner 		/* there is at least one either unicast or broadcast packet */
1256fb578518SFranco Fichtner 		brd_next = brddst->bq_head;
1257fb578518SFranco Fichtner 		next = d->bq_head;
1258fb578518SFranco Fichtner 		/* we need to reserve this many slots. If fewer are
1259fb578518SFranco Fichtner 		 * available, some packets will be dropped.
1260fb578518SFranco Fichtner 		 * Packets may have multiple fragments, so we may not use
1261fb578518SFranco Fichtner 		 * there is a chance that we may not use all of the slots
1262fb578518SFranco Fichtner 		 * we have claimed, so we will need to handle the leftover
1263fb578518SFranco Fichtner 		 * ones when we regain the lock.
1264fb578518SFranco Fichtner 		 */
1265fb578518SFranco Fichtner 		needed = d->bq_len + brddst->bq_len;
1266fb578518SFranco Fichtner 
1267fb578518SFranco Fichtner 		ND(5, "pass 2 dst %d is %x %s",
1268fb578518SFranco Fichtner 			i, d_i, is_vp ? "virtual" : "nic/host");
1269fb578518SFranco Fichtner 		dst_nr = d_i & (NM_BDG_MAXRINGS-1);
1270fb578518SFranco Fichtner 		nrings = dst_na->up.num_rx_rings;
1271fb578518SFranco Fichtner 		if (dst_nr >= nrings)
1272fb578518SFranco Fichtner 			dst_nr = dst_nr % nrings;
1273fb578518SFranco Fichtner 		kring = &dst_na->up.rx_rings[dst_nr];
1274fb578518SFranco Fichtner 		ring = kring->ring;
1275fb578518SFranco Fichtner 		lim = kring->nkr_num_slots - 1;
1276fb578518SFranco Fichtner 
1277fb578518SFranco Fichtner retry:
1278fb578518SFranco Fichtner 
1279fb578518SFranco Fichtner 		/* reserve the buffers in the queue and an entry
1280fb578518SFranco Fichtner 		 * to report completion, and drop lock.
1281fb578518SFranco Fichtner 		 * XXX this might become a helper function.
1282fb578518SFranco Fichtner 		 */
1283ed9bd855SFranco Fichtner 		lockmgr(&kring->q_lock, LK_EXCLUSIVE);
1284fb578518SFranco Fichtner 		if (kring->nkr_stopped) {
1285ed9bd855SFranco Fichtner 			lockmgr(&kring->q_lock, LK_RELEASE);
1286fb578518SFranco Fichtner 			goto cleanup;
1287fb578518SFranco Fichtner 		}
1288fb578518SFranco Fichtner 		if (dst_na->retry) {
1289fb578518SFranco Fichtner 			dst_na->up.nm_notify(&dst_na->up, dst_nr, NR_RX, 0);
1290fb578518SFranco Fichtner 		}
1291fb578518SFranco Fichtner 		my_start = j = kring->nkr_hwlease;
1292fb578518SFranco Fichtner 		howmany = nm_kr_space(kring, 1);
1293fb578518SFranco Fichtner 		if (needed < howmany)
1294fb578518SFranco Fichtner 			howmany = needed;
1295fb578518SFranco Fichtner 		lease_idx = nm_kr_lease(kring, howmany, 1);
1296ed9bd855SFranco Fichtner 		lockmgr(&kring->q_lock, LK_RELEASE);
1297fb578518SFranco Fichtner 
1298fb578518SFranco Fichtner 		/* only retry if we need more than available slots */
1299fb578518SFranco Fichtner 		if (retry && needed <= howmany)
1300fb578518SFranco Fichtner 			retry = 0;
1301fb578518SFranco Fichtner 
1302fb578518SFranco Fichtner 		/* copy to the destination queue */
1303fb578518SFranco Fichtner 		while (howmany > 0) {
1304fb578518SFranco Fichtner 			struct netmap_slot *slot;
1305fb578518SFranco Fichtner 			struct nm_bdg_fwd *ft_p, *ft_end;
1306fb578518SFranco Fichtner 			u_int cnt;
1307fb578518SFranco Fichtner 
1308fb578518SFranco Fichtner 			/* find the queue from which we pick next packet.
1309fb578518SFranco Fichtner 			 * NM_FT_NULL is always higher than valid indexes
1310fb578518SFranco Fichtner 			 * so we never dereference it if the other list
1311fb578518SFranco Fichtner 			 * has packets (and if both are empty we never
1312fb578518SFranco Fichtner 			 * get here).
1313fb578518SFranco Fichtner 			 */
1314fb578518SFranco Fichtner 			if (next < brd_next) {
1315fb578518SFranco Fichtner 				ft_p = ft + next;
1316fb578518SFranco Fichtner 				next = ft_p->ft_next;
1317fb578518SFranco Fichtner 			} else { /* insert broadcast */
1318fb578518SFranco Fichtner 				ft_p = ft + brd_next;
1319fb578518SFranco Fichtner 				brd_next = ft_p->ft_next;
1320fb578518SFranco Fichtner 			}
1321fb578518SFranco Fichtner 			cnt = ft_p->ft_frags; // cnt > 0
1322fb578518SFranco Fichtner 			if (unlikely(cnt > howmany))
1323fb578518SFranco Fichtner 			    break; /* no more space */
1324fb578518SFranco Fichtner 			howmany -= cnt;
1325fb578518SFranco Fichtner 			if (netmap_verbose && cnt > 1)
1326fb578518SFranco Fichtner 				RD(5, "rx %d frags to %d", cnt, j);
1327fb578518SFranco Fichtner 			ft_end = ft_p + cnt;
1328fb578518SFranco Fichtner 			do {
1329fb578518SFranco Fichtner 			    void *dst, *src = ft_p->ft_buf;
1330fb578518SFranco Fichtner 			    size_t len = (ft_p->ft_len + 63) & ~63;
1331fb578518SFranco Fichtner 
1332fb578518SFranco Fichtner 			    slot = &ring->slot[j];
1333fb578518SFranco Fichtner 			    dst = BDG_NMB(&dst_na->up, slot);
1334fb578518SFranco Fichtner 			    /* round to a multiple of 64 */
1335fb578518SFranco Fichtner 
1336fb578518SFranco Fichtner 			    ND("send %d %d bytes at %s:%d",
1337fb578518SFranco Fichtner 				i, ft_p->ft_len, NM_IFPNAME(dst_ifp), j);
1338fb578518SFranco Fichtner 			    if (ft_p->ft_flags & NS_INDIRECT) {
1339fb578518SFranco Fichtner 				if (copyin(src, dst, len)) {
1340fb578518SFranco Fichtner 					// invalid user pointer, pretend len is 0
1341fb578518SFranco Fichtner 					ft_p->ft_len = 0;
1342fb578518SFranco Fichtner 				}
1343fb578518SFranco Fichtner 			    } else {
1344fb578518SFranco Fichtner 				//memcpy(dst, src, len);
1345fb578518SFranco Fichtner 				pkt_copy(src, dst, (int)len);
1346fb578518SFranco Fichtner 			    }
1347fb578518SFranco Fichtner 			    slot->len = ft_p->ft_len;
1348fb578518SFranco Fichtner 			    slot->flags = (cnt << 8)| NS_MOREFRAG;
1349fb578518SFranco Fichtner 			    j = nm_next(j, lim);
1350fb578518SFranco Fichtner 			    ft_p++;
1351fb578518SFranco Fichtner 			    sent++;
1352fb578518SFranco Fichtner 			} while (ft_p != ft_end);
1353fb578518SFranco Fichtner 			slot->flags = (cnt << 8); /* clear flag on last entry */
1354fb578518SFranco Fichtner 			/* are we done ? */
1355fb578518SFranco Fichtner 			if (next == NM_FT_NULL && brd_next == NM_FT_NULL)
1356fb578518SFranco Fichtner 				break;
1357fb578518SFranco Fichtner 		}
1358fb578518SFranco Fichtner 		{
1359fb578518SFranco Fichtner 		    /* current position */
1360fb578518SFranco Fichtner 		    uint32_t *p = kring->nkr_leases; /* shorthand */
1361fb578518SFranco Fichtner 		    uint32_t update_pos;
1362fb578518SFranco Fichtner 		    int still_locked = 1;
1363fb578518SFranco Fichtner 
1364ed9bd855SFranco Fichtner 		    lockmgr(&kring->q_lock, LK_EXCLUSIVE);
1365fb578518SFranco Fichtner 		    if (unlikely(howmany > 0)) {
1366fb578518SFranco Fichtner 			/* not used all bufs. If i am the last one
1367fb578518SFranco Fichtner 			 * i can recover the slots, otherwise must
1368fb578518SFranco Fichtner 			 * fill them with 0 to mark empty packets.
1369fb578518SFranco Fichtner 			 */
1370fb578518SFranco Fichtner 			ND("leftover %d bufs", howmany);
1371fb578518SFranco Fichtner 			if (nm_next(lease_idx, lim) == kring->nkr_lease_idx) {
1372fb578518SFranco Fichtner 			    /* yes i am the last one */
1373fb578518SFranco Fichtner 			    ND("roll back nkr_hwlease to %d", j);
1374fb578518SFranco Fichtner 			    kring->nkr_hwlease = j;
1375fb578518SFranco Fichtner 			} else {
1376fb578518SFranco Fichtner 			    while (howmany-- > 0) {
1377fb578518SFranco Fichtner 				ring->slot[j].len = 0;
1378fb578518SFranco Fichtner 				ring->slot[j].flags = 0;
1379fb578518SFranco Fichtner 				j = nm_next(j, lim);
1380fb578518SFranco Fichtner 			    }
1381fb578518SFranco Fichtner 			}
1382fb578518SFranco Fichtner 		    }
1383fb578518SFranco Fichtner 		    p[lease_idx] = j; /* report I am done */
1384fb578518SFranco Fichtner 
1385fb578518SFranco Fichtner 		    update_pos = nm_kr_rxpos(kring);
1386fb578518SFranco Fichtner 
1387fb578518SFranco Fichtner 		    if (my_start == update_pos) {
1388fb578518SFranco Fichtner 			/* all slots before my_start have been reported,
1389fb578518SFranco Fichtner 			 * so scan subsequent leases to see if other ranges
1390fb578518SFranco Fichtner 			 * have been completed, and to a selwakeup or txsync.
1391fb578518SFranco Fichtner 		         */
1392fb578518SFranco Fichtner 			while (lease_idx != kring->nkr_lease_idx &&
1393fb578518SFranco Fichtner 				p[lease_idx] != NR_NOSLOT) {
1394fb578518SFranco Fichtner 			    j = p[lease_idx];
1395fb578518SFranco Fichtner 			    p[lease_idx] = NR_NOSLOT;
1396fb578518SFranco Fichtner 			    lease_idx = nm_next(lease_idx, lim);
1397fb578518SFranco Fichtner 			}
1398fb578518SFranco Fichtner 			/* j is the new 'write' position. j != my_start
1399fb578518SFranco Fichtner 			 * means there are new buffers to report
1400fb578518SFranco Fichtner 			 */
1401fb578518SFranco Fichtner 			if (likely(j != my_start)) {
1402fb578518SFranco Fichtner 				uint32_t old_avail = kring->nr_hwavail;
1403fb578518SFranco Fichtner 
1404fb578518SFranco Fichtner 				kring->nr_hwavail = (j >= kring->nr_hwcur) ?
1405fb578518SFranco Fichtner 					j - kring->nr_hwcur :
1406fb578518SFranco Fichtner 					j + lim + 1 - kring->nr_hwcur;
1407fb578518SFranco Fichtner 				if (kring->nr_hwavail < old_avail) {
1408fb578518SFranco Fichtner 					D("avail shrink %d -> %d",
1409fb578518SFranco Fichtner 						old_avail, kring->nr_hwavail);
1410fb578518SFranco Fichtner 				}
1411fb578518SFranco Fichtner 				dst_na->up.nm_notify(&dst_na->up, dst_nr, NR_RX, 0);
1412fb578518SFranco Fichtner 				still_locked = 0;
1413ed9bd855SFranco Fichtner 				lockmgr(&kring->q_lock, LK_RELEASE);
1414fb578518SFranco Fichtner 				if (dst_na->retry && retry--)
1415fb578518SFranco Fichtner 					goto retry;
1416fb578518SFranco Fichtner 			}
1417fb578518SFranco Fichtner 		    }
1418fb578518SFranco Fichtner 		    if (still_locked)
1419ed9bd855SFranco Fichtner 			lockmgr(&kring->q_lock, LK_RELEASE);
1420fb578518SFranco Fichtner 		}
1421fb578518SFranco Fichtner cleanup:
1422fb578518SFranco Fichtner 		d->bq_head = d->bq_tail = NM_FT_NULL; /* cleanup */
1423fb578518SFranco Fichtner 		d->bq_len = 0;
1424fb578518SFranco Fichtner 	}
1425fb578518SFranco Fichtner 	brddst->bq_head = brddst->bq_tail = NM_FT_NULL; /* cleanup */
1426fb578518SFranco Fichtner 	brddst->bq_len = 0;
1427fb578518SFranco Fichtner 	return 0;
1428fb578518SFranco Fichtner }
1429fb578518SFranco Fichtner 
1430fb578518SFranco Fichtner static int
netmap_vp_txsync(struct netmap_vp_adapter * na,u_int ring_nr,int flags)1431fb578518SFranco Fichtner netmap_vp_txsync(struct netmap_vp_adapter *na, u_int ring_nr, int flags)
1432fb578518SFranco Fichtner {
1433fb578518SFranco Fichtner 	struct netmap_kring *kring = &na->up.tx_rings[ring_nr];
1434fb578518SFranco Fichtner 	struct netmap_ring *ring = kring->ring;
1435fb578518SFranco Fichtner 	u_int j, k, lim = kring->nkr_num_slots - 1;
1436fb578518SFranco Fichtner 
1437fb578518SFranco Fichtner 	k = ring->cur;
1438fb578518SFranco Fichtner 	if (k > lim)
1439fb578518SFranco Fichtner 		return netmap_ring_reinit(kring);
1440fb578518SFranco Fichtner 
1441fb578518SFranco Fichtner 	if (bridge_batch <= 0) { /* testing only */
1442fb578518SFranco Fichtner 		j = k; // used all
1443fb578518SFranco Fichtner 		goto done;
1444fb578518SFranco Fichtner 	}
1445fb578518SFranco Fichtner 	if (bridge_batch > NM_BDG_BATCH)
1446fb578518SFranco Fichtner 		bridge_batch = NM_BDG_BATCH;
1447fb578518SFranco Fichtner 
1448fb578518SFranco Fichtner 	j = nm_bdg_preflush(na, ring_nr, kring, k);
1449fb578518SFranco Fichtner 	if (j != k)
1450fb578518SFranco Fichtner 		D("early break at %d/ %d, avail %d", j, k, kring->nr_hwavail);
1451fb578518SFranco Fichtner 	/* k-j modulo ring size is the number of slots processed */
1452fb578518SFranco Fichtner 	if (k < j)
1453fb578518SFranco Fichtner 		k += kring->nkr_num_slots;
1454fb578518SFranco Fichtner 	kring->nr_hwavail = lim - (k - j);
1455fb578518SFranco Fichtner 
1456fb578518SFranco Fichtner done:
1457fb578518SFranco Fichtner 	kring->nr_hwcur = j;
1458fb578518SFranco Fichtner 	ring->avail = kring->nr_hwavail;
1459fb578518SFranco Fichtner 	if (netmap_verbose)
1460fb578518SFranco Fichtner 		D("%s ring %d flags %d", NM_IFPNAME(na->up.ifp), ring_nr, flags);
1461fb578518SFranco Fichtner 	return 0;
1462fb578518SFranco Fichtner }
1463fb578518SFranco Fichtner 
1464fb578518SFranco Fichtner 
1465fb578518SFranco Fichtner /*
1466fb578518SFranco Fichtner  * main dispatch routine for the bridge.
1467fb578518SFranco Fichtner  * We already know that only one thread is running this.
1468fb578518SFranco Fichtner  * we must run nm_bdg_preflush without lock.
1469fb578518SFranco Fichtner  */
1470fb578518SFranco Fichtner static int
bdg_netmap_txsync(struct netmap_adapter * na,u_int ring_nr,int flags)1471fb578518SFranco Fichtner bdg_netmap_txsync(struct netmap_adapter *na, u_int ring_nr, int flags)
1472fb578518SFranco Fichtner {
1473fb578518SFranco Fichtner 	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter*)na;
1474fb578518SFranco Fichtner 	return netmap_vp_txsync(vpna, ring_nr, flags);
1475fb578518SFranco Fichtner }
1476fb578518SFranco Fichtner 
1477fb578518SFranco Fichtner 
1478fb578518SFranco Fichtner /*
1479fb578518SFranco Fichtner  * user process reading from a VALE switch.
1480fb578518SFranco Fichtner  * Already protected against concurrent calls from userspace,
1481fb578518SFranco Fichtner  * but we must acquire the queue's lock to protect against
1482fb578518SFranco Fichtner  * writers on the same queue.
1483fb578518SFranco Fichtner  */
1484fb578518SFranco Fichtner static int
bdg_netmap_rxsync(struct netmap_adapter * na,u_int ring_nr,int flags)1485fb578518SFranco Fichtner bdg_netmap_rxsync(struct netmap_adapter *na, u_int ring_nr, int flags)
1486fb578518SFranco Fichtner {
1487fb578518SFranco Fichtner 	struct netmap_kring *kring = &na->rx_rings[ring_nr];
1488fb578518SFranco Fichtner 	struct netmap_ring *ring = kring->ring;
1489fb578518SFranco Fichtner 	u_int j, lim = kring->nkr_num_slots - 1;
1490fb578518SFranco Fichtner 	u_int k = ring->cur, resvd = ring->reserved;
1491fb578518SFranco Fichtner 	int n;
1492fb578518SFranco Fichtner 
1493ed9bd855SFranco Fichtner 	lockmgr(&kring->q_lock, LK_EXCLUSIVE);
1494fb578518SFranco Fichtner 	if (k > lim) {
1495fb578518SFranco Fichtner 		D("ouch dangerous reset!!!");
1496fb578518SFranco Fichtner 		n = netmap_ring_reinit(kring);
1497fb578518SFranco Fichtner 		goto done;
1498fb578518SFranco Fichtner 	}
1499fb578518SFranco Fichtner 
1500fb578518SFranco Fichtner 	/* skip past packets that userspace has released */
1501fb578518SFranco Fichtner 	j = kring->nr_hwcur;    /* netmap ring index */
1502fb578518SFranco Fichtner 	if (resvd > 0) {
1503fb578518SFranco Fichtner 		if (resvd + ring->avail >= lim + 1) {
1504fb578518SFranco Fichtner 			D("XXX invalid reserve/avail %d %d", resvd, ring->avail);
1505fb578518SFranco Fichtner 			ring->reserved = resvd = 0; // XXX panic...
1506fb578518SFranco Fichtner 		}
1507fb578518SFranco Fichtner 		k = (k >= resvd) ? k - resvd : k + lim + 1 - resvd;
1508fb578518SFranco Fichtner 	}
1509fb578518SFranco Fichtner 
1510fb578518SFranco Fichtner 	if (j != k) { /* userspace has released some packets. */
1511fb578518SFranco Fichtner 		n = k - j;
1512fb578518SFranco Fichtner 		if (n < 0)
1513fb578518SFranco Fichtner 			n += kring->nkr_num_slots;
1514fb578518SFranco Fichtner 		ND("userspace releases %d packets", n);
1515fb578518SFranco Fichtner 		for (n = 0; likely(j != k); n++) {
1516fb578518SFranco Fichtner 			struct netmap_slot *slot = &ring->slot[j];
1517fb578518SFranco Fichtner 			void *addr = BDG_NMB(na, slot);
1518fb578518SFranco Fichtner 
1519fb578518SFranco Fichtner 			if (addr == netmap_buffer_base) { /* bad buf */
1520fb578518SFranco Fichtner 				D("bad buffer index %d, ignore ?",
1521fb578518SFranco Fichtner 					slot->buf_idx);
1522fb578518SFranco Fichtner 			}
1523fb578518SFranco Fichtner 			slot->flags &= ~NS_BUF_CHANGED;
1524fb578518SFranco Fichtner 			j = nm_next(j, lim);
1525fb578518SFranco Fichtner 		}
1526fb578518SFranco Fichtner 		kring->nr_hwavail -= n;
1527fb578518SFranco Fichtner 		kring->nr_hwcur = k;
1528fb578518SFranco Fichtner 	}
1529fb578518SFranco Fichtner 	/* tell userspace that there are new packets */
1530fb578518SFranco Fichtner 	ring->avail = kring->nr_hwavail - resvd;
1531fb578518SFranco Fichtner 	n = 0;
1532fb578518SFranco Fichtner done:
1533ed9bd855SFranco Fichtner 	lockmgr(&kring->q_lock, LK_RELEASE);
1534fb578518SFranco Fichtner 	return n;
1535fb578518SFranco Fichtner }
1536fb578518SFranco Fichtner 
1537fb578518SFranco Fichtner static int
bdg_netmap_attach(struct netmap_adapter * arg)1538fb578518SFranco Fichtner bdg_netmap_attach(struct netmap_adapter *arg)
1539fb578518SFranco Fichtner {
1540fb578518SFranco Fichtner 	struct netmap_vp_adapter *vpna;
1541fb578518SFranco Fichtner 	struct netmap_adapter *na;
1542fb578518SFranco Fichtner 	int error;
1543fb578518SFranco Fichtner 
1544ed9bd855SFranco Fichtner 	vpna = kmalloc(sizeof(*vpna), M_DEVBUF, M_NOWAIT | M_ZERO);
1545fb578518SFranco Fichtner 	if (vpna == NULL)
1546fb578518SFranco Fichtner 		return ENOMEM;
1547fb578518SFranco Fichtner 	na = &vpna->up;
1548fb578518SFranco Fichtner 	*na = *arg;
1549fb578518SFranco Fichtner 	na->na_flags |= NAF_BDG_MAYSLEEP | NAF_MEM_OWNER;
1550fb578518SFranco Fichtner 	na->nm_txsync = bdg_netmap_txsync;
1551fb578518SFranco Fichtner 	na->nm_rxsync = bdg_netmap_rxsync;
1552fb578518SFranco Fichtner 	na->nm_register = bdg_netmap_reg;
1553fb578518SFranco Fichtner 	na->nm_dtor = netmap_adapter_vp_dtor;
1554fb578518SFranco Fichtner 	na->nm_krings_create = netmap_vp_krings_create;
1555fb578518SFranco Fichtner 	na->nm_krings_delete = netmap_vp_krings_delete;
1556fb578518SFranco Fichtner 	na->nm_mem = netmap_mem_private_new(NM_IFPNAME(arg->ifp),
1557fb578518SFranco Fichtner 			na->num_tx_rings, na->num_tx_desc,
1558fb578518SFranco Fichtner 			na->num_rx_rings, na->num_rx_desc);
1559fb578518SFranco Fichtner 	/* other nmd fields are set in the common routine */
1560fb578518SFranco Fichtner 	error = netmap_attach_common(na);
1561fb578518SFranco Fichtner 	if (error) {
1562ed9bd855SFranco Fichtner 		kfree(vpna, M_DEVBUF);
1563fb578518SFranco Fichtner 		return error;
1564fb578518SFranco Fichtner 	}
1565fb578518SFranco Fichtner 	return 0;
1566fb578518SFranco Fichtner }
1567fb578518SFranco Fichtner 
1568fb578518SFranco Fichtner static void
netmap_bwrap_dtor(struct netmap_adapter * na)1569fb578518SFranco Fichtner netmap_bwrap_dtor(struct netmap_adapter *na)
1570fb578518SFranco Fichtner {
1571fb578518SFranco Fichtner 	struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter*)na;
1572fb578518SFranco Fichtner 	struct netmap_adapter *hwna = bna->hwna;
1573fb578518SFranco Fichtner 	struct nm_bridge *b = bna->up.na_bdg,
1574fb578518SFranco Fichtner 		*bh = bna->host.na_bdg;
1575fb578518SFranco Fichtner 	struct ifnet *ifp = na->ifp;
1576fb578518SFranco Fichtner 
1577fb578518SFranco Fichtner 	ND("na %p", na);
1578fb578518SFranco Fichtner 
1579fb578518SFranco Fichtner 	if (b) {
1580fb578518SFranco Fichtner 		netmap_bdg_detach_common(b, bna->up.bdg_port,
1581fb578518SFranco Fichtner 			(bh ? bna->host.bdg_port : -1));
1582fb578518SFranco Fichtner 	}
1583fb578518SFranco Fichtner 
1584fb578518SFranco Fichtner 	hwna->na_private = NULL;
1585fb578518SFranco Fichtner 	netmap_adapter_put(hwna);
1586fb578518SFranco Fichtner 
1587fb578518SFranco Fichtner 	bzero(ifp, sizeof(*ifp));
1588ed9bd855SFranco Fichtner 	kfree(ifp, M_DEVBUF);
1589fb578518SFranco Fichtner 	na->ifp = NULL;
1590fb578518SFranco Fichtner 
1591fb578518SFranco Fichtner }
1592fb578518SFranco Fichtner 
1593fb578518SFranco Fichtner /*
1594fb578518SFranco Fichtner  * Pass packets from nic to the bridge.
1595fb578518SFranco Fichtner  * XXX TODO check locking: this is called from the interrupt
1596fb578518SFranco Fichtner  * handler so we should make sure that the interface is not
1597fb578518SFranco Fichtner  * disconnected while passing down an interrupt.
1598fb578518SFranco Fichtner  *
1599fb578518SFranco Fichtner  * Note, no user process can access this NIC so we can ignore
1600fb578518SFranco Fichtner  * the info in the 'ring'.
1601fb578518SFranco Fichtner  */
1602fb578518SFranco Fichtner /* callback that overwrites the hwna notify callback.
1603fb578518SFranco Fichtner  * Packets come from the outside or from the host stack and are put on an hwna rx ring.
1604fb578518SFranco Fichtner  * The bridge wrapper then sends the packets through the bridge.
1605fb578518SFranco Fichtner  */
1606fb578518SFranco Fichtner static int
netmap_bwrap_intr_notify(struct netmap_adapter * na,u_int ring_nr,enum txrx tx,int flags)1607fb578518SFranco Fichtner netmap_bwrap_intr_notify(struct netmap_adapter *na, u_int ring_nr, enum txrx tx, int flags)
1608fb578518SFranco Fichtner {
1609fb578518SFranco Fichtner 	struct ifnet *ifp = na->ifp;
1610fb578518SFranco Fichtner 	struct netmap_bwrap_adapter *bna = na->na_private;
1611fb578518SFranco Fichtner 	struct netmap_vp_adapter *hostna = &bna->host;
1612fb578518SFranco Fichtner 	struct netmap_kring *kring, *bkring;
1613fb578518SFranco Fichtner 	struct netmap_ring *ring;
1614fb578518SFranco Fichtner 	int is_host_ring = ring_nr == na->num_rx_rings;
1615fb578518SFranco Fichtner 	struct netmap_vp_adapter *vpna = &bna->up;
1616fb578518SFranco Fichtner 	int error = 0;
1617fb578518SFranco Fichtner 
1618fb578518SFranco Fichtner 	ND("%s[%d] %s %x", NM_IFPNAME(ifp), ring_nr, (tx == NR_TX ? "TX" : "RX"), flags);
1619fb578518SFranco Fichtner 
1620fb578518SFranco Fichtner 	if (flags & NAF_DISABLE_NOTIFY) {
1621fb578518SFranco Fichtner 		kring = tx == NR_TX ? na->tx_rings : na->rx_rings;
1622fb578518SFranco Fichtner 		bkring = tx == NR_TX ? vpna->up.rx_rings : vpna->up.tx_rings;
1623fb578518SFranco Fichtner 		if (kring->nkr_stopped)
1624fb578518SFranco Fichtner 			netmap_disable_ring(bkring);
1625fb578518SFranco Fichtner 		else
1626fb578518SFranco Fichtner 			bkring->nkr_stopped = 0;
1627fb578518SFranco Fichtner 		return 0;
1628fb578518SFranco Fichtner 	}
1629fb578518SFranco Fichtner 
1630fb578518SFranco Fichtner 	if (ifp == NULL || !(ifp->if_capenable & IFCAP_NETMAP))
1631fb578518SFranco Fichtner 		return 0;
1632fb578518SFranco Fichtner 
1633fb578518SFranco Fichtner 	if (tx == NR_TX)
1634fb578518SFranco Fichtner 		return 0;
1635fb578518SFranco Fichtner 
1636fb578518SFranco Fichtner 	kring = &na->rx_rings[ring_nr];
1637fb578518SFranco Fichtner 	ring = kring->ring;
1638fb578518SFranco Fichtner 
1639fb578518SFranco Fichtner 	/* make sure the ring is not disabled */
1640fb578518SFranco Fichtner 	if (nm_kr_tryget(kring))
1641fb578518SFranco Fichtner 		return 0;
1642fb578518SFranco Fichtner 
1643fb578518SFranco Fichtner 	if (is_host_ring && hostna->na_bdg == NULL) {
1644fb578518SFranco Fichtner 		error = bna->save_notify(na, ring_nr, tx, flags);
1645fb578518SFranco Fichtner 		goto put_out;
1646fb578518SFranco Fichtner 	}
1647fb578518SFranco Fichtner 
1648fb578518SFranco Fichtner 	if (is_host_ring) {
1649fb578518SFranco Fichtner 		vpna = hostna;
1650fb578518SFranco Fichtner 		ring_nr = 0;
1651fb578518SFranco Fichtner 	} else {
1652fb578518SFranco Fichtner 		/* fetch packets that have arrived.
1653fb578518SFranco Fichtner 		 * XXX maybe do this in a loop ?
1654fb578518SFranco Fichtner 		 */
1655fb578518SFranco Fichtner 		error = na->nm_rxsync(na, ring_nr, 0);
1656fb578518SFranco Fichtner 		if (error)
1657fb578518SFranco Fichtner 			goto put_out;
1658fb578518SFranco Fichtner 	}
1659fb578518SFranco Fichtner 	if (kring->nr_hwavail == 0 && netmap_verbose) {
1660fb578518SFranco Fichtner 		D("how strange, interrupt with no packets on %s",
1661fb578518SFranco Fichtner 			NM_IFPNAME(ifp));
1662fb578518SFranco Fichtner 		goto put_out;
1663fb578518SFranco Fichtner 	}
1664fb578518SFranco Fichtner 	/* XXX avail ? */
1665fb578518SFranco Fichtner 	ring->cur = nm_kr_rxpos(kring);
1666fb578518SFranco Fichtner 	netmap_vp_txsync(vpna, ring_nr, flags);
1667fb578518SFranco Fichtner 
1668fb578518SFranco Fichtner 	if (!is_host_ring)
1669fb578518SFranco Fichtner 		error = na->nm_rxsync(na, ring_nr, 0);
1670fb578518SFranco Fichtner 
1671fb578518SFranco Fichtner put_out:
1672fb578518SFranco Fichtner 	nm_kr_put(kring);
1673fb578518SFranco Fichtner 	return error;
1674fb578518SFranco Fichtner }
1675fb578518SFranco Fichtner 
1676fb578518SFranco Fichtner static int
netmap_bwrap_register(struct netmap_adapter * na,int onoff)1677fb578518SFranco Fichtner netmap_bwrap_register(struct netmap_adapter *na, int onoff)
1678fb578518SFranco Fichtner {
1679fb578518SFranco Fichtner 	struct netmap_bwrap_adapter *bna =
1680fb578518SFranco Fichtner 		(struct netmap_bwrap_adapter *)na;
1681fb578518SFranco Fichtner 	struct netmap_adapter *hwna = bna->hwna;
1682fb578518SFranco Fichtner 	struct netmap_vp_adapter *hostna = &bna->host;
1683fb578518SFranco Fichtner 	int error;
1684fb578518SFranco Fichtner 
1685fb578518SFranco Fichtner 	ND("%s %d", NM_IFPNAME(ifp), onoff);
1686fb578518SFranco Fichtner 
1687fb578518SFranco Fichtner 	if (onoff) {
1688fb578518SFranco Fichtner 		int i;
1689fb578518SFranco Fichtner 
1690fb578518SFranco Fichtner 		hwna->na_lut = na->na_lut;
1691fb578518SFranco Fichtner 		hwna->na_lut_objtotal = na->na_lut_objtotal;
1692fb578518SFranco Fichtner 
1693fb578518SFranco Fichtner 		if (hostna->na_bdg) {
1694fb578518SFranco Fichtner 			hostna->up.na_lut = na->na_lut;
1695fb578518SFranco Fichtner 			hostna->up.na_lut_objtotal = na->na_lut_objtotal;
1696fb578518SFranco Fichtner 		}
1697fb578518SFranco Fichtner 
1698fb578518SFranco Fichtner 		/* cross-link the netmap rings */
1699fb578518SFranco Fichtner 		for (i = 0; i <= na->num_tx_rings; i++) {
1700fb578518SFranco Fichtner 			hwna->tx_rings[i].nkr_num_slots = na->rx_rings[i].nkr_num_slots;
1701fb578518SFranco Fichtner 			hwna->tx_rings[i].ring = na->rx_rings[i].ring;
1702fb578518SFranco Fichtner 		}
1703fb578518SFranco Fichtner 		for (i = 0; i <= na->num_rx_rings; i++) {
1704fb578518SFranco Fichtner 			hwna->rx_rings[i].nkr_num_slots = na->tx_rings[i].nkr_num_slots;
1705fb578518SFranco Fichtner 			hwna->rx_rings[i].ring = na->tx_rings[i].ring;
1706fb578518SFranco Fichtner 		}
1707fb578518SFranco Fichtner 	}
1708fb578518SFranco Fichtner 
1709fb578518SFranco Fichtner 	if (hwna->ifp) {
1710fb578518SFranco Fichtner 		error = hwna->nm_register(hwna, onoff);
1711fb578518SFranco Fichtner 		if (error)
1712fb578518SFranco Fichtner 			return error;
1713fb578518SFranco Fichtner 	}
1714fb578518SFranco Fichtner 
1715fb578518SFranco Fichtner 	bdg_netmap_reg(na, onoff);
1716fb578518SFranco Fichtner 
1717fb578518SFranco Fichtner 	if (onoff) {
1718fb578518SFranco Fichtner 		bna->save_notify = hwna->nm_notify;
1719fb578518SFranco Fichtner 		hwna->nm_notify = netmap_bwrap_intr_notify;
1720fb578518SFranco Fichtner 	} else {
1721fb578518SFranco Fichtner 		hwna->nm_notify = bna->save_notify;
1722fb578518SFranco Fichtner 		hwna->na_lut = NULL;
1723fb578518SFranco Fichtner 		hwna->na_lut_objtotal = 0;
1724fb578518SFranco Fichtner 	}
1725fb578518SFranco Fichtner 
1726fb578518SFranco Fichtner 	return 0;
1727fb578518SFranco Fichtner }
1728fb578518SFranco Fichtner 
1729fb578518SFranco Fichtner static int
netmap_bwrap_config(struct netmap_adapter * na,u_int * txr,u_int * txd,u_int * rxr,u_int * rxd)1730fb578518SFranco Fichtner netmap_bwrap_config(struct netmap_adapter *na, u_int *txr, u_int *txd,
1731fb578518SFranco Fichtner 				    u_int *rxr, u_int *rxd)
1732fb578518SFranco Fichtner {
1733fb578518SFranco Fichtner 	struct netmap_bwrap_adapter *bna =
1734fb578518SFranco Fichtner 		(struct netmap_bwrap_adapter *)na;
1735fb578518SFranco Fichtner 	struct netmap_adapter *hwna = bna->hwna;
1736fb578518SFranco Fichtner 
1737fb578518SFranco Fichtner 	/* forward the request */
1738fb578518SFranco Fichtner 	netmap_update_config(hwna);
1739fb578518SFranco Fichtner 	/* swap the results */
1740fb578518SFranco Fichtner 	*txr = hwna->num_rx_rings;
1741fb578518SFranco Fichtner 	*txd = hwna->num_rx_desc;
1742fb578518SFranco Fichtner 	*rxr = hwna->num_tx_rings;
1743fb578518SFranco Fichtner 	*rxd = hwna->num_rx_desc;
1744fb578518SFranco Fichtner 
1745fb578518SFranco Fichtner 	return 0;
1746fb578518SFranco Fichtner }
1747fb578518SFranco Fichtner 
1748fb578518SFranco Fichtner static int
netmap_bwrap_krings_create(struct netmap_adapter * na)1749fb578518SFranco Fichtner netmap_bwrap_krings_create(struct netmap_adapter *na)
1750fb578518SFranco Fichtner {
1751fb578518SFranco Fichtner 	struct netmap_bwrap_adapter *bna =
1752fb578518SFranco Fichtner 		(struct netmap_bwrap_adapter *)na;
1753fb578518SFranco Fichtner 	struct netmap_adapter *hwna = bna->hwna;
1754fb578518SFranco Fichtner 	struct netmap_adapter *hostna = &bna->host.up;
1755fb578518SFranco Fichtner 	int error;
1756fb578518SFranco Fichtner 
1757fb578518SFranco Fichtner 	ND("%s", NM_IFPNAME(na->ifp));
1758fb578518SFranco Fichtner 
1759fb578518SFranco Fichtner 	error = netmap_vp_krings_create(na);
1760fb578518SFranco Fichtner 	if (error)
1761fb578518SFranco Fichtner 		return error;
1762fb578518SFranco Fichtner 
1763fb578518SFranco Fichtner 	error = hwna->nm_krings_create(hwna);
1764fb578518SFranco Fichtner 	if (error) {
1765fb578518SFranco Fichtner 		netmap_vp_krings_delete(na);
1766fb578518SFranco Fichtner 		return error;
1767fb578518SFranco Fichtner 	}
1768fb578518SFranco Fichtner 
1769fb578518SFranco Fichtner 	hostna->tx_rings = na->tx_rings + na->num_tx_rings;
1770fb578518SFranco Fichtner 	hostna->rx_rings = na->rx_rings + na->num_rx_rings;
1771fb578518SFranco Fichtner 
1772fb578518SFranco Fichtner 	return 0;
1773fb578518SFranco Fichtner }
1774fb578518SFranco Fichtner 
1775fb578518SFranco Fichtner static void
netmap_bwrap_krings_delete(struct netmap_adapter * na)1776fb578518SFranco Fichtner netmap_bwrap_krings_delete(struct netmap_adapter *na)
1777fb578518SFranco Fichtner {
1778fb578518SFranco Fichtner 	struct netmap_bwrap_adapter *bna =
1779fb578518SFranco Fichtner 		(struct netmap_bwrap_adapter *)na;
1780fb578518SFranco Fichtner 	struct netmap_adapter *hwna = bna->hwna;
1781fb578518SFranco Fichtner 
1782fb578518SFranco Fichtner 	ND("%s", NM_IFPNAME(na->ifp));
1783fb578518SFranco Fichtner 
1784fb578518SFranco Fichtner 	hwna->nm_krings_delete(hwna);
1785fb578518SFranco Fichtner 	netmap_vp_krings_delete(na);
1786fb578518SFranco Fichtner }
1787fb578518SFranco Fichtner 
1788fb578518SFranco Fichtner /* notify method for the bridge-->hwna direction */
1789fb578518SFranco Fichtner static int
netmap_bwrap_notify(struct netmap_adapter * na,u_int ring_n,enum txrx tx,int flags)1790fb578518SFranco Fichtner netmap_bwrap_notify(struct netmap_adapter *na, u_int ring_n, enum txrx tx, int flags)
1791fb578518SFranco Fichtner {
1792fb578518SFranco Fichtner 	struct netmap_bwrap_adapter *bna =
1793fb578518SFranco Fichtner 		(struct netmap_bwrap_adapter *)na;
1794fb578518SFranco Fichtner 	struct netmap_adapter *hwna = bna->hwna;
1795fb578518SFranco Fichtner 	struct netmap_kring *kring, *hw_kring;
1796fb578518SFranco Fichtner 	struct netmap_ring *ring;
1797fb578518SFranco Fichtner 	u_int lim, k;
1798fb578518SFranco Fichtner 	int error = 0;
1799fb578518SFranco Fichtner 
1800fb578518SFranco Fichtner 	if (tx == NR_TX)
1801fb578518SFranco Fichtner 	        return ENXIO;
1802fb578518SFranco Fichtner 
1803fb578518SFranco Fichtner 	kring = &na->rx_rings[ring_n];
1804fb578518SFranco Fichtner 	hw_kring = &hwna->tx_rings[ring_n];
1805fb578518SFranco Fichtner 	ring = kring->ring;
1806fb578518SFranco Fichtner 
1807fb578518SFranco Fichtner 	lim = kring->nkr_num_slots - 1;
1808fb578518SFranco Fichtner 	k = nm_kr_rxpos(kring);
1809fb578518SFranco Fichtner 
1810fb578518SFranco Fichtner 	if (hwna->ifp == NULL || !(hwna->ifp->if_capenable & IFCAP_NETMAP))
1811fb578518SFranco Fichtner 		return 0;
1812fb578518SFranco Fichtner 	ring->cur = k;
1813fb578518SFranco Fichtner 	ND("%s[%d] PRE rx(%d, %d, %d, %d) ring(%d, %d, %d) tx(%d, %d)",
1814fb578518SFranco Fichtner 		NM_IFPNAME(na->ifp), ring_n,
1815fb578518SFranco Fichtner 		kring->nr_hwcur, kring->nr_hwavail, kring->nkr_hwlease, kring->nr_hwreserved,
1816fb578518SFranco Fichtner 		ring->cur, ring->avail, ring->reserved,
1817fb578518SFranco Fichtner 		hw_kring->nr_hwcur, hw_kring->nr_hwavail);
1818fb578518SFranco Fichtner 	if (ring_n == na->num_rx_rings) {
1819fb578518SFranco Fichtner 		netmap_txsync_to_host(hwna);
1820fb578518SFranco Fichtner 	} else {
1821fb578518SFranco Fichtner 		error = hwna->nm_txsync(hwna, ring_n, flags);
1822fb578518SFranco Fichtner 	}
1823fb578518SFranco Fichtner 	kring->nr_hwcur = ring->cur;
1824fb578518SFranco Fichtner 	kring->nr_hwavail = 0;
1825fb578518SFranco Fichtner 	kring->nr_hwreserved = lim - ring->avail;
1826fb578518SFranco Fichtner 	ND("%s[%d] PST rx(%d, %d, %d, %d) ring(%d, %d, %d) tx(%d, %d)",
1827fb578518SFranco Fichtner 		NM_IFPNAME(na->ifp), ring_n,
1828fb578518SFranco Fichtner 		kring->nr_hwcur, kring->nr_hwavail, kring->nkr_hwlease, kring->nr_hwreserved,
1829fb578518SFranco Fichtner 		ring->cur, ring->avail, ring->reserved,
1830fb578518SFranco Fichtner 		hw_kring->nr_hwcur, hw_kring->nr_hwavail);
1831fb578518SFranco Fichtner 
1832fb578518SFranco Fichtner 	return error;
1833fb578518SFranco Fichtner }
1834fb578518SFranco Fichtner 
1835fb578518SFranco Fichtner static int
netmap_bwrap_host_notify(struct netmap_adapter * na,u_int ring_n,enum txrx tx,int flags)1836fb578518SFranco Fichtner netmap_bwrap_host_notify(struct netmap_adapter *na, u_int ring_n, enum txrx tx, int flags)
1837fb578518SFranco Fichtner {
1838fb578518SFranco Fichtner 	struct netmap_bwrap_adapter *bna = na->na_private;
1839fb578518SFranco Fichtner 	struct netmap_adapter *port_na = &bna->up.up;
1840fb578518SFranco Fichtner 	if (tx == NR_TX || ring_n != 0)
1841fb578518SFranco Fichtner 		return ENXIO;
1842fb578518SFranco Fichtner 	return netmap_bwrap_notify(port_na, port_na->num_rx_rings, NR_RX, flags);
1843fb578518SFranco Fichtner }
1844fb578518SFranco Fichtner 
1845fb578518SFranco Fichtner /* attach a bridge wrapper to the 'real' device */
1846fb578518SFranco Fichtner static int
netmap_bwrap_attach(struct ifnet * fake,struct ifnet * real)1847fb578518SFranco Fichtner netmap_bwrap_attach(struct ifnet *fake, struct ifnet *real)
1848fb578518SFranco Fichtner {
1849fb578518SFranco Fichtner 	struct netmap_bwrap_adapter *bna;
1850fb578518SFranco Fichtner 	struct netmap_adapter *na;
1851fb578518SFranco Fichtner 	struct netmap_adapter *hwna = NA(real);
1852fb578518SFranco Fichtner 	struct netmap_adapter *hostna;
1853fb578518SFranco Fichtner 	int error;
1854fb578518SFranco Fichtner 
1855fb578518SFranco Fichtner 
1856ed9bd855SFranco Fichtner 	bna = kmalloc(sizeof(*bna), M_DEVBUF, M_NOWAIT | M_ZERO);
1857fb578518SFranco Fichtner 	if (bna == NULL)
1858fb578518SFranco Fichtner 		return ENOMEM;
1859fb578518SFranco Fichtner 
1860fb578518SFranco Fichtner 	na = &bna->up.up;
1861fb578518SFranco Fichtner 	na->ifp = fake;
1862fb578518SFranco Fichtner 	/* fill the ring data for the bwrap adapter with rx/tx meanings
1863fb578518SFranco Fichtner 	 * swapped. The real cross-linking will be done during register,
1864fb578518SFranco Fichtner 	 * when all the krings will have been created.
1865fb578518SFranco Fichtner 	 */
1866fb578518SFranco Fichtner 	na->num_rx_rings = hwna->num_tx_rings;
1867fb578518SFranco Fichtner 	na->num_tx_rings = hwna->num_rx_rings;
1868fb578518SFranco Fichtner 	na->num_tx_desc = hwna->num_rx_desc;
1869fb578518SFranco Fichtner 	na->num_rx_desc = hwna->num_tx_desc;
1870fb578518SFranco Fichtner 	na->nm_dtor = netmap_bwrap_dtor;
1871fb578518SFranco Fichtner 	na->nm_register = netmap_bwrap_register;
1872fb578518SFranco Fichtner 	// na->nm_txsync = netmap_bwrap_txsync;
1873fb578518SFranco Fichtner 	// na->nm_rxsync = netmap_bwrap_rxsync;
1874fb578518SFranco Fichtner 	na->nm_config = netmap_bwrap_config;
1875fb578518SFranco Fichtner 	na->nm_krings_create = netmap_bwrap_krings_create;
1876fb578518SFranco Fichtner 	na->nm_krings_delete = netmap_bwrap_krings_delete;
1877fb578518SFranco Fichtner 	na->nm_notify = netmap_bwrap_notify;
1878fb578518SFranco Fichtner 	na->nm_mem = hwna->nm_mem;
1879fb578518SFranco Fichtner 	na->na_private = na; /* prevent NIOCREGIF */
1880fb578518SFranco Fichtner 	bna->up.retry = 1; /* XXX maybe this should depend on the hwna */
1881fb578518SFranco Fichtner 
1882fb578518SFranco Fichtner 	bna->hwna = hwna;
1883fb578518SFranco Fichtner 	netmap_adapter_get(hwna);
1884fb578518SFranco Fichtner 	hwna->na_private = bna; /* weak reference */
1885fb578518SFranco Fichtner 
1886fb578518SFranco Fichtner 	hostna = &bna->host.up;
1887fb578518SFranco Fichtner 	hostna->ifp = hwna->ifp;
1888fb578518SFranco Fichtner 	hostna->num_tx_rings = 1;
1889fb578518SFranco Fichtner 	hostna->num_tx_desc = hwna->num_rx_desc;
1890fb578518SFranco Fichtner 	hostna->num_rx_rings = 1;
1891fb578518SFranco Fichtner 	hostna->num_rx_desc = hwna->num_tx_desc;
1892fb578518SFranco Fichtner 	// hostna->nm_txsync = netmap_bwrap_host_txsync;
1893fb578518SFranco Fichtner 	// hostna->nm_rxsync = netmap_bwrap_host_rxsync;
1894fb578518SFranco Fichtner 	hostna->nm_notify = netmap_bwrap_host_notify;
1895fb578518SFranco Fichtner 	hostna->nm_mem = na->nm_mem;
1896fb578518SFranco Fichtner 	hostna->na_private = bna;
1897fb578518SFranco Fichtner 
1898fb578518SFranco Fichtner 	D("%s<->%s txr %d txd %d rxr %d rxd %d", fake->if_xname, real->if_xname,
1899fb578518SFranco Fichtner 		na->num_tx_rings, na->num_tx_desc,
1900fb578518SFranco Fichtner 		na->num_rx_rings, na->num_rx_desc);
1901fb578518SFranco Fichtner 
1902fb578518SFranco Fichtner 	error = netmap_attach_common(na);
1903fb578518SFranco Fichtner 	if (error) {
1904fb578518SFranco Fichtner 		netmap_adapter_put(hwna);
1905ed9bd855SFranco Fichtner 		kfree(bna, M_DEVBUF);
1906fb578518SFranco Fichtner 		return error;
1907fb578518SFranco Fichtner 	}
1908fb578518SFranco Fichtner 	return 0;
1909fb578518SFranco Fichtner }
1910fb578518SFranco Fichtner 
1911fb578518SFranco Fichtner void
netmap_init_bridges(void)1912fb578518SFranco Fichtner netmap_init_bridges(void)
1913fb578518SFranco Fichtner {
1914fb578518SFranco Fichtner 	int i;
1915fb578518SFranco Fichtner 	bzero(nm_bridges, sizeof(struct nm_bridge) * NM_BRIDGES); /* safety */
1916fb578518SFranco Fichtner 	for (i = 0; i < NM_BRIDGES; i++)
1917fb578518SFranco Fichtner 		BDG_RWINIT(&nm_bridges[i]);
1918fb578518SFranco Fichtner }
1919fb578518SFranco Fichtner #endif /* WITH_VALE */
1920