vkernel: Adjust vke(4) for the if_media.h changes (fixes vkernel build).
[dragonfly.git] / sys / dev / virtual / vkernel / net / if_vke.c
1 /*
2  * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Sepherosa Ziehau <sepherosa@gmail.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #include <sys/param.h>
36 #include <sys/endian.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
39 #include <sys/proc.h>
40 #include <sys/serialize.h>
41 #include <sys/socket.h>
42 #include <sys/sockio.h>
43 #include <sys/sysctl.h>
44
45 #include <machine/md_var.h>
46 #include <machine/cothread.h>
47
48 #include <net/ethernet.h>
49 #include <net/if.h>
50 #include <net/bpf.h>
51 #include <net/if_arp.h>
52 #include <net/if_media.h>
53 #include <net/ifq_var.h>
54 #include <net/vlan/if_vlan_ether.h>
55
56 #include <netinet/in_var.h>
57
58 #include <sys/stat.h>
59 #include <net/tap/if_tap.h>
60 #include <err.h>
61 #include <errno.h>
62 #include <stdio.h>
63 #include <string.h>
64 #include <unistd.h>
65 #include <fcntl.h>
66
67 #define VKE_DEVNAME             "vke"
68
69 #define VKE_CHUNK       8 /* number of mbufs to queue before interrupting */
70
71 #define NETFIFOINDEX(u, sc) ((u) & ((sc)->sc_ringsize - 1))
72
73 #define VKE_COTD_RUN    0
74 #define VKE_COTD_EXIT   1
75 #define VKE_COTD_DEAD   2
76
77 struct vke_fifo {
78         struct mbuf     **array;
79         int             rindex;
80         int             windex;
81 };
82 typedef struct vke_fifo *fifo_t;
83
84 /* Default value for a long time */
85 #define VKE_DEFAULT_RINGSIZE    256
86 static int vke_max_ringsize = 0;
87 TUNABLE_INT("hw.vke.max_ringsize", &vke_max_ringsize);
88
89 #define LOW_POW_2(n)    (1 << (fls(n) - 1))
90
91 struct vke_softc {
92         struct arpcom           arpcom;
93         int                     sc_fd;
94         int                     sc_unit;
95
96         cothread_t              cotd_tx;
97         cothread_t              cotd_rx;
98
99         int                     cotd_tx_exit;
100         int                     cotd_rx_exit;
101
102         void                    *sc_txbuf;
103         int                     sc_txbuf_len;
104
105         fifo_t                  sc_txfifo;
106         fifo_t                  sc_txfifo_done;
107         fifo_t                  sc_rxfifo;
108
109         int                     sc_ringsize;
110
111         long                    cotd_ipackets;
112         long                    cotd_oerrors;
113         long                    cotd_opackets;
114
115         struct sysctl_ctx_list  sc_sysctl_ctx;
116         struct sysctl_oid       *sc_sysctl_tree;
117
118         int                     sc_tap_unit;    /* unit of backend tap(4) */
119         in_addr_t               sc_addr;        /* address */
120         in_addr_t               sc_mask;        /* netmask */
121
122         struct ifmedia          sc_media;
123 };
124
125 static void     vke_start(struct ifnet *, struct ifaltq_subque *);
126 static void     vke_init(void *);
127 static int      vke_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
128
129 static int      vke_media_change(struct ifnet *);
130 static void     vke_media_status(struct ifnet *, struct ifmediareq *);
131
132 static int      vke_attach(const struct vknetif_info *, int);
133 static int      vke_stop(struct vke_softc *);
134 static int      vke_init_addr(struct ifnet *, in_addr_t, in_addr_t);
135 static void     vke_tx_intr(cothread_t cotd);
136 static void     vke_tx_thread(cothread_t cotd);
137 static void     vke_rx_intr(cothread_t cotd);
138 static void     vke_rx_thread(cothread_t cotd);
139
140 static int vke_txfifo_enqueue(struct vke_softc *sc, struct mbuf *m);
141 static struct mbuf *vke_txfifo_dequeue(struct vke_softc *sc);
142
143 static int vke_txfifo_done_enqueue(struct vke_softc *sc, struct mbuf *m);
144 static struct mbuf * vke_txfifo_done_dequeue(struct vke_softc *sc, struct mbuf *nm);
145
146 static struct mbuf *vke_rxfifo_dequeue(struct vke_softc *sc, struct mbuf *nm);
147 static struct mbuf *vke_rxfifo_sniff(struct vke_softc *sc);
148
149 static void
150 vke_sysinit(void *arg __unused)
151 {
152         int i, unit;
153
154         KASSERT(NetifNum <= VKNETIF_MAX, ("too many netifs: %d", NetifNum));
155
156         unit = 0;
157         for (i = 0; i < NetifNum; ++i) {
158                 if (vke_attach(&NetifInfo[i], unit) == 0)
159                         ++unit;
160         }
161 }
162 SYSINIT(vke, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, vke_sysinit, NULL);
163
164 /*
165  * vke_txfifo_done_enqueue() - Add an mbuf to the transmit done fifo.  Since
166  * the cothread cannot free transmit mbufs after processing we put them on
167  * the done fifo so the kernel can free them.
168  */
169 static int
170 vke_txfifo_done_enqueue(struct vke_softc *sc, struct mbuf *m)
171 {
172         fifo_t fifo = sc->sc_txfifo_done;
173
174         while (NETFIFOINDEX(fifo->windex + 1, sc) ==
175                NETFIFOINDEX(fifo->rindex, sc)) {
176                 usleep(20000);
177         }
178         fifo->array[NETFIFOINDEX(fifo->windex, sc)] = m;
179         cpu_sfence();
180         ++fifo->windex;
181
182         return (0);
183 }
184
185 /*
186  * vke_txfifo_done_dequeue() - Remove an mbuf from the transmit done fifo.
187  */
188 static struct mbuf *
189 vke_txfifo_done_dequeue(struct vke_softc *sc, struct mbuf *nm)
190 {
191         fifo_t fifo = sc->sc_txfifo_done;
192         struct mbuf *m;
193
194         if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc))
195                 return (NULL);
196
197         cpu_lfence();
198         m = fifo->array[NETFIFOINDEX(fifo->rindex, sc)];
199         fifo->array[NETFIFOINDEX(fifo->rindex, sc)] = nm;
200         ++fifo->rindex;
201
202         return (m);
203 }
204
205 /*
206  * vke_txfifo_enqueue() - Add an mbuf to the transmit fifo.
207  */
208 static int
209 vke_txfifo_enqueue(struct vke_softc *sc, struct mbuf *m)
210 {
211         fifo_t fifo = sc->sc_txfifo;
212
213         if (NETFIFOINDEX(fifo->windex + 1, sc) ==
214             NETFIFOINDEX(fifo->rindex, sc)) {
215                 return (-1);
216         }
217
218         fifo->array[NETFIFOINDEX(fifo->windex, sc)] = m;
219         cpu_sfence();
220         ++fifo->windex;
221
222         return (0);
223 }
224
225 /*
226  * vke_txfifo_dequeue() - Return next mbuf on the transmit fifo if one
227  * exists.
228  */
229 static struct mbuf *
230 vke_txfifo_dequeue(struct vke_softc *sc)
231 {
232         fifo_t fifo = sc->sc_txfifo;
233         struct mbuf *m;
234
235         if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc))
236                 return (NULL);
237
238         cpu_lfence();
239         m = fifo->array[NETFIFOINDEX(fifo->rindex, sc)];
240         fifo->array[NETFIFOINDEX(fifo->rindex, sc)] = NULL;
241         cpu_sfence();
242         ++fifo->rindex;
243
244         return (m);
245 }
246
247 static int
248 vke_txfifo_empty(struct vke_softc *sc)
249 {
250         fifo_t fifo = sc->sc_txfifo;
251
252         if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc))
253                 return (1);
254         return(0);
255 }
256
257 /*
258  * vke_rxfifo_dequeue() - Return next mbuf on the receice fifo if one
259  * exists replacing it with newm which should point to a newly allocated
260  * mbuf.
261  */
262 static struct mbuf *
263 vke_rxfifo_dequeue(struct vke_softc *sc, struct mbuf *newm)
264 {
265         fifo_t fifo = sc->sc_rxfifo;
266         struct mbuf *m;
267
268         if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc))
269                 return (NULL);
270
271         cpu_lfence();
272         m = fifo->array[NETFIFOINDEX(fifo->rindex, sc)];
273         fifo->array[NETFIFOINDEX(fifo->rindex, sc)] = newm;
274         cpu_sfence();
275         ++fifo->rindex;
276
277         return (m);
278 }
279
280 /*
281  * Return the next mbuf if available but do NOT remove it from the FIFO.
282  */
283 static struct mbuf *
284 vke_rxfifo_sniff(struct vke_softc *sc)
285 {
286         fifo_t fifo = sc->sc_rxfifo;
287         struct mbuf *m;
288
289         if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc))
290                 return (NULL);
291
292         cpu_lfence();
293         m = fifo->array[NETFIFOINDEX(fifo->rindex, sc)];
294
295         return (m);
296 }
297
298 static void
299 vke_init(void *xsc)
300 {
301         struct vke_softc *sc = xsc;
302         struct ifnet *ifp = &sc->arpcom.ac_if;
303         size_t ringsize = sc->sc_ringsize * sizeof(struct mbuf *);
304         int i;
305
306         ASSERT_SERIALIZED(ifp->if_serializer);
307
308         vke_stop(sc);
309
310         ifp->if_flags |= IFF_RUNNING;
311         ifsq_clr_oactive(ifq_get_subq_default(&ifp->if_snd));
312
313         /*
314          * Allocate memory for FIFO structures and mbufs.
315          */
316         sc->sc_txfifo = kmalloc(sizeof(*sc->sc_txfifo),
317                                 M_DEVBUF, M_WAITOK | M_ZERO);
318         sc->sc_txfifo_done = kmalloc(sizeof(*sc->sc_txfifo_done),
319                                 M_DEVBUF, M_WAITOK | M_ZERO);
320         sc->sc_rxfifo = kmalloc(sizeof(*sc->sc_rxfifo),
321                                 M_DEVBUF, M_WAITOK | M_ZERO);
322         sc->sc_txfifo->array = kmalloc(ringsize,
323                                 M_DEVBUF, M_WAITOK | M_ZERO);
324         sc->sc_txfifo_done->array = kmalloc(ringsize,
325                                 M_DEVBUF, M_WAITOK | M_ZERO);
326         sc->sc_rxfifo->array = kmalloc(ringsize,
327                                 M_DEVBUF, M_WAITOK | M_ZERO);
328
329         for (i = 0; i < sc->sc_ringsize; i++) {
330                 sc->sc_rxfifo->array[i] = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR);
331                 sc->sc_txfifo->array[i] = NULL;
332                 sc->sc_txfifo_done->array[i] = NULL;
333         }
334
335         sc->cotd_tx_exit = sc->cotd_rx_exit = VKE_COTD_RUN;
336         sc->cotd_tx = cothread_create(vke_tx_thread, vke_tx_intr, sc, "vke_tx");
337         sc->cotd_rx = cothread_create(vke_rx_thread, vke_rx_intr, sc, "vke_rx");
338
339         if (sc->sc_addr != 0) {
340                 in_addr_t addr, mask;
341
342                 addr = sc->sc_addr;
343                 mask = sc->sc_mask;
344
345                 /*
346                  * Make sure vkernel assigned
347                  * address will not be added
348                  * again.
349                  */
350                 sc->sc_addr = 0;
351                 sc->sc_mask = 0;
352
353                 vke_init_addr(ifp, addr, mask);
354         }
355
356 }
357
358 /*
359  * Called from kernel.
360  *
361  * NOTE: We can't make any kernel callbacks while holding cothread lock
362  *       because the cothread lock is not governed by the kernel scheduler
363  *       (so mplock, tokens, etc will not be released).
364  */
365 static void
366 vke_start(struct ifnet *ifp, struct ifaltq_subque *ifsq)
367 {
368         struct vke_softc *sc = ifp->if_softc;
369         struct mbuf *m;
370         cothread_t cotd = sc->cotd_tx;
371         int count;
372
373         ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq);
374         ASSERT_SERIALIZED(ifp->if_serializer);
375
376         if ((ifp->if_flags & IFF_RUNNING) == 0 || ifsq_is_oactive(ifsq))
377                 return;
378
379         count = 0;
380         while ((m = ifsq_dequeue(ifsq)) != NULL) {
381                 if (vke_txfifo_enqueue(sc, m) != -1) {
382                         ETHER_BPF_MTAP(ifp, m);
383                         if (count++ == VKE_CHUNK) {
384                                 cothread_lock(cotd, 0);
385                                 cothread_signal(cotd);
386                                 cothread_unlock(cotd, 0);
387                                 count = 0;
388                         }
389                 } else {
390                         m_freem(m);
391                 }
392         }
393         if (count) {
394                 cothread_lock(cotd, 0);
395                 cothread_signal(cotd);
396                 cothread_unlock(cotd, 0);
397         }
398 }
399
400 static int
401 vke_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
402 {
403         struct vke_softc *sc = ifp->if_softc;
404         struct ifreq *ifr = (struct ifreq *)data;
405         int error = 0;
406
407         ASSERT_SERIALIZED(ifp->if_serializer);
408
409         switch (cmd) {
410         case SIOCSIFFLAGS:
411                 if (ifp->if_flags & IFF_UP) {
412                         if ((ifp->if_flags & IFF_RUNNING) == 0)
413                                 vke_init(sc);
414                 } else {
415                         if (ifp->if_flags & IFF_RUNNING)
416                                 vke_stop(sc);
417                 }
418                 break;
419         case SIOCGIFMEDIA:
420         case SIOCSIFMEDIA:
421                 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
422                 break;
423         case SIOCGIFSTATUS: {
424                 struct ifstat *ifs = (struct ifstat *)data;
425                 int len;
426
427                 len = strlen(ifs->ascii);
428                 if (len < sizeof(ifs->ascii)) {
429                         if (sc->sc_tap_unit >= 0) {
430                                 ksnprintf(ifs->ascii + len,
431                                           sizeof(ifs->ascii) - len,
432                                           "\tBacked by tap%d\n",
433                                           sc->sc_tap_unit);
434                         }
435                 }
436                 break;
437         }
438         case SIOCSIFADDR:
439                 if (((struct ifaddr *)data)->ifa_addr->sa_family == AF_INET) {
440                         /*
441                          * If we are explicitly requested to change address,
442                          * we should invalidate address/netmask passed in
443                          * from vkernel command line.
444                          */
445                         sc->sc_addr = 0;
446                         sc->sc_mask = 0;
447                 }
448                 /* FALL THROUGH */
449         default:
450                 error = ether_ioctl(ifp, cmd, data);
451                 break;
452         }
453         return error;
454 }
455
456 static int
457 vke_stop(struct vke_softc *sc)
458 {
459         struct ifnet *ifp = &sc->arpcom.ac_if;
460         int i;
461
462         ASSERT_SERIALIZED(ifp->if_serializer);
463
464         ifp->if_flags &= ~IFF_RUNNING;
465         ifsq_clr_oactive(ifq_get_subq_default(&ifp->if_snd));
466
467         if (sc) {
468                 if (sc->cotd_tx) {
469                         cothread_lock(sc->cotd_tx, 0);
470                         if (sc->cotd_tx_exit == VKE_COTD_RUN)
471                                 sc->cotd_tx_exit = VKE_COTD_EXIT;
472                         cothread_signal(sc->cotd_tx);
473                         cothread_unlock(sc->cotd_tx, 0);
474                         cothread_delete(&sc->cotd_tx);
475                 }
476                 if (sc->cotd_rx) {
477                         cothread_lock(sc->cotd_rx, 0);
478                         if (sc->cotd_rx_exit == VKE_COTD_RUN)
479                                 sc->cotd_rx_exit = VKE_COTD_EXIT;
480                         cothread_signal(sc->cotd_rx);
481                         cothread_unlock(sc->cotd_rx, 0);
482                         cothread_delete(&sc->cotd_rx);
483                 }
484
485                 for (i = 0; i < sc->sc_ringsize; i++) {
486                         if (sc->sc_rxfifo && sc->sc_rxfifo->array[i]) {
487                                 m_freem(sc->sc_rxfifo->array[i]);
488                                 sc->sc_rxfifo->array[i] = NULL;
489                         }
490                         if (sc->sc_txfifo && sc->sc_txfifo->array[i]) {
491                                 m_freem(sc->sc_txfifo->array[i]);
492                                 sc->sc_txfifo->array[i] = NULL;
493                         }
494                         if (sc->sc_txfifo_done && sc->sc_txfifo_done->array[i]) {
495                                 m_freem(sc->sc_txfifo_done->array[i]);
496                                 sc->sc_txfifo_done->array[i] = NULL;
497                         }
498                 }
499
500                 if (sc->sc_txfifo) {
501                         if (sc->sc_txfifo->array)
502                                 kfree(sc->sc_txfifo->array, M_DEVBUF);
503                         kfree(sc->sc_txfifo, M_DEVBUF);
504                         sc->sc_txfifo = NULL;
505                 }
506
507                 if (sc->sc_txfifo_done) {
508                         if (sc->sc_txfifo_done->array)
509                                 kfree(sc->sc_txfifo_done->array, M_DEVBUF);
510                         kfree(sc->sc_txfifo_done, M_DEVBUF);
511                         sc->sc_txfifo_done = NULL;
512                 }
513
514                 if (sc->sc_rxfifo) {
515                         if (sc->sc_rxfifo->array)
516                                 kfree(sc->sc_rxfifo->array, M_DEVBUF);
517                         kfree(sc->sc_rxfifo, M_DEVBUF);
518                         sc->sc_rxfifo = NULL;
519                 }
520         }
521
522
523         return 0;
524 }
525
526 /*
527  * vke_rx_intr() is the interrupt function for the receive cothread.
528  */
529 static void
530 vke_rx_intr(cothread_t cotd)
531 {
532         struct mbuf *m;
533         struct mbuf *nm;
534         struct vke_softc *sc = cotd->arg;
535         struct ifnet *ifp = &sc->arpcom.ac_if;
536         static int count = 0;
537
538         ifnet_serialize_all(ifp);
539         cothread_lock(cotd, 0);
540
541         if (sc->cotd_rx_exit != VKE_COTD_RUN) {
542                 cothread_unlock(cotd, 0);
543                 ifnet_deserialize_all(ifp);
544                 return;
545         }
546         if (sc->cotd_ipackets) {
547                 IFNET_STAT_INC(ifp, ipackets, 1);
548                 sc->cotd_ipackets = 0;
549         }
550         cothread_unlock(cotd, 0);
551
552         while ((m = vke_rxfifo_sniff(sc)) != NULL) {
553                 nm = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
554                 if (nm) {
555                         vke_rxfifo_dequeue(sc, nm);
556                         ifp->if_input(ifp, m, NULL, -1);
557                         if (count++ == VKE_CHUNK) {
558                                 cothread_lock(cotd, 0);
559                                 cothread_signal(cotd);
560                                 cothread_unlock(cotd, 0);
561                                 count = 0;
562                         }
563                 } else {
564                         vke_rxfifo_dequeue(sc, m);
565                 }
566         }
567
568         if (count) {
569                 cothread_lock(cotd, 0);
570                 cothread_signal(cotd);
571                 cothread_unlock(cotd, 0);
572         }
573         ifnet_deserialize_all(ifp);
574 }
575
576 /*
577  * vke_tx_intr() is the interrupt function for the transmit cothread.
578  * Calls vke_start() to handle processing transmit mbufs.
579  */
580 static void
581 vke_tx_intr(cothread_t cotd)
582 {
583         struct vke_softc *sc = cotd->arg;
584         struct ifnet *ifp = &sc->arpcom.ac_if;
585         struct mbuf *m;
586
587         ifnet_serialize_all(ifp);
588         cothread_lock(cotd, 0);
589         if (sc->cotd_tx_exit != VKE_COTD_RUN) {
590                 cothread_unlock(cotd, 0);
591                 ifnet_deserialize_all(ifp);
592                 return;
593         }
594         if (sc->cotd_opackets) {
595                 IFNET_STAT_INC(ifp, opackets, 1);
596                 sc->cotd_opackets = 0;
597         }
598         if (sc->cotd_oerrors) {
599                 IFNET_STAT_INC(ifp, oerrors, 1);
600                 sc->cotd_oerrors = 0;
601         }
602         cothread_unlock(cotd, 0);
603
604         /*
605          * Free TX mbufs that have been processed before starting new
606          * ones going to be pipeline friendly.
607          */
608         while ((m = vke_txfifo_done_dequeue(sc, NULL)) != NULL) {
609                 m_freem(m);
610         }
611
612         if ((ifp->if_flags & IFF_RUNNING) == 0)
613                 if_devstart(ifp);
614
615         ifnet_deserialize_all(ifp);
616 }
617
618 /*
619  * vke_rx_thread() is the body of the receive cothread.
620  *
621  * WARNING!  THIS IS A COTHREAD WHICH HAS NO PER-CPU GLOBALDATA!!!!!
622  */
623 static void
624 vke_rx_thread(cothread_t cotd)
625 {
626         struct mbuf *m;
627         struct vke_softc *sc = cotd->arg;
628         struct ifnet *ifp = &sc->arpcom.ac_if;
629         fifo_t fifo = sc->sc_rxfifo;
630         fd_set fdset;
631         struct timeval tv;
632         int count;
633         int n;
634         int r;
635
636         /* Select timeout cannot be infinite since we need to check for
637          * the exit flag sc->cotd_rx_exit.
638          */
639         tv.tv_sec = 0;
640         tv.tv_usec = 500000;
641
642         FD_ZERO(&fdset);
643         count = 0;
644
645         while (sc->cotd_rx_exit == VKE_COTD_RUN) {
646                 /*
647                  * Wait for the RX FIFO to be loaded with
648                  * empty mbufs.
649                  */
650                 if (NETFIFOINDEX(fifo->windex + 1, sc) ==
651                     NETFIFOINDEX(fifo->rindex, sc)) {
652                         usleep(20000);
653                         continue;
654                 }
655
656                 /*
657                  * Load data into the rx fifo
658                  */
659                 cpu_lfence();
660                 m = fifo->array[NETFIFOINDEX(fifo->windex, sc)];
661                 if (m == NULL) {
662                         fprintf(stderr,
663                                 VKE_DEVNAME "%d: NULL rxring mbuf\n",
664                                 sc->sc_unit);
665                         *(volatile int *)0 = 1;
666                 }
667                 n = read(sc->sc_fd, mtod(m, void *), MCLBYTES);
668                 if (n > 0) {
669                         /* no mycpu in cothread */
670                         /*IFNET_STAT_INC(ifp, ipackets, 1);*/
671                         ++sc->cotd_ipackets;
672                         m->m_pkthdr.rcvif = ifp;
673                         m->m_pkthdr.len = m->m_len = n;
674                         cpu_sfence();
675                         ++fifo->windex;
676                         if (count++ == VKE_CHUNK) {
677                                 cothread_intr(cotd);
678                                 count = 0;
679                         }
680                 } else {
681                         if (count) {
682                                 cothread_intr(cotd);
683                                 count = 0;
684                         }
685                         FD_SET(sc->sc_fd, &fdset);
686                         r = select(sc->sc_fd + 1, &fdset, NULL, NULL, &tv);
687                         if (r == -1) {
688                                 fprintf(stderr,
689                                         VKE_DEVNAME "%d: select failed for "
690                                         "TAP device\n", sc->sc_unit);
691                                 usleep(1000000);
692                         }
693                 }
694         }
695         cpu_sfence();
696         sc->cotd_rx_exit = VKE_COTD_DEAD;
697 }
698
699 /*
700  * vke_tx_thread() is the body of the transmit cothread.
701  *
702  * WARNING!  THIS IS A COTHREAD WHICH HAS NO PER-CPU GLOBALDATA!!!!!
703  */
704 static void
705 vke_tx_thread(cothread_t cotd)
706 {
707         struct mbuf *m;
708         struct vke_softc *sc = cotd->arg;
709         /*struct ifnet *ifp = &sc->arpcom.ac_if;*/
710         int count = 0;
711
712         while (sc->cotd_tx_exit == VKE_COTD_RUN) {
713                 /*
714                  * Write outgoing packets to the TAP interface
715                  */
716                 m = vke_txfifo_dequeue(sc);
717                 if (m) {
718                         if (m->m_pkthdr.len <= MCLBYTES) {
719                                 m_copydata(m, 0, m->m_pkthdr.len, sc->sc_txbuf);
720                                 sc->sc_txbuf_len = m->m_pkthdr.len;
721
722                                 if (write(sc->sc_fd, sc->sc_txbuf,
723                                           sc->sc_txbuf_len) < 0) {
724                                         /* no mycpu in cothread */
725                                         /*IFNET_STAT_INC(ifp, oerrors, 1);*/
726                                         ++sc->cotd_oerrors;
727                                 } else {
728                                         /* no mycpu in cothread */
729                                         /*IFNET_STAT_INC(ifp, opackets, 1);*/
730                                         ++sc->cotd_opackets;
731                                 }
732                         }
733                         if (count++ == VKE_CHUNK) {
734                                 cothread_intr(cotd);
735                                 count = 0;
736                         }
737                         vke_txfifo_done_enqueue(sc, m);
738                 } else {
739                         if (count) {
740                                 cothread_intr(cotd);
741                                 count = 0;
742                         }
743                         cothread_lock(cotd, 1);
744                         if (vke_txfifo_empty(sc))
745                                 cothread_wait(cotd);
746                         cothread_unlock(cotd, 1);
747                 }
748         }
749         cpu_sfence();
750         sc->cotd_tx_exit = VKE_COTD_DEAD;
751 }
752
753 static int
754 vke_attach(const struct vknetif_info *info, int unit)
755 {
756         struct vke_softc *sc;
757         struct ifnet *ifp;
758         struct tapinfo tapinfo;
759         uint8_t enaddr[ETHER_ADDR_LEN];
760         int nmbufs;
761         int fd;
762
763         KKASSERT(info->tap_fd >= 0);
764         fd = info->tap_fd;
765
766         if (info->enaddr) {
767                 /*
768                  * enaddr is supplied
769                  */
770                 bcopy(info->enaddr, enaddr, ETHER_ADDR_LEN);
771         } else {
772                 /*
773                  * This is only a TAP device if tap_unit is non-zero.  If
774                  * connecting to a virtual socket we generate a unique MAC.
775                  *
776                  * WARNING: enaddr[0] bit 0 is the multicast bit, when
777                  *          randomizing enaddr[] just leave the first
778                  *          two bytes 00 00 for now.
779                  */
780                 bzero(enaddr, sizeof(enaddr));
781                 if (info->tap_unit >= 0) {
782                         if (ioctl(fd, TAPGIFINFO, &tapinfo) < 0) {
783                                 kprintf(VKE_DEVNAME "%d: ioctl(TAPGIFINFO) "
784                                         "failed: %s\n", unit, strerror(errno));
785                                 return ENXIO;
786                         }
787
788                         if (ioctl(fd, SIOCGIFADDR, enaddr) < 0) {
789                                 kprintf(VKE_DEVNAME "%d: ioctl(SIOCGIFADDR) "
790                                         "failed: %s\n", unit, strerror(errno));
791                                 return ENXIO;
792                         }
793                 } else {
794                         int fd = open("/dev/urandom", O_RDONLY);
795                         if (fd >= 0) {
796                                 read(fd, enaddr + 2, 4);
797                                 close(fd);
798                         }
799                         enaddr[4] = (int)getpid() >> 8;
800                         enaddr[5] = (int)getpid() & 255;
801
802                 }
803                 enaddr[1] += 1;
804         }
805         if (ETHER_IS_MULTICAST(enaddr)) {
806                 kprintf(VKE_DEVNAME "%d: illegal MULTICAST ether mac!\n", unit);
807                 return ENXIO;
808         }
809
810         sc = kmalloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
811
812         sc->sc_txbuf = kmalloc(MCLBYTES, M_DEVBUF, M_WAITOK);
813         sc->sc_fd = fd;
814         sc->sc_unit = unit;
815         sc->sc_tap_unit = info->tap_unit;
816         sc->sc_addr = info->netif_addr;
817         sc->sc_mask = info->netif_mask;
818
819         if (vke_max_ringsize == 0) {
820                 nmbufs = nmbclusters / (NetifNum * 2);
821                 sc->sc_ringsize = LOW_POW_2(nmbufs);
822                 if (sc->sc_ringsize > VKE_DEFAULT_RINGSIZE)
823                         sc->sc_ringsize = VKE_DEFAULT_RINGSIZE;
824         } else if (vke_max_ringsize >= VKE_CHUNK) {     /* Tunable specified */
825                 sc->sc_ringsize = LOW_POW_2(vke_max_ringsize);
826         } else {
827                 sc->sc_ringsize = LOW_POW_2(VKE_CHUNK);
828         }
829
830         ifp = &sc->arpcom.ac_if;
831         if_initname(ifp, VKE_DEVNAME, sc->sc_unit);
832
833         /* NB: after if_initname() */
834         sysctl_ctx_init(&sc->sc_sysctl_ctx);
835         sc->sc_sysctl_tree = SYSCTL_ADD_NODE(&sc->sc_sysctl_ctx,
836                                              SYSCTL_STATIC_CHILDREN(_hw),
837                                              OID_AUTO, ifp->if_xname,
838                                              CTLFLAG_RD, 0, "");
839         if (sc->sc_sysctl_tree == NULL) {
840                 kprintf(VKE_DEVNAME "%d: can't add sysctl node\n", unit);
841         } else {
842                 SYSCTL_ADD_INT(&sc->sc_sysctl_ctx,
843                                SYSCTL_CHILDREN(sc->sc_sysctl_tree),
844                                OID_AUTO, "tap_unit",
845                                CTLFLAG_RD, &sc->sc_tap_unit, 0,
846                                "Backend tap(4) unit");
847         }
848
849         ifp->if_softc = sc;
850         ifp->if_ioctl = vke_ioctl;
851         ifp->if_start = vke_start;
852         ifp->if_init = vke_init;
853         ifp->if_mtu = tapinfo.mtu;
854         ifp->if_baudrate = tapinfo.baudrate;
855         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
856         ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
857         ifq_set_ready(&ifp->if_snd);
858
859         ifmedia_init(&sc->sc_media, 0, vke_media_change, vke_media_status);
860         /* We support as many media types as we please for
861            debugging purposes */
862         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_T, 0, NULL);
863         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL);
864         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_2, 0, NULL);
865         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_5, 0, NULL);
866         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_TX, 0, NULL);
867         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL);
868         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_FX, 0, NULL);
869         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_T4, 0, NULL);
870         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_VG, 0, NULL);
871         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_T2, 0, NULL);
872         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_1000_SX, 0, NULL);
873         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_STP, 0, NULL);
874         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_FL, 0, NULL);
875         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_1000_LX, 0, NULL);
876         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_1000_CX, 0, NULL);
877         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_1000_T, 0, NULL);
878         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL);
879         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_HPNA_1, 0, NULL);
880         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10G_LR, 0, NULL);
881         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10G_SR, 0, NULL);
882         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10G_CX4, 0, NULL);
883         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_2500_SX, 0, NULL);
884         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
885         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10G_TWINAX_LONG, 0, NULL);
886         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10G_LRM, 0, NULL);
887         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10G_T, 0, NULL);
888         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_40G_CR4, 0, NULL);
889         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_40G_SR4, 0, NULL);
890         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_40G_LR4, 0, NULL);
891         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
892
893         ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
894
895         ifp->if_link_state = LINK_STATE_UP;
896
897         ether_ifattach(ifp, enaddr, NULL);
898
899         if (bootverbose && sc->sc_addr != 0) {
900                 if_printf(ifp, "pre-configured "
901                     "address 0x%08x, netmask 0x%08x, %d mbuf clusters\n",
902                     ntohl(sc->sc_addr), ntohl(sc->sc_mask), sc->sc_ringsize);
903         }
904
905         return 0;
906 }
907
908 static int
909 vke_init_addr(struct ifnet *ifp, in_addr_t addr, in_addr_t mask)
910 {
911         struct ifaliasreq ifra;
912         struct sockaddr_in *sin;
913         int ret;
914
915         ASSERT_SERIALIZED(ifp->if_serializer);
916
917         if (bootverbose) {
918                 if_printf(ifp, "add pre-configured "
919                           "address 0x%08x, netmask 0x%08x\n",
920                           ntohl(addr), ntohl(mask));
921         }
922
923         bzero(&ifra, sizeof(ifra));
924
925         /* NB: no need to set ifaliasreq.ifra_name */
926
927         sin = (struct sockaddr_in *)&ifra.ifra_addr;
928         sin->sin_family = AF_INET;
929         sin->sin_len = sizeof(*sin);
930         sin->sin_addr.s_addr = addr;
931
932         if (mask != 0) {
933                 sin = (struct sockaddr_in *)&ifra.ifra_mask;
934                 sin->sin_len = sizeof(*sin);
935                 sin->sin_addr.s_addr = mask;
936         }
937
938         /*
939          * Temporarily release serializer, in_control() will hold
940          * it again before calling ifnet.if_ioctl().
941          */
942         ifnet_deserialize_all(ifp);
943         ret = in_control(SIOCAIFADDR, (caddr_t)&ifra, ifp, NULL);
944         ifnet_serialize_all(ifp);
945
946         return ret;
947 }
948
949 static int vke_media_change(struct ifnet *ifp)
950 {
951         /* ignored */
952         return(0);
953 }
954
955 static void vke_media_status(struct ifnet *ifp, struct ifmediareq *imr)
956 {
957         struct vke_softc *sc = (struct vke_softc *)ifp->if_softc;
958
959         imr->ifm_status = IFM_AVALID;
960         imr->ifm_status |= IFM_ACTIVE;
961
962         if(sc->sc_media.ifm_cur) {
963                 if(sc->sc_media.ifm_cur->ifm_media == IFM_ETHER) {
964                         imr->ifm_active = IFM_ETHER | IFM_1000_T | IFM_FDX;
965                 } else {
966                         imr->ifm_active = sc->sc_media.ifm_cur->ifm_media;
967                 }
968         } else {
969                 imr->ifm_active = IFM_ETHER | IFM_1000_T | IFM_FDX;
970         }
971 }