19ed84223SSascha Wildner /*
29ed84223SSascha Wildner * Copyright (c) 2007 The DragonFly Project. All rights reserved.
39ed84223SSascha Wildner *
49ed84223SSascha Wildner * This code is derived from software contributed to The DragonFly Project
59ed84223SSascha Wildner * by Sepherosa Ziehau <sepherosa@gmail.com>
69ed84223SSascha Wildner *
79ed84223SSascha Wildner * Redistribution and use in source and binary forms, with or without
89ed84223SSascha Wildner * modification, are permitted provided that the following conditions
99ed84223SSascha Wildner * are met:
109ed84223SSascha Wildner *
119ed84223SSascha Wildner * 1. Redistributions of source code must retain the above copyright
129ed84223SSascha Wildner * notice, this list of conditions and the following disclaimer.
139ed84223SSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright
149ed84223SSascha Wildner * notice, this list of conditions and the following disclaimer in
159ed84223SSascha Wildner * the documentation and/or other materials provided with the
169ed84223SSascha Wildner * distribution.
179ed84223SSascha Wildner * 3. Neither the name of The DragonFly Project nor the names of its
189ed84223SSascha Wildner * contributors may be used to endorse or promote products derived
199ed84223SSascha Wildner * from this software without specific, prior written permission.
209ed84223SSascha Wildner *
219ed84223SSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
229ed84223SSascha Wildner * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
239ed84223SSascha Wildner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
249ed84223SSascha Wildner * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
259ed84223SSascha Wildner * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
269ed84223SSascha Wildner * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
279ed84223SSascha Wildner * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
289ed84223SSascha Wildner * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
299ed84223SSascha Wildner * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
309ed84223SSascha Wildner * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
319ed84223SSascha Wildner * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
329ed84223SSascha Wildner * SUCH DAMAGE.
339ed84223SSascha Wildner */
349ed84223SSascha Wildner
359ed84223SSascha Wildner #include <sys/param.h>
369ed84223SSascha Wildner #include <sys/endian.h>
379ed84223SSascha Wildner #include <sys/kernel.h>
389ed84223SSascha Wildner #include <sys/malloc.h>
399ed84223SSascha Wildner #include <sys/proc.h>
409ed84223SSascha Wildner #include <sys/serialize.h>
419ed84223SSascha Wildner #include <sys/socket.h>
429ed84223SSascha Wildner #include <sys/sockio.h>
439ed84223SSascha Wildner #include <sys/sysctl.h>
449ed84223SSascha Wildner
459ed84223SSascha Wildner #include <machine/md_var.h>
469ed84223SSascha Wildner #include <machine/cothread.h>
479ed84223SSascha Wildner
489ed84223SSascha Wildner #include <net/ethernet.h>
499ed84223SSascha Wildner #include <net/if.h>
509ed84223SSascha Wildner #include <net/bpf.h>
519ed84223SSascha Wildner #include <net/if_arp.h>
5270515437SMarkus Pfeiffer #include <net/if_media.h>
539ed84223SSascha Wildner #include <net/ifq_var.h>
54c90aaf98SMatthew Dillon #include <net/vlan/if_vlan_ether.h>
559ed84223SSascha Wildner
569ed84223SSascha Wildner #include <netinet/in_var.h>
579ed84223SSascha Wildner
589ed84223SSascha Wildner #include <sys/stat.h>
599ed84223SSascha Wildner #include <net/tap/if_tap.h>
609ed84223SSascha Wildner #include <err.h>
619ed84223SSascha Wildner #include <errno.h>
629ed84223SSascha Wildner #include <stdio.h>
639ed84223SSascha Wildner #include <string.h>
649ed84223SSascha Wildner #include <unistd.h>
659ed84223SSascha Wildner #include <fcntl.h>
669ed84223SSascha Wildner
679ed84223SSascha Wildner #define VKE_DEVNAME "vke"
689ed84223SSascha Wildner
699ed84223SSascha Wildner #define VKE_CHUNK 8 /* number of mbufs to queue before interrupting */
709ed84223SSascha Wildner
713351469cSAntonio Huete Jimenez #define NETFIFOINDEX(u, sc) ((u) & ((sc)->sc_ringsize - 1))
729ed84223SSascha Wildner
739ed84223SSascha Wildner #define VKE_COTD_RUN 0
749ed84223SSascha Wildner #define VKE_COTD_EXIT 1
759ed84223SSascha Wildner #define VKE_COTD_DEAD 2
769ed84223SSascha Wildner
779ed84223SSascha Wildner struct vke_fifo {
783351469cSAntonio Huete Jimenez struct mbuf **array;
799ed84223SSascha Wildner int rindex;
809ed84223SSascha Wildner int windex;
819ed84223SSascha Wildner };
829ed84223SSascha Wildner typedef struct vke_fifo *fifo_t;
839ed84223SSascha Wildner
8433c27d6cSAntonio Huete Jimenez /* Default value for a long time */
8533c27d6cSAntonio Huete Jimenez #define VKE_DEFAULT_RINGSIZE 256
8633c27d6cSAntonio Huete Jimenez static int vke_max_ringsize = 0;
8733c27d6cSAntonio Huete Jimenez TUNABLE_INT("hw.vke.max_ringsize", &vke_max_ringsize);
8833c27d6cSAntonio Huete Jimenez
8933c27d6cSAntonio Huete Jimenez #define LOW_POW_2(n) (1 << (fls(n) - 1))
9033c27d6cSAntonio Huete Jimenez
919ed84223SSascha Wildner struct vke_softc {
929ed84223SSascha Wildner struct arpcom arpcom;
939ed84223SSascha Wildner int sc_fd;
949ed84223SSascha Wildner int sc_unit;
959ed84223SSascha Wildner
969ed84223SSascha Wildner cothread_t cotd_tx;
979ed84223SSascha Wildner cothread_t cotd_rx;
989ed84223SSascha Wildner
999ed84223SSascha Wildner int cotd_tx_exit;
1009ed84223SSascha Wildner int cotd_rx_exit;
1019ed84223SSascha Wildner
1029ed84223SSascha Wildner void *sc_txbuf;
1039ed84223SSascha Wildner int sc_txbuf_len;
1049ed84223SSascha Wildner
1059ed84223SSascha Wildner fifo_t sc_txfifo;
1069ed84223SSascha Wildner fifo_t sc_txfifo_done;
1079ed84223SSascha Wildner fifo_t sc_rxfifo;
1089ed84223SSascha Wildner
1093351469cSAntonio Huete Jimenez int sc_ringsize;
1103351469cSAntonio Huete Jimenez
111a9844950SMatthew Dillon long cotd_ipackets;
112a9844950SMatthew Dillon long cotd_oerrors;
113a9844950SMatthew Dillon long cotd_opackets;
114a9844950SMatthew Dillon
1159ed84223SSascha Wildner struct sysctl_ctx_list sc_sysctl_ctx;
1169ed84223SSascha Wildner struct sysctl_oid *sc_sysctl_tree;
1179ed84223SSascha Wildner
1189ed84223SSascha Wildner int sc_tap_unit; /* unit of backend tap(4) */
1199ed84223SSascha Wildner in_addr_t sc_addr; /* address */
1209ed84223SSascha Wildner in_addr_t sc_mask; /* netmask */
12170515437SMarkus Pfeiffer
12270515437SMarkus Pfeiffer struct ifmedia sc_media;
1239ed84223SSascha Wildner };
1249ed84223SSascha Wildner
125f0a26983SSepherosa Ziehau static void vke_start(struct ifnet *, struct ifaltq_subque *);
1269ed84223SSascha Wildner static void vke_init(void *);
1279ed84223SSascha Wildner static int vke_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
1289ed84223SSascha Wildner
12970515437SMarkus Pfeiffer static int vke_media_change(struct ifnet *);
13070515437SMarkus Pfeiffer static void vke_media_status(struct ifnet *, struct ifmediareq *);
13170515437SMarkus Pfeiffer
1329ed84223SSascha Wildner static int vke_attach(const struct vknetif_info *, int);
1339ed84223SSascha Wildner static int vke_stop(struct vke_softc *);
1349ed84223SSascha Wildner static int vke_init_addr(struct ifnet *, in_addr_t, in_addr_t);
1359ed84223SSascha Wildner static void vke_tx_intr(cothread_t cotd);
1369ed84223SSascha Wildner static void vke_tx_thread(cothread_t cotd);
1379ed84223SSascha Wildner static void vke_rx_intr(cothread_t cotd);
1389ed84223SSascha Wildner static void vke_rx_thread(cothread_t cotd);
1399ed84223SSascha Wildner
1409ed84223SSascha Wildner static int vke_txfifo_enqueue(struct vke_softc *sc, struct mbuf *m);
1419ed84223SSascha Wildner static struct mbuf *vke_txfifo_dequeue(struct vke_softc *sc);
1429ed84223SSascha Wildner
1439ed84223SSascha Wildner static int vke_txfifo_done_enqueue(struct vke_softc *sc, struct mbuf *m);
1449ed84223SSascha Wildner static struct mbuf * vke_txfifo_done_dequeue(struct vke_softc *sc, struct mbuf *nm);
1459ed84223SSascha Wildner
1469ed84223SSascha Wildner static struct mbuf *vke_rxfifo_dequeue(struct vke_softc *sc, struct mbuf *nm);
1479ed84223SSascha Wildner static struct mbuf *vke_rxfifo_sniff(struct vke_softc *sc);
1489ed84223SSascha Wildner
1499ed84223SSascha Wildner static void
vke_sysinit(void * arg __unused)1509ed84223SSascha Wildner vke_sysinit(void *arg __unused)
1519ed84223SSascha Wildner {
1529ed84223SSascha Wildner int i, unit;
1539ed84223SSascha Wildner
154ed20d0e3SSascha Wildner KASSERT(NetifNum <= VKNETIF_MAX, ("too many netifs: %d", NetifNum));
1559ed84223SSascha Wildner
1569ed84223SSascha Wildner unit = 0;
1579ed84223SSascha Wildner for (i = 0; i < NetifNum; ++i) {
1589ed84223SSascha Wildner if (vke_attach(&NetifInfo[i], unit) == 0)
1599ed84223SSascha Wildner ++unit;
1609ed84223SSascha Wildner }
1619ed84223SSascha Wildner }
1629ed84223SSascha Wildner SYSINIT(vke, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, vke_sysinit, NULL);
1639ed84223SSascha Wildner
1649ed84223SSascha Wildner /*
1659ed84223SSascha Wildner * vke_txfifo_done_enqueue() - Add an mbuf to the transmit done fifo. Since
1669ed84223SSascha Wildner * the cothread cannot free transmit mbufs after processing we put them on
1679ed84223SSascha Wildner * the done fifo so the kernel can free them.
1689ed84223SSascha Wildner */
1699ed84223SSascha Wildner static int
vke_txfifo_done_enqueue(struct vke_softc * sc,struct mbuf * m)1709ed84223SSascha Wildner vke_txfifo_done_enqueue(struct vke_softc *sc, struct mbuf *m)
1719ed84223SSascha Wildner {
1729ed84223SSascha Wildner fifo_t fifo = sc->sc_txfifo_done;
1739ed84223SSascha Wildner
1740e645f47SMatthew Dillon while (NETFIFOINDEX(fifo->windex + 1, sc) ==
1750e645f47SMatthew Dillon NETFIFOINDEX(fifo->rindex, sc)) {
1769ed84223SSascha Wildner usleep(20000);
1779ed84223SSascha Wildner }
1783351469cSAntonio Huete Jimenez fifo->array[NETFIFOINDEX(fifo->windex, sc)] = m;
1799ed84223SSascha Wildner cpu_sfence();
1809ed84223SSascha Wildner ++fifo->windex;
1810e645f47SMatthew Dillon
1829ed84223SSascha Wildner return (0);
1839ed84223SSascha Wildner }
1849ed84223SSascha Wildner
1859ed84223SSascha Wildner /*
1869ed84223SSascha Wildner * vke_txfifo_done_dequeue() - Remove an mbuf from the transmit done fifo.
1879ed84223SSascha Wildner */
1889ed84223SSascha Wildner static struct mbuf *
vke_txfifo_done_dequeue(struct vke_softc * sc,struct mbuf * nm)1899ed84223SSascha Wildner vke_txfifo_done_dequeue(struct vke_softc *sc, struct mbuf *nm)
1909ed84223SSascha Wildner {
1919ed84223SSascha Wildner fifo_t fifo = sc->sc_txfifo_done;
1929ed84223SSascha Wildner struct mbuf *m;
1939ed84223SSascha Wildner
1943351469cSAntonio Huete Jimenez if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc))
1959ed84223SSascha Wildner return (NULL);
1969ed84223SSascha Wildner
1970e645f47SMatthew Dillon cpu_lfence();
1983351469cSAntonio Huete Jimenez m = fifo->array[NETFIFOINDEX(fifo->rindex, sc)];
1993351469cSAntonio Huete Jimenez fifo->array[NETFIFOINDEX(fifo->rindex, sc)] = nm;
2009ed84223SSascha Wildner ++fifo->rindex;
2010e645f47SMatthew Dillon
2029ed84223SSascha Wildner return (m);
2039ed84223SSascha Wildner }
2049ed84223SSascha Wildner
2059ed84223SSascha Wildner /*
2069ed84223SSascha Wildner * vke_txfifo_enqueue() - Add an mbuf to the transmit fifo.
2079ed84223SSascha Wildner */
2089ed84223SSascha Wildner static int
vke_txfifo_enqueue(struct vke_softc * sc,struct mbuf * m)2099ed84223SSascha Wildner vke_txfifo_enqueue(struct vke_softc *sc, struct mbuf *m)
2109ed84223SSascha Wildner {
2119ed84223SSascha Wildner fifo_t fifo = sc->sc_txfifo;
2129ed84223SSascha Wildner
2130e645f47SMatthew Dillon if (NETFIFOINDEX(fifo->windex + 1, sc) ==
2140e645f47SMatthew Dillon NETFIFOINDEX(fifo->rindex, sc)) {
2159ed84223SSascha Wildner return (-1);
2160e645f47SMatthew Dillon }
2179ed84223SSascha Wildner
2183351469cSAntonio Huete Jimenez fifo->array[NETFIFOINDEX(fifo->windex, sc)] = m;
2199ed84223SSascha Wildner cpu_sfence();
2209ed84223SSascha Wildner ++fifo->windex;
2219ed84223SSascha Wildner
2229ed84223SSascha Wildner return (0);
2239ed84223SSascha Wildner }
2249ed84223SSascha Wildner
2259ed84223SSascha Wildner /*
2269ed84223SSascha Wildner * vke_txfifo_dequeue() - Return next mbuf on the transmit fifo if one
2279ed84223SSascha Wildner * exists.
2289ed84223SSascha Wildner */
2299ed84223SSascha Wildner static struct mbuf *
vke_txfifo_dequeue(struct vke_softc * sc)2309ed84223SSascha Wildner vke_txfifo_dequeue(struct vke_softc *sc)
2319ed84223SSascha Wildner {
2329ed84223SSascha Wildner fifo_t fifo = sc->sc_txfifo;
2339ed84223SSascha Wildner struct mbuf *m;
2349ed84223SSascha Wildner
2353351469cSAntonio Huete Jimenez if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc))
2369ed84223SSascha Wildner return (NULL);
2379ed84223SSascha Wildner
2380e645f47SMatthew Dillon cpu_lfence();
2393351469cSAntonio Huete Jimenez m = fifo->array[NETFIFOINDEX(fifo->rindex, sc)];
2403351469cSAntonio Huete Jimenez fifo->array[NETFIFOINDEX(fifo->rindex, sc)] = NULL;
2410e645f47SMatthew Dillon cpu_sfence();
2429ed84223SSascha Wildner ++fifo->rindex;
2430e645f47SMatthew Dillon
2449ed84223SSascha Wildner return (m);
2459ed84223SSascha Wildner }
2469ed84223SSascha Wildner
2479ed84223SSascha Wildner static int
vke_txfifo_empty(struct vke_softc * sc)2489ed84223SSascha Wildner vke_txfifo_empty(struct vke_softc *sc)
2499ed84223SSascha Wildner {
2509ed84223SSascha Wildner fifo_t fifo = sc->sc_txfifo;
2519ed84223SSascha Wildner
2523351469cSAntonio Huete Jimenez if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc))
2539ed84223SSascha Wildner return (1);
2549ed84223SSascha Wildner return(0);
2559ed84223SSascha Wildner }
2569ed84223SSascha Wildner
2579ed84223SSascha Wildner /*
2589ed84223SSascha Wildner * vke_rxfifo_dequeue() - Return next mbuf on the receice fifo if one
2599ed84223SSascha Wildner * exists replacing it with newm which should point to a newly allocated
2609ed84223SSascha Wildner * mbuf.
2619ed84223SSascha Wildner */
2629ed84223SSascha Wildner static struct mbuf *
vke_rxfifo_dequeue(struct vke_softc * sc,struct mbuf * newm)2639ed84223SSascha Wildner vke_rxfifo_dequeue(struct vke_softc *sc, struct mbuf *newm)
2649ed84223SSascha Wildner {
2659ed84223SSascha Wildner fifo_t fifo = sc->sc_rxfifo;
2669ed84223SSascha Wildner struct mbuf *m;
2679ed84223SSascha Wildner
2683351469cSAntonio Huete Jimenez if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc))
2699ed84223SSascha Wildner return (NULL);
2709ed84223SSascha Wildner
2710e645f47SMatthew Dillon cpu_lfence();
2723351469cSAntonio Huete Jimenez m = fifo->array[NETFIFOINDEX(fifo->rindex, sc)];
2733351469cSAntonio Huete Jimenez fifo->array[NETFIFOINDEX(fifo->rindex, sc)] = newm;
2740e645f47SMatthew Dillon cpu_sfence();
2759ed84223SSascha Wildner ++fifo->rindex;
2760e645f47SMatthew Dillon
2779ed84223SSascha Wildner return (m);
2789ed84223SSascha Wildner }
2799ed84223SSascha Wildner
2809ed84223SSascha Wildner /*
2819ed84223SSascha Wildner * Return the next mbuf if available but do NOT remove it from the FIFO.
2829ed84223SSascha Wildner */
2839ed84223SSascha Wildner static struct mbuf *
vke_rxfifo_sniff(struct vke_softc * sc)2849ed84223SSascha Wildner vke_rxfifo_sniff(struct vke_softc *sc)
2859ed84223SSascha Wildner {
2869ed84223SSascha Wildner fifo_t fifo = sc->sc_rxfifo;
2879ed84223SSascha Wildner struct mbuf *m;
2889ed84223SSascha Wildner
2893351469cSAntonio Huete Jimenez if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc))
2909ed84223SSascha Wildner return (NULL);
2919ed84223SSascha Wildner
2929ed84223SSascha Wildner cpu_lfence();
2930e645f47SMatthew Dillon m = fifo->array[NETFIFOINDEX(fifo->rindex, sc)];
2940e645f47SMatthew Dillon
2959ed84223SSascha Wildner return (m);
2969ed84223SSascha Wildner }
2979ed84223SSascha Wildner
2989ed84223SSascha Wildner static void
vke_init(void * xsc)2999ed84223SSascha Wildner vke_init(void *xsc)
3009ed84223SSascha Wildner {
3019ed84223SSascha Wildner struct vke_softc *sc = xsc;
3029ed84223SSascha Wildner struct ifnet *ifp = &sc->arpcom.ac_if;
3033351469cSAntonio Huete Jimenez size_t ringsize = sc->sc_ringsize * sizeof(struct mbuf *);
3049ed84223SSascha Wildner int i;
3059ed84223SSascha Wildner
3069ed84223SSascha Wildner ASSERT_SERIALIZED(ifp->if_serializer);
3079ed84223SSascha Wildner
3089ed84223SSascha Wildner vke_stop(sc);
3099ed84223SSascha Wildner
3109ed84223SSascha Wildner ifp->if_flags |= IFF_RUNNING;
311f0a26983SSepherosa Ziehau ifsq_clr_oactive(ifq_get_subq_default(&ifp->if_snd));
3129ed84223SSascha Wildner
3133351469cSAntonio Huete Jimenez /*
3143351469cSAntonio Huete Jimenez * Allocate memory for FIFO structures and mbufs.
3153351469cSAntonio Huete Jimenez */
316c5cc7ccfSAntonio Huete Jimenez sc->sc_txfifo = kmalloc(sizeof(*sc->sc_txfifo),
317c5cc7ccfSAntonio Huete Jimenez M_DEVBUF, M_WAITOK | M_ZERO);
318c5cc7ccfSAntonio Huete Jimenez sc->sc_txfifo_done = kmalloc(sizeof(*sc->sc_txfifo_done),
319c5cc7ccfSAntonio Huete Jimenez M_DEVBUF, M_WAITOK | M_ZERO);
320c5cc7ccfSAntonio Huete Jimenez sc->sc_rxfifo = kmalloc(sizeof(*sc->sc_rxfifo),
321c5cc7ccfSAntonio Huete Jimenez M_DEVBUF, M_WAITOK | M_ZERO);
3220e645f47SMatthew Dillon sc->sc_txfifo->array = kmalloc(ringsize,
3230e645f47SMatthew Dillon M_DEVBUF, M_WAITOK | M_ZERO);
3240e645f47SMatthew Dillon sc->sc_txfifo_done->array = kmalloc(ringsize,
3250e645f47SMatthew Dillon M_DEVBUF, M_WAITOK | M_ZERO);
3260e645f47SMatthew Dillon sc->sc_rxfifo->array = kmalloc(ringsize,
3270e645f47SMatthew Dillon M_DEVBUF, M_WAITOK | M_ZERO);
3283351469cSAntonio Huete Jimenez
3293351469cSAntonio Huete Jimenez for (i = 0; i < sc->sc_ringsize; i++) {
330b5523eacSSascha Wildner sc->sc_rxfifo->array[i] = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR);
3319ed84223SSascha Wildner sc->sc_txfifo->array[i] = NULL;
3329ed84223SSascha Wildner sc->sc_txfifo_done->array[i] = NULL;
3339ed84223SSascha Wildner }
3349ed84223SSascha Wildner
3359ed84223SSascha Wildner sc->cotd_tx_exit = sc->cotd_rx_exit = VKE_COTD_RUN;
3369ed84223SSascha Wildner sc->cotd_tx = cothread_create(vke_tx_thread, vke_tx_intr, sc, "vke_tx");
3379ed84223SSascha Wildner sc->cotd_rx = cothread_create(vke_rx_thread, vke_rx_intr, sc, "vke_rx");
3389ed84223SSascha Wildner
3399ed84223SSascha Wildner if (sc->sc_addr != 0) {
3409ed84223SSascha Wildner in_addr_t addr, mask;
3419ed84223SSascha Wildner
3429ed84223SSascha Wildner addr = sc->sc_addr;
3439ed84223SSascha Wildner mask = sc->sc_mask;
3449ed84223SSascha Wildner
3459ed84223SSascha Wildner /*
3469ed84223SSascha Wildner * Make sure vkernel assigned
3479ed84223SSascha Wildner * address will not be added
3489ed84223SSascha Wildner * again.
3499ed84223SSascha Wildner */
3509ed84223SSascha Wildner sc->sc_addr = 0;
3519ed84223SSascha Wildner sc->sc_mask = 0;
3529ed84223SSascha Wildner
3539ed84223SSascha Wildner vke_init_addr(ifp, addr, mask);
3549ed84223SSascha Wildner }
3559ed84223SSascha Wildner
3569ed84223SSascha Wildner }
3579ed84223SSascha Wildner
3589ed84223SSascha Wildner /*
3599ed84223SSascha Wildner * Called from kernel.
3609ed84223SSascha Wildner *
3619ed84223SSascha Wildner * NOTE: We can't make any kernel callbacks while holding cothread lock
3629ed84223SSascha Wildner * because the cothread lock is not governed by the kernel scheduler
3639ed84223SSascha Wildner * (so mplock, tokens, etc will not be released).
3649ed84223SSascha Wildner */
3659ed84223SSascha Wildner static void
vke_start(struct ifnet * ifp,struct ifaltq_subque * ifsq)366f0a26983SSepherosa Ziehau vke_start(struct ifnet *ifp, struct ifaltq_subque *ifsq)
3679ed84223SSascha Wildner {
3689ed84223SSascha Wildner struct vke_softc *sc = ifp->if_softc;
3699ed84223SSascha Wildner struct mbuf *m;
3709ed84223SSascha Wildner cothread_t cotd = sc->cotd_tx;
3719ed84223SSascha Wildner int count;
3729ed84223SSascha Wildner
373f0a26983SSepherosa Ziehau ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq);
3749ed84223SSascha Wildner ASSERT_SERIALIZED(ifp->if_serializer);
3759ed84223SSascha Wildner
376f0a26983SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0 || ifsq_is_oactive(ifsq))
3779ed84223SSascha Wildner return;
3789ed84223SSascha Wildner
3799ed84223SSascha Wildner count = 0;
380ac9843a1SSepherosa Ziehau while ((m = ifsq_dequeue(ifsq)) != NULL) {
3819ed84223SSascha Wildner if (vke_txfifo_enqueue(sc, m) != -1) {
382c90aaf98SMatthew Dillon ETHER_BPF_MTAP(ifp, m);
3839ed84223SSascha Wildner if (count++ == VKE_CHUNK) {
3849ed84223SSascha Wildner cothread_lock(cotd, 0);
3859ed84223SSascha Wildner cothread_signal(cotd);
3869ed84223SSascha Wildner cothread_unlock(cotd, 0);
3879ed84223SSascha Wildner count = 0;
3889ed84223SSascha Wildner }
3899ed84223SSascha Wildner } else {
3909ed84223SSascha Wildner m_freem(m);
3919ed84223SSascha Wildner }
3929ed84223SSascha Wildner }
3939ed84223SSascha Wildner if (count) {
3949ed84223SSascha Wildner cothread_lock(cotd, 0);
3959ed84223SSascha Wildner cothread_signal(cotd);
3969ed84223SSascha Wildner cothread_unlock(cotd, 0);
3979ed84223SSascha Wildner }
3989ed84223SSascha Wildner }
3999ed84223SSascha Wildner
4009ed84223SSascha Wildner static int
vke_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data,struct ucred * cr)4019ed84223SSascha Wildner vke_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
4029ed84223SSascha Wildner {
4039ed84223SSascha Wildner struct vke_softc *sc = ifp->if_softc;
40470515437SMarkus Pfeiffer struct ifreq *ifr = (struct ifreq *)data;
4059ed84223SSascha Wildner int error = 0;
4069ed84223SSascha Wildner
4079ed84223SSascha Wildner ASSERT_SERIALIZED(ifp->if_serializer);
4089ed84223SSascha Wildner
4099ed84223SSascha Wildner switch (cmd) {
4109ed84223SSascha Wildner case SIOCSIFFLAGS:
4119ed84223SSascha Wildner if (ifp->if_flags & IFF_UP) {
4129ed84223SSascha Wildner if ((ifp->if_flags & IFF_RUNNING) == 0)
4139ed84223SSascha Wildner vke_init(sc);
4149ed84223SSascha Wildner } else {
4159ed84223SSascha Wildner if (ifp->if_flags & IFF_RUNNING)
4169ed84223SSascha Wildner vke_stop(sc);
4179ed84223SSascha Wildner }
4189ed84223SSascha Wildner break;
4199ed84223SSascha Wildner case SIOCGIFMEDIA:
4201e1c5facSSepherosa Ziehau case SIOCGIFXMEDIA:
4219ed84223SSascha Wildner case SIOCSIFMEDIA:
42270515437SMarkus Pfeiffer error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
4239ed84223SSascha Wildner break;
4249ed84223SSascha Wildner case SIOCGIFSTATUS: {
4259ed84223SSascha Wildner struct ifstat *ifs = (struct ifstat *)data;
4269ed84223SSascha Wildner int len;
4279ed84223SSascha Wildner
4289ed84223SSascha Wildner len = strlen(ifs->ascii);
4299ed84223SSascha Wildner if (len < sizeof(ifs->ascii)) {
4300e645f47SMatthew Dillon if (sc->sc_tap_unit >= 0) {
4310e645f47SMatthew Dillon ksnprintf(ifs->ascii + len,
4320e645f47SMatthew Dillon sizeof(ifs->ascii) - len,
4330e645f47SMatthew Dillon "\tBacked by tap%d\n",
4340e645f47SMatthew Dillon sc->sc_tap_unit);
4350e645f47SMatthew Dillon }
4369ed84223SSascha Wildner }
4379ed84223SSascha Wildner break;
4389ed84223SSascha Wildner }
4399ed84223SSascha Wildner case SIOCSIFADDR:
4409ed84223SSascha Wildner if (((struct ifaddr *)data)->ifa_addr->sa_family == AF_INET) {
4419ed84223SSascha Wildner /*
4429ed84223SSascha Wildner * If we are explicitly requested to change address,
4439ed84223SSascha Wildner * we should invalidate address/netmask passed in
4449ed84223SSascha Wildner * from vkernel command line.
4459ed84223SSascha Wildner */
4469ed84223SSascha Wildner sc->sc_addr = 0;
4479ed84223SSascha Wildner sc->sc_mask = 0;
4489ed84223SSascha Wildner }
4499ed84223SSascha Wildner /* FALL THROUGH */
4509ed84223SSascha Wildner default:
4519ed84223SSascha Wildner error = ether_ioctl(ifp, cmd, data);
4529ed84223SSascha Wildner break;
4539ed84223SSascha Wildner }
4549ed84223SSascha Wildner return error;
4559ed84223SSascha Wildner }
4569ed84223SSascha Wildner
4579ed84223SSascha Wildner static int
vke_stop(struct vke_softc * sc)4589ed84223SSascha Wildner vke_stop(struct vke_softc *sc)
4599ed84223SSascha Wildner {
4609ed84223SSascha Wildner struct ifnet *ifp = &sc->arpcom.ac_if;
4619ed84223SSascha Wildner int i;
4629ed84223SSascha Wildner
4639ed84223SSascha Wildner ASSERT_SERIALIZED(ifp->if_serializer);
4649ed84223SSascha Wildner
4659ed293e0SSepherosa Ziehau ifp->if_flags &= ~IFF_RUNNING;
466f0a26983SSepherosa Ziehau ifsq_clr_oactive(ifq_get_subq_default(&ifp->if_snd));
4679ed84223SSascha Wildner
4689ed84223SSascha Wildner if (sc) {
4699ed84223SSascha Wildner if (sc->cotd_tx) {
4709ed84223SSascha Wildner cothread_lock(sc->cotd_tx, 0);
4719ed84223SSascha Wildner if (sc->cotd_tx_exit == VKE_COTD_RUN)
4729ed84223SSascha Wildner sc->cotd_tx_exit = VKE_COTD_EXIT;
4739ed84223SSascha Wildner cothread_signal(sc->cotd_tx);
4749ed84223SSascha Wildner cothread_unlock(sc->cotd_tx, 0);
4759ed84223SSascha Wildner cothread_delete(&sc->cotd_tx);
4769ed84223SSascha Wildner }
4779ed84223SSascha Wildner if (sc->cotd_rx) {
4789ed84223SSascha Wildner cothread_lock(sc->cotd_rx, 0);
4799ed84223SSascha Wildner if (sc->cotd_rx_exit == VKE_COTD_RUN)
4809ed84223SSascha Wildner sc->cotd_rx_exit = VKE_COTD_EXIT;
4819ed84223SSascha Wildner cothread_signal(sc->cotd_rx);
4829ed84223SSascha Wildner cothread_unlock(sc->cotd_rx, 0);
4839ed84223SSascha Wildner cothread_delete(&sc->cotd_rx);
4849ed84223SSascha Wildner }
4859ed84223SSascha Wildner
4863351469cSAntonio Huete Jimenez for (i = 0; i < sc->sc_ringsize; i++) {
4879ed84223SSascha Wildner if (sc->sc_rxfifo && sc->sc_rxfifo->array[i]) {
4889ed84223SSascha Wildner m_freem(sc->sc_rxfifo->array[i]);
4899ed84223SSascha Wildner sc->sc_rxfifo->array[i] = NULL;
4909ed84223SSascha Wildner }
4919ed84223SSascha Wildner if (sc->sc_txfifo && sc->sc_txfifo->array[i]) {
4929ed84223SSascha Wildner m_freem(sc->sc_txfifo->array[i]);
4939ed84223SSascha Wildner sc->sc_txfifo->array[i] = NULL;
4949ed84223SSascha Wildner }
4959ed84223SSascha Wildner if (sc->sc_txfifo_done && sc->sc_txfifo_done->array[i]) {
4969ed84223SSascha Wildner m_freem(sc->sc_txfifo_done->array[i]);
4979ed84223SSascha Wildner sc->sc_txfifo_done->array[i] = NULL;
4989ed84223SSascha Wildner }
4999ed84223SSascha Wildner }
5009ed84223SSascha Wildner
5019ed84223SSascha Wildner if (sc->sc_txfifo) {
5023351469cSAntonio Huete Jimenez if (sc->sc_txfifo->array)
5033351469cSAntonio Huete Jimenez kfree(sc->sc_txfifo->array, M_DEVBUF);
5049ed84223SSascha Wildner kfree(sc->sc_txfifo, M_DEVBUF);
5059ed84223SSascha Wildner sc->sc_txfifo = NULL;
5069ed84223SSascha Wildner }
5079ed84223SSascha Wildner
5089ed84223SSascha Wildner if (sc->sc_txfifo_done) {
5093351469cSAntonio Huete Jimenez if (sc->sc_txfifo_done->array)
5103351469cSAntonio Huete Jimenez kfree(sc->sc_txfifo_done->array, M_DEVBUF);
5119ed84223SSascha Wildner kfree(sc->sc_txfifo_done, M_DEVBUF);
5129ed84223SSascha Wildner sc->sc_txfifo_done = NULL;
5139ed84223SSascha Wildner }
5149ed84223SSascha Wildner
5159ed84223SSascha Wildner if (sc->sc_rxfifo) {
5163351469cSAntonio Huete Jimenez if (sc->sc_rxfifo->array)
5173351469cSAntonio Huete Jimenez kfree(sc->sc_rxfifo->array, M_DEVBUF);
5189ed84223SSascha Wildner kfree(sc->sc_rxfifo, M_DEVBUF);
5199ed84223SSascha Wildner sc->sc_rxfifo = NULL;
5209ed84223SSascha Wildner }
5219ed84223SSascha Wildner }
5229ed84223SSascha Wildner
5239ed84223SSascha Wildner
5249ed84223SSascha Wildner return 0;
5259ed84223SSascha Wildner }
5269ed84223SSascha Wildner
5279ed84223SSascha Wildner /*
5289ed84223SSascha Wildner * vke_rx_intr() is the interrupt function for the receive cothread.
5299ed84223SSascha Wildner */
5309ed84223SSascha Wildner static void
vke_rx_intr(cothread_t cotd)5319ed84223SSascha Wildner vke_rx_intr(cothread_t cotd)
5329ed84223SSascha Wildner {
5339ed84223SSascha Wildner struct mbuf *m;
5349ed84223SSascha Wildner struct mbuf *nm;
5359ed84223SSascha Wildner struct vke_softc *sc = cotd->arg;
5369ed84223SSascha Wildner struct ifnet *ifp = &sc->arpcom.ac_if;
5379ed84223SSascha Wildner static int count = 0;
5389ed84223SSascha Wildner
5399ed84223SSascha Wildner ifnet_serialize_all(ifp);
5409ed84223SSascha Wildner cothread_lock(cotd, 0);
5419ed84223SSascha Wildner
5429ed84223SSascha Wildner if (sc->cotd_rx_exit != VKE_COTD_RUN) {
5439ed84223SSascha Wildner cothread_unlock(cotd, 0);
5449ed84223SSascha Wildner ifnet_deserialize_all(ifp);
5459ed84223SSascha Wildner return;
5469ed84223SSascha Wildner }
547a9844950SMatthew Dillon if (sc->cotd_ipackets) {
548a9844950SMatthew Dillon IFNET_STAT_INC(ifp, ipackets, 1);
549a9844950SMatthew Dillon sc->cotd_ipackets = 0;
550a9844950SMatthew Dillon }
5519ed84223SSascha Wildner cothread_unlock(cotd, 0);
5529ed84223SSascha Wildner
5539ed84223SSascha Wildner while ((m = vke_rxfifo_sniff(sc)) != NULL) {
554b5523eacSSascha Wildner nm = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
5559ed84223SSascha Wildner if (nm) {
5569ed84223SSascha Wildner vke_rxfifo_dequeue(sc, nm);
55773029d08SFranco Fichtner ifp->if_input(ifp, m, NULL, -1);
5589ed84223SSascha Wildner if (count++ == VKE_CHUNK) {
5599ed84223SSascha Wildner cothread_lock(cotd, 0);
5609ed84223SSascha Wildner cothread_signal(cotd);
5619ed84223SSascha Wildner cothread_unlock(cotd, 0);
5629ed84223SSascha Wildner count = 0;
5639ed84223SSascha Wildner }
5649ed84223SSascha Wildner } else {
5659ed84223SSascha Wildner vke_rxfifo_dequeue(sc, m);
5669ed84223SSascha Wildner }
5679ed84223SSascha Wildner }
5689ed84223SSascha Wildner
5699ed84223SSascha Wildner if (count) {
5709ed84223SSascha Wildner cothread_lock(cotd, 0);
5719ed84223SSascha Wildner cothread_signal(cotd);
5729ed84223SSascha Wildner cothread_unlock(cotd, 0);
5739ed84223SSascha Wildner }
5749ed84223SSascha Wildner ifnet_deserialize_all(ifp);
5759ed84223SSascha Wildner }
5769ed84223SSascha Wildner
5779ed84223SSascha Wildner /*
5789ed84223SSascha Wildner * vke_tx_intr() is the interrupt function for the transmit cothread.
5799ed84223SSascha Wildner * Calls vke_start() to handle processing transmit mbufs.
5809ed84223SSascha Wildner */
5819ed84223SSascha Wildner static void
vke_tx_intr(cothread_t cotd)5829ed84223SSascha Wildner vke_tx_intr(cothread_t cotd)
5839ed84223SSascha Wildner {
5849ed84223SSascha Wildner struct vke_softc *sc = cotd->arg;
5859ed84223SSascha Wildner struct ifnet *ifp = &sc->arpcom.ac_if;
5869ed84223SSascha Wildner struct mbuf *m;
5879ed84223SSascha Wildner
5889ed84223SSascha Wildner ifnet_serialize_all(ifp);
5899ed84223SSascha Wildner cothread_lock(cotd, 0);
5909ed84223SSascha Wildner if (sc->cotd_tx_exit != VKE_COTD_RUN) {
5919ed84223SSascha Wildner cothread_unlock(cotd, 0);
5929ed84223SSascha Wildner ifnet_deserialize_all(ifp);
5939ed84223SSascha Wildner return;
5949ed84223SSascha Wildner }
595a9844950SMatthew Dillon if (sc->cotd_opackets) {
596a9844950SMatthew Dillon IFNET_STAT_INC(ifp, opackets, 1);
597a9844950SMatthew Dillon sc->cotd_opackets = 0;
598a9844950SMatthew Dillon }
599a9844950SMatthew Dillon if (sc->cotd_oerrors) {
600a9844950SMatthew Dillon IFNET_STAT_INC(ifp, oerrors, 1);
601a9844950SMatthew Dillon sc->cotd_oerrors = 0;
602a9844950SMatthew Dillon }
6039ed84223SSascha Wildner cothread_unlock(cotd, 0);
6049ed84223SSascha Wildner
6059ed84223SSascha Wildner /*
6069ed84223SSascha Wildner * Free TX mbufs that have been processed before starting new
6079ed84223SSascha Wildner * ones going to be pipeline friendly.
6089ed84223SSascha Wildner */
6099ed84223SSascha Wildner while ((m = vke_txfifo_done_dequeue(sc, NULL)) != NULL) {
6109ed84223SSascha Wildner m_freem(m);
6119ed84223SSascha Wildner }
6129ed84223SSascha Wildner
6139ed84223SSascha Wildner if ((ifp->if_flags & IFF_RUNNING) == 0)
614f0a26983SSepherosa Ziehau if_devstart(ifp);
6159ed84223SSascha Wildner
6169ed84223SSascha Wildner ifnet_deserialize_all(ifp);
6179ed84223SSascha Wildner }
6189ed84223SSascha Wildner
6199ed84223SSascha Wildner /*
6209ed84223SSascha Wildner * vke_rx_thread() is the body of the receive cothread.
621a9844950SMatthew Dillon *
622a9844950SMatthew Dillon * WARNING! THIS IS A COTHREAD WHICH HAS NO PER-CPU GLOBALDATA!!!!!
6239ed84223SSascha Wildner */
6249ed84223SSascha Wildner static void
vke_rx_thread(cothread_t cotd)6259ed84223SSascha Wildner vke_rx_thread(cothread_t cotd)
6269ed84223SSascha Wildner {
6279ed84223SSascha Wildner struct mbuf *m;
6289ed84223SSascha Wildner struct vke_softc *sc = cotd->arg;
6299ed84223SSascha Wildner struct ifnet *ifp = &sc->arpcom.ac_if;
6309ed84223SSascha Wildner fifo_t fifo = sc->sc_rxfifo;
6319ed84223SSascha Wildner fd_set fdset;
6329ed84223SSascha Wildner struct timeval tv;
6339ed84223SSascha Wildner int count;
6349ed84223SSascha Wildner int n;
6350e645f47SMatthew Dillon int r;
6369ed84223SSascha Wildner
6379ed84223SSascha Wildner /* Select timeout cannot be infinite since we need to check for
6389ed84223SSascha Wildner * the exit flag sc->cotd_rx_exit.
6399ed84223SSascha Wildner */
6409ed84223SSascha Wildner tv.tv_sec = 0;
6419ed84223SSascha Wildner tv.tv_usec = 500000;
6429ed84223SSascha Wildner
6439ed84223SSascha Wildner FD_ZERO(&fdset);
6449ed84223SSascha Wildner count = 0;
6459ed84223SSascha Wildner
6469ed84223SSascha Wildner while (sc->cotd_rx_exit == VKE_COTD_RUN) {
6479ed84223SSascha Wildner /*
6489ed84223SSascha Wildner * Wait for the RX FIFO to be loaded with
6499ed84223SSascha Wildner * empty mbufs.
6509ed84223SSascha Wildner */
6513351469cSAntonio Huete Jimenez if (NETFIFOINDEX(fifo->windex + 1, sc) ==
6523351469cSAntonio Huete Jimenez NETFIFOINDEX(fifo->rindex, sc)) {
6539ed84223SSascha Wildner usleep(20000);
6549ed84223SSascha Wildner continue;
6559ed84223SSascha Wildner }
6569ed84223SSascha Wildner
6579ed84223SSascha Wildner /*
6589ed84223SSascha Wildner * Load data into the rx fifo
6599ed84223SSascha Wildner */
6600e645f47SMatthew Dillon cpu_lfence();
6613351469cSAntonio Huete Jimenez m = fifo->array[NETFIFOINDEX(fifo->windex, sc)];
6620e645f47SMatthew Dillon if (m == NULL) {
6630e645f47SMatthew Dillon fprintf(stderr,
6640e645f47SMatthew Dillon VKE_DEVNAME "%d: NULL rxring mbuf\n",
6650e645f47SMatthew Dillon sc->sc_unit);
666cc6703edSzrj *(volatile int *)0 = 1;
6670e645f47SMatthew Dillon }
6689ed84223SSascha Wildner n = read(sc->sc_fd, mtod(m, void *), MCLBYTES);
6699ed84223SSascha Wildner if (n > 0) {
670a9844950SMatthew Dillon /* no mycpu in cothread */
671a9844950SMatthew Dillon /*IFNET_STAT_INC(ifp, ipackets, 1);*/
672a9844950SMatthew Dillon ++sc->cotd_ipackets;
6739ed84223SSascha Wildner m->m_pkthdr.rcvif = ifp;
6749ed84223SSascha Wildner m->m_pkthdr.len = m->m_len = n;
6759ed84223SSascha Wildner cpu_sfence();
6769ed84223SSascha Wildner ++fifo->windex;
6779ed84223SSascha Wildner if (count++ == VKE_CHUNK) {
6789ed84223SSascha Wildner cothread_intr(cotd);
6799ed84223SSascha Wildner count = 0;
6809ed84223SSascha Wildner }
6819ed84223SSascha Wildner } else {
6829ed84223SSascha Wildner if (count) {
6839ed84223SSascha Wildner cothread_intr(cotd);
6849ed84223SSascha Wildner count = 0;
6859ed84223SSascha Wildner }
6869ed84223SSascha Wildner FD_SET(sc->sc_fd, &fdset);
6870e645f47SMatthew Dillon r = select(sc->sc_fd + 1, &fdset, NULL, NULL, &tv);
6880e645f47SMatthew Dillon if (r == -1) {
689a9844950SMatthew Dillon fprintf(stderr,
690a9844950SMatthew Dillon VKE_DEVNAME "%d: select failed for "
6919ed84223SSascha Wildner "TAP device\n", sc->sc_unit);
6929ed84223SSascha Wildner usleep(1000000);
6939ed84223SSascha Wildner }
6949ed84223SSascha Wildner }
6959ed84223SSascha Wildner }
6969ed84223SSascha Wildner cpu_sfence();
6979ed84223SSascha Wildner sc->cotd_rx_exit = VKE_COTD_DEAD;
6989ed84223SSascha Wildner }
6999ed84223SSascha Wildner
7009ed84223SSascha Wildner /*
7019ed84223SSascha Wildner * vke_tx_thread() is the body of the transmit cothread.
702a9844950SMatthew Dillon *
703a9844950SMatthew Dillon * WARNING! THIS IS A COTHREAD WHICH HAS NO PER-CPU GLOBALDATA!!!!!
7049ed84223SSascha Wildner */
7059ed84223SSascha Wildner static void
vke_tx_thread(cothread_t cotd)7069ed84223SSascha Wildner vke_tx_thread(cothread_t cotd)
7079ed84223SSascha Wildner {
7089ed84223SSascha Wildner struct mbuf *m;
7099ed84223SSascha Wildner struct vke_softc *sc = cotd->arg;
710171a58dfSSascha Wildner /*struct ifnet *ifp = &sc->arpcom.ac_if;*/
7119ed84223SSascha Wildner int count = 0;
7129ed84223SSascha Wildner
7139ed84223SSascha Wildner while (sc->cotd_tx_exit == VKE_COTD_RUN) {
7149ed84223SSascha Wildner /*
7159ed84223SSascha Wildner * Write outgoing packets to the TAP interface
7169ed84223SSascha Wildner */
7179ed84223SSascha Wildner m = vke_txfifo_dequeue(sc);
7189ed84223SSascha Wildner if (m) {
7199ed84223SSascha Wildner if (m->m_pkthdr.len <= MCLBYTES) {
7209ed84223SSascha Wildner m_copydata(m, 0, m->m_pkthdr.len, sc->sc_txbuf);
7219ed84223SSascha Wildner sc->sc_txbuf_len = m->m_pkthdr.len;
7229ed84223SSascha Wildner
7239ed84223SSascha Wildner if (write(sc->sc_fd, sc->sc_txbuf,
7249ed84223SSascha Wildner sc->sc_txbuf_len) < 0) {
725a9844950SMatthew Dillon /* no mycpu in cothread */
726a9844950SMatthew Dillon /*IFNET_STAT_INC(ifp, oerrors, 1);*/
727a9844950SMatthew Dillon ++sc->cotd_oerrors;
7289ed84223SSascha Wildner } else {
729a9844950SMatthew Dillon /* no mycpu in cothread */
730a9844950SMatthew Dillon /*IFNET_STAT_INC(ifp, opackets, 1);*/
731a9844950SMatthew Dillon ++sc->cotd_opackets;
7329ed84223SSascha Wildner }
7339ed84223SSascha Wildner }
7349ed84223SSascha Wildner if (count++ == VKE_CHUNK) {
7359ed84223SSascha Wildner cothread_intr(cotd);
7369ed84223SSascha Wildner count = 0;
7379ed84223SSascha Wildner }
7389ed84223SSascha Wildner vke_txfifo_done_enqueue(sc, m);
7399ed84223SSascha Wildner } else {
7409ed84223SSascha Wildner if (count) {
7419ed84223SSascha Wildner cothread_intr(cotd);
7429ed84223SSascha Wildner count = 0;
7439ed84223SSascha Wildner }
7449ed84223SSascha Wildner cothread_lock(cotd, 1);
7459ed84223SSascha Wildner if (vke_txfifo_empty(sc))
7469ed84223SSascha Wildner cothread_wait(cotd);
7479ed84223SSascha Wildner cothread_unlock(cotd, 1);
7489ed84223SSascha Wildner }
7499ed84223SSascha Wildner }
7509ed84223SSascha Wildner cpu_sfence();
7519ed84223SSascha Wildner sc->cotd_tx_exit = VKE_COTD_DEAD;
7529ed84223SSascha Wildner }
7539ed84223SSascha Wildner
7541e1c5facSSepherosa Ziehau static void
vke_ifmedia_add(struct vke_softc * sc,int mword)7551e1c5facSSepherosa Ziehau vke_ifmedia_add(struct vke_softc *sc, int mword)
7561e1c5facSSepherosa Ziehau {
7571e1c5facSSepherosa Ziehau ifmedia_add(&sc->sc_media, IFM_ETHER | mword, 0, NULL);
7581e1c5facSSepherosa Ziehau }
7591e1c5facSSepherosa Ziehau
7601e1c5facSSepherosa Ziehau static void
vke_ifmedia_addfdx(struct vke_softc * sc,int mword)7611e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(struct vke_softc *sc, int mword)
7621e1c5facSSepherosa Ziehau {
763*57e25d68SSascha Wildner vke_ifmedia_add(sc, mword | IFM_FDX);
7641e1c5facSSepherosa Ziehau }
7651e1c5facSSepherosa Ziehau
7669ed84223SSascha Wildner static int
vke_attach(const struct vknetif_info * info,int unit)7679ed84223SSascha Wildner vke_attach(const struct vknetif_info *info, int unit)
7689ed84223SSascha Wildner {
7699ed84223SSascha Wildner struct vke_softc *sc;
7709ed84223SSascha Wildner struct ifnet *ifp;
7719ed84223SSascha Wildner struct tapinfo tapinfo;
7729ed84223SSascha Wildner uint8_t enaddr[ETHER_ADDR_LEN];
7733351469cSAntonio Huete Jimenez int nmbufs;
7749ed84223SSascha Wildner int fd;
7759ed84223SSascha Wildner
7769ed84223SSascha Wildner KKASSERT(info->tap_fd >= 0);
7779ed84223SSascha Wildner fd = info->tap_fd;
7789ed84223SSascha Wildner
77986d2b040SAntonio Huete Jimenez if (info->enaddr) {
780b3a6732eSMatthew Dillon /*
781b3a6732eSMatthew Dillon * enaddr is supplied
782b3a6732eSMatthew Dillon */
78386d2b040SAntonio Huete Jimenez bcopy(info->enaddr, enaddr, ETHER_ADDR_LEN);
784b3a6732eSMatthew Dillon } else {
7859ed84223SSascha Wildner /*
7869ed84223SSascha Wildner * This is only a TAP device if tap_unit is non-zero. If
7879ed84223SSascha Wildner * connecting to a virtual socket we generate a unique MAC.
788b3a6732eSMatthew Dillon *
789b3a6732eSMatthew Dillon * WARNING: enaddr[0] bit 0 is the multicast bit, when
790b3a6732eSMatthew Dillon * randomizing enaddr[] just leave the first
791b3a6732eSMatthew Dillon * two bytes 00 00 for now.
7929ed84223SSascha Wildner */
793b3a6732eSMatthew Dillon bzero(enaddr, sizeof(enaddr));
7949ed84223SSascha Wildner if (info->tap_unit >= 0) {
7959ed84223SSascha Wildner if (ioctl(fd, TAPGIFINFO, &tapinfo) < 0) {
7969ed84223SSascha Wildner kprintf(VKE_DEVNAME "%d: ioctl(TAPGIFINFO) "
7979ed84223SSascha Wildner "failed: %s\n", unit, strerror(errno));
7989ed84223SSascha Wildner return ENXIO;
7999ed84223SSascha Wildner }
8009ed84223SSascha Wildner
8019ed84223SSascha Wildner if (ioctl(fd, SIOCGIFADDR, enaddr) < 0) {
8029ed84223SSascha Wildner kprintf(VKE_DEVNAME "%d: ioctl(SIOCGIFADDR) "
8039ed84223SSascha Wildner "failed: %s\n", unit, strerror(errno));
8049ed84223SSascha Wildner return ENXIO;
8059ed84223SSascha Wildner }
8069ed84223SSascha Wildner } else {
8079ed84223SSascha Wildner int fd = open("/dev/urandom", O_RDONLY);
8089ed84223SSascha Wildner if (fd >= 0) {
8099ed84223SSascha Wildner read(fd, enaddr + 2, 4);
8109ed84223SSascha Wildner close(fd);
8119ed84223SSascha Wildner }
8129ed84223SSascha Wildner enaddr[4] = (int)getpid() >> 8;
8139ed84223SSascha Wildner enaddr[5] = (int)getpid() & 255;
8149ed84223SSascha Wildner
8159ed84223SSascha Wildner }
8169ed84223SSascha Wildner enaddr[1] += 1;
817b3a6732eSMatthew Dillon }
818b3a6732eSMatthew Dillon if (ETHER_IS_MULTICAST(enaddr)) {
819b3a6732eSMatthew Dillon kprintf(VKE_DEVNAME "%d: illegal MULTICAST ether mac!\n", unit);
820b3a6732eSMatthew Dillon return ENXIO;
821b3a6732eSMatthew Dillon }
8229ed84223SSascha Wildner
8239ed84223SSascha Wildner sc = kmalloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
8249ed84223SSascha Wildner
8259ed84223SSascha Wildner sc->sc_txbuf = kmalloc(MCLBYTES, M_DEVBUF, M_WAITOK);
8269ed84223SSascha Wildner sc->sc_fd = fd;
8279ed84223SSascha Wildner sc->sc_unit = unit;
8289ed84223SSascha Wildner sc->sc_tap_unit = info->tap_unit;
8299ed84223SSascha Wildner sc->sc_addr = info->netif_addr;
8309ed84223SSascha Wildner sc->sc_mask = info->netif_mask;
8319ed84223SSascha Wildner
83233c27d6cSAntonio Huete Jimenez if (vke_max_ringsize == 0) {
8333351469cSAntonio Huete Jimenez nmbufs = nmbclusters / (NetifNum * 2);
83433c27d6cSAntonio Huete Jimenez sc->sc_ringsize = LOW_POW_2(nmbufs);
83533c27d6cSAntonio Huete Jimenez if (sc->sc_ringsize > VKE_DEFAULT_RINGSIZE)
83633c27d6cSAntonio Huete Jimenez sc->sc_ringsize = VKE_DEFAULT_RINGSIZE;
83733c27d6cSAntonio Huete Jimenez } else if (vke_max_ringsize >= VKE_CHUNK) { /* Tunable specified */
83833c27d6cSAntonio Huete Jimenez sc->sc_ringsize = LOW_POW_2(vke_max_ringsize);
83933c27d6cSAntonio Huete Jimenez } else {
84033c27d6cSAntonio Huete Jimenez sc->sc_ringsize = LOW_POW_2(VKE_CHUNK);
84133c27d6cSAntonio Huete Jimenez }
8423351469cSAntonio Huete Jimenez
8439ed84223SSascha Wildner ifp = &sc->arpcom.ac_if;
8449ed84223SSascha Wildner if_initname(ifp, VKE_DEVNAME, sc->sc_unit);
8459ed84223SSascha Wildner
8469ed84223SSascha Wildner /* NB: after if_initname() */
8479ed84223SSascha Wildner sysctl_ctx_init(&sc->sc_sysctl_ctx);
8489ed84223SSascha Wildner sc->sc_sysctl_tree = SYSCTL_ADD_NODE(&sc->sc_sysctl_ctx,
8499ed84223SSascha Wildner SYSCTL_STATIC_CHILDREN(_hw),
8509ed84223SSascha Wildner OID_AUTO, ifp->if_xname,
8519ed84223SSascha Wildner CTLFLAG_RD, 0, "");
8529ed84223SSascha Wildner if (sc->sc_sysctl_tree == NULL) {
8539ed84223SSascha Wildner kprintf(VKE_DEVNAME "%d: can't add sysctl node\n", unit);
8549ed84223SSascha Wildner } else {
8559ed84223SSascha Wildner SYSCTL_ADD_INT(&sc->sc_sysctl_ctx,
8569ed84223SSascha Wildner SYSCTL_CHILDREN(sc->sc_sysctl_tree),
8579ed84223SSascha Wildner OID_AUTO, "tap_unit",
8589ed84223SSascha Wildner CTLFLAG_RD, &sc->sc_tap_unit, 0,
8599ed84223SSascha Wildner "Backend tap(4) unit");
8609ed84223SSascha Wildner }
8619ed84223SSascha Wildner
8629ed84223SSascha Wildner ifp->if_softc = sc;
8639ed84223SSascha Wildner ifp->if_ioctl = vke_ioctl;
8649ed84223SSascha Wildner ifp->if_start = vke_start;
8659ed84223SSascha Wildner ifp->if_init = vke_init;
8669ed84223SSascha Wildner ifp->if_mtu = tapinfo.mtu;
8679ed84223SSascha Wildner ifp->if_baudrate = tapinfo.baudrate;
8689ed84223SSascha Wildner ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
8699ed84223SSascha Wildner ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
8709ed84223SSascha Wildner ifq_set_ready(&ifp->if_snd);
8719ed84223SSascha Wildner
87270515437SMarkus Pfeiffer ifmedia_init(&sc->sc_media, 0, vke_media_change, vke_media_status);
87370515437SMarkus Pfeiffer /* We support as many media types as we please for
87470515437SMarkus Pfeiffer debugging purposes */
8751e1c5facSSepherosa Ziehau vke_ifmedia_add(sc, IFM_10_T);
8761e1c5facSSepherosa Ziehau vke_ifmedia_add(sc, IFM_10_T);
8771e1c5facSSepherosa Ziehau vke_ifmedia_add(sc, IFM_10_2);
8781e1c5facSSepherosa Ziehau vke_ifmedia_add(sc, IFM_10_5);
8791e1c5facSSepherosa Ziehau vke_ifmedia_add(sc, IFM_100_TX);
8801e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_100_TX);
8811e1c5facSSepherosa Ziehau vke_ifmedia_add(sc, IFM_100_FX);
8821e1c5facSSepherosa Ziehau vke_ifmedia_add(sc, IFM_100_T4);
8831e1c5facSSepherosa Ziehau vke_ifmedia_add(sc, IFM_100_VG);
8841e1c5facSSepherosa Ziehau vke_ifmedia_add(sc, IFM_100_T2);
8851e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_1000_SX);
8861e1c5facSSepherosa Ziehau vke_ifmedia_add(sc, IFM_10_STP);
8871e1c5facSSepherosa Ziehau vke_ifmedia_add(sc, IFM_10_FL);
8881e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_1000_LX);
8891e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_1000_CX);
8901e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_1000_T);
8911e1c5facSSepherosa Ziehau vke_ifmedia_add(sc, IFM_HPNA_1);
8921e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_10G_LR);
8931e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_10G_SR);
8941e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_10G_CX4);
8951e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_2500_SX);
8961e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_10G_TWINAX);
8971e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_10G_TWINAX_LONG);
8981e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_10G_LRM);
8991e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_10G_T);
9001e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_40G_CR4);
9011e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_40G_SR4);
9021e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_40G_LR4);
9031e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_1000_KX);
9041e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_10G_KX4);
9051e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_10G_KR);
9061e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_10G_CR1);
9071e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_20G_KR2);
9081e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_2500_KX);
9091e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_2500_T);
9101e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_5000_T);
9111e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_50G_PCIE);
9121e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_25G_PCIE);
9131e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_1000_SGMII);
9141e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_10G_SFI);
9151e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_40G_XLPPI);
9161e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_1000_CX_SGMII);
9171e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_40G_KR4);
9181e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_10G_ER);
9191e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_100G_CR4);
9201e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_100G_SR4);
9211e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_100G_KR4);
9221e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_100G_LR4);
9231e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_56G_R4);
9241e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_100_T);
9251e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_25G_CR);
9261e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_25G_KR);
9271e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_25G_SR);
9281e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_50G_CR2);
9291e1c5facSSepherosa Ziehau vke_ifmedia_addfdx(sc, IFM_50G_KR2);
9301e1c5facSSepherosa Ziehau vke_ifmedia_add(sc, IFM_AUTO);
93170515437SMarkus Pfeiffer
93270515437SMarkus Pfeiffer ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
93370515437SMarkus Pfeiffer
93470515437SMarkus Pfeiffer ifp->if_link_state = LINK_STATE_UP;
9359ed84223SSascha Wildner
9369ed84223SSascha Wildner ether_ifattach(ifp, enaddr, NULL);
9379ed84223SSascha Wildner
9389ed84223SSascha Wildner if (bootverbose && sc->sc_addr != 0) {
9399ed84223SSascha Wildner if_printf(ifp, "pre-configured "
9403351469cSAntonio Huete Jimenez "address 0x%08x, netmask 0x%08x, %d mbuf clusters\n",
9413351469cSAntonio Huete Jimenez ntohl(sc->sc_addr), ntohl(sc->sc_mask), sc->sc_ringsize);
9429ed84223SSascha Wildner }
9439ed84223SSascha Wildner
9449ed84223SSascha Wildner return 0;
9459ed84223SSascha Wildner }
9469ed84223SSascha Wildner
9479ed84223SSascha Wildner static int
vke_init_addr(struct ifnet * ifp,in_addr_t addr,in_addr_t mask)9489ed84223SSascha Wildner vke_init_addr(struct ifnet *ifp, in_addr_t addr, in_addr_t mask)
9499ed84223SSascha Wildner {
9509ed84223SSascha Wildner struct ifaliasreq ifra;
9519ed84223SSascha Wildner struct sockaddr_in *sin;
9529ed84223SSascha Wildner int ret;
9539ed84223SSascha Wildner
9549ed84223SSascha Wildner ASSERT_SERIALIZED(ifp->if_serializer);
9559ed84223SSascha Wildner
9569ed84223SSascha Wildner if (bootverbose) {
9579ed84223SSascha Wildner if_printf(ifp, "add pre-configured "
9589ed84223SSascha Wildner "address 0x%08x, netmask 0x%08x\n",
9599ed84223SSascha Wildner ntohl(addr), ntohl(mask));
9609ed84223SSascha Wildner }
9619ed84223SSascha Wildner
9629ed84223SSascha Wildner bzero(&ifra, sizeof(ifra));
9639ed84223SSascha Wildner
9649ed84223SSascha Wildner /* NB: no need to set ifaliasreq.ifra_name */
9659ed84223SSascha Wildner
9669ed84223SSascha Wildner sin = (struct sockaddr_in *)&ifra.ifra_addr;
9679ed84223SSascha Wildner sin->sin_family = AF_INET;
9689ed84223SSascha Wildner sin->sin_len = sizeof(*sin);
9699ed84223SSascha Wildner sin->sin_addr.s_addr = addr;
9709ed84223SSascha Wildner
9719ed84223SSascha Wildner if (mask != 0) {
9729ed84223SSascha Wildner sin = (struct sockaddr_in *)&ifra.ifra_mask;
9739ed84223SSascha Wildner sin->sin_len = sizeof(*sin);
9749ed84223SSascha Wildner sin->sin_addr.s_addr = mask;
9759ed84223SSascha Wildner }
9769ed84223SSascha Wildner
9779ed84223SSascha Wildner /*
9789ed84223SSascha Wildner * Temporarily release serializer, in_control() will hold
9799ed84223SSascha Wildner * it again before calling ifnet.if_ioctl().
9809ed84223SSascha Wildner */
9819ed84223SSascha Wildner ifnet_deserialize_all(ifp);
9822501b0eaSSepherosa Ziehau ret = in_control(SIOCAIFADDR, (caddr_t)&ifra, ifp, NULL);
9839ed84223SSascha Wildner ifnet_serialize_all(ifp);
9849ed84223SSascha Wildner
9859ed84223SSascha Wildner return ret;
9869ed84223SSascha Wildner }
98770515437SMarkus Pfeiffer
vke_media_change(struct ifnet * ifp)98870515437SMarkus Pfeiffer static int vke_media_change(struct ifnet *ifp)
98970515437SMarkus Pfeiffer {
99070515437SMarkus Pfeiffer /* ignored */
99170515437SMarkus Pfeiffer return(0);
99270515437SMarkus Pfeiffer }
99370515437SMarkus Pfeiffer
vke_media_status(struct ifnet * ifp,struct ifmediareq * imr)99470515437SMarkus Pfeiffer static void vke_media_status(struct ifnet *ifp, struct ifmediareq *imr)
99570515437SMarkus Pfeiffer {
99670515437SMarkus Pfeiffer struct vke_softc *sc = (struct vke_softc *)ifp->if_softc;
99770515437SMarkus Pfeiffer
99870515437SMarkus Pfeiffer imr->ifm_status = IFM_AVALID;
99970515437SMarkus Pfeiffer imr->ifm_status |= IFM_ACTIVE;
100070515437SMarkus Pfeiffer
100170515437SMarkus Pfeiffer if(sc->sc_media.ifm_cur) {
100270515437SMarkus Pfeiffer if(sc->sc_media.ifm_cur->ifm_media == IFM_ETHER) {
100370515437SMarkus Pfeiffer imr->ifm_active = IFM_ETHER | IFM_1000_T | IFM_FDX;
100470515437SMarkus Pfeiffer } else {
100570515437SMarkus Pfeiffer imr->ifm_active = sc->sc_media.ifm_cur->ifm_media;
100670515437SMarkus Pfeiffer }
100770515437SMarkus Pfeiffer } else {
100870515437SMarkus Pfeiffer imr->ifm_active = IFM_ETHER | IFM_1000_T | IFM_FDX;
100970515437SMarkus Pfeiffer }
101070515437SMarkus Pfeiffer }
1011