xref: /freebsd/sys/dev/netmap/netmap_freebsd.c (revision 4436b51dff5736e74da464946049ea6899a88938)
1 /*
2  * Copyright (C) 2013-2014 Universita` di Pisa. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *   1. Redistributions of source code must retain the above copyright
8  *      notice, this list of conditions and the following disclaimer.
9  *   2. Redistributions in binary form must reproduce the above copyright
10  *      notice, this list of conditions and the following disclaimer in the
11  *      documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25 
26 /* $FreeBSD$ */
27 #include "opt_inet.h"
28 #include "opt_inet6.h"
29 
30 #include <sys/types.h>
31 #include <sys/module.h>
32 #include <sys/errno.h>
33 #include <sys/param.h>  /* defines used in kernel.h */
34 #include <sys/poll.h>  /* POLLIN, POLLOUT */
35 #include <sys/kernel.h> /* types used in module initialization */
36 #include <sys/conf.h>	/* DEV_MODULE */
37 #include <sys/endian.h>
38 
39 #include <sys/rwlock.h>
40 
41 #include <vm/vm.h>      /* vtophys */
42 #include <vm/pmap.h>    /* vtophys */
43 #include <vm/vm_param.h>
44 #include <vm/vm_object.h>
45 #include <vm/vm_page.h>
46 #include <vm/vm_pager.h>
47 #include <vm/uma.h>
48 
49 
50 #include <sys/malloc.h>
51 #include <sys/socket.h> /* sockaddrs */
52 #include <sys/selinfo.h>
53 #include <net/if.h>
54 #include <net/if_var.h>
55 #include <net/if_types.h> /* IFT_ETHER */
56 #include <net/ethernet.h> /* ether_ifdetach */
57 #include <net/if_dl.h> /* LLADDR */
58 #include <machine/bus.h>        /* bus_dmamap_* */
59 #include <netinet/in.h>		/* in6_cksum_pseudo() */
60 #include <machine/in_cksum.h>  /* in_pseudo(), in_cksum_hdr() */
61 
62 #include <net/netmap.h>
63 #include <dev/netmap/netmap_kern.h>
64 #include <dev/netmap/netmap_mem2.h>
65 
66 
67 /* ======================== FREEBSD-SPECIFIC ROUTINES ================== */
68 
69 rawsum_t
70 nm_csum_raw(uint8_t *data, size_t len, rawsum_t cur_sum)
71 {
72 	/* TODO XXX please use the FreeBSD implementation for this. */
73 	uint16_t *words = (uint16_t *)data;
74 	int nw = len / 2;
75 	int i;
76 
77 	for (i = 0; i < nw; i++)
78 		cur_sum += be16toh(words[i]);
79 
80 	if (len & 1)
81 		cur_sum += (data[len-1] << 8);
82 
83 	return cur_sum;
84 }
85 
86 /* Fold a raw checksum: 'cur_sum' is in host byte order, while the
87  * return value is in network byte order.
88  */
89 uint16_t
90 nm_csum_fold(rawsum_t cur_sum)
91 {
92 	/* TODO XXX please use the FreeBSD implementation for this. */
93 	while (cur_sum >> 16)
94 		cur_sum = (cur_sum & 0xFFFF) + (cur_sum >> 16);
95 
96 	return htobe16((~cur_sum) & 0xFFFF);
97 }
98 
99 uint16_t nm_csum_ipv4(struct nm_iphdr *iph)
100 {
101 #if 0
102 	return in_cksum_hdr((void *)iph);
103 #else
104 	return nm_csum_fold(nm_csum_raw((uint8_t*)iph, sizeof(struct nm_iphdr), 0));
105 #endif
106 }
107 
108 void
109 nm_csum_tcpudp_ipv4(struct nm_iphdr *iph, void *data,
110 					size_t datalen, uint16_t *check)
111 {
112 #ifdef INET
113 	uint16_t pseudolen = datalen + iph->protocol;
114 
115 	/* Compute and insert the pseudo-header cheksum. */
116 	*check = in_pseudo(iph->saddr, iph->daddr,
117 				 htobe16(pseudolen));
118 	/* Compute the checksum on TCP/UDP header + payload
119 	 * (includes the pseudo-header).
120 	 */
121 	*check = nm_csum_fold(nm_csum_raw(data, datalen, 0));
122 #else
123 	static int notsupported = 0;
124 	if (!notsupported) {
125 		notsupported = 1;
126 		D("inet4 segmentation not supported");
127 	}
128 #endif
129 }
130 
131 void
132 nm_csum_tcpudp_ipv6(struct nm_ipv6hdr *ip6h, void *data,
133 					size_t datalen, uint16_t *check)
134 {
135 #ifdef INET6
136 	*check = in6_cksum_pseudo((void*)ip6h, datalen, ip6h->nexthdr, 0);
137 	*check = nm_csum_fold(nm_csum_raw(data, datalen, 0));
138 #else
139 	static int notsupported = 0;
140 	if (!notsupported) {
141 		notsupported = 1;
142 		D("inet6 segmentation not supported");
143 	}
144 #endif
145 }
146 
147 
148 /*
149  * Intercept the rx routine in the standard device driver.
150  * Second argument is non-zero to intercept, 0 to restore
151  */
152 int
153 netmap_catch_rx(struct netmap_generic_adapter *gna, int intercept)
154 {
155 	struct netmap_adapter *na = &gna->up.up;
156 	struct ifnet *ifp = na->ifp;
157 
158 	if (intercept) {
159 		if (gna->save_if_input) {
160 			D("cannot intercept again");
161 			return EINVAL; /* already set */
162 		}
163 		gna->save_if_input = ifp->if_input;
164 		ifp->if_input = generic_rx_handler;
165 	} else {
166 		if (!gna->save_if_input){
167 			D("cannot restore");
168 			return EINVAL;  /* not saved */
169 		}
170 		ifp->if_input = gna->save_if_input;
171 		gna->save_if_input = NULL;
172 	}
173 
174 	return 0;
175 }
176 
177 
178 /*
179  * Intercept the packet steering routine in the tx path,
180  * so that we can decide which queue is used for an mbuf.
181  * Second argument is non-zero to intercept, 0 to restore.
182  * On freebsd we just intercept if_transmit.
183  */
184 void
185 netmap_catch_tx(struct netmap_generic_adapter *gna, int enable)
186 {
187 	struct netmap_adapter *na = &gna->up.up;
188 	struct ifnet *ifp = netmap_generic_getifp(gna);
189 
190 	if (enable) {
191 		na->if_transmit = ifp->if_transmit;
192 		ifp->if_transmit = netmap_transmit;
193 	} else {
194 		ifp->if_transmit = na->if_transmit;
195 	}
196 }
197 
198 
199 /*
200  * Transmit routine used by generic_netmap_txsync(). Returns 0 on success
201  * and non-zero on error (which may be packet drops or other errors).
202  * addr and len identify the netmap buffer, m is the (preallocated)
203  * mbuf to use for transmissions.
204  *
205  * We should add a reference to the mbuf so the m_freem() at the end
206  * of the transmission does not consume resources.
207  *
208  * On FreeBSD, and on multiqueue cards, we can force the queue using
209  *      if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
210  *              i = m->m_pkthdr.flowid % adapter->num_queues;
211  *      else
212  *              i = curcpu % adapter->num_queues;
213  *
214  */
215 int
216 generic_xmit_frame(struct ifnet *ifp, struct mbuf *m,
217 	void *addr, u_int len, u_int ring_nr)
218 {
219 	int ret;
220 
221 	/*
222 	 * The mbuf should be a cluster from our special pool,
223 	 * so we do not need to do an m_copyback but just copy
224 	 * (and eventually, just reference the netmap buffer)
225 	 */
226 
227 	if (GET_MBUF_REFCNT(m) != 1) {
228 		D("invalid refcnt %d for %p",
229 			GET_MBUF_REFCNT(m), m);
230 		panic("in generic_xmit_frame");
231 	}
232 	// XXX the ext_size check is unnecessary if we link the netmap buf
233 	if (m->m_ext.ext_size < len) {
234 		RD(5, "size %d < len %d", m->m_ext.ext_size, len);
235 		len = m->m_ext.ext_size;
236 	}
237 	if (0) { /* XXX seems to have negligible benefits */
238 		m->m_ext.ext_buf = m->m_data = addr;
239 	} else {
240 		bcopy(addr, m->m_data, len);
241 	}
242 	m->m_len = m->m_pkthdr.len = len;
243 	// inc refcount. All ours, we could skip the atomic
244 	atomic_fetchadd_int(PNT_MBUF_REFCNT(m), 1);
245 	M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
246 	m->m_pkthdr.flowid = ring_nr;
247 	m->m_pkthdr.rcvif = ifp; /* used for tx notification */
248 	ret = NA(ifp)->if_transmit(ifp, m);
249 	return ret;
250 }
251 
252 
253 #if __FreeBSD_version >= 1100005
254 struct netmap_adapter *
255 netmap_getna(if_t ifp)
256 {
257 	return (NA((struct ifnet *)ifp));
258 }
259 #endif /* __FreeBSD_version >= 1100005 */
260 
261 /*
262  * The following two functions are empty until we have a generic
263  * way to extract the info from the ifp
264  */
265 int
266 generic_find_num_desc(struct ifnet *ifp, unsigned int *tx, unsigned int *rx)
267 {
268 	D("called, in tx %d rx %d", *tx, *rx);
269 	return 0;
270 }
271 
272 
273 void
274 generic_find_num_queues(struct ifnet *ifp, u_int *txq, u_int *rxq)
275 {
276 	D("called, in txq %d rxq %d", *txq, *rxq);
277 	*txq = netmap_generic_rings;
278 	*rxq = netmap_generic_rings;
279 }
280 
281 
282 void
283 netmap_mitigation_init(struct nm_generic_mit *mit, int idx, struct netmap_adapter *na)
284 {
285 	ND("called");
286 	mit->mit_pending = 0;
287 	mit->mit_ring_idx = idx;
288 	mit->mit_na = na;
289 }
290 
291 
292 void
293 netmap_mitigation_start(struct nm_generic_mit *mit)
294 {
295 	ND("called");
296 }
297 
298 
299 void
300 netmap_mitigation_restart(struct nm_generic_mit *mit)
301 {
302 	ND("called");
303 }
304 
305 
306 int
307 netmap_mitigation_active(struct nm_generic_mit *mit)
308 {
309 	ND("called");
310 	return 0;
311 }
312 
313 
314 void
315 netmap_mitigation_cleanup(struct nm_generic_mit *mit)
316 {
317 	ND("called");
318 }
319 
320 static int
321 nm_vi_dummy(struct ifnet *ifp, u_long cmd, caddr_t addr)
322 {
323 	return EINVAL;
324 }
325 
326 static void
327 nm_vi_start(struct ifnet *ifp)
328 {
329 	panic("nm_vi_start() must not be called");
330 }
331 
332 /*
333  * Index manager of persistent virtual interfaces.
334  * It is used to decide the lowest byte of the MAC address.
335  * We use the same algorithm with management of bridge port index.
336  */
337 #define NM_VI_MAX	255
338 static struct {
339 	uint8_t index[NM_VI_MAX]; /* XXX just for a reasonable number */
340 	uint8_t active;
341 	struct mtx lock;
342 } nm_vi_indices;
343 
344 void
345 nm_vi_init_index(void)
346 {
347 	int i;
348 	for (i = 0; i < NM_VI_MAX; i++)
349 		nm_vi_indices.index[i] = i;
350 	nm_vi_indices.active = 0;
351 	mtx_init(&nm_vi_indices.lock, "nm_vi_indices_lock", NULL, MTX_DEF);
352 }
353 
354 /* return -1 if no index available */
355 static int
356 nm_vi_get_index(void)
357 {
358 	int ret;
359 
360 	mtx_lock(&nm_vi_indices.lock);
361 	ret = nm_vi_indices.active == NM_VI_MAX ? -1 :
362 		nm_vi_indices.index[nm_vi_indices.active++];
363 	mtx_unlock(&nm_vi_indices.lock);
364 	return ret;
365 }
366 
367 static void
368 nm_vi_free_index(uint8_t val)
369 {
370 	int i, lim;
371 
372 	mtx_lock(&nm_vi_indices.lock);
373 	lim = nm_vi_indices.active;
374 	for (i = 0; i < lim; i++) {
375 		if (nm_vi_indices.index[i] == val) {
376 			/* swap index[lim-1] and j */
377 			int tmp = nm_vi_indices.index[lim-1];
378 			nm_vi_indices.index[lim-1] = val;
379 			nm_vi_indices.index[i] = tmp;
380 			nm_vi_indices.active--;
381 			break;
382 		}
383 	}
384 	if (lim == nm_vi_indices.active)
385 		D("funny, index %u didn't found", val);
386 	mtx_unlock(&nm_vi_indices.lock);
387 }
388 #undef NM_VI_MAX
389 
390 /*
391  * Implementation of a netmap-capable virtual interface that
392  * registered to the system.
393  * It is based on if_tap.c and ip_fw_log.c in FreeBSD 9.
394  *
395  * Note: Linux sets refcount to 0 on allocation of net_device,
396  * then increments it on registration to the system.
397  * FreeBSD sets refcount to 1 on if_alloc(), and does not
398  * increment this refcount on if_attach().
399  */
400 int
401 nm_vi_persist(const char *name, struct ifnet **ret)
402 {
403 	struct ifnet *ifp;
404 	u_short macaddr_hi;
405 	uint32_t macaddr_mid;
406 	u_char eaddr[6];
407 	int unit = nm_vi_get_index(); /* just to decide MAC address */
408 
409 	if (unit < 0)
410 		return EBUSY;
411 	/*
412 	 * We use the same MAC address generation method with tap
413 	 * except for the highest octet is 00:be instead of 00:bd
414 	 */
415 	macaddr_hi = htons(0x00be); /* XXX tap + 1 */
416 	macaddr_mid = (uint32_t) ticks;
417 	bcopy(&macaddr_hi, eaddr, sizeof(short));
418 	bcopy(&macaddr_mid, &eaddr[2], sizeof(uint32_t));
419 	eaddr[5] = (uint8_t)unit;
420 
421 	ifp = if_alloc(IFT_ETHER);
422 	if (ifp == NULL) {
423 		D("if_alloc failed");
424 		return ENOMEM;
425 	}
426 	if_initname(ifp, name, IF_DUNIT_NONE);
427 	ifp->if_mtu = 65536;
428 	ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST;
429 	ifp->if_init = (void *)nm_vi_dummy;
430 	ifp->if_ioctl = nm_vi_dummy;
431 	ifp->if_start = nm_vi_start;
432 	ifp->if_mtu = ETHERMTU;
433 	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
434 	ifp->if_capabilities |= IFCAP_LINKSTATE;
435 	ifp->if_capenable |= IFCAP_LINKSTATE;
436 
437 	ether_ifattach(ifp, eaddr);
438 	*ret = ifp;
439 	return 0;
440 }
441 /* unregister from the system and drop the final refcount */
442 void
443 nm_vi_detach(struct ifnet *ifp)
444 {
445 	nm_vi_free_index(((char *)IF_LLADDR(ifp))[5]);
446 	ether_ifdetach(ifp);
447 	if_free(ifp);
448 }
449 
450 /*
451  * In order to track whether pages are still mapped, we hook into
452  * the standard cdev_pager and intercept the constructor and
453  * destructor.
454  */
455 
456 struct netmap_vm_handle_t {
457 	struct cdev 		*dev;
458 	struct netmap_priv_d	*priv;
459 };
460 
461 
462 static int
463 netmap_dev_pager_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot,
464     vm_ooffset_t foff, struct ucred *cred, u_short *color)
465 {
466 	struct netmap_vm_handle_t *vmh = handle;
467 
468 	if (netmap_verbose)
469 		D("handle %p size %jd prot %d foff %jd",
470 			handle, (intmax_t)size, prot, (intmax_t)foff);
471 	if (color)
472 		*color = 0;
473 	dev_ref(vmh->dev);
474 	return 0;
475 }
476 
477 
478 static void
479 netmap_dev_pager_dtor(void *handle)
480 {
481 	struct netmap_vm_handle_t *vmh = handle;
482 	struct cdev *dev = vmh->dev;
483 	struct netmap_priv_d *priv = vmh->priv;
484 
485 	if (netmap_verbose)
486 		D("handle %p", handle);
487 	netmap_dtor(priv);
488 	free(vmh, M_DEVBUF);
489 	dev_rel(dev);
490 }
491 
492 
493 static int
494 netmap_dev_pager_fault(vm_object_t object, vm_ooffset_t offset,
495 	int prot, vm_page_t *mres)
496 {
497 	struct netmap_vm_handle_t *vmh = object->handle;
498 	struct netmap_priv_d *priv = vmh->priv;
499 	struct netmap_adapter *na = priv->np_na;
500 	vm_paddr_t paddr;
501 	vm_page_t page;
502 	vm_memattr_t memattr;
503 	vm_pindex_t pidx;
504 
505 	ND("object %p offset %jd prot %d mres %p",
506 			object, (intmax_t)offset, prot, mres);
507 	memattr = object->memattr;
508 	pidx = OFF_TO_IDX(offset);
509 	paddr = netmap_mem_ofstophys(na->nm_mem, offset);
510 	if (paddr == 0)
511 		return VM_PAGER_FAIL;
512 
513 	if (((*mres)->flags & PG_FICTITIOUS) != 0) {
514 		/*
515 		 * If the passed in result page is a fake page, update it with
516 		 * the new physical address.
517 		 */
518 		page = *mres;
519 		vm_page_updatefake(page, paddr, memattr);
520 	} else {
521 		/*
522 		 * Replace the passed in reqpage page with our own fake page and
523 		 * free up the all of the original pages.
524 		 */
525 #ifndef VM_OBJECT_WUNLOCK	/* FreeBSD < 10.x */
526 #define VM_OBJECT_WUNLOCK VM_OBJECT_UNLOCK
527 #define VM_OBJECT_WLOCK	VM_OBJECT_LOCK
528 #endif /* VM_OBJECT_WUNLOCK */
529 
530 		VM_OBJECT_WUNLOCK(object);
531 		page = vm_page_getfake(paddr, memattr);
532 		VM_OBJECT_WLOCK(object);
533 		vm_page_lock(*mres);
534 		vm_page_free(*mres);
535 		vm_page_unlock(*mres);
536 		*mres = page;
537 		vm_page_insert(page, object, pidx);
538 	}
539 	page->valid = VM_PAGE_BITS_ALL;
540 	return (VM_PAGER_OK);
541 }
542 
543 
544 static struct cdev_pager_ops netmap_cdev_pager_ops = {
545 	.cdev_pg_ctor = netmap_dev_pager_ctor,
546 	.cdev_pg_dtor = netmap_dev_pager_dtor,
547 	.cdev_pg_fault = netmap_dev_pager_fault,
548 };
549 
550 
551 static int
552 netmap_mmap_single(struct cdev *cdev, vm_ooffset_t *foff,
553 	vm_size_t objsize,  vm_object_t *objp, int prot)
554 {
555 	int error;
556 	struct netmap_vm_handle_t *vmh;
557 	struct netmap_priv_d *priv;
558 	vm_object_t obj;
559 
560 	if (netmap_verbose)
561 		D("cdev %p foff %jd size %jd objp %p prot %d", cdev,
562 		    (intmax_t )*foff, (intmax_t )objsize, objp, prot);
563 
564 	vmh = malloc(sizeof(struct netmap_vm_handle_t), M_DEVBUF,
565 			      M_NOWAIT | M_ZERO);
566 	if (vmh == NULL)
567 		return ENOMEM;
568 	vmh->dev = cdev;
569 
570 	NMG_LOCK();
571 	error = devfs_get_cdevpriv((void**)&priv);
572 	if (error)
573 		goto err_unlock;
574 	if (priv->np_nifp == NULL) {
575 		error = EINVAL;
576 		goto err_unlock;
577 	}
578 	vmh->priv = priv;
579 	priv->np_refs++;
580 	NMG_UNLOCK();
581 
582 	obj = cdev_pager_allocate(vmh, OBJT_DEVICE,
583 		&netmap_cdev_pager_ops, objsize, prot,
584 		*foff, NULL);
585 	if (obj == NULL) {
586 		D("cdev_pager_allocate failed");
587 		error = EINVAL;
588 		goto err_deref;
589 	}
590 
591 	*objp = obj;
592 	return 0;
593 
594 err_deref:
595 	NMG_LOCK();
596 	priv->np_refs--;
597 err_unlock:
598 	NMG_UNLOCK();
599 // err:
600 	free(vmh, M_DEVBUF);
601 	return error;
602 }
603 
604 /*
605  * On FreeBSD the close routine is only called on the last close on
606  * the device (/dev/netmap) so we cannot do anything useful.
607  * To track close() on individual file descriptors we pass netmap_dtor() to
608  * devfs_set_cdevpriv() on open(). The FreeBSD kernel will call the destructor
609  * when the last fd pointing to the device is closed.
610  *
611  * Note that FreeBSD does not even munmap() on close() so we also have
612  * to track mmap() ourselves, and postpone the call to
613  * netmap_dtor() is called when the process has no open fds and no active
614  * memory maps on /dev/netmap, as in linux.
615  */
616 static int
617 netmap_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
618 {
619 	if (netmap_verbose)
620 		D("dev %p fflag 0x%x devtype %d td %p",
621 			dev, fflag, devtype, td);
622 	return 0;
623 }
624 
625 
626 static int
627 netmap_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
628 {
629 	struct netmap_priv_d *priv;
630 	int error;
631 
632 	(void)dev;
633 	(void)oflags;
634 	(void)devtype;
635 	(void)td;
636 
637 	priv = malloc(sizeof(struct netmap_priv_d), M_DEVBUF,
638 			      M_NOWAIT | M_ZERO);
639 	if (priv == NULL)
640 		return ENOMEM;
641 	priv->np_refs = 1;
642 	error = devfs_set_cdevpriv(priv, netmap_dtor);
643 	if (error) {
644 		free(priv, M_DEVBUF);
645 	} else {
646 		NMG_LOCK();
647 		netmap_use_count++;
648 		NMG_UNLOCK();
649 	}
650 	return error;
651 }
652 
653 /******************** kqueue support ****************/
654 
655 /*
656  * The OS_selwakeup also needs to issue a KNOTE_UNLOCKED.
657  * We use a non-zero argument to distinguish the call from the one
658  * in kevent_scan() which instead also needs to run netmap_poll().
659  * The knote uses a global mutex for the time being. We might
660  * try to reuse the one in the si, but it is not allocated
661  * permanently so it might be a bit tricky.
662  *
663  * The *kqfilter function registers one or another f_event
664  * depending on read or write mode.
665  * In the call to f_event() td_fpop is NULL so any child function
666  * calling devfs_get_cdevpriv() would fail - and we need it in
667  * netmap_poll(). As a workaround we store priv into kn->kn_hook
668  * and pass it as first argument to netmap_poll(), which then
669  * uses the failure to tell that we are called from f_event()
670  * and do not need the selrecord().
671  */
672 
673 
674 void
675 freebsd_selwakeup(struct nm_selinfo *si, int pri)
676 {
677 	if (netmap_verbose)
678 		D("on knote %p", &si->si.si_note);
679 	selwakeuppri(&si->si, pri);
680 	/* use a non-zero hint to tell the notification from the
681 	 * call done in kqueue_scan() which uses 0
682 	 */
683 	KNOTE_UNLOCKED(&si->si.si_note, 0x100 /* notification */);
684 }
685 
686 static void
687 netmap_knrdetach(struct knote *kn)
688 {
689 	struct netmap_priv_d *priv = (struct netmap_priv_d *)kn->kn_hook;
690 	struct selinfo *si = &priv->np_si[NR_RX]->si;
691 
692 	D("remove selinfo %p", si);
693 	knlist_remove(&si->si_note, kn, 0);
694 }
695 
696 static void
697 netmap_knwdetach(struct knote *kn)
698 {
699 	struct netmap_priv_d *priv = (struct netmap_priv_d *)kn->kn_hook;
700 	struct selinfo *si = &priv->np_si[NR_TX]->si;
701 
702 	D("remove selinfo %p", si);
703 	knlist_remove(&si->si_note, kn, 0);
704 }
705 
706 /*
707  * callback from notifies (generated externally) and our
708  * calls to kevent(). The former we just return 1 (ready)
709  * since we do not know better.
710  * In the latter we call netmap_poll and return 0/1 accordingly.
711  */
712 static int
713 netmap_knrw(struct knote *kn, long hint, int events)
714 {
715 	struct netmap_priv_d *priv;
716 	int revents;
717 
718 	if (hint != 0) {
719 		ND(5, "call from notify");
720 		return 1; /* assume we are ready */
721 	}
722 	priv = kn->kn_hook;
723 	/* the notification may come from an external thread,
724 	 * in which case we do not want to run the netmap_poll
725 	 * This should be filtered above, but check just in case.
726 	 */
727 	if (curthread != priv->np_td) { /* should not happen */
728 		RD(5, "curthread changed %p %p", curthread, priv->np_td);
729 		return 1;
730 	} else {
731 		revents = netmap_poll((void *)priv, events, curthread);
732 		return (events & revents) ? 1 : 0;
733 	}
734 }
735 
736 static int
737 netmap_knread(struct knote *kn, long hint)
738 {
739 	return netmap_knrw(kn, hint, POLLIN);
740 }
741 
742 static int
743 netmap_knwrite(struct knote *kn, long hint)
744 {
745 	return netmap_knrw(kn, hint, POLLOUT);
746 }
747 
748 static struct filterops netmap_rfiltops = {
749 	.f_isfd = 1,
750 	.f_detach = netmap_knrdetach,
751 	.f_event = netmap_knread,
752 };
753 
754 static struct filterops netmap_wfiltops = {
755 	.f_isfd = 1,
756 	.f_detach = netmap_knwdetach,
757 	.f_event = netmap_knwrite,
758 };
759 
760 
761 /*
762  * This is called when a thread invokes kevent() to record
763  * a change in the configuration of the kqueue().
764  * The 'priv' should be the same as in the netmap device.
765  */
766 static int
767 netmap_kqfilter(struct cdev *dev, struct knote *kn)
768 {
769 	struct netmap_priv_d *priv;
770 	int error;
771 	struct netmap_adapter *na;
772 	struct nm_selinfo *si;
773 	int ev = kn->kn_filter;
774 
775 	if (ev != EVFILT_READ && ev != EVFILT_WRITE) {
776 		D("bad filter request %d", ev);
777 		return 1;
778 	}
779 	error = devfs_get_cdevpriv((void**)&priv);
780 	if (error) {
781 		D("device not yet setup");
782 		return 1;
783 	}
784 	na = priv->np_na;
785 	if (na == NULL) {
786 		D("no netmap adapter for this file descriptor");
787 		return 1;
788 	}
789 	/* the si is indicated in the priv */
790 	si = priv->np_si[(ev == EVFILT_WRITE) ? NR_TX : NR_RX];
791 	// XXX lock(priv) ?
792 	kn->kn_fop = (ev == EVFILT_WRITE) ?
793 		&netmap_wfiltops : &netmap_rfiltops;
794 	kn->kn_hook = priv;
795 	knlist_add(&si->si.si_note, kn, 1);
796 	// XXX unlock(priv)
797 	ND("register %p %s td %p priv %p kn %p np_nifp %p kn_fp/fpop %s",
798 		na, na->ifp->if_xname, curthread, priv, kn,
799 		priv->np_nifp,
800 		kn->kn_fp == curthread->td_fpop ? "match" : "MISMATCH");
801 	return 0;
802 }
803 
804 struct cdevsw netmap_cdevsw = {
805 	.d_version = D_VERSION,
806 	.d_name = "netmap",
807 	.d_open = netmap_open,
808 	.d_mmap_single = netmap_mmap_single,
809 	.d_ioctl = netmap_ioctl,
810 	.d_poll = netmap_poll,
811 	.d_kqfilter = netmap_kqfilter,
812 	.d_close = netmap_close,
813 };
814 /*--- end of kqueue support ----*/
815 
816 /*
817  * Kernel entry point.
818  *
819  * Initialize/finalize the module and return.
820  *
821  * Return 0 on success, errno on failure.
822  */
823 static int
824 netmap_loader(__unused struct module *module, int event, __unused void *arg)
825 {
826 	int error = 0;
827 
828 	switch (event) {
829 	case MOD_LOAD:
830 		error = netmap_init();
831 		break;
832 
833 	case MOD_UNLOAD:
834 		/*
835 		 * if some one is still using netmap,
836 		 * then the module can not be unloaded.
837 		 */
838 		if (netmap_use_count) {
839 			D("netmap module can not be unloaded - netmap_use_count: %d",
840 					netmap_use_count);
841 			error = EBUSY;
842 			break;
843 		}
844 		netmap_fini();
845 		break;
846 
847 	default:
848 		error = EOPNOTSUPP;
849 		break;
850 	}
851 
852 	return (error);
853 }
854 
855 
856 DEV_MODULE(netmap, netmap_loader, NULL);
857 MODULE_VERSION(netmap, 1);
858