xref: /dflybsd-src/sys/dev/virtual/vkernel/net/if_vke.c (revision b5523eac31a95e6876e05e20e6fe836ec3a45202)
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