Module Name: src Committed By: pooka Date: Mon Nov 15 20:23:12 UTC 2010
Modified Files: src/sys/rump/net/lib/libvirtif: if_virt.c Log Message: Make interface support ifconfig {down,destroy} and generally make it a little less eager to panic. To generate a diff of this commit: cvs rdiff -u -r1.20 -r1.21 src/sys/rump/net/lib/libvirtif/if_virt.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/rump/net/lib/libvirtif/if_virt.c diff -u src/sys/rump/net/lib/libvirtif/if_virt.c:1.20 src/sys/rump/net/lib/libvirtif/if_virt.c:1.21 --- src/sys/rump/net/lib/libvirtif/if_virt.c:1.20 Tue Oct 19 19:19:41 2010 +++ src/sys/rump/net/lib/libvirtif/if_virt.c Mon Nov 15 20:23:11 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: if_virt.c,v 1.20 2010/10/19 19:19:41 pooka Exp $ */ +/* $NetBSD: if_virt.c,v 1.21 2010/11/15 20:23:11 pooka Exp $ */ /* * Copyright (c) 2008 Antti Kantee. All Rights Reserved. @@ -26,11 +26,12 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_virt.c,v 1.20 2010/10/19 19:19:41 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_virt.c,v 1.21 2010/11/15 20:23:11 pooka Exp $"); #include <sys/param.h> #include <sys/condvar.h> #include <sys/fcntl.h> +#include <sys/kernel.h> #include <sys/kmem.h> #include <sys/kthread.h> #include <sys/mutex.h> @@ -68,11 +69,13 @@ struct virtif_sc { struct ethercom sc_ec; int sc_tapfd; - kmutex_t sc_sendmtx; - kcondvar_t sc_sendcv; + bool sc_dying; + struct lwp *sc_l_snd, *sc_l_rcv; + kmutex_t sc_mtx; + kcondvar_t sc_cv; }; -static void virtif_worker(void *); +static void virtif_receiver(void *); static void virtif_sender(void *); static int virtif_clone(struct if_clone *, int); static int virtif_unclone(struct ifnet *); @@ -87,7 +90,10 @@ struct ifnet *ifp; uint8_t enaddr[ETHER_ADDR_LEN] = { 0xb2, 0x0a, 0x00, 0x0b, 0x0e, 0x01 }; char tapdev[16]; - int fd, error; + int fd, error = 0; + + if (num >= 0x100) + return E2BIG; snprintf(tapdev, sizeof(tapdev), "/dev/tap%d", num); fd = rumpuser_open(tapdev, O_RDWR, &error); @@ -96,29 +102,48 @@ num, error); return error; } - KASSERT(num < 0x100); enaddr[2] = arc4random() & 0xff; enaddr[5] = num; sc = kmem_zalloc(sizeof(*sc), KM_SLEEP); + sc->sc_dying = false; sc->sc_tapfd = fd; + mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_NONE); + cv_init(&sc->sc_cv, "virtsnd"); ifp = &sc->sc_ec.ec_if; sprintf(ifp->if_xname, "%s%d", VIRTIF_BASE, num); ifp->if_softc = sc; + + if (rump_threads) { + if ((error = kthread_create(PRI_NONE, KTHREAD_JOINABLE, NULL, + virtif_receiver, ifp, &sc->sc_l_rcv, "virtifr")) != 0) + goto out; + + if ((error = kthread_create(PRI_NONE, + KTHREAD_JOINABLE | KTHREAD_MPSAFE, NULL, + virtif_sender, ifp, &sc->sc_l_snd, "virtifs")) != 0) + goto out; + } else { + printf("WARNING: threads not enabled, receive NOT working\n"); + } + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_init = virtif_init; ifp->if_ioctl = virtif_ioctl; ifp->if_start = virtif_start; ifp->if_stop = virtif_stop; - - mutex_init(&sc->sc_sendmtx, MUTEX_DEFAULT, IPL_NONE); - cv_init(&sc->sc_sendcv, "virtsnd"); + IFQ_SET_READY(&ifp->if_snd); if_attach(ifp); ether_ifattach(ifp, enaddr); - return 0; + out: + if (error) { + virtif_unclone(ifp); + } + + return error; } static int @@ -131,31 +156,51 @@ static int virtif_unclone(struct ifnet *ifp) { + struct virtif_sc *sc = ifp->if_softc; - return EOPNOTSUPP; + mutex_enter(&sc->sc_mtx); + if (sc->sc_dying) { + mutex_exit(&sc->sc_mtx); + return EINPROGRESS; + } + sc->sc_dying = true; + cv_broadcast(&sc->sc_cv); + mutex_exit(&sc->sc_mtx); + + virtif_stop(ifp, 1); + if_down(ifp); + + if (sc->sc_l_snd) { + kthread_join(sc->sc_l_snd); + sc->sc_l_snd = NULL; + } + if (sc->sc_l_rcv) { + kthread_join(sc->sc_l_rcv); + sc->sc_l_rcv = NULL; + } + + rumpuser_close(sc->sc_tapfd, NULL); + + mutex_destroy(&sc->sc_mtx); + cv_destroy(&sc->sc_cv); + kmem_free(sc, sizeof(*sc)); + + ether_ifdetach(ifp); + if_detach(ifp); + + return 0; } static int virtif_init(struct ifnet *ifp) { - int rv; + struct virtif_sc *sc = ifp->if_softc; - if (rump_threads) { - rv = kthread_create(PRI_NONE, 0, NULL, virtif_worker, ifp, - NULL, "virtifi"); - /* XXX: should do proper cleanup */ - if (rv) { - panic("if_virt: can't create worker"); - } - rv = kthread_create(PRI_NONE, 0, NULL, virtif_sender, ifp, - NULL, "virtifs"); - if (rv) { - panic("if_virt: can't create sender"); - } - } else { - printf("WARNING: threads not enabled, receive NOT working\n"); - } ifp->if_flags |= IFF_RUNNING; + + mutex_enter(&sc->sc_mtx); + cv_broadcast(&sc->sc_cv); + mutex_exit(&sc->sc_mtx); return 0; } @@ -180,66 +225,86 @@ { struct virtif_sc *sc = ifp->if_softc; - mutex_enter(&sc->sc_sendmtx); - cv_signal(&sc->sc_sendcv); - mutex_exit(&sc->sc_sendmtx); + mutex_enter(&sc->sc_mtx); + ifp->if_flags |= IFF_OACTIVE; + cv_broadcast(&sc->sc_cv); + mutex_exit(&sc->sc_mtx); } static void virtif_stop(struct ifnet *ifp, int disable) { + struct virtif_sc *sc = ifp->if_softc; - panic("%s: unimpl", __func__); + ifp->if_flags &= ~IFF_RUNNING; + + mutex_enter(&sc->sc_mtx); + cv_broadcast(&sc->sc_cv); + mutex_exit(&sc->sc_mtx); } +#define POLLTIMO_MS 1 static void -virtif_worker(void *arg) +virtif_receiver(void *arg) { struct ifnet *ifp = arg; struct virtif_sc *sc = ifp->if_softc; struct mbuf *m; size_t plen = ETHER_MAX_LEN_JUMBO+1; + struct pollfd pfd; ssize_t n; - int error; + int error, rv; + + pfd.fd = sc->sc_tapfd; + pfd.events = POLLIN; + + KASSERT(rump_kernel_isbiglocked()); for (;;) { m = m_gethdr(M_WAIT, MT_DATA); MEXTMALLOC(m, plen, M_WAIT); again: + /* poll, but periodically check if we should die */ + rv = rumpuser_poll(&pfd, 1, POLLTIMO_MS, &error); + if (sc->sc_dying) { + m_freem(m); + break; + } + if (rv == 0) + goto again; + n = rumpuser_read(sc->sc_tapfd, mtod(m, void *), plen, &error); KASSERT(n < ETHER_MAX_LEN_JUMBO); if (__predict_false(n < 0)) { - /* - * work around tap bug: /dev/tap is opened in - * non-blocking mode if it previously was - * non-blocking. - */ if (n == -1 && error == EAGAIN) { - struct pollfd pfd; - - pfd.fd = sc->sc_tapfd; - pfd.events = POLLIN; - - rumpuser_poll(&pfd, 1, INFTIM, &error); goto again; } - m_freem(m); - break; + printf("%s: read from /dev/tap failed. host if down?\n", + ifp->if_xname); + mutex_enter(&sc->sc_mtx); + /* could check if need go, done soon anyway */ + cv_timedwait(&sc->sc_cv, &sc->sc_mtx, hz); + mutex_exit(&sc->sc_mtx); + goto again; } /* tap sometimes returns EOF. don't sweat it and plow on */ if (__predict_false(n == 0)) goto again; + /* discard if we're not up */ + if ((ifp->if_flags & IFF_RUNNING) == 0) + goto again; + m->m_len = m->m_pkthdr.len = n; m->m_pkthdr.rcvif = ifp; bpf_mtap(ifp, m); ether_input(ifp, m); } - panic("virtif_workin is a lazy boy %d\n", error); + kthread_exit(0); } /* lazy bum stetson-harrison magic value */ @@ -253,14 +318,20 @@ struct rumpuser_iovec io[LB_SH]; int i, error; - mutex_enter(&sc->sc_sendmtx); - for (;;) { + mutex_enter(&sc->sc_mtx); + KERNEL_LOCK(1, NULL); + while (!sc->sc_dying) { + if (!ifp->if_flags & IFF_RUNNING) { + cv_wait(&sc->sc_cv, &sc->sc_mtx); + continue; + } IF_DEQUEUE(&ifp->if_snd, m0); if (!m0) { - cv_wait(&sc->sc_sendcv, &sc->sc_sendmtx); + ifp->if_flags &= ~IFF_OACTIVE; + cv_wait(&sc->sc_cv, &sc->sc_mtx); continue; } - mutex_exit(&sc->sc_sendmtx); + mutex_exit(&sc->sc_mtx); m = m0; for (i = 0; i < LB_SH && m; i++) { @@ -271,12 +342,19 @@ if (i == LB_SH) panic("lazy bum"); bpf_mtap(ifp, m0); + KERNEL_UNLOCK_LAST(curlwp); + rumpuser_writev(sc->sc_tapfd, io, i, &error); + + KERNEL_LOCK(1, NULL); m_freem(m0); - mutex_enter(&sc->sc_sendmtx); + mutex_enter(&sc->sc_mtx); } + KERNEL_UNLOCK_LAST(curlwp); + + mutex_exit(&sc->sc_mtx); - mutex_exit(softnet_lock); + kthread_exit(0); } /*