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