]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/netmap/netmap_freebsd.c
MFC r324075 (by imp): Tweak performance of nda completions
[FreeBSD/FreeBSD.git] / sys / dev / netmap / netmap_freebsd.c
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         /* Link the external storage to the netmap buffer, so that
222          * no copy is necessary. */
223         m->m_ext.ext_buf = m->m_data = addr;
224         m->m_ext.ext_size = len;
225
226         m->m_len = m->m_pkthdr.len = len;
227
228         /* mbuf refcnt is not contended, no need to use atomic
229          * (a memory barrier is enough). */
230         SET_MBUF_REFCNT(m, 2);
231         M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
232         m->m_pkthdr.flowid = ring_nr;
233         m->m_pkthdr.rcvif = ifp; /* used for tx notification */
234         ret = NA(ifp)->if_transmit(ifp, m);
235         return ret;
236 }
237
238
239 #if __FreeBSD_version >= 1100005
240 struct netmap_adapter *
241 netmap_getna(if_t ifp)
242 {
243         return (NA((struct ifnet *)ifp));
244 }
245 #endif /* __FreeBSD_version >= 1100005 */
246
247 /*
248  * The following two functions are empty until we have a generic
249  * way to extract the info from the ifp
250  */
251 int
252 generic_find_num_desc(struct ifnet *ifp, unsigned int *tx, unsigned int *rx)
253 {
254         D("called, in tx %d rx %d", *tx, *rx);
255         return 0;
256 }
257
258
259 void
260 generic_find_num_queues(struct ifnet *ifp, u_int *txq, u_int *rxq)
261 {
262         D("called, in txq %d rxq %d", *txq, *rxq);
263         *txq = netmap_generic_rings;
264         *rxq = netmap_generic_rings;
265 }
266
267
268 void
269 netmap_mitigation_init(struct nm_generic_mit *mit, int idx, struct netmap_adapter *na)
270 {
271         ND("called");
272         mit->mit_pending = 0;
273         mit->mit_ring_idx = idx;
274         mit->mit_na = na;
275 }
276
277
278 void
279 netmap_mitigation_start(struct nm_generic_mit *mit)
280 {
281         ND("called");
282 }
283
284
285 void
286 netmap_mitigation_restart(struct nm_generic_mit *mit)
287 {
288         ND("called");
289 }
290
291
292 int
293 netmap_mitigation_active(struct nm_generic_mit *mit)
294 {
295         ND("called");
296         return 0;
297 }
298
299
300 void
301 netmap_mitigation_cleanup(struct nm_generic_mit *mit)
302 {
303         ND("called");
304 }
305
306 static int
307 nm_vi_dummy(struct ifnet *ifp, u_long cmd, caddr_t addr)
308 {
309         return EINVAL;
310 }
311
312 static void
313 nm_vi_start(struct ifnet *ifp)
314 {
315         panic("nm_vi_start() must not be called");
316 }
317
318 /*
319  * Index manager of persistent virtual interfaces.
320  * It is used to decide the lowest byte of the MAC address.
321  * We use the same algorithm with management of bridge port index.
322  */
323 #define NM_VI_MAX       255
324 static struct {
325         uint8_t index[NM_VI_MAX]; /* XXX just for a reasonable number */
326         uint8_t active;
327         struct mtx lock;
328 } nm_vi_indices;
329
330 void
331 nm_vi_init_index(void)
332 {
333         int i;
334         for (i = 0; i < NM_VI_MAX; i++)
335                 nm_vi_indices.index[i] = i;
336         nm_vi_indices.active = 0;
337         mtx_init(&nm_vi_indices.lock, "nm_vi_indices_lock", NULL, MTX_DEF);
338 }
339
340 /* return -1 if no index available */
341 static int
342 nm_vi_get_index(void)
343 {
344         int ret;
345
346         mtx_lock(&nm_vi_indices.lock);
347         ret = nm_vi_indices.active == NM_VI_MAX ? -1 :
348                 nm_vi_indices.index[nm_vi_indices.active++];
349         mtx_unlock(&nm_vi_indices.lock);
350         return ret;
351 }
352
353 static void
354 nm_vi_free_index(uint8_t val)
355 {
356         int i, lim;
357
358         mtx_lock(&nm_vi_indices.lock);
359         lim = nm_vi_indices.active;
360         for (i = 0; i < lim; i++) {
361                 if (nm_vi_indices.index[i] == val) {
362                         /* swap index[lim-1] and j */
363                         int tmp = nm_vi_indices.index[lim-1];
364                         nm_vi_indices.index[lim-1] = val;
365                         nm_vi_indices.index[i] = tmp;
366                         nm_vi_indices.active--;
367                         break;
368                 }
369         }
370         if (lim == nm_vi_indices.active)
371                 D("funny, index %u didn't found", val);
372         mtx_unlock(&nm_vi_indices.lock);
373 }
374 #undef NM_VI_MAX
375
376 /*
377  * Implementation of a netmap-capable virtual interface that
378  * registered to the system.
379  * It is based on if_tap.c and ip_fw_log.c in FreeBSD 9.
380  *
381  * Note: Linux sets refcount to 0 on allocation of net_device,
382  * then increments it on registration to the system.
383  * FreeBSD sets refcount to 1 on if_alloc(), and does not
384  * increment this refcount on if_attach().
385  */
386 int
387 nm_vi_persist(const char *name, struct ifnet **ret)
388 {
389         struct ifnet *ifp;
390         u_short macaddr_hi;
391         uint32_t macaddr_mid;
392         u_char eaddr[6];
393         int unit = nm_vi_get_index(); /* just to decide MAC address */
394
395         if (unit < 0)
396                 return EBUSY;
397         /*
398          * We use the same MAC address generation method with tap
399          * except for the highest octet is 00:be instead of 00:bd
400          */
401         macaddr_hi = htons(0x00be); /* XXX tap + 1 */
402         macaddr_mid = (uint32_t) ticks;
403         bcopy(&macaddr_hi, eaddr, sizeof(short));
404         bcopy(&macaddr_mid, &eaddr[2], sizeof(uint32_t));
405         eaddr[5] = (uint8_t)unit;
406
407         ifp = if_alloc(IFT_ETHER);
408         if (ifp == NULL) {
409                 D("if_alloc failed");
410                 return ENOMEM;
411         }
412         if_initname(ifp, name, IF_DUNIT_NONE);
413         ifp->if_mtu = 65536;
414         ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST;
415         ifp->if_init = (void *)nm_vi_dummy;
416         ifp->if_ioctl = nm_vi_dummy;
417         ifp->if_start = nm_vi_start;
418         ifp->if_mtu = ETHERMTU;
419         IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
420         ifp->if_capabilities |= IFCAP_LINKSTATE;
421         ifp->if_capenable |= IFCAP_LINKSTATE;
422
423         ether_ifattach(ifp, eaddr);
424         *ret = ifp;
425         return 0;
426 }
427 /* unregister from the system and drop the final refcount */
428 void
429 nm_vi_detach(struct ifnet *ifp)
430 {
431         nm_vi_free_index(((char *)IF_LLADDR(ifp))[5]);
432         ether_ifdetach(ifp);
433         if_free(ifp);
434 }
435
436 /*
437  * In order to track whether pages are still mapped, we hook into
438  * the standard cdev_pager and intercept the constructor and
439  * destructor.
440  */
441
442 struct netmap_vm_handle_t {
443         struct cdev             *dev;
444         struct netmap_priv_d    *priv;
445 };
446
447
448 static int
449 netmap_dev_pager_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot,
450     vm_ooffset_t foff, struct ucred *cred, u_short *color)
451 {
452         struct netmap_vm_handle_t *vmh = handle;
453
454         if (netmap_verbose)
455                 D("handle %p size %jd prot %d foff %jd",
456                         handle, (intmax_t)size, prot, (intmax_t)foff);
457         if (color)
458                 *color = 0;
459         dev_ref(vmh->dev);
460         return 0;
461 }
462
463
464 static void
465 netmap_dev_pager_dtor(void *handle)
466 {
467         struct netmap_vm_handle_t *vmh = handle;
468         struct cdev *dev = vmh->dev;
469         struct netmap_priv_d *priv = vmh->priv;
470
471         if (netmap_verbose)
472                 D("handle %p", handle);
473         netmap_dtor(priv);
474         free(vmh, M_DEVBUF);
475         dev_rel(dev);
476 }
477
478
479 static int
480 netmap_dev_pager_fault(vm_object_t object, vm_ooffset_t offset,
481         int prot, vm_page_t *mres)
482 {
483         struct netmap_vm_handle_t *vmh = object->handle;
484         struct netmap_priv_d *priv = vmh->priv;
485         struct netmap_adapter *na = priv->np_na;
486         vm_paddr_t paddr;
487         vm_page_t page;
488         vm_memattr_t memattr;
489         vm_pindex_t pidx;
490
491         ND("object %p offset %jd prot %d mres %p",
492                         object, (intmax_t)offset, prot, mres);
493         memattr = object->memattr;
494         pidx = OFF_TO_IDX(offset);
495         paddr = netmap_mem_ofstophys(na->nm_mem, offset);
496         if (paddr == 0)
497                 return VM_PAGER_FAIL;
498
499         if (((*mres)->flags & PG_FICTITIOUS) != 0) {
500                 /*
501                  * If the passed in result page is a fake page, update it with
502                  * the new physical address.
503                  */
504                 page = *mres;
505                 vm_page_updatefake(page, paddr, memattr);
506         } else {
507                 /*
508                  * Replace the passed in reqpage page with our own fake page and
509                  * free up the all of the original pages.
510                  */
511 #ifndef VM_OBJECT_WUNLOCK       /* FreeBSD < 10.x */
512 #define VM_OBJECT_WUNLOCK VM_OBJECT_UNLOCK
513 #define VM_OBJECT_WLOCK VM_OBJECT_LOCK
514 #endif /* VM_OBJECT_WUNLOCK */
515
516                 VM_OBJECT_WUNLOCK(object);
517                 page = vm_page_getfake(paddr, memattr);
518                 VM_OBJECT_WLOCK(object);
519                 vm_page_lock(*mres);
520                 vm_page_free(*mres);
521                 vm_page_unlock(*mres);
522                 *mres = page;
523                 vm_page_insert(page, object, pidx);
524         }
525         page->valid = VM_PAGE_BITS_ALL;
526         return (VM_PAGER_OK);
527 }
528
529
530 static struct cdev_pager_ops netmap_cdev_pager_ops = {
531         .cdev_pg_ctor = netmap_dev_pager_ctor,
532         .cdev_pg_dtor = netmap_dev_pager_dtor,
533         .cdev_pg_fault = netmap_dev_pager_fault,
534 };
535
536
537 static int
538 netmap_mmap_single(struct cdev *cdev, vm_ooffset_t *foff,
539         vm_size_t objsize,  vm_object_t *objp, int prot)
540 {
541         int error;
542         struct netmap_vm_handle_t *vmh;
543         struct netmap_priv_d *priv;
544         vm_object_t obj;
545
546         if (netmap_verbose)
547                 D("cdev %p foff %jd size %jd objp %p prot %d", cdev,
548                     (intmax_t )*foff, (intmax_t )objsize, objp, prot);
549
550         vmh = malloc(sizeof(struct netmap_vm_handle_t), M_DEVBUF,
551                               M_NOWAIT | M_ZERO);
552         if (vmh == NULL)
553                 return ENOMEM;
554         vmh->dev = cdev;
555
556         NMG_LOCK();
557         error = devfs_get_cdevpriv((void**)&priv);
558         if (error)
559                 goto err_unlock;
560         if (priv->np_nifp == NULL) {
561                 error = EINVAL;
562                 goto err_unlock;
563         }
564         vmh->priv = priv;
565         priv->np_refs++;
566         NMG_UNLOCK();
567
568         obj = cdev_pager_allocate(vmh, OBJT_DEVICE,
569                 &netmap_cdev_pager_ops, objsize, prot,
570                 *foff, NULL);
571         if (obj == NULL) {
572                 D("cdev_pager_allocate failed");
573                 error = EINVAL;
574                 goto err_deref;
575         }
576
577         *objp = obj;
578         return 0;
579
580 err_deref:
581         NMG_LOCK();
582         priv->np_refs--;
583 err_unlock:
584         NMG_UNLOCK();
585 // err:
586         free(vmh, M_DEVBUF);
587         return error;
588 }
589
590 /*
591  * On FreeBSD the close routine is only called on the last close on
592  * the device (/dev/netmap) so we cannot do anything useful.
593  * To track close() on individual file descriptors we pass netmap_dtor() to
594  * devfs_set_cdevpriv() on open(). The FreeBSD kernel will call the destructor
595  * when the last fd pointing to the device is closed. 
596  *
597  * Note that FreeBSD does not even munmap() on close() so we also have
598  * to track mmap() ourselves, and postpone the call to
599  * netmap_dtor() is called when the process has no open fds and no active
600  * memory maps on /dev/netmap, as in linux.
601  */
602 static int
603 netmap_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
604 {
605         if (netmap_verbose)
606                 D("dev %p fflag 0x%x devtype %d td %p",
607                         dev, fflag, devtype, td);
608         return 0;
609 }
610
611
612 static int
613 netmap_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
614 {
615         struct netmap_priv_d *priv;
616         int error;
617
618         (void)dev;
619         (void)oflags;
620         (void)devtype;
621         (void)td;
622
623         priv = malloc(sizeof(struct netmap_priv_d), M_DEVBUF,
624                               M_NOWAIT | M_ZERO);
625         if (priv == NULL)
626                 return ENOMEM;
627         priv->np_refs = 1;
628         error = devfs_set_cdevpriv(priv, netmap_dtor);
629         if (error) {
630                 free(priv, M_DEVBUF);
631         } else {
632                 NMG_LOCK();
633                 netmap_use_count++;
634                 NMG_UNLOCK();
635         }
636         return error;
637 }
638
639 /******************** kqueue support ****************/
640
641 /*
642  * The OS_selwakeup also needs to issue a KNOTE_UNLOCKED.
643  * We use a non-zero argument to distinguish the call from the one
644  * in kevent_scan() which instead also needs to run netmap_poll().
645  * The knote uses a global mutex for the time being. We might
646  * try to reuse the one in the si, but it is not allocated
647  * permanently so it might be a bit tricky.
648  *
649  * The *kqfilter function registers one or another f_event
650  * depending on read or write mode.
651  * In the call to f_event() td_fpop is NULL so any child function
652  * calling devfs_get_cdevpriv() would fail - and we need it in
653  * netmap_poll(). As a workaround we store priv into kn->kn_hook
654  * and pass it as first argument to netmap_poll(), which then
655  * uses the failure to tell that we are called from f_event()
656  * and do not need the selrecord().
657  */
658
659
660 void
661 freebsd_selwakeup(struct nm_selinfo *si, int pri)
662 {
663         if (netmap_verbose)
664                 D("on knote %p", &si->si.si_note);
665         selwakeuppri(&si->si, pri);
666         /* use a non-zero hint to tell the notification from the
667          * call done in kqueue_scan() which uses 0
668          */
669         KNOTE_UNLOCKED(&si->si.si_note, 0x100 /* notification */);
670 }
671
672 static void
673 netmap_knrdetach(struct knote *kn)
674 {
675         struct netmap_priv_d *priv = (struct netmap_priv_d *)kn->kn_hook;
676         struct selinfo *si = &priv->np_si[NR_RX]->si;
677
678         D("remove selinfo %p", si);
679         knlist_remove(&si->si_note, kn, 0);
680 }
681
682 static void
683 netmap_knwdetach(struct knote *kn)
684 {
685         struct netmap_priv_d *priv = (struct netmap_priv_d *)kn->kn_hook;
686         struct selinfo *si = &priv->np_si[NR_TX]->si;
687
688         D("remove selinfo %p", si);
689         knlist_remove(&si->si_note, kn, 0);
690 }
691
692 /*
693  * callback from notifies (generated externally) and our
694  * calls to kevent(). The former we just return 1 (ready)
695  * since we do not know better.
696  * In the latter we call netmap_poll and return 0/1 accordingly.
697  */
698 static int
699 netmap_knrw(struct knote *kn, long hint, int events)
700 {
701         struct netmap_priv_d *priv;
702         int revents;
703
704         if (hint != 0) {
705                 ND(5, "call from notify");
706                 return 1; /* assume we are ready */
707         }
708         priv = kn->kn_hook;
709         /* the notification may come from an external thread,
710          * in which case we do not want to run the netmap_poll
711          * This should be filtered above, but check just in case.
712          */
713         if (curthread != priv->np_td) { /* should not happen */
714                 RD(5, "curthread changed %p %p", curthread, priv->np_td);
715                 return 1;
716         } else {
717                 revents = netmap_poll((void *)priv, events, curthread);
718                 return (events & revents) ? 1 : 0;
719         }
720 }
721
722 static int
723 netmap_knread(struct knote *kn, long hint)
724 {
725         return netmap_knrw(kn, hint, POLLIN);
726 }
727
728 static int
729 netmap_knwrite(struct knote *kn, long hint)
730 {
731         return netmap_knrw(kn, hint, POLLOUT);
732 }
733
734 static struct filterops netmap_rfiltops = {
735         .f_isfd = 1,
736         .f_detach = netmap_knrdetach,
737         .f_event = netmap_knread,
738 };
739
740 static struct filterops netmap_wfiltops = {
741         .f_isfd = 1,
742         .f_detach = netmap_knwdetach,
743         .f_event = netmap_knwrite,
744 };
745
746
747 /*
748  * This is called when a thread invokes kevent() to record
749  * a change in the configuration of the kqueue().
750  * The 'priv' should be the same as in the netmap device.
751  */
752 static int
753 netmap_kqfilter(struct cdev *dev, struct knote *kn)
754 {
755         struct netmap_priv_d *priv;
756         int error;
757         struct netmap_adapter *na;
758         struct nm_selinfo *si;
759         int ev = kn->kn_filter;
760
761         if (ev != EVFILT_READ && ev != EVFILT_WRITE) {
762                 D("bad filter request %d", ev);
763                 return 1;
764         }
765         error = devfs_get_cdevpriv((void**)&priv);
766         if (error) {
767                 D("device not yet setup");
768                 return 1;
769         }
770         na = priv->np_na;
771         if (na == NULL) {
772                 D("no netmap adapter for this file descriptor");
773                 return 1;
774         }
775         /* the si is indicated in the priv */
776         si = priv->np_si[(ev == EVFILT_WRITE) ? NR_TX : NR_RX];
777         // XXX lock(priv) ?
778         kn->kn_fop = (ev == EVFILT_WRITE) ?
779                 &netmap_wfiltops : &netmap_rfiltops;
780         kn->kn_hook = priv;
781         knlist_add(&si->si.si_note, kn, 1);
782         // XXX unlock(priv)
783         ND("register %p %s td %p priv %p kn %p np_nifp %p kn_fp/fpop %s",
784                 na, na->ifp->if_xname, curthread, priv, kn,
785                 priv->np_nifp,
786                 kn->kn_fp == curthread->td_fpop ? "match" : "MISMATCH");
787         return 0;
788 }
789
790 struct cdevsw netmap_cdevsw = {
791         .d_version = D_VERSION,
792         .d_name = "netmap",
793         .d_open = netmap_open,
794         .d_mmap_single = netmap_mmap_single,
795         .d_ioctl = netmap_ioctl,
796         .d_poll = netmap_poll,
797         .d_kqfilter = netmap_kqfilter,
798         .d_close = netmap_close,
799 };
800 /*--- end of kqueue support ----*/
801
802 /*
803  * Kernel entry point.
804  *
805  * Initialize/finalize the module and return.
806  *
807  * Return 0 on success, errno on failure.
808  */
809 static int
810 netmap_loader(__unused struct module *module, int event, __unused void *arg)
811 {
812         int error = 0;
813
814         switch (event) {
815         case MOD_LOAD:
816                 error = netmap_init();
817                 break;
818
819         case MOD_UNLOAD:
820                 /*
821                  * if some one is still using netmap,
822                  * then the module can not be unloaded.
823                  */
824                 if (netmap_use_count) {
825                         D("netmap module can not be unloaded - netmap_use_count: %d",
826                                         netmap_use_count);
827                         error = EBUSY;
828                         break;
829                 }
830                 netmap_fini();
831                 break;
832
833         default:
834                 error = EOPNOTSUPP;
835                 break;
836         }
837
838         return (error);
839 }
840
841
842 DEV_MODULE(netmap, netmap_loader, NULL);
843 MODULE_VERSION(netmap, 1);