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> 529ed84223SSascha Wildner #include <net/ifq_var.h> 539ed84223SSascha Wildner 549ed84223SSascha Wildner #include <netinet/in_var.h> 559ed84223SSascha Wildner 569ed84223SSascha Wildner #include <sys/stat.h> 579ed84223SSascha Wildner #include <net/tap/if_tap.h> 589ed84223SSascha Wildner #include <err.h> 599ed84223SSascha Wildner #include <errno.h> 609ed84223SSascha Wildner #include <stdio.h> 619ed84223SSascha Wildner #include <string.h> 629ed84223SSascha Wildner #include <unistd.h> 639ed84223SSascha Wildner #include <fcntl.h> 649ed84223SSascha Wildner 659ed84223SSascha Wildner #define VKE_DEVNAME "vke" 669ed84223SSascha Wildner 679ed84223SSascha Wildner #define VKE_CHUNK 8 /* number of mbufs to queue before interrupting */ 689ed84223SSascha Wildner 693351469cSAntonio Huete Jimenez #define NETFIFOINDEX(u, sc) ((u) & ((sc)->sc_ringsize - 1)) 709ed84223SSascha Wildner 719ed84223SSascha Wildner #define VKE_COTD_RUN 0 729ed84223SSascha Wildner #define VKE_COTD_EXIT 1 739ed84223SSascha Wildner #define VKE_COTD_DEAD 2 749ed84223SSascha Wildner 759ed84223SSascha Wildner struct vke_fifo { 763351469cSAntonio Huete Jimenez struct mbuf **array; 779ed84223SSascha Wildner int rindex; 789ed84223SSascha Wildner int windex; 799ed84223SSascha Wildner }; 809ed84223SSascha Wildner typedef struct vke_fifo *fifo_t; 819ed84223SSascha Wildner 82*33c27d6cSAntonio Huete Jimenez /* Default value for a long time */ 83*33c27d6cSAntonio Huete Jimenez #define VKE_DEFAULT_RINGSIZE 256 84*33c27d6cSAntonio Huete Jimenez static int vke_max_ringsize = 0; 85*33c27d6cSAntonio Huete Jimenez TUNABLE_INT("hw.vke.max_ringsize", &vke_max_ringsize); 86*33c27d6cSAntonio Huete Jimenez 87*33c27d6cSAntonio Huete Jimenez #define LOW_POW_2(n) (1 << (fls(n) - 1)) 88*33c27d6cSAntonio Huete Jimenez 899ed84223SSascha Wildner struct vke_softc { 909ed84223SSascha Wildner struct arpcom arpcom; 919ed84223SSascha Wildner int sc_fd; 929ed84223SSascha Wildner int sc_unit; 939ed84223SSascha Wildner 949ed84223SSascha Wildner cothread_t cotd_tx; 959ed84223SSascha Wildner cothread_t cotd_rx; 969ed84223SSascha Wildner 979ed84223SSascha Wildner int cotd_tx_exit; 989ed84223SSascha Wildner int cotd_rx_exit; 999ed84223SSascha Wildner 1009ed84223SSascha Wildner void *sc_txbuf; 1019ed84223SSascha Wildner int sc_txbuf_len; 1029ed84223SSascha Wildner 1039ed84223SSascha Wildner fifo_t sc_txfifo; 1049ed84223SSascha Wildner fifo_t sc_txfifo_done; 1059ed84223SSascha Wildner fifo_t sc_rxfifo; 1069ed84223SSascha Wildner 1073351469cSAntonio Huete Jimenez int sc_ringsize; 1083351469cSAntonio Huete Jimenez 109a9844950SMatthew Dillon long cotd_ipackets; 110a9844950SMatthew Dillon long cotd_oerrors; 111a9844950SMatthew Dillon long cotd_opackets; 112a9844950SMatthew Dillon 1139ed84223SSascha Wildner struct sysctl_ctx_list sc_sysctl_ctx; 1149ed84223SSascha Wildner struct sysctl_oid *sc_sysctl_tree; 1159ed84223SSascha Wildner 1169ed84223SSascha Wildner int sc_tap_unit; /* unit of backend tap(4) */ 1179ed84223SSascha Wildner in_addr_t sc_addr; /* address */ 1189ed84223SSascha Wildner in_addr_t sc_mask; /* netmask */ 1199ed84223SSascha Wildner }; 1209ed84223SSascha Wildner 121f0a26983SSepherosa Ziehau static void vke_start(struct ifnet *, struct ifaltq_subque *); 1229ed84223SSascha Wildner static void vke_init(void *); 1239ed84223SSascha Wildner static int vke_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *); 1249ed84223SSascha Wildner 1259ed84223SSascha Wildner static int vke_attach(const struct vknetif_info *, int); 1269ed84223SSascha Wildner static int vke_stop(struct vke_softc *); 1279ed84223SSascha Wildner static int vke_init_addr(struct ifnet *, in_addr_t, in_addr_t); 1289ed84223SSascha Wildner static void vke_tx_intr(cothread_t cotd); 1299ed84223SSascha Wildner static void vke_tx_thread(cothread_t cotd); 1309ed84223SSascha Wildner static void vke_rx_intr(cothread_t cotd); 1319ed84223SSascha Wildner static void vke_rx_thread(cothread_t cotd); 1329ed84223SSascha Wildner 1339ed84223SSascha Wildner static int vke_txfifo_enqueue(struct vke_softc *sc, struct mbuf *m); 1349ed84223SSascha Wildner static struct mbuf *vke_txfifo_dequeue(struct vke_softc *sc); 1359ed84223SSascha Wildner 1369ed84223SSascha Wildner static int vke_txfifo_done_enqueue(struct vke_softc *sc, struct mbuf *m); 1379ed84223SSascha Wildner static struct mbuf * vke_txfifo_done_dequeue(struct vke_softc *sc, struct mbuf *nm); 1389ed84223SSascha Wildner 1399ed84223SSascha Wildner static struct mbuf *vke_rxfifo_dequeue(struct vke_softc *sc, struct mbuf *nm); 1409ed84223SSascha Wildner static struct mbuf *vke_rxfifo_sniff(struct vke_softc *sc); 1419ed84223SSascha Wildner 1429ed84223SSascha Wildner static void 1439ed84223SSascha Wildner vke_sysinit(void *arg __unused) 1449ed84223SSascha Wildner { 1459ed84223SSascha Wildner int i, unit; 1469ed84223SSascha Wildner 147ed20d0e3SSascha Wildner KASSERT(NetifNum <= VKNETIF_MAX, ("too many netifs: %d", NetifNum)); 1489ed84223SSascha Wildner 1499ed84223SSascha Wildner unit = 0; 1509ed84223SSascha Wildner for (i = 0; i < NetifNum; ++i) { 1519ed84223SSascha Wildner if (vke_attach(&NetifInfo[i], unit) == 0) 1529ed84223SSascha Wildner ++unit; 1539ed84223SSascha Wildner } 1549ed84223SSascha Wildner } 1559ed84223SSascha Wildner SYSINIT(vke, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, vke_sysinit, NULL); 1569ed84223SSascha Wildner 1579ed84223SSascha Wildner /* 1589ed84223SSascha Wildner * vke_txfifo_done_enqueue() - Add an mbuf to the transmit done fifo. Since 1599ed84223SSascha Wildner * the cothread cannot free transmit mbufs after processing we put them on 1609ed84223SSascha Wildner * the done fifo so the kernel can free them. 1619ed84223SSascha Wildner */ 1629ed84223SSascha Wildner static int 1639ed84223SSascha Wildner vke_txfifo_done_enqueue(struct vke_softc *sc, struct mbuf *m) 1649ed84223SSascha Wildner { 1659ed84223SSascha Wildner fifo_t fifo = sc->sc_txfifo_done; 1669ed84223SSascha Wildner 1673351469cSAntonio Huete Jimenez while (NETFIFOINDEX(fifo->windex + 1, sc) == NETFIFOINDEX(fifo->rindex, sc)) { 1689ed84223SSascha Wildner usleep(20000); 1699ed84223SSascha Wildner } 1709ed84223SSascha Wildner 1713351469cSAntonio Huete Jimenez fifo->array[NETFIFOINDEX(fifo->windex, sc)] = m; 1729ed84223SSascha Wildner cpu_sfence(); 1739ed84223SSascha Wildner ++fifo->windex; 1749ed84223SSascha Wildner return (0); 1759ed84223SSascha Wildner } 1769ed84223SSascha Wildner 1779ed84223SSascha Wildner /* 1789ed84223SSascha Wildner * vke_txfifo_done_dequeue() - Remove an mbuf from the transmit done fifo. 1799ed84223SSascha Wildner */ 1809ed84223SSascha Wildner static struct mbuf * 1819ed84223SSascha Wildner vke_txfifo_done_dequeue(struct vke_softc *sc, struct mbuf *nm) 1829ed84223SSascha Wildner { 1839ed84223SSascha Wildner fifo_t fifo = sc->sc_txfifo_done; 1849ed84223SSascha Wildner struct mbuf *m; 1859ed84223SSascha Wildner 1863351469cSAntonio Huete Jimenez if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc)) 1879ed84223SSascha Wildner return (NULL); 1889ed84223SSascha Wildner 1893351469cSAntonio Huete Jimenez m = fifo->array[NETFIFOINDEX(fifo->rindex, sc)]; 1903351469cSAntonio Huete Jimenez fifo->array[NETFIFOINDEX(fifo->rindex, sc)] = nm; 1919ed84223SSascha Wildner cpu_lfence(); 1929ed84223SSascha Wildner ++fifo->rindex; 1939ed84223SSascha Wildner return (m); 1949ed84223SSascha Wildner } 1959ed84223SSascha Wildner 1969ed84223SSascha Wildner /* 1979ed84223SSascha Wildner * vke_txfifo_enqueue() - Add an mbuf to the transmit fifo. 1989ed84223SSascha Wildner */ 1999ed84223SSascha Wildner static int 2009ed84223SSascha Wildner vke_txfifo_enqueue(struct vke_softc *sc, struct mbuf *m) 2019ed84223SSascha Wildner { 2029ed84223SSascha Wildner fifo_t fifo = sc->sc_txfifo; 2039ed84223SSascha Wildner 2043351469cSAntonio Huete Jimenez if (NETFIFOINDEX(fifo->windex + 1, sc) == NETFIFOINDEX(fifo->rindex, sc)) 2059ed84223SSascha Wildner return (-1); 2069ed84223SSascha Wildner 2073351469cSAntonio Huete Jimenez fifo->array[NETFIFOINDEX(fifo->windex, sc)] = m; 2089ed84223SSascha Wildner cpu_sfence(); 2099ed84223SSascha Wildner ++fifo->windex; 2109ed84223SSascha Wildner 2119ed84223SSascha Wildner return (0); 2129ed84223SSascha Wildner } 2139ed84223SSascha Wildner 2149ed84223SSascha Wildner /* 2159ed84223SSascha Wildner * vke_txfifo_dequeue() - Return next mbuf on the transmit fifo if one 2169ed84223SSascha Wildner * exists. 2179ed84223SSascha Wildner */ 2189ed84223SSascha Wildner static struct mbuf * 2199ed84223SSascha Wildner vke_txfifo_dequeue(struct vke_softc *sc) 2209ed84223SSascha Wildner { 2219ed84223SSascha Wildner fifo_t fifo = sc->sc_txfifo; 2229ed84223SSascha Wildner struct mbuf *m; 2239ed84223SSascha Wildner 2243351469cSAntonio Huete Jimenez if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc)) 2259ed84223SSascha Wildner return (NULL); 2269ed84223SSascha Wildner 2273351469cSAntonio Huete Jimenez m = fifo->array[NETFIFOINDEX(fifo->rindex, sc)]; 2283351469cSAntonio Huete Jimenez fifo->array[NETFIFOINDEX(fifo->rindex, sc)] = NULL; 2299ed84223SSascha Wildner 2309ed84223SSascha Wildner cpu_lfence(); 2319ed84223SSascha Wildner ++fifo->rindex; 2329ed84223SSascha Wildner return (m); 2339ed84223SSascha Wildner } 2349ed84223SSascha Wildner 2359ed84223SSascha Wildner static int 2369ed84223SSascha Wildner vke_txfifo_empty(struct vke_softc *sc) 2379ed84223SSascha Wildner { 2389ed84223SSascha Wildner fifo_t fifo = sc->sc_txfifo; 2399ed84223SSascha Wildner 2403351469cSAntonio Huete Jimenez if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc)) 2419ed84223SSascha Wildner return (1); 2429ed84223SSascha Wildner return(0); 2439ed84223SSascha Wildner } 2449ed84223SSascha Wildner 2459ed84223SSascha Wildner /* 2469ed84223SSascha Wildner * vke_rxfifo_dequeue() - Return next mbuf on the receice fifo if one 2479ed84223SSascha Wildner * exists replacing it with newm which should point to a newly allocated 2489ed84223SSascha Wildner * mbuf. 2499ed84223SSascha Wildner */ 2509ed84223SSascha Wildner static struct mbuf * 2519ed84223SSascha Wildner vke_rxfifo_dequeue(struct vke_softc *sc, struct mbuf *newm) 2529ed84223SSascha Wildner { 2539ed84223SSascha Wildner fifo_t fifo = sc->sc_rxfifo; 2549ed84223SSascha Wildner struct mbuf *m; 2559ed84223SSascha Wildner 2563351469cSAntonio Huete Jimenez if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc)) 2579ed84223SSascha Wildner return (NULL); 2589ed84223SSascha Wildner 2593351469cSAntonio Huete Jimenez m = fifo->array[NETFIFOINDEX(fifo->rindex, sc)]; 2603351469cSAntonio Huete Jimenez fifo->array[NETFIFOINDEX(fifo->rindex, sc)] = newm; 2619ed84223SSascha Wildner cpu_lfence(); 2629ed84223SSascha Wildner ++fifo->rindex; 2639ed84223SSascha Wildner return (m); 2649ed84223SSascha Wildner } 2659ed84223SSascha Wildner 2669ed84223SSascha Wildner /* 2679ed84223SSascha Wildner * Return the next mbuf if available but do NOT remove it from the FIFO. 2689ed84223SSascha Wildner */ 2699ed84223SSascha Wildner static struct mbuf * 2709ed84223SSascha Wildner vke_rxfifo_sniff(struct vke_softc *sc) 2719ed84223SSascha Wildner { 2729ed84223SSascha Wildner fifo_t fifo = sc->sc_rxfifo; 2739ed84223SSascha Wildner struct mbuf *m; 2749ed84223SSascha Wildner 2753351469cSAntonio Huete Jimenez if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc)) 2769ed84223SSascha Wildner return (NULL); 2779ed84223SSascha Wildner 2783351469cSAntonio Huete Jimenez m = fifo->array[NETFIFOINDEX(fifo->rindex, sc)]; 2799ed84223SSascha Wildner cpu_lfence(); 2809ed84223SSascha Wildner return (m); 2819ed84223SSascha Wildner } 2829ed84223SSascha Wildner 2839ed84223SSascha Wildner static void 2849ed84223SSascha Wildner vke_init(void *xsc) 2859ed84223SSascha Wildner { 2869ed84223SSascha Wildner struct vke_softc *sc = xsc; 2879ed84223SSascha Wildner struct ifnet *ifp = &sc->arpcom.ac_if; 2883351469cSAntonio Huete Jimenez size_t ringsize = sc->sc_ringsize * sizeof(struct mbuf *); 2899ed84223SSascha Wildner int i; 2909ed84223SSascha Wildner 2919ed84223SSascha Wildner ASSERT_SERIALIZED(ifp->if_serializer); 2929ed84223SSascha Wildner 2939ed84223SSascha Wildner vke_stop(sc); 2949ed84223SSascha Wildner 2959ed84223SSascha Wildner ifp->if_flags |= IFF_RUNNING; 296f0a26983SSepherosa Ziehau ifsq_clr_oactive(ifq_get_subq_default(&ifp->if_snd)); 2979ed84223SSascha Wildner 2983351469cSAntonio Huete Jimenez /* 2993351469cSAntonio Huete Jimenez * Allocate memory for FIFO structures and mbufs. 3003351469cSAntonio Huete Jimenez */ 3019ed84223SSascha Wildner sc->sc_txfifo = kmalloc(sizeof(*sc->sc_txfifo), M_DEVBUF, M_WAITOK); 3029ed84223SSascha Wildner sc->sc_txfifo_done = kmalloc(sizeof(*sc->sc_txfifo_done), M_DEVBUF, M_WAITOK); 3039ed84223SSascha Wildner sc->sc_rxfifo = kmalloc(sizeof(*sc->sc_rxfifo), M_DEVBUF, M_WAITOK); 3043351469cSAntonio Huete Jimenez sc->sc_txfifo->array = kmalloc(ringsize, M_DEVBUF, M_WAITOK | M_ZERO); 3053351469cSAntonio Huete Jimenez sc->sc_txfifo_done->array = kmalloc(ringsize, M_DEVBUF, M_WAITOK | M_ZERO); 3063351469cSAntonio Huete Jimenez sc->sc_rxfifo->array = kmalloc(ringsize, M_DEVBUF, M_WAITOK | M_ZERO); 3073351469cSAntonio Huete Jimenez 3083351469cSAntonio Huete Jimenez for (i = 0; i < sc->sc_ringsize; i++) { 3099ed84223SSascha Wildner sc->sc_rxfifo->array[i] = m_getcl(MB_WAIT, MT_DATA, M_PKTHDR); 3109ed84223SSascha Wildner sc->sc_txfifo->array[i] = NULL; 3119ed84223SSascha Wildner sc->sc_txfifo_done->array[i] = NULL; 3129ed84223SSascha Wildner } 3139ed84223SSascha Wildner 3149ed84223SSascha Wildner sc->cotd_tx_exit = sc->cotd_rx_exit = VKE_COTD_RUN; 3159ed84223SSascha Wildner sc->cotd_tx = cothread_create(vke_tx_thread, vke_tx_intr, sc, "vke_tx"); 3169ed84223SSascha Wildner sc->cotd_rx = cothread_create(vke_rx_thread, vke_rx_intr, sc, "vke_rx"); 3179ed84223SSascha Wildner 3189ed84223SSascha Wildner if (sc->sc_addr != 0) { 3199ed84223SSascha Wildner in_addr_t addr, mask; 3209ed84223SSascha Wildner 3219ed84223SSascha Wildner addr = sc->sc_addr; 3229ed84223SSascha Wildner mask = sc->sc_mask; 3239ed84223SSascha Wildner 3249ed84223SSascha Wildner /* 3259ed84223SSascha Wildner * Make sure vkernel assigned 3269ed84223SSascha Wildner * address will not be added 3279ed84223SSascha Wildner * again. 3289ed84223SSascha Wildner */ 3299ed84223SSascha Wildner sc->sc_addr = 0; 3309ed84223SSascha Wildner sc->sc_mask = 0; 3319ed84223SSascha Wildner 3329ed84223SSascha Wildner vke_init_addr(ifp, addr, mask); 3339ed84223SSascha Wildner } 3349ed84223SSascha Wildner 3359ed84223SSascha Wildner } 3369ed84223SSascha Wildner 3379ed84223SSascha Wildner /* 3389ed84223SSascha Wildner * Called from kernel. 3399ed84223SSascha Wildner * 3409ed84223SSascha Wildner * NOTE: We can't make any kernel callbacks while holding cothread lock 3419ed84223SSascha Wildner * because the cothread lock is not governed by the kernel scheduler 3429ed84223SSascha Wildner * (so mplock, tokens, etc will not be released). 3439ed84223SSascha Wildner */ 3449ed84223SSascha Wildner static void 345f0a26983SSepherosa Ziehau vke_start(struct ifnet *ifp, struct ifaltq_subque *ifsq) 3469ed84223SSascha Wildner { 3479ed84223SSascha Wildner struct vke_softc *sc = ifp->if_softc; 3489ed84223SSascha Wildner struct mbuf *m; 3499ed84223SSascha Wildner cothread_t cotd = sc->cotd_tx; 3509ed84223SSascha Wildner int count; 3519ed84223SSascha Wildner 352f0a26983SSepherosa Ziehau ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq); 3539ed84223SSascha Wildner ASSERT_SERIALIZED(ifp->if_serializer); 3549ed84223SSascha Wildner 355f0a26983SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0 || ifsq_is_oactive(ifsq)) 3569ed84223SSascha Wildner return; 3579ed84223SSascha Wildner 3589ed84223SSascha Wildner count = 0; 359f0a26983SSepherosa Ziehau while ((m = ifsq_dequeue(ifsq, NULL)) != NULL) { 3609ed84223SSascha Wildner if (vke_txfifo_enqueue(sc, m) != -1) { 3619ed84223SSascha Wildner if (count++ == VKE_CHUNK) { 3629ed84223SSascha Wildner cothread_lock(cotd, 0); 3639ed84223SSascha Wildner cothread_signal(cotd); 3649ed84223SSascha Wildner cothread_unlock(cotd, 0); 3659ed84223SSascha Wildner count = 0; 3669ed84223SSascha Wildner } 3679ed84223SSascha Wildner } else { 3689ed84223SSascha Wildner m_freem(m); 3699ed84223SSascha Wildner } 3709ed84223SSascha Wildner } 3719ed84223SSascha Wildner if (count) { 3729ed84223SSascha Wildner cothread_lock(cotd, 0); 3739ed84223SSascha Wildner cothread_signal(cotd); 3749ed84223SSascha Wildner cothread_unlock(cotd, 0); 3759ed84223SSascha Wildner } 3769ed84223SSascha Wildner } 3779ed84223SSascha Wildner 3789ed84223SSascha Wildner static int 3799ed84223SSascha Wildner vke_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr) 3809ed84223SSascha Wildner { 3819ed84223SSascha Wildner struct vke_softc *sc = ifp->if_softc; 3829ed84223SSascha Wildner int error = 0; 3839ed84223SSascha Wildner 3849ed84223SSascha Wildner ASSERT_SERIALIZED(ifp->if_serializer); 3859ed84223SSascha Wildner 3869ed84223SSascha Wildner switch (cmd) { 3879ed84223SSascha Wildner case SIOCSIFFLAGS: 3889ed84223SSascha Wildner if (ifp->if_flags & IFF_UP) { 3899ed84223SSascha Wildner if ((ifp->if_flags & IFF_RUNNING) == 0) 3909ed84223SSascha Wildner vke_init(sc); 3919ed84223SSascha Wildner } else { 3929ed84223SSascha Wildner if (ifp->if_flags & IFF_RUNNING) 3939ed84223SSascha Wildner vke_stop(sc); 3949ed84223SSascha Wildner } 3959ed84223SSascha Wildner break; 3969ed84223SSascha Wildner case SIOCGIFMEDIA: 3979ed84223SSascha Wildner case SIOCSIFMEDIA: 3989ed84223SSascha Wildner error = EOPNOTSUPP; 3999ed84223SSascha Wildner /* TODO */ 4009ed84223SSascha Wildner break; 4019ed84223SSascha Wildner case SIOCGIFSTATUS: { 4029ed84223SSascha Wildner struct ifstat *ifs = (struct ifstat *)data; 4039ed84223SSascha Wildner int len; 4049ed84223SSascha Wildner 4059ed84223SSascha Wildner len = strlen(ifs->ascii); 4069ed84223SSascha Wildner if (len < sizeof(ifs->ascii)) { 4077cdacfbbSAntonio Huete Jimenez if (sc->sc_tap_unit >= 0) 4089ed84223SSascha Wildner ksnprintf(ifs->ascii + len, sizeof(ifs->ascii) - len, 4099ed84223SSascha Wildner "\tBacked by tap%d\n", sc->sc_tap_unit); 4109ed84223SSascha Wildner } 4119ed84223SSascha Wildner break; 4129ed84223SSascha Wildner } 4139ed84223SSascha Wildner case SIOCSIFADDR: 4149ed84223SSascha Wildner if (((struct ifaddr *)data)->ifa_addr->sa_family == AF_INET) { 4159ed84223SSascha Wildner /* 4169ed84223SSascha Wildner * If we are explicitly requested to change address, 4179ed84223SSascha Wildner * we should invalidate address/netmask passed in 4189ed84223SSascha Wildner * from vkernel command line. 4199ed84223SSascha Wildner */ 4209ed84223SSascha Wildner sc->sc_addr = 0; 4219ed84223SSascha Wildner sc->sc_mask = 0; 4229ed84223SSascha Wildner } 4239ed84223SSascha Wildner /* FALL THROUGH */ 4249ed84223SSascha Wildner default: 4259ed84223SSascha Wildner error = ether_ioctl(ifp, cmd, data); 4269ed84223SSascha Wildner break; 4279ed84223SSascha Wildner } 4289ed84223SSascha Wildner return error; 4299ed84223SSascha Wildner } 4309ed84223SSascha Wildner 4319ed84223SSascha Wildner static int 4329ed84223SSascha Wildner vke_stop(struct vke_softc *sc) 4339ed84223SSascha Wildner { 4349ed84223SSascha Wildner struct ifnet *ifp = &sc->arpcom.ac_if; 4359ed84223SSascha Wildner int i; 4369ed84223SSascha Wildner 4379ed84223SSascha Wildner ASSERT_SERIALIZED(ifp->if_serializer); 4389ed84223SSascha Wildner 4399ed293e0SSepherosa Ziehau ifp->if_flags &= ~IFF_RUNNING; 440f0a26983SSepherosa Ziehau ifsq_clr_oactive(ifq_get_subq_default(&ifp->if_snd)); 4419ed84223SSascha Wildner 4429ed84223SSascha Wildner if (sc) { 4439ed84223SSascha Wildner if (sc->cotd_tx) { 4449ed84223SSascha Wildner cothread_lock(sc->cotd_tx, 0); 4459ed84223SSascha Wildner if (sc->cotd_tx_exit == VKE_COTD_RUN) 4469ed84223SSascha Wildner sc->cotd_tx_exit = VKE_COTD_EXIT; 4479ed84223SSascha Wildner cothread_signal(sc->cotd_tx); 4489ed84223SSascha Wildner cothread_unlock(sc->cotd_tx, 0); 4499ed84223SSascha Wildner cothread_delete(&sc->cotd_tx); 4509ed84223SSascha Wildner } 4519ed84223SSascha Wildner if (sc->cotd_rx) { 4529ed84223SSascha Wildner cothread_lock(sc->cotd_rx, 0); 4539ed84223SSascha Wildner if (sc->cotd_rx_exit == VKE_COTD_RUN) 4549ed84223SSascha Wildner sc->cotd_rx_exit = VKE_COTD_EXIT; 4559ed84223SSascha Wildner cothread_signal(sc->cotd_rx); 4569ed84223SSascha Wildner cothread_unlock(sc->cotd_rx, 0); 4579ed84223SSascha Wildner cothread_delete(&sc->cotd_rx); 4589ed84223SSascha Wildner } 4599ed84223SSascha Wildner 4603351469cSAntonio Huete Jimenez for (i = 0; i < sc->sc_ringsize; i++) { 4619ed84223SSascha Wildner if (sc->sc_rxfifo && sc->sc_rxfifo->array[i]) { 4629ed84223SSascha Wildner m_freem(sc->sc_rxfifo->array[i]); 4639ed84223SSascha Wildner sc->sc_rxfifo->array[i] = NULL; 4649ed84223SSascha Wildner } 4659ed84223SSascha Wildner if (sc->sc_txfifo && sc->sc_txfifo->array[i]) { 4669ed84223SSascha Wildner m_freem(sc->sc_txfifo->array[i]); 4679ed84223SSascha Wildner sc->sc_txfifo->array[i] = NULL; 4689ed84223SSascha Wildner } 4699ed84223SSascha Wildner if (sc->sc_txfifo_done && sc->sc_txfifo_done->array[i]) { 4709ed84223SSascha Wildner m_freem(sc->sc_txfifo_done->array[i]); 4719ed84223SSascha Wildner sc->sc_txfifo_done->array[i] = NULL; 4729ed84223SSascha Wildner } 4739ed84223SSascha Wildner } 4749ed84223SSascha Wildner 4759ed84223SSascha Wildner if (sc->sc_txfifo) { 4763351469cSAntonio Huete Jimenez if (sc->sc_txfifo->array) 4773351469cSAntonio Huete Jimenez kfree(sc->sc_txfifo->array, M_DEVBUF); 4789ed84223SSascha Wildner kfree(sc->sc_txfifo, M_DEVBUF); 4799ed84223SSascha Wildner sc->sc_txfifo = NULL; 4809ed84223SSascha Wildner } 4819ed84223SSascha Wildner 4829ed84223SSascha Wildner if (sc->sc_txfifo_done) { 4833351469cSAntonio Huete Jimenez if (sc->sc_txfifo_done->array) 4843351469cSAntonio Huete Jimenez kfree(sc->sc_txfifo_done->array, M_DEVBUF); 4859ed84223SSascha Wildner kfree(sc->sc_txfifo_done, M_DEVBUF); 4869ed84223SSascha Wildner sc->sc_txfifo_done = NULL; 4879ed84223SSascha Wildner } 4889ed84223SSascha Wildner 4899ed84223SSascha Wildner if (sc->sc_rxfifo) { 4903351469cSAntonio Huete Jimenez if (sc->sc_rxfifo->array) 4913351469cSAntonio Huete Jimenez kfree(sc->sc_rxfifo->array, M_DEVBUF); 4929ed84223SSascha Wildner kfree(sc->sc_rxfifo, M_DEVBUF); 4939ed84223SSascha Wildner sc->sc_rxfifo = NULL; 4949ed84223SSascha Wildner } 4959ed84223SSascha Wildner } 4969ed84223SSascha Wildner 4979ed84223SSascha Wildner 4989ed84223SSascha Wildner return 0; 4999ed84223SSascha Wildner } 5009ed84223SSascha Wildner 5019ed84223SSascha Wildner /* 5029ed84223SSascha Wildner * vke_rx_intr() is the interrupt function for the receive cothread. 5039ed84223SSascha Wildner */ 5049ed84223SSascha Wildner static void 5059ed84223SSascha Wildner vke_rx_intr(cothread_t cotd) 5069ed84223SSascha Wildner { 5079ed84223SSascha Wildner struct mbuf *m; 5089ed84223SSascha Wildner struct mbuf *nm; 5099ed84223SSascha Wildner struct vke_softc *sc = cotd->arg; 5109ed84223SSascha Wildner struct ifnet *ifp = &sc->arpcom.ac_if; 5119ed84223SSascha Wildner static int count = 0; 5129ed84223SSascha Wildner 5139ed84223SSascha Wildner ifnet_serialize_all(ifp); 5149ed84223SSascha Wildner cothread_lock(cotd, 0); 5159ed84223SSascha Wildner 5169ed84223SSascha Wildner if (sc->cotd_rx_exit != VKE_COTD_RUN) { 5179ed84223SSascha Wildner cothread_unlock(cotd, 0); 5189ed84223SSascha Wildner ifnet_deserialize_all(ifp); 5199ed84223SSascha Wildner return; 5209ed84223SSascha Wildner } 521a9844950SMatthew Dillon if (sc->cotd_ipackets) { 522a9844950SMatthew Dillon IFNET_STAT_INC(ifp, ipackets, 1); 523a9844950SMatthew Dillon sc->cotd_ipackets = 0; 524a9844950SMatthew Dillon } 5259ed84223SSascha Wildner cothread_unlock(cotd, 0); 5269ed84223SSascha Wildner 5279ed84223SSascha Wildner while ((m = vke_rxfifo_sniff(sc)) != NULL) { 5289ed84223SSascha Wildner nm = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR); 5299ed84223SSascha Wildner if (nm) { 5309ed84223SSascha Wildner vke_rxfifo_dequeue(sc, nm); 5319ed84223SSascha Wildner ifp->if_input(ifp, m); 5329ed84223SSascha Wildner if (count++ == VKE_CHUNK) { 5339ed84223SSascha Wildner cothread_lock(cotd, 0); 5349ed84223SSascha Wildner cothread_signal(cotd); 5359ed84223SSascha Wildner cothread_unlock(cotd, 0); 5369ed84223SSascha Wildner count = 0; 5379ed84223SSascha Wildner } 5389ed84223SSascha Wildner } else { 5399ed84223SSascha Wildner vke_rxfifo_dequeue(sc, m); 5409ed84223SSascha Wildner } 5419ed84223SSascha Wildner } 5429ed84223SSascha Wildner 5439ed84223SSascha Wildner if (count) { 5449ed84223SSascha Wildner cothread_lock(cotd, 0); 5459ed84223SSascha Wildner cothread_signal(cotd); 5469ed84223SSascha Wildner cothread_unlock(cotd, 0); 5479ed84223SSascha Wildner } 5489ed84223SSascha Wildner ifnet_deserialize_all(ifp); 5499ed84223SSascha Wildner } 5509ed84223SSascha Wildner 5519ed84223SSascha Wildner /* 5529ed84223SSascha Wildner * vke_tx_intr() is the interrupt function for the transmit cothread. 5539ed84223SSascha Wildner * Calls vke_start() to handle processing transmit mbufs. 5549ed84223SSascha Wildner */ 5559ed84223SSascha Wildner static void 5569ed84223SSascha Wildner vke_tx_intr(cothread_t cotd) 5579ed84223SSascha Wildner { 5589ed84223SSascha Wildner struct vke_softc *sc = cotd->arg; 5599ed84223SSascha Wildner struct ifnet *ifp = &sc->arpcom.ac_if; 5609ed84223SSascha Wildner struct mbuf *m; 5619ed84223SSascha Wildner 5629ed84223SSascha Wildner ifnet_serialize_all(ifp); 5639ed84223SSascha Wildner cothread_lock(cotd, 0); 5649ed84223SSascha Wildner if (sc->cotd_tx_exit != VKE_COTD_RUN) { 5659ed84223SSascha Wildner cothread_unlock(cotd, 0); 5669ed84223SSascha Wildner ifnet_deserialize_all(ifp); 5679ed84223SSascha Wildner return; 5689ed84223SSascha Wildner } 569a9844950SMatthew Dillon if (sc->cotd_opackets) { 570a9844950SMatthew Dillon IFNET_STAT_INC(ifp, opackets, 1); 571a9844950SMatthew Dillon sc->cotd_opackets = 0; 572a9844950SMatthew Dillon } 573a9844950SMatthew Dillon if (sc->cotd_oerrors) { 574a9844950SMatthew Dillon IFNET_STAT_INC(ifp, oerrors, 1); 575a9844950SMatthew Dillon sc->cotd_oerrors = 0; 576a9844950SMatthew Dillon } 5779ed84223SSascha Wildner cothread_unlock(cotd, 0); 5789ed84223SSascha Wildner 5799ed84223SSascha Wildner /* 5809ed84223SSascha Wildner * Free TX mbufs that have been processed before starting new 5819ed84223SSascha Wildner * ones going to be pipeline friendly. 5829ed84223SSascha Wildner */ 5839ed84223SSascha Wildner while ((m = vke_txfifo_done_dequeue(sc, NULL)) != NULL) { 5849ed84223SSascha Wildner m_freem(m); 5859ed84223SSascha Wildner } 5869ed84223SSascha Wildner 5879ed84223SSascha Wildner if ((ifp->if_flags & IFF_RUNNING) == 0) 588f0a26983SSepherosa Ziehau if_devstart(ifp); 5899ed84223SSascha Wildner 5909ed84223SSascha Wildner ifnet_deserialize_all(ifp); 5919ed84223SSascha Wildner } 5929ed84223SSascha Wildner 5939ed84223SSascha Wildner /* 5949ed84223SSascha Wildner * vke_rx_thread() is the body of the receive cothread. 595a9844950SMatthew Dillon * 596a9844950SMatthew Dillon * WARNING! THIS IS A COTHREAD WHICH HAS NO PER-CPU GLOBALDATA!!!!! 5979ed84223SSascha Wildner */ 5989ed84223SSascha Wildner static void 5999ed84223SSascha Wildner vke_rx_thread(cothread_t cotd) 6009ed84223SSascha Wildner { 6019ed84223SSascha Wildner struct mbuf *m; 6029ed84223SSascha Wildner struct vke_softc *sc = cotd->arg; 6039ed84223SSascha Wildner struct ifnet *ifp = &sc->arpcom.ac_if; 6049ed84223SSascha Wildner fifo_t fifo = sc->sc_rxfifo; 6059ed84223SSascha Wildner fd_set fdset; 6069ed84223SSascha Wildner struct timeval tv; 6079ed84223SSascha Wildner int count; 6089ed84223SSascha Wildner int n; 6099ed84223SSascha Wildner 6109ed84223SSascha Wildner /* Select timeout cannot be infinite since we need to check for 6119ed84223SSascha Wildner * the exit flag sc->cotd_rx_exit. 6129ed84223SSascha Wildner */ 6139ed84223SSascha Wildner tv.tv_sec = 0; 6149ed84223SSascha Wildner tv.tv_usec = 500000; 6159ed84223SSascha Wildner 6169ed84223SSascha Wildner FD_ZERO(&fdset); 6179ed84223SSascha Wildner count = 0; 6189ed84223SSascha Wildner 6199ed84223SSascha Wildner while (sc->cotd_rx_exit == VKE_COTD_RUN) { 6209ed84223SSascha Wildner /* 6219ed84223SSascha Wildner * Wait for the RX FIFO to be loaded with 6229ed84223SSascha Wildner * empty mbufs. 6239ed84223SSascha Wildner */ 6243351469cSAntonio Huete Jimenez if (NETFIFOINDEX(fifo->windex + 1, sc) == 6253351469cSAntonio Huete Jimenez NETFIFOINDEX(fifo->rindex, sc)) { 6269ed84223SSascha Wildner usleep(20000); 6279ed84223SSascha Wildner continue; 6289ed84223SSascha Wildner } 6299ed84223SSascha Wildner 6309ed84223SSascha Wildner /* 6319ed84223SSascha Wildner * Load data into the rx fifo 6329ed84223SSascha Wildner */ 6333351469cSAntonio Huete Jimenez m = fifo->array[NETFIFOINDEX(fifo->windex, sc)]; 6349ed84223SSascha Wildner if (m == NULL) 6359ed84223SSascha Wildner continue; 6369ed84223SSascha Wildner n = read(sc->sc_fd, mtod(m, void *), MCLBYTES); 6379ed84223SSascha Wildner if (n > 0) { 638a9844950SMatthew Dillon /* no mycpu in cothread */ 639a9844950SMatthew Dillon /*IFNET_STAT_INC(ifp, ipackets, 1);*/ 640a9844950SMatthew Dillon ++sc->cotd_ipackets; 6419ed84223SSascha Wildner m->m_pkthdr.rcvif = ifp; 6429ed84223SSascha Wildner m->m_pkthdr.len = m->m_len = n; 6439ed84223SSascha Wildner cpu_sfence(); 6449ed84223SSascha Wildner ++fifo->windex; 6459ed84223SSascha Wildner if (count++ == VKE_CHUNK) { 6469ed84223SSascha Wildner cothread_intr(cotd); 6479ed84223SSascha Wildner count = 0; 6489ed84223SSascha Wildner } 6499ed84223SSascha Wildner } else { 6509ed84223SSascha Wildner if (count) { 6519ed84223SSascha Wildner cothread_intr(cotd); 6529ed84223SSascha Wildner count = 0; 6539ed84223SSascha Wildner } 6549ed84223SSascha Wildner FD_SET(sc->sc_fd, &fdset); 6559ed84223SSascha Wildner 6569ed84223SSascha Wildner if (select(sc->sc_fd + 1, &fdset, NULL, NULL, &tv) == -1) { 657a9844950SMatthew Dillon fprintf(stderr, 658a9844950SMatthew Dillon VKE_DEVNAME "%d: select failed for " 6599ed84223SSascha Wildner "TAP device\n", sc->sc_unit); 6609ed84223SSascha Wildner usleep(1000000); 6619ed84223SSascha Wildner } 6629ed84223SSascha Wildner } 6639ed84223SSascha Wildner } 6649ed84223SSascha Wildner cpu_sfence(); 6659ed84223SSascha Wildner sc->cotd_rx_exit = VKE_COTD_DEAD; 6669ed84223SSascha Wildner } 6679ed84223SSascha Wildner 6689ed84223SSascha Wildner /* 6699ed84223SSascha Wildner * vke_tx_thread() is the body of the transmit cothread. 670a9844950SMatthew Dillon * 671a9844950SMatthew Dillon * WARNING! THIS IS A COTHREAD WHICH HAS NO PER-CPU GLOBALDATA!!!!! 6729ed84223SSascha Wildner */ 6739ed84223SSascha Wildner static void 6749ed84223SSascha Wildner vke_tx_thread(cothread_t cotd) 6759ed84223SSascha Wildner { 6769ed84223SSascha Wildner struct mbuf *m; 6779ed84223SSascha Wildner struct vke_softc *sc = cotd->arg; 678171a58dfSSascha Wildner /*struct ifnet *ifp = &sc->arpcom.ac_if;*/ 6799ed84223SSascha Wildner int count = 0; 6809ed84223SSascha Wildner 6819ed84223SSascha Wildner while (sc->cotd_tx_exit == VKE_COTD_RUN) { 6829ed84223SSascha Wildner /* 6839ed84223SSascha Wildner * Write outgoing packets to the TAP interface 6849ed84223SSascha Wildner */ 6859ed84223SSascha Wildner m = vke_txfifo_dequeue(sc); 6869ed84223SSascha Wildner if (m) { 6879ed84223SSascha Wildner if (m->m_pkthdr.len <= MCLBYTES) { 6889ed84223SSascha Wildner m_copydata(m, 0, m->m_pkthdr.len, sc->sc_txbuf); 6899ed84223SSascha Wildner sc->sc_txbuf_len = m->m_pkthdr.len; 6909ed84223SSascha Wildner 6919ed84223SSascha Wildner if (write(sc->sc_fd, sc->sc_txbuf, 6929ed84223SSascha Wildner sc->sc_txbuf_len) < 0) { 693a9844950SMatthew Dillon /* no mycpu in cothread */ 694a9844950SMatthew Dillon /*IFNET_STAT_INC(ifp, oerrors, 1);*/ 695a9844950SMatthew Dillon ++sc->cotd_oerrors; 6969ed84223SSascha Wildner } else { 697a9844950SMatthew Dillon /* no mycpu in cothread */ 698a9844950SMatthew Dillon /*IFNET_STAT_INC(ifp, opackets, 1);*/ 699a9844950SMatthew Dillon ++sc->cotd_opackets; 7009ed84223SSascha Wildner } 7019ed84223SSascha Wildner } 7029ed84223SSascha Wildner if (count++ == VKE_CHUNK) { 7039ed84223SSascha Wildner cothread_intr(cotd); 7049ed84223SSascha Wildner count = 0; 7059ed84223SSascha Wildner } 7069ed84223SSascha Wildner vke_txfifo_done_enqueue(sc, m); 7079ed84223SSascha Wildner } else { 7089ed84223SSascha Wildner if (count) { 7099ed84223SSascha Wildner cothread_intr(cotd); 7109ed84223SSascha Wildner count = 0; 7119ed84223SSascha Wildner } 7129ed84223SSascha Wildner cothread_lock(cotd, 1); 7139ed84223SSascha Wildner if (vke_txfifo_empty(sc)) 7149ed84223SSascha Wildner cothread_wait(cotd); 7159ed84223SSascha Wildner cothread_unlock(cotd, 1); 7169ed84223SSascha Wildner } 7179ed84223SSascha Wildner } 7189ed84223SSascha Wildner cpu_sfence(); 7199ed84223SSascha Wildner sc->cotd_tx_exit = VKE_COTD_DEAD; 7209ed84223SSascha Wildner } 7219ed84223SSascha Wildner 7229ed84223SSascha Wildner static int 7239ed84223SSascha Wildner vke_attach(const struct vknetif_info *info, int unit) 7249ed84223SSascha Wildner { 7259ed84223SSascha Wildner struct vke_softc *sc; 7269ed84223SSascha Wildner struct ifnet *ifp; 7279ed84223SSascha Wildner struct tapinfo tapinfo; 7289ed84223SSascha Wildner uint8_t enaddr[ETHER_ADDR_LEN]; 7293351469cSAntonio Huete Jimenez int nmbufs; 7309ed84223SSascha Wildner int fd; 7319ed84223SSascha Wildner 7329ed84223SSascha Wildner KKASSERT(info->tap_fd >= 0); 7339ed84223SSascha Wildner fd = info->tap_fd; 7349ed84223SSascha Wildner 73586d2b040SAntonio Huete Jimenez if (info->enaddr) { 73686d2b040SAntonio Huete Jimenez bcopy(info->enaddr, enaddr, ETHER_ADDR_LEN); 73786d2b040SAntonio Huete Jimenez goto havemac; 73886d2b040SAntonio Huete Jimenez } 73986d2b040SAntonio Huete Jimenez 7409ed84223SSascha Wildner /* 7419ed84223SSascha Wildner * This is only a TAP device if tap_unit is non-zero. If 7429ed84223SSascha Wildner * connecting to a virtual socket we generate a unique MAC. 7439ed84223SSascha Wildner */ 7449ed84223SSascha Wildner if (info->tap_unit >= 0) { 7459ed84223SSascha Wildner if (ioctl(fd, TAPGIFINFO, &tapinfo) < 0) { 7469ed84223SSascha Wildner kprintf(VKE_DEVNAME "%d: ioctl(TAPGIFINFO) " 7479ed84223SSascha Wildner "failed: %s\n", unit, strerror(errno)); 7489ed84223SSascha Wildner return ENXIO; 7499ed84223SSascha Wildner } 7509ed84223SSascha Wildner 7519ed84223SSascha Wildner if (ioctl(fd, SIOCGIFADDR, enaddr) < 0) { 7529ed84223SSascha Wildner kprintf(VKE_DEVNAME "%d: ioctl(SIOCGIFADDR) " 7539ed84223SSascha Wildner "failed: %s\n", unit, strerror(errno)); 7549ed84223SSascha Wildner return ENXIO; 7559ed84223SSascha Wildner } 7569ed84223SSascha Wildner } else { 7579ed84223SSascha Wildner int fd = open("/dev/urandom", O_RDONLY); 7589ed84223SSascha Wildner if (fd >= 0) { 7599ed84223SSascha Wildner read(fd, enaddr + 2, 4); 7609ed84223SSascha Wildner close(fd); 7619ed84223SSascha Wildner } 7629ed84223SSascha Wildner enaddr[4] = (int)getpid() >> 8; 7639ed84223SSascha Wildner enaddr[5] = (int)getpid() & 255; 7649ed84223SSascha Wildner 7659ed84223SSascha Wildner } 7669ed84223SSascha Wildner enaddr[1] += 1; 7679ed84223SSascha Wildner 76886d2b040SAntonio Huete Jimenez havemac: 7699ed84223SSascha Wildner sc = kmalloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 7709ed84223SSascha Wildner 7719ed84223SSascha Wildner sc->sc_txbuf = kmalloc(MCLBYTES, M_DEVBUF, M_WAITOK); 7729ed84223SSascha Wildner sc->sc_fd = fd; 7739ed84223SSascha Wildner sc->sc_unit = unit; 7749ed84223SSascha Wildner sc->sc_tap_unit = info->tap_unit; 7759ed84223SSascha Wildner sc->sc_addr = info->netif_addr; 7769ed84223SSascha Wildner sc->sc_mask = info->netif_mask; 7779ed84223SSascha Wildner 778*33c27d6cSAntonio Huete Jimenez if (vke_max_ringsize == 0) { 7793351469cSAntonio Huete Jimenez nmbufs = nmbclusters / (NetifNum * 2); 780*33c27d6cSAntonio Huete Jimenez sc->sc_ringsize = LOW_POW_2(nmbufs); 781*33c27d6cSAntonio Huete Jimenez if (sc->sc_ringsize > VKE_DEFAULT_RINGSIZE) 782*33c27d6cSAntonio Huete Jimenez sc->sc_ringsize = VKE_DEFAULT_RINGSIZE; 783*33c27d6cSAntonio Huete Jimenez } else if (vke_max_ringsize >= VKE_CHUNK) { /* Tunable specified */ 784*33c27d6cSAntonio Huete Jimenez sc->sc_ringsize = LOW_POW_2(vke_max_ringsize); 785*33c27d6cSAntonio Huete Jimenez } else { 786*33c27d6cSAntonio Huete Jimenez sc->sc_ringsize = LOW_POW_2(VKE_CHUNK); 787*33c27d6cSAntonio Huete Jimenez } 7883351469cSAntonio Huete Jimenez 7899ed84223SSascha Wildner ifp = &sc->arpcom.ac_if; 7909ed84223SSascha Wildner if_initname(ifp, VKE_DEVNAME, sc->sc_unit); 7919ed84223SSascha Wildner 7929ed84223SSascha Wildner /* NB: after if_initname() */ 7939ed84223SSascha Wildner sysctl_ctx_init(&sc->sc_sysctl_ctx); 7949ed84223SSascha Wildner sc->sc_sysctl_tree = SYSCTL_ADD_NODE(&sc->sc_sysctl_ctx, 7959ed84223SSascha Wildner SYSCTL_STATIC_CHILDREN(_hw), 7969ed84223SSascha Wildner OID_AUTO, ifp->if_xname, 7979ed84223SSascha Wildner CTLFLAG_RD, 0, ""); 7989ed84223SSascha Wildner if (sc->sc_sysctl_tree == NULL) { 7999ed84223SSascha Wildner kprintf(VKE_DEVNAME "%d: can't add sysctl node\n", unit); 8009ed84223SSascha Wildner } else { 8019ed84223SSascha Wildner SYSCTL_ADD_INT(&sc->sc_sysctl_ctx, 8029ed84223SSascha Wildner SYSCTL_CHILDREN(sc->sc_sysctl_tree), 8039ed84223SSascha Wildner OID_AUTO, "tap_unit", 8049ed84223SSascha Wildner CTLFLAG_RD, &sc->sc_tap_unit, 0, 8059ed84223SSascha Wildner "Backend tap(4) unit"); 8069ed84223SSascha Wildner } 8079ed84223SSascha Wildner 8089ed84223SSascha Wildner ifp->if_softc = sc; 8099ed84223SSascha Wildner ifp->if_ioctl = vke_ioctl; 8109ed84223SSascha Wildner ifp->if_start = vke_start; 8119ed84223SSascha Wildner ifp->if_init = vke_init; 8129ed84223SSascha Wildner ifp->if_mtu = tapinfo.mtu; 8139ed84223SSascha Wildner ifp->if_baudrate = tapinfo.baudrate; 8149ed84223SSascha Wildner ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 8159ed84223SSascha Wildner ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN); 8169ed84223SSascha Wildner ifq_set_ready(&ifp->if_snd); 8179ed84223SSascha Wildner 8189ed84223SSascha Wildner /* TODO: if_media */ 8199ed84223SSascha Wildner 8209ed84223SSascha Wildner ether_ifattach(ifp, enaddr, NULL); 8219ed84223SSascha Wildner 8229ed84223SSascha Wildner if (bootverbose && sc->sc_addr != 0) { 8239ed84223SSascha Wildner if_printf(ifp, "pre-configured " 8243351469cSAntonio Huete Jimenez "address 0x%08x, netmask 0x%08x, %d mbuf clusters\n", 8253351469cSAntonio Huete Jimenez ntohl(sc->sc_addr), ntohl(sc->sc_mask), sc->sc_ringsize); 8269ed84223SSascha Wildner } 8279ed84223SSascha Wildner 8289ed84223SSascha Wildner return 0; 8299ed84223SSascha Wildner } 8309ed84223SSascha Wildner 8319ed84223SSascha Wildner static int 8329ed84223SSascha Wildner vke_init_addr(struct ifnet *ifp, in_addr_t addr, in_addr_t mask) 8339ed84223SSascha Wildner { 8349ed84223SSascha Wildner struct ifaliasreq ifra; 8359ed84223SSascha Wildner struct sockaddr_in *sin; 8369ed84223SSascha Wildner int ret; 8379ed84223SSascha Wildner 8389ed84223SSascha Wildner ASSERT_SERIALIZED(ifp->if_serializer); 8399ed84223SSascha Wildner 8409ed84223SSascha Wildner if (bootverbose) { 8419ed84223SSascha Wildner if_printf(ifp, "add pre-configured " 8429ed84223SSascha Wildner "address 0x%08x, netmask 0x%08x\n", 8439ed84223SSascha Wildner ntohl(addr), ntohl(mask)); 8449ed84223SSascha Wildner } 8459ed84223SSascha Wildner 8469ed84223SSascha Wildner bzero(&ifra, sizeof(ifra)); 8479ed84223SSascha Wildner 8489ed84223SSascha Wildner /* NB: no need to set ifaliasreq.ifra_name */ 8499ed84223SSascha Wildner 8509ed84223SSascha Wildner sin = (struct sockaddr_in *)&ifra.ifra_addr; 8519ed84223SSascha Wildner sin->sin_family = AF_INET; 8529ed84223SSascha Wildner sin->sin_len = sizeof(*sin); 8539ed84223SSascha Wildner sin->sin_addr.s_addr = addr; 8549ed84223SSascha Wildner 8559ed84223SSascha Wildner if (mask != 0) { 8569ed84223SSascha Wildner sin = (struct sockaddr_in *)&ifra.ifra_mask; 8579ed84223SSascha Wildner sin->sin_len = sizeof(*sin); 8589ed84223SSascha Wildner sin->sin_addr.s_addr = mask; 8599ed84223SSascha Wildner } 8609ed84223SSascha Wildner 8619ed84223SSascha Wildner /* 8629ed84223SSascha Wildner * Temporarily release serializer, in_control() will hold 8639ed84223SSascha Wildner * it again before calling ifnet.if_ioctl(). 8649ed84223SSascha Wildner */ 8659ed84223SSascha Wildner ifnet_deserialize_all(ifp); 8669ed84223SSascha Wildner ret = in_control(NULL, SIOCAIFADDR, (caddr_t)&ifra, ifp, NULL); 8679ed84223SSascha Wildner ifnet_serialize_all(ifp); 8689ed84223SSascha Wildner 8699ed84223SSascha Wildner return ret; 8709ed84223SSascha Wildner } 871