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 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 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 1743351469cSAntonio Huete Jimenez while (NETFIFOINDEX(fifo->windex + 1, sc) == NETFIFOINDEX(fifo->rindex, sc)) { 1759ed84223SSascha Wildner usleep(20000); 1769ed84223SSascha Wildner } 1779ed84223SSascha Wildner 1783351469cSAntonio Huete Jimenez fifo->array[NETFIFOINDEX(fifo->windex, sc)] = m; 1799ed84223SSascha Wildner cpu_sfence(); 1809ed84223SSascha Wildner ++fifo->windex; 1819ed84223SSascha Wildner return (0); 1829ed84223SSascha Wildner } 1839ed84223SSascha Wildner 1849ed84223SSascha Wildner /* 1859ed84223SSascha Wildner * vke_txfifo_done_dequeue() - Remove an mbuf from the transmit done fifo. 1869ed84223SSascha Wildner */ 1879ed84223SSascha Wildner static struct mbuf * 1889ed84223SSascha Wildner vke_txfifo_done_dequeue(struct vke_softc *sc, struct mbuf *nm) 1899ed84223SSascha Wildner { 1909ed84223SSascha Wildner fifo_t fifo = sc->sc_txfifo_done; 1919ed84223SSascha Wildner struct mbuf *m; 1929ed84223SSascha Wildner 1933351469cSAntonio Huete Jimenez if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc)) 1949ed84223SSascha Wildner return (NULL); 1959ed84223SSascha Wildner 1963351469cSAntonio Huete Jimenez m = fifo->array[NETFIFOINDEX(fifo->rindex, sc)]; 1973351469cSAntonio Huete Jimenez fifo->array[NETFIFOINDEX(fifo->rindex, sc)] = nm; 1989ed84223SSascha Wildner cpu_lfence(); 1999ed84223SSascha Wildner ++fifo->rindex; 2009ed84223SSascha Wildner return (m); 2019ed84223SSascha Wildner } 2029ed84223SSascha Wildner 2039ed84223SSascha Wildner /* 2049ed84223SSascha Wildner * vke_txfifo_enqueue() - Add an mbuf to the transmit fifo. 2059ed84223SSascha Wildner */ 2069ed84223SSascha Wildner static int 2079ed84223SSascha Wildner vke_txfifo_enqueue(struct vke_softc *sc, struct mbuf *m) 2089ed84223SSascha Wildner { 2099ed84223SSascha Wildner fifo_t fifo = sc->sc_txfifo; 2109ed84223SSascha Wildner 2113351469cSAntonio Huete Jimenez if (NETFIFOINDEX(fifo->windex + 1, sc) == NETFIFOINDEX(fifo->rindex, sc)) 2129ed84223SSascha Wildner return (-1); 2139ed84223SSascha Wildner 2143351469cSAntonio Huete Jimenez fifo->array[NETFIFOINDEX(fifo->windex, sc)] = m; 2159ed84223SSascha Wildner cpu_sfence(); 2169ed84223SSascha Wildner ++fifo->windex; 2179ed84223SSascha Wildner 2189ed84223SSascha Wildner return (0); 2199ed84223SSascha Wildner } 2209ed84223SSascha Wildner 2219ed84223SSascha Wildner /* 2229ed84223SSascha Wildner * vke_txfifo_dequeue() - Return next mbuf on the transmit fifo if one 2239ed84223SSascha Wildner * exists. 2249ed84223SSascha Wildner */ 2259ed84223SSascha Wildner static struct mbuf * 2269ed84223SSascha Wildner vke_txfifo_dequeue(struct vke_softc *sc) 2279ed84223SSascha Wildner { 2289ed84223SSascha Wildner fifo_t fifo = sc->sc_txfifo; 2299ed84223SSascha Wildner struct mbuf *m; 2309ed84223SSascha Wildner 2313351469cSAntonio Huete Jimenez if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc)) 2329ed84223SSascha Wildner return (NULL); 2339ed84223SSascha Wildner 2343351469cSAntonio Huete Jimenez m = fifo->array[NETFIFOINDEX(fifo->rindex, sc)]; 2353351469cSAntonio Huete Jimenez fifo->array[NETFIFOINDEX(fifo->rindex, sc)] = NULL; 2369ed84223SSascha Wildner 2379ed84223SSascha Wildner cpu_lfence(); 2389ed84223SSascha Wildner ++fifo->rindex; 2399ed84223SSascha Wildner return (m); 2409ed84223SSascha Wildner } 2419ed84223SSascha Wildner 2429ed84223SSascha Wildner static int 2439ed84223SSascha Wildner vke_txfifo_empty(struct vke_softc *sc) 2449ed84223SSascha Wildner { 2459ed84223SSascha Wildner fifo_t fifo = sc->sc_txfifo; 2469ed84223SSascha Wildner 2473351469cSAntonio Huete Jimenez if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc)) 2489ed84223SSascha Wildner return (1); 2499ed84223SSascha Wildner return(0); 2509ed84223SSascha Wildner } 2519ed84223SSascha Wildner 2529ed84223SSascha Wildner /* 2539ed84223SSascha Wildner * vke_rxfifo_dequeue() - Return next mbuf on the receice fifo if one 2549ed84223SSascha Wildner * exists replacing it with newm which should point to a newly allocated 2559ed84223SSascha Wildner * mbuf. 2569ed84223SSascha Wildner */ 2579ed84223SSascha Wildner static struct mbuf * 2589ed84223SSascha Wildner vke_rxfifo_dequeue(struct vke_softc *sc, struct mbuf *newm) 2599ed84223SSascha Wildner { 2609ed84223SSascha Wildner fifo_t fifo = sc->sc_rxfifo; 2619ed84223SSascha Wildner struct mbuf *m; 2629ed84223SSascha Wildner 2633351469cSAntonio Huete Jimenez if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc)) 2649ed84223SSascha Wildner return (NULL); 2659ed84223SSascha Wildner 2663351469cSAntonio Huete Jimenez m = fifo->array[NETFIFOINDEX(fifo->rindex, sc)]; 2673351469cSAntonio Huete Jimenez fifo->array[NETFIFOINDEX(fifo->rindex, sc)] = newm; 2689ed84223SSascha Wildner cpu_lfence(); 2699ed84223SSascha Wildner ++fifo->rindex; 2709ed84223SSascha Wildner return (m); 2719ed84223SSascha Wildner } 2729ed84223SSascha Wildner 2739ed84223SSascha Wildner /* 2749ed84223SSascha Wildner * Return the next mbuf if available but do NOT remove it from the FIFO. 2759ed84223SSascha Wildner */ 2769ed84223SSascha Wildner static struct mbuf * 2779ed84223SSascha Wildner vke_rxfifo_sniff(struct vke_softc *sc) 2789ed84223SSascha Wildner { 2799ed84223SSascha Wildner fifo_t fifo = sc->sc_rxfifo; 2809ed84223SSascha Wildner struct mbuf *m; 2819ed84223SSascha Wildner 2823351469cSAntonio Huete Jimenez if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc)) 2839ed84223SSascha Wildner return (NULL); 2849ed84223SSascha Wildner 2853351469cSAntonio Huete Jimenez m = fifo->array[NETFIFOINDEX(fifo->rindex, sc)]; 2869ed84223SSascha Wildner cpu_lfence(); 2879ed84223SSascha Wildner return (m); 2889ed84223SSascha Wildner } 2899ed84223SSascha Wildner 2909ed84223SSascha Wildner static void 2919ed84223SSascha Wildner vke_init(void *xsc) 2929ed84223SSascha Wildner { 2939ed84223SSascha Wildner struct vke_softc *sc = xsc; 2949ed84223SSascha Wildner struct ifnet *ifp = &sc->arpcom.ac_if; 2953351469cSAntonio Huete Jimenez size_t ringsize = sc->sc_ringsize * sizeof(struct mbuf *); 2969ed84223SSascha Wildner int i; 2979ed84223SSascha Wildner 2989ed84223SSascha Wildner ASSERT_SERIALIZED(ifp->if_serializer); 2999ed84223SSascha Wildner 3009ed84223SSascha Wildner vke_stop(sc); 3019ed84223SSascha Wildner 3029ed84223SSascha Wildner ifp->if_flags |= IFF_RUNNING; 303f0a26983SSepherosa Ziehau ifsq_clr_oactive(ifq_get_subq_default(&ifp->if_snd)); 3049ed84223SSascha Wildner 3053351469cSAntonio Huete Jimenez /* 3063351469cSAntonio Huete Jimenez * Allocate memory for FIFO structures and mbufs. 3073351469cSAntonio Huete Jimenez */ 308c5cc7ccfSAntonio Huete Jimenez sc->sc_txfifo = kmalloc(sizeof(*sc->sc_txfifo), 309c5cc7ccfSAntonio Huete Jimenez M_DEVBUF, M_WAITOK | M_ZERO); 310c5cc7ccfSAntonio Huete Jimenez sc->sc_txfifo_done = kmalloc(sizeof(*sc->sc_txfifo_done), 311c5cc7ccfSAntonio Huete Jimenez M_DEVBUF, M_WAITOK | M_ZERO); 312c5cc7ccfSAntonio Huete Jimenez sc->sc_rxfifo = kmalloc(sizeof(*sc->sc_rxfifo), 313c5cc7ccfSAntonio Huete Jimenez M_DEVBUF, M_WAITOK | M_ZERO); 3143351469cSAntonio Huete Jimenez sc->sc_txfifo->array = kmalloc(ringsize, M_DEVBUF, M_WAITOK | M_ZERO); 3153351469cSAntonio Huete Jimenez sc->sc_txfifo_done->array = kmalloc(ringsize, M_DEVBUF, M_WAITOK | M_ZERO); 3163351469cSAntonio Huete Jimenez sc->sc_rxfifo->array = kmalloc(ringsize, M_DEVBUF, M_WAITOK | M_ZERO); 3173351469cSAntonio Huete Jimenez 3183351469cSAntonio Huete Jimenez for (i = 0; i < sc->sc_ringsize; i++) { 319*b5523eacSSascha Wildner sc->sc_rxfifo->array[i] = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR); 3209ed84223SSascha Wildner sc->sc_txfifo->array[i] = NULL; 3219ed84223SSascha Wildner sc->sc_txfifo_done->array[i] = NULL; 3229ed84223SSascha Wildner } 3239ed84223SSascha Wildner 3249ed84223SSascha Wildner sc->cotd_tx_exit = sc->cotd_rx_exit = VKE_COTD_RUN; 3259ed84223SSascha Wildner sc->cotd_tx = cothread_create(vke_tx_thread, vke_tx_intr, sc, "vke_tx"); 3269ed84223SSascha Wildner sc->cotd_rx = cothread_create(vke_rx_thread, vke_rx_intr, sc, "vke_rx"); 3279ed84223SSascha Wildner 3289ed84223SSascha Wildner if (sc->sc_addr != 0) { 3299ed84223SSascha Wildner in_addr_t addr, mask; 3309ed84223SSascha Wildner 3319ed84223SSascha Wildner addr = sc->sc_addr; 3329ed84223SSascha Wildner mask = sc->sc_mask; 3339ed84223SSascha Wildner 3349ed84223SSascha Wildner /* 3359ed84223SSascha Wildner * Make sure vkernel assigned 3369ed84223SSascha Wildner * address will not be added 3379ed84223SSascha Wildner * again. 3389ed84223SSascha Wildner */ 3399ed84223SSascha Wildner sc->sc_addr = 0; 3409ed84223SSascha Wildner sc->sc_mask = 0; 3419ed84223SSascha Wildner 3429ed84223SSascha Wildner vke_init_addr(ifp, addr, mask); 3439ed84223SSascha Wildner } 3449ed84223SSascha Wildner 3459ed84223SSascha Wildner } 3469ed84223SSascha Wildner 3479ed84223SSascha Wildner /* 3489ed84223SSascha Wildner * Called from kernel. 3499ed84223SSascha Wildner * 3509ed84223SSascha Wildner * NOTE: We can't make any kernel callbacks while holding cothread lock 3519ed84223SSascha Wildner * because the cothread lock is not governed by the kernel scheduler 3529ed84223SSascha Wildner * (so mplock, tokens, etc will not be released). 3539ed84223SSascha Wildner */ 3549ed84223SSascha Wildner static void 355f0a26983SSepherosa Ziehau vke_start(struct ifnet *ifp, struct ifaltq_subque *ifsq) 3569ed84223SSascha Wildner { 3579ed84223SSascha Wildner struct vke_softc *sc = ifp->if_softc; 3589ed84223SSascha Wildner struct mbuf *m; 3599ed84223SSascha Wildner cothread_t cotd = sc->cotd_tx; 3609ed84223SSascha Wildner int count; 3619ed84223SSascha Wildner 362f0a26983SSepherosa Ziehau ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq); 3639ed84223SSascha Wildner ASSERT_SERIALIZED(ifp->if_serializer); 3649ed84223SSascha Wildner 365f0a26983SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0 || ifsq_is_oactive(ifsq)) 3669ed84223SSascha Wildner return; 3679ed84223SSascha Wildner 3689ed84223SSascha Wildner count = 0; 369ac9843a1SSepherosa Ziehau while ((m = ifsq_dequeue(ifsq)) != NULL) { 3709ed84223SSascha Wildner if (vke_txfifo_enqueue(sc, m) != -1) { 371c90aaf98SMatthew Dillon ETHER_BPF_MTAP(ifp, m); 3729ed84223SSascha Wildner if (count++ == VKE_CHUNK) { 3739ed84223SSascha Wildner cothread_lock(cotd, 0); 3749ed84223SSascha Wildner cothread_signal(cotd); 3759ed84223SSascha Wildner cothread_unlock(cotd, 0); 3769ed84223SSascha Wildner count = 0; 3779ed84223SSascha Wildner } 3789ed84223SSascha Wildner } else { 3799ed84223SSascha Wildner m_freem(m); 3809ed84223SSascha Wildner } 3819ed84223SSascha Wildner } 3829ed84223SSascha Wildner if (count) { 3839ed84223SSascha Wildner cothread_lock(cotd, 0); 3849ed84223SSascha Wildner cothread_signal(cotd); 3859ed84223SSascha Wildner cothread_unlock(cotd, 0); 3869ed84223SSascha Wildner } 3879ed84223SSascha Wildner } 3889ed84223SSascha Wildner 3899ed84223SSascha Wildner static int 3909ed84223SSascha Wildner vke_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr) 3919ed84223SSascha Wildner { 3929ed84223SSascha Wildner struct vke_softc *sc = ifp->if_softc; 39370515437SMarkus Pfeiffer struct ifreq *ifr = (struct ifreq *)data; 3949ed84223SSascha Wildner int error = 0; 3959ed84223SSascha Wildner 3969ed84223SSascha Wildner ASSERT_SERIALIZED(ifp->if_serializer); 3979ed84223SSascha Wildner 3989ed84223SSascha Wildner switch (cmd) { 3999ed84223SSascha Wildner case SIOCSIFFLAGS: 4009ed84223SSascha Wildner if (ifp->if_flags & IFF_UP) { 4019ed84223SSascha Wildner if ((ifp->if_flags & IFF_RUNNING) == 0) 4029ed84223SSascha Wildner vke_init(sc); 4039ed84223SSascha Wildner } else { 4049ed84223SSascha Wildner if (ifp->if_flags & IFF_RUNNING) 4059ed84223SSascha Wildner vke_stop(sc); 4069ed84223SSascha Wildner } 4079ed84223SSascha Wildner break; 4089ed84223SSascha Wildner case SIOCGIFMEDIA: 4099ed84223SSascha Wildner case SIOCSIFMEDIA: 41070515437SMarkus Pfeiffer error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 4119ed84223SSascha Wildner break; 4129ed84223SSascha Wildner case SIOCGIFSTATUS: { 4139ed84223SSascha Wildner struct ifstat *ifs = (struct ifstat *)data; 4149ed84223SSascha Wildner int len; 4159ed84223SSascha Wildner 4169ed84223SSascha Wildner len = strlen(ifs->ascii); 4179ed84223SSascha Wildner if (len < sizeof(ifs->ascii)) { 4187cdacfbbSAntonio Huete Jimenez if (sc->sc_tap_unit >= 0) 4199ed84223SSascha Wildner ksnprintf(ifs->ascii + len, sizeof(ifs->ascii) - len, 4209ed84223SSascha Wildner "\tBacked by tap%d\n", sc->sc_tap_unit); 4219ed84223SSascha Wildner } 4229ed84223SSascha Wildner break; 4239ed84223SSascha Wildner } 4249ed84223SSascha Wildner case SIOCSIFADDR: 4259ed84223SSascha Wildner if (((struct ifaddr *)data)->ifa_addr->sa_family == AF_INET) { 4269ed84223SSascha Wildner /* 4279ed84223SSascha Wildner * If we are explicitly requested to change address, 4289ed84223SSascha Wildner * we should invalidate address/netmask passed in 4299ed84223SSascha Wildner * from vkernel command line. 4309ed84223SSascha Wildner */ 4319ed84223SSascha Wildner sc->sc_addr = 0; 4329ed84223SSascha Wildner sc->sc_mask = 0; 4339ed84223SSascha Wildner } 4349ed84223SSascha Wildner /* FALL THROUGH */ 4359ed84223SSascha Wildner default: 4369ed84223SSascha Wildner error = ether_ioctl(ifp, cmd, data); 4379ed84223SSascha Wildner break; 4389ed84223SSascha Wildner } 4399ed84223SSascha Wildner return error; 4409ed84223SSascha Wildner } 4419ed84223SSascha Wildner 4429ed84223SSascha Wildner static int 4439ed84223SSascha Wildner vke_stop(struct vke_softc *sc) 4449ed84223SSascha Wildner { 4459ed84223SSascha Wildner struct ifnet *ifp = &sc->arpcom.ac_if; 4469ed84223SSascha Wildner int i; 4479ed84223SSascha Wildner 4489ed84223SSascha Wildner ASSERT_SERIALIZED(ifp->if_serializer); 4499ed84223SSascha Wildner 4509ed293e0SSepherosa Ziehau ifp->if_flags &= ~IFF_RUNNING; 451f0a26983SSepherosa Ziehau ifsq_clr_oactive(ifq_get_subq_default(&ifp->if_snd)); 4529ed84223SSascha Wildner 4539ed84223SSascha Wildner if (sc) { 4549ed84223SSascha Wildner if (sc->cotd_tx) { 4559ed84223SSascha Wildner cothread_lock(sc->cotd_tx, 0); 4569ed84223SSascha Wildner if (sc->cotd_tx_exit == VKE_COTD_RUN) 4579ed84223SSascha Wildner sc->cotd_tx_exit = VKE_COTD_EXIT; 4589ed84223SSascha Wildner cothread_signal(sc->cotd_tx); 4599ed84223SSascha Wildner cothread_unlock(sc->cotd_tx, 0); 4609ed84223SSascha Wildner cothread_delete(&sc->cotd_tx); 4619ed84223SSascha Wildner } 4629ed84223SSascha Wildner if (sc->cotd_rx) { 4639ed84223SSascha Wildner cothread_lock(sc->cotd_rx, 0); 4649ed84223SSascha Wildner if (sc->cotd_rx_exit == VKE_COTD_RUN) 4659ed84223SSascha Wildner sc->cotd_rx_exit = VKE_COTD_EXIT; 4669ed84223SSascha Wildner cothread_signal(sc->cotd_rx); 4679ed84223SSascha Wildner cothread_unlock(sc->cotd_rx, 0); 4689ed84223SSascha Wildner cothread_delete(&sc->cotd_rx); 4699ed84223SSascha Wildner } 4709ed84223SSascha Wildner 4713351469cSAntonio Huete Jimenez for (i = 0; i < sc->sc_ringsize; i++) { 4729ed84223SSascha Wildner if (sc->sc_rxfifo && sc->sc_rxfifo->array[i]) { 4739ed84223SSascha Wildner m_freem(sc->sc_rxfifo->array[i]); 4749ed84223SSascha Wildner sc->sc_rxfifo->array[i] = NULL; 4759ed84223SSascha Wildner } 4769ed84223SSascha Wildner if (sc->sc_txfifo && sc->sc_txfifo->array[i]) { 4779ed84223SSascha Wildner m_freem(sc->sc_txfifo->array[i]); 4789ed84223SSascha Wildner sc->sc_txfifo->array[i] = NULL; 4799ed84223SSascha Wildner } 4809ed84223SSascha Wildner if (sc->sc_txfifo_done && sc->sc_txfifo_done->array[i]) { 4819ed84223SSascha Wildner m_freem(sc->sc_txfifo_done->array[i]); 4829ed84223SSascha Wildner sc->sc_txfifo_done->array[i] = NULL; 4839ed84223SSascha Wildner } 4849ed84223SSascha Wildner } 4859ed84223SSascha Wildner 4869ed84223SSascha Wildner if (sc->sc_txfifo) { 4873351469cSAntonio Huete Jimenez if (sc->sc_txfifo->array) 4883351469cSAntonio Huete Jimenez kfree(sc->sc_txfifo->array, M_DEVBUF); 4899ed84223SSascha Wildner kfree(sc->sc_txfifo, M_DEVBUF); 4909ed84223SSascha Wildner sc->sc_txfifo = NULL; 4919ed84223SSascha Wildner } 4929ed84223SSascha Wildner 4939ed84223SSascha Wildner if (sc->sc_txfifo_done) { 4943351469cSAntonio Huete Jimenez if (sc->sc_txfifo_done->array) 4953351469cSAntonio Huete Jimenez kfree(sc->sc_txfifo_done->array, M_DEVBUF); 4969ed84223SSascha Wildner kfree(sc->sc_txfifo_done, M_DEVBUF); 4979ed84223SSascha Wildner sc->sc_txfifo_done = NULL; 4989ed84223SSascha Wildner } 4999ed84223SSascha Wildner 5009ed84223SSascha Wildner if (sc->sc_rxfifo) { 5013351469cSAntonio Huete Jimenez if (sc->sc_rxfifo->array) 5023351469cSAntonio Huete Jimenez kfree(sc->sc_rxfifo->array, M_DEVBUF); 5039ed84223SSascha Wildner kfree(sc->sc_rxfifo, M_DEVBUF); 5049ed84223SSascha Wildner sc->sc_rxfifo = NULL; 5059ed84223SSascha Wildner } 5069ed84223SSascha Wildner } 5079ed84223SSascha Wildner 5089ed84223SSascha Wildner 5099ed84223SSascha Wildner return 0; 5109ed84223SSascha Wildner } 5119ed84223SSascha Wildner 5129ed84223SSascha Wildner /* 5139ed84223SSascha Wildner * vke_rx_intr() is the interrupt function for the receive cothread. 5149ed84223SSascha Wildner */ 5159ed84223SSascha Wildner static void 5169ed84223SSascha Wildner vke_rx_intr(cothread_t cotd) 5179ed84223SSascha Wildner { 5189ed84223SSascha Wildner struct mbuf *m; 5199ed84223SSascha Wildner struct mbuf *nm; 5209ed84223SSascha Wildner struct vke_softc *sc = cotd->arg; 5219ed84223SSascha Wildner struct ifnet *ifp = &sc->arpcom.ac_if; 5229ed84223SSascha Wildner static int count = 0; 5239ed84223SSascha Wildner 5249ed84223SSascha Wildner ifnet_serialize_all(ifp); 5259ed84223SSascha Wildner cothread_lock(cotd, 0); 5269ed84223SSascha Wildner 5279ed84223SSascha Wildner if (sc->cotd_rx_exit != VKE_COTD_RUN) { 5289ed84223SSascha Wildner cothread_unlock(cotd, 0); 5299ed84223SSascha Wildner ifnet_deserialize_all(ifp); 5309ed84223SSascha Wildner return; 5319ed84223SSascha Wildner } 532a9844950SMatthew Dillon if (sc->cotd_ipackets) { 533a9844950SMatthew Dillon IFNET_STAT_INC(ifp, ipackets, 1); 534a9844950SMatthew Dillon sc->cotd_ipackets = 0; 535a9844950SMatthew Dillon } 5369ed84223SSascha Wildner cothread_unlock(cotd, 0); 5379ed84223SSascha Wildner 5389ed84223SSascha Wildner while ((m = vke_rxfifo_sniff(sc)) != NULL) { 539*b5523eacSSascha Wildner nm = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 5409ed84223SSascha Wildner if (nm) { 5419ed84223SSascha Wildner vke_rxfifo_dequeue(sc, nm); 54273029d08SFranco Fichtner ifp->if_input(ifp, m, NULL, -1); 5439ed84223SSascha Wildner if (count++ == VKE_CHUNK) { 5449ed84223SSascha Wildner cothread_lock(cotd, 0); 5459ed84223SSascha Wildner cothread_signal(cotd); 5469ed84223SSascha Wildner cothread_unlock(cotd, 0); 5479ed84223SSascha Wildner count = 0; 5489ed84223SSascha Wildner } 5499ed84223SSascha Wildner } else { 5509ed84223SSascha Wildner vke_rxfifo_dequeue(sc, m); 5519ed84223SSascha Wildner } 5529ed84223SSascha Wildner } 5539ed84223SSascha Wildner 5549ed84223SSascha Wildner if (count) { 5559ed84223SSascha Wildner cothread_lock(cotd, 0); 5569ed84223SSascha Wildner cothread_signal(cotd); 5579ed84223SSascha Wildner cothread_unlock(cotd, 0); 5589ed84223SSascha Wildner } 5599ed84223SSascha Wildner ifnet_deserialize_all(ifp); 5609ed84223SSascha Wildner } 5619ed84223SSascha Wildner 5629ed84223SSascha Wildner /* 5639ed84223SSascha Wildner * vke_tx_intr() is the interrupt function for the transmit cothread. 5649ed84223SSascha Wildner * Calls vke_start() to handle processing transmit mbufs. 5659ed84223SSascha Wildner */ 5669ed84223SSascha Wildner static void 5679ed84223SSascha Wildner vke_tx_intr(cothread_t cotd) 5689ed84223SSascha Wildner { 5699ed84223SSascha Wildner struct vke_softc *sc = cotd->arg; 5709ed84223SSascha Wildner struct ifnet *ifp = &sc->arpcom.ac_if; 5719ed84223SSascha Wildner struct mbuf *m; 5729ed84223SSascha Wildner 5739ed84223SSascha Wildner ifnet_serialize_all(ifp); 5749ed84223SSascha Wildner cothread_lock(cotd, 0); 5759ed84223SSascha Wildner if (sc->cotd_tx_exit != VKE_COTD_RUN) { 5769ed84223SSascha Wildner cothread_unlock(cotd, 0); 5779ed84223SSascha Wildner ifnet_deserialize_all(ifp); 5789ed84223SSascha Wildner return; 5799ed84223SSascha Wildner } 580a9844950SMatthew Dillon if (sc->cotd_opackets) { 581a9844950SMatthew Dillon IFNET_STAT_INC(ifp, opackets, 1); 582a9844950SMatthew Dillon sc->cotd_opackets = 0; 583a9844950SMatthew Dillon } 584a9844950SMatthew Dillon if (sc->cotd_oerrors) { 585a9844950SMatthew Dillon IFNET_STAT_INC(ifp, oerrors, 1); 586a9844950SMatthew Dillon sc->cotd_oerrors = 0; 587a9844950SMatthew Dillon } 5889ed84223SSascha Wildner cothread_unlock(cotd, 0); 5899ed84223SSascha Wildner 5909ed84223SSascha Wildner /* 5919ed84223SSascha Wildner * Free TX mbufs that have been processed before starting new 5929ed84223SSascha Wildner * ones going to be pipeline friendly. 5939ed84223SSascha Wildner */ 5949ed84223SSascha Wildner while ((m = vke_txfifo_done_dequeue(sc, NULL)) != NULL) { 5959ed84223SSascha Wildner m_freem(m); 5969ed84223SSascha Wildner } 5979ed84223SSascha Wildner 5989ed84223SSascha Wildner if ((ifp->if_flags & IFF_RUNNING) == 0) 599f0a26983SSepherosa Ziehau if_devstart(ifp); 6009ed84223SSascha Wildner 6019ed84223SSascha Wildner ifnet_deserialize_all(ifp); 6029ed84223SSascha Wildner } 6039ed84223SSascha Wildner 6049ed84223SSascha Wildner /* 6059ed84223SSascha Wildner * vke_rx_thread() is the body of the receive cothread. 606a9844950SMatthew Dillon * 607a9844950SMatthew Dillon * WARNING! THIS IS A COTHREAD WHICH HAS NO PER-CPU GLOBALDATA!!!!! 6089ed84223SSascha Wildner */ 6099ed84223SSascha Wildner static void 6109ed84223SSascha Wildner vke_rx_thread(cothread_t cotd) 6119ed84223SSascha Wildner { 6129ed84223SSascha Wildner struct mbuf *m; 6139ed84223SSascha Wildner struct vke_softc *sc = cotd->arg; 6149ed84223SSascha Wildner struct ifnet *ifp = &sc->arpcom.ac_if; 6159ed84223SSascha Wildner fifo_t fifo = sc->sc_rxfifo; 6169ed84223SSascha Wildner fd_set fdset; 6179ed84223SSascha Wildner struct timeval tv; 6189ed84223SSascha Wildner int count; 6199ed84223SSascha Wildner int n; 6209ed84223SSascha Wildner 6219ed84223SSascha Wildner /* Select timeout cannot be infinite since we need to check for 6229ed84223SSascha Wildner * the exit flag sc->cotd_rx_exit. 6239ed84223SSascha Wildner */ 6249ed84223SSascha Wildner tv.tv_sec = 0; 6259ed84223SSascha Wildner tv.tv_usec = 500000; 6269ed84223SSascha Wildner 6279ed84223SSascha Wildner FD_ZERO(&fdset); 6289ed84223SSascha Wildner count = 0; 6299ed84223SSascha Wildner 6309ed84223SSascha Wildner while (sc->cotd_rx_exit == VKE_COTD_RUN) { 6319ed84223SSascha Wildner /* 6329ed84223SSascha Wildner * Wait for the RX FIFO to be loaded with 6339ed84223SSascha Wildner * empty mbufs. 6349ed84223SSascha Wildner */ 6353351469cSAntonio Huete Jimenez if (NETFIFOINDEX(fifo->windex + 1, sc) == 6363351469cSAntonio Huete Jimenez NETFIFOINDEX(fifo->rindex, sc)) { 6379ed84223SSascha Wildner usleep(20000); 6389ed84223SSascha Wildner continue; 6399ed84223SSascha Wildner } 6409ed84223SSascha Wildner 6419ed84223SSascha Wildner /* 6429ed84223SSascha Wildner * Load data into the rx fifo 6439ed84223SSascha Wildner */ 6443351469cSAntonio Huete Jimenez m = fifo->array[NETFIFOINDEX(fifo->windex, sc)]; 6459ed84223SSascha Wildner if (m == NULL) 6469ed84223SSascha Wildner continue; 6479ed84223SSascha Wildner n = read(sc->sc_fd, mtod(m, void *), MCLBYTES); 6489ed84223SSascha Wildner if (n > 0) { 649a9844950SMatthew Dillon /* no mycpu in cothread */ 650a9844950SMatthew Dillon /*IFNET_STAT_INC(ifp, ipackets, 1);*/ 651a9844950SMatthew Dillon ++sc->cotd_ipackets; 6529ed84223SSascha Wildner m->m_pkthdr.rcvif = ifp; 6539ed84223SSascha Wildner m->m_pkthdr.len = m->m_len = n; 6549ed84223SSascha Wildner cpu_sfence(); 6559ed84223SSascha Wildner ++fifo->windex; 6569ed84223SSascha Wildner if (count++ == VKE_CHUNK) { 6579ed84223SSascha Wildner cothread_intr(cotd); 6589ed84223SSascha Wildner count = 0; 6599ed84223SSascha Wildner } 6609ed84223SSascha Wildner } else { 6619ed84223SSascha Wildner if (count) { 6629ed84223SSascha Wildner cothread_intr(cotd); 6639ed84223SSascha Wildner count = 0; 6649ed84223SSascha Wildner } 6659ed84223SSascha Wildner FD_SET(sc->sc_fd, &fdset); 6669ed84223SSascha Wildner 6679ed84223SSascha Wildner if (select(sc->sc_fd + 1, &fdset, NULL, NULL, &tv) == -1) { 668a9844950SMatthew Dillon fprintf(stderr, 669a9844950SMatthew Dillon VKE_DEVNAME "%d: select failed for " 6709ed84223SSascha Wildner "TAP device\n", sc->sc_unit); 6719ed84223SSascha Wildner usleep(1000000); 6729ed84223SSascha Wildner } 6739ed84223SSascha Wildner } 6749ed84223SSascha Wildner } 6759ed84223SSascha Wildner cpu_sfence(); 6769ed84223SSascha Wildner sc->cotd_rx_exit = VKE_COTD_DEAD; 6779ed84223SSascha Wildner } 6789ed84223SSascha Wildner 6799ed84223SSascha Wildner /* 6809ed84223SSascha Wildner * vke_tx_thread() is the body of the transmit cothread. 681a9844950SMatthew Dillon * 682a9844950SMatthew Dillon * WARNING! THIS IS A COTHREAD WHICH HAS NO PER-CPU GLOBALDATA!!!!! 6839ed84223SSascha Wildner */ 6849ed84223SSascha Wildner static void 6859ed84223SSascha Wildner vke_tx_thread(cothread_t cotd) 6869ed84223SSascha Wildner { 6879ed84223SSascha Wildner struct mbuf *m; 6889ed84223SSascha Wildner struct vke_softc *sc = cotd->arg; 689171a58dfSSascha Wildner /*struct ifnet *ifp = &sc->arpcom.ac_if;*/ 6909ed84223SSascha Wildner int count = 0; 6919ed84223SSascha Wildner 6929ed84223SSascha Wildner while (sc->cotd_tx_exit == VKE_COTD_RUN) { 6939ed84223SSascha Wildner /* 6949ed84223SSascha Wildner * Write outgoing packets to the TAP interface 6959ed84223SSascha Wildner */ 6969ed84223SSascha Wildner m = vke_txfifo_dequeue(sc); 6979ed84223SSascha Wildner if (m) { 6989ed84223SSascha Wildner if (m->m_pkthdr.len <= MCLBYTES) { 6999ed84223SSascha Wildner m_copydata(m, 0, m->m_pkthdr.len, sc->sc_txbuf); 7009ed84223SSascha Wildner sc->sc_txbuf_len = m->m_pkthdr.len; 7019ed84223SSascha Wildner 7029ed84223SSascha Wildner if (write(sc->sc_fd, sc->sc_txbuf, 7039ed84223SSascha Wildner sc->sc_txbuf_len) < 0) { 704a9844950SMatthew Dillon /* no mycpu in cothread */ 705a9844950SMatthew Dillon /*IFNET_STAT_INC(ifp, oerrors, 1);*/ 706a9844950SMatthew Dillon ++sc->cotd_oerrors; 7079ed84223SSascha Wildner } else { 708a9844950SMatthew Dillon /* no mycpu in cothread */ 709a9844950SMatthew Dillon /*IFNET_STAT_INC(ifp, opackets, 1);*/ 710a9844950SMatthew Dillon ++sc->cotd_opackets; 7119ed84223SSascha Wildner } 7129ed84223SSascha Wildner } 7139ed84223SSascha Wildner if (count++ == VKE_CHUNK) { 7149ed84223SSascha Wildner cothread_intr(cotd); 7159ed84223SSascha Wildner count = 0; 7169ed84223SSascha Wildner } 7179ed84223SSascha Wildner vke_txfifo_done_enqueue(sc, m); 7189ed84223SSascha Wildner } else { 7199ed84223SSascha Wildner if (count) { 7209ed84223SSascha Wildner cothread_intr(cotd); 7219ed84223SSascha Wildner count = 0; 7229ed84223SSascha Wildner } 7239ed84223SSascha Wildner cothread_lock(cotd, 1); 7249ed84223SSascha Wildner if (vke_txfifo_empty(sc)) 7259ed84223SSascha Wildner cothread_wait(cotd); 7269ed84223SSascha Wildner cothread_unlock(cotd, 1); 7279ed84223SSascha Wildner } 7289ed84223SSascha Wildner } 7299ed84223SSascha Wildner cpu_sfence(); 7309ed84223SSascha Wildner sc->cotd_tx_exit = VKE_COTD_DEAD; 7319ed84223SSascha Wildner } 7329ed84223SSascha Wildner 7339ed84223SSascha Wildner static int 7349ed84223SSascha Wildner vke_attach(const struct vknetif_info *info, int unit) 7359ed84223SSascha Wildner { 7369ed84223SSascha Wildner struct vke_softc *sc; 7379ed84223SSascha Wildner struct ifnet *ifp; 7389ed84223SSascha Wildner struct tapinfo tapinfo; 7399ed84223SSascha Wildner uint8_t enaddr[ETHER_ADDR_LEN]; 7403351469cSAntonio Huete Jimenez int nmbufs; 7419ed84223SSascha Wildner int fd; 7429ed84223SSascha Wildner 7439ed84223SSascha Wildner KKASSERT(info->tap_fd >= 0); 7449ed84223SSascha Wildner fd = info->tap_fd; 7459ed84223SSascha Wildner 74686d2b040SAntonio Huete Jimenez if (info->enaddr) { 747b3a6732eSMatthew Dillon /* 748b3a6732eSMatthew Dillon * enaddr is supplied 749b3a6732eSMatthew Dillon */ 75086d2b040SAntonio Huete Jimenez bcopy(info->enaddr, enaddr, ETHER_ADDR_LEN); 751b3a6732eSMatthew Dillon } else { 7529ed84223SSascha Wildner /* 7539ed84223SSascha Wildner * This is only a TAP device if tap_unit is non-zero. If 7549ed84223SSascha Wildner * connecting to a virtual socket we generate a unique MAC. 755b3a6732eSMatthew Dillon * 756b3a6732eSMatthew Dillon * WARNING: enaddr[0] bit 0 is the multicast bit, when 757b3a6732eSMatthew Dillon * randomizing enaddr[] just leave the first 758b3a6732eSMatthew Dillon * two bytes 00 00 for now. 7599ed84223SSascha Wildner */ 760b3a6732eSMatthew Dillon bzero(enaddr, sizeof(enaddr)); 7619ed84223SSascha Wildner if (info->tap_unit >= 0) { 7629ed84223SSascha Wildner if (ioctl(fd, TAPGIFINFO, &tapinfo) < 0) { 7639ed84223SSascha Wildner kprintf(VKE_DEVNAME "%d: ioctl(TAPGIFINFO) " 7649ed84223SSascha Wildner "failed: %s\n", unit, strerror(errno)); 7659ed84223SSascha Wildner return ENXIO; 7669ed84223SSascha Wildner } 7679ed84223SSascha Wildner 7689ed84223SSascha Wildner if (ioctl(fd, SIOCGIFADDR, enaddr) < 0) { 7699ed84223SSascha Wildner kprintf(VKE_DEVNAME "%d: ioctl(SIOCGIFADDR) " 7709ed84223SSascha Wildner "failed: %s\n", unit, strerror(errno)); 7719ed84223SSascha Wildner return ENXIO; 7729ed84223SSascha Wildner } 7739ed84223SSascha Wildner } else { 7749ed84223SSascha Wildner int fd = open("/dev/urandom", O_RDONLY); 7759ed84223SSascha Wildner if (fd >= 0) { 7769ed84223SSascha Wildner read(fd, enaddr + 2, 4); 7779ed84223SSascha Wildner close(fd); 7789ed84223SSascha Wildner } 7799ed84223SSascha Wildner enaddr[4] = (int)getpid() >> 8; 7809ed84223SSascha Wildner enaddr[5] = (int)getpid() & 255; 7819ed84223SSascha Wildner 7829ed84223SSascha Wildner } 7839ed84223SSascha Wildner enaddr[1] += 1; 784b3a6732eSMatthew Dillon } 785b3a6732eSMatthew Dillon if (ETHER_IS_MULTICAST(enaddr)) { 786b3a6732eSMatthew Dillon kprintf(VKE_DEVNAME "%d: illegal MULTICAST ether mac!\n", unit); 787b3a6732eSMatthew Dillon return ENXIO; 788b3a6732eSMatthew Dillon } 7899ed84223SSascha Wildner 7909ed84223SSascha Wildner sc = kmalloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 7919ed84223SSascha Wildner 7929ed84223SSascha Wildner sc->sc_txbuf = kmalloc(MCLBYTES, M_DEVBUF, M_WAITOK); 7939ed84223SSascha Wildner sc->sc_fd = fd; 7949ed84223SSascha Wildner sc->sc_unit = unit; 7959ed84223SSascha Wildner sc->sc_tap_unit = info->tap_unit; 7969ed84223SSascha Wildner sc->sc_addr = info->netif_addr; 7979ed84223SSascha Wildner sc->sc_mask = info->netif_mask; 7989ed84223SSascha Wildner 79933c27d6cSAntonio Huete Jimenez if (vke_max_ringsize == 0) { 8003351469cSAntonio Huete Jimenez nmbufs = nmbclusters / (NetifNum * 2); 80133c27d6cSAntonio Huete Jimenez sc->sc_ringsize = LOW_POW_2(nmbufs); 80233c27d6cSAntonio Huete Jimenez if (sc->sc_ringsize > VKE_DEFAULT_RINGSIZE) 80333c27d6cSAntonio Huete Jimenez sc->sc_ringsize = VKE_DEFAULT_RINGSIZE; 80433c27d6cSAntonio Huete Jimenez } else if (vke_max_ringsize >= VKE_CHUNK) { /* Tunable specified */ 80533c27d6cSAntonio Huete Jimenez sc->sc_ringsize = LOW_POW_2(vke_max_ringsize); 80633c27d6cSAntonio Huete Jimenez } else { 80733c27d6cSAntonio Huete Jimenez sc->sc_ringsize = LOW_POW_2(VKE_CHUNK); 80833c27d6cSAntonio Huete Jimenez } 8093351469cSAntonio Huete Jimenez 8109ed84223SSascha Wildner ifp = &sc->arpcom.ac_if; 8119ed84223SSascha Wildner if_initname(ifp, VKE_DEVNAME, sc->sc_unit); 8129ed84223SSascha Wildner 8139ed84223SSascha Wildner /* NB: after if_initname() */ 8149ed84223SSascha Wildner sysctl_ctx_init(&sc->sc_sysctl_ctx); 8159ed84223SSascha Wildner sc->sc_sysctl_tree = SYSCTL_ADD_NODE(&sc->sc_sysctl_ctx, 8169ed84223SSascha Wildner SYSCTL_STATIC_CHILDREN(_hw), 8179ed84223SSascha Wildner OID_AUTO, ifp->if_xname, 8189ed84223SSascha Wildner CTLFLAG_RD, 0, ""); 8199ed84223SSascha Wildner if (sc->sc_sysctl_tree == NULL) { 8209ed84223SSascha Wildner kprintf(VKE_DEVNAME "%d: can't add sysctl node\n", unit); 8219ed84223SSascha Wildner } else { 8229ed84223SSascha Wildner SYSCTL_ADD_INT(&sc->sc_sysctl_ctx, 8239ed84223SSascha Wildner SYSCTL_CHILDREN(sc->sc_sysctl_tree), 8249ed84223SSascha Wildner OID_AUTO, "tap_unit", 8259ed84223SSascha Wildner CTLFLAG_RD, &sc->sc_tap_unit, 0, 8269ed84223SSascha Wildner "Backend tap(4) unit"); 8279ed84223SSascha Wildner } 8289ed84223SSascha Wildner 8299ed84223SSascha Wildner ifp->if_softc = sc; 8309ed84223SSascha Wildner ifp->if_ioctl = vke_ioctl; 8319ed84223SSascha Wildner ifp->if_start = vke_start; 8329ed84223SSascha Wildner ifp->if_init = vke_init; 8339ed84223SSascha Wildner ifp->if_mtu = tapinfo.mtu; 8349ed84223SSascha Wildner ifp->if_baudrate = tapinfo.baudrate; 8359ed84223SSascha Wildner ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 8369ed84223SSascha Wildner ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN); 8379ed84223SSascha Wildner ifq_set_ready(&ifp->if_snd); 8389ed84223SSascha Wildner 83970515437SMarkus Pfeiffer ifmedia_init(&sc->sc_media, 0, vke_media_change, vke_media_status); 84070515437SMarkus Pfeiffer /* We support as many media types as we please for 84170515437SMarkus Pfeiffer debugging purposes */ 84270515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_T, 0, NULL); 84370515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL); 84470515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_2, 0, NULL); 84570515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_5, 0, NULL); 84670515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_TX, 0, NULL); 84770515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL); 84870515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_FX, 0, NULL); 84970515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_T4, 0, NULL); 85070515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_VG, 0, NULL); 85170515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_T2, 0, NULL); 85270515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_1000_FX, 0, NULL); 85370515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_STP, 0, NULL); 85470515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_FL, 0, NULL); 85570515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_1000_SX, 0, NULL); 85670515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_1000_LX, 0, NULL); 85770515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_1000_CX, 0, NULL); 85870515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_1000_T, 0, NULL); 85970515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); 86070515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_HPNA_1, 0, NULL); 86170515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10G_LR, 0, NULL); 86270515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10G_SR, 0, NULL); 86370515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10G_CX4, 0, NULL); 86470515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_2500_SX, 0, NULL); 86570515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); 86670515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10G_TWINAX_LONG, 0, NULL); 86770515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10G_LRM, 0, NULL); 86870515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10G_T, 0, NULL); 86970515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_40G_CR4, 0, NULL); 87070515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_40G_SR4, 0, NULL); 87170515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_40G_LR4, 0, NULL); 87270515437SMarkus Pfeiffer ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL); 87370515437SMarkus Pfeiffer 87470515437SMarkus Pfeiffer ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO); 87570515437SMarkus Pfeiffer 87670515437SMarkus Pfeiffer ifp->if_link_state = LINK_STATE_UP; 8779ed84223SSascha Wildner 8789ed84223SSascha Wildner ether_ifattach(ifp, enaddr, NULL); 8799ed84223SSascha Wildner 8809ed84223SSascha Wildner if (bootverbose && sc->sc_addr != 0) { 8819ed84223SSascha Wildner if_printf(ifp, "pre-configured " 8823351469cSAntonio Huete Jimenez "address 0x%08x, netmask 0x%08x, %d mbuf clusters\n", 8833351469cSAntonio Huete Jimenez ntohl(sc->sc_addr), ntohl(sc->sc_mask), sc->sc_ringsize); 8849ed84223SSascha Wildner } 8859ed84223SSascha Wildner 8869ed84223SSascha Wildner return 0; 8879ed84223SSascha Wildner } 8889ed84223SSascha Wildner 8899ed84223SSascha Wildner static int 8909ed84223SSascha Wildner vke_init_addr(struct ifnet *ifp, in_addr_t addr, in_addr_t mask) 8919ed84223SSascha Wildner { 8929ed84223SSascha Wildner struct ifaliasreq ifra; 8939ed84223SSascha Wildner struct sockaddr_in *sin; 8949ed84223SSascha Wildner int ret; 8959ed84223SSascha Wildner 8969ed84223SSascha Wildner ASSERT_SERIALIZED(ifp->if_serializer); 8979ed84223SSascha Wildner 8989ed84223SSascha Wildner if (bootverbose) { 8999ed84223SSascha Wildner if_printf(ifp, "add pre-configured " 9009ed84223SSascha Wildner "address 0x%08x, netmask 0x%08x\n", 9019ed84223SSascha Wildner ntohl(addr), ntohl(mask)); 9029ed84223SSascha Wildner } 9039ed84223SSascha Wildner 9049ed84223SSascha Wildner bzero(&ifra, sizeof(ifra)); 9059ed84223SSascha Wildner 9069ed84223SSascha Wildner /* NB: no need to set ifaliasreq.ifra_name */ 9079ed84223SSascha Wildner 9089ed84223SSascha Wildner sin = (struct sockaddr_in *)&ifra.ifra_addr; 9099ed84223SSascha Wildner sin->sin_family = AF_INET; 9109ed84223SSascha Wildner sin->sin_len = sizeof(*sin); 9119ed84223SSascha Wildner sin->sin_addr.s_addr = addr; 9129ed84223SSascha Wildner 9139ed84223SSascha Wildner if (mask != 0) { 9149ed84223SSascha Wildner sin = (struct sockaddr_in *)&ifra.ifra_mask; 9159ed84223SSascha Wildner sin->sin_len = sizeof(*sin); 9169ed84223SSascha Wildner sin->sin_addr.s_addr = mask; 9179ed84223SSascha Wildner } 9189ed84223SSascha Wildner 9199ed84223SSascha Wildner /* 9209ed84223SSascha Wildner * Temporarily release serializer, in_control() will hold 9219ed84223SSascha Wildner * it again before calling ifnet.if_ioctl(). 9229ed84223SSascha Wildner */ 9239ed84223SSascha Wildner ifnet_deserialize_all(ifp); 9242501b0eaSSepherosa Ziehau ret = in_control(SIOCAIFADDR, (caddr_t)&ifra, ifp, NULL); 9259ed84223SSascha Wildner ifnet_serialize_all(ifp); 9269ed84223SSascha Wildner 9279ed84223SSascha Wildner return ret; 9289ed84223SSascha Wildner } 92970515437SMarkus Pfeiffer 93070515437SMarkus Pfeiffer static int vke_media_change(struct ifnet *ifp) 93170515437SMarkus Pfeiffer { 93270515437SMarkus Pfeiffer /* ignored */ 93370515437SMarkus Pfeiffer return(0); 93470515437SMarkus Pfeiffer } 93570515437SMarkus Pfeiffer 93670515437SMarkus Pfeiffer static void vke_media_status(struct ifnet *ifp, struct ifmediareq *imr) 93770515437SMarkus Pfeiffer { 93870515437SMarkus Pfeiffer struct vke_softc *sc = (struct vke_softc *)ifp->if_softc; 93970515437SMarkus Pfeiffer 94070515437SMarkus Pfeiffer imr->ifm_status = IFM_AVALID; 94170515437SMarkus Pfeiffer imr->ifm_status |= IFM_ACTIVE; 94270515437SMarkus Pfeiffer 94370515437SMarkus Pfeiffer if(sc->sc_media.ifm_cur) { 94470515437SMarkus Pfeiffer if(sc->sc_media.ifm_cur->ifm_media == IFM_ETHER) { 94570515437SMarkus Pfeiffer imr->ifm_active = IFM_ETHER | IFM_1000_T | IFM_FDX; 94670515437SMarkus Pfeiffer } else { 94770515437SMarkus Pfeiffer imr->ifm_active = sc->sc_media.ifm_cur->ifm_media; 94870515437SMarkus Pfeiffer } 94970515437SMarkus Pfeiffer } else { 95070515437SMarkus Pfeiffer imr->ifm_active = IFM_ETHER | IFM_1000_T | IFM_FDX; 95170515437SMarkus Pfeiffer } 95270515437SMarkus Pfeiffer } 953