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