From owner-svn-soc-all@freebsd.org Tue Aug 4 15:22:55 2015 Return-Path: Delivered-To: svn-soc-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 579E79B37E3 for ; Tue, 4 Aug 2015 15:22:55 +0000 (UTC) (envelope-from stefano@FreeBSD.org) Received: from socsvn.freebsd.org (socsvn.freebsd.org [IPv6:2001:1900:2254:206a::50:2]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 473421E04 for ; Tue, 4 Aug 2015 15:22:55 +0000 (UTC) (envelope-from stefano@FreeBSD.org) Received: from socsvn.freebsd.org ([127.0.1.124]) by socsvn.freebsd.org (8.15.2/8.15.2) with ESMTP id t74FMtHC062576 for ; Tue, 4 Aug 2015 15:22:55 GMT (envelope-from stefano@FreeBSD.org) Received: (from www@localhost) by socsvn.freebsd.org (8.15.2/8.15.2/Submit) id t74FMrVY062555 for svn-soc-all@FreeBSD.org; Tue, 4 Aug 2015 15:22:53 GMT (envelope-from stefano@FreeBSD.org) Date: Tue, 4 Aug 2015 15:22:53 GMT Message-Id: <201508041522.t74FMrVY062555@socsvn.freebsd.org> X-Authentication-Warning: socsvn.freebsd.org: www set sender to stefano@FreeBSD.org using -f From: stefano@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r289212 - soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-soc-all@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for the entire Summer of Code repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 04 Aug 2015 15:22:55 -0000 Author: stefano Date: Tue Aug 4 15:22:52 2015 New Revision: 289212 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=289212 Log: [bhyve/ptnetmap] add guest/host(kthread) notification and cleanup 1) notification from ptnetmap kthread to guest VM (interrupt/irq) The bhyve user-space, during netmap configuration, passes the ioctl parameters (fd, com, data) to ptnetmap kthreads. The ptnetmap kthread (attached to bhyve process) uses kern_ioctl() with these parameters to notify the guest VM. 2) notification from guest VM to ptnetmap kthread (write into the specific register) Use new IOCTL on vmm.ko (VM_IO_REG_HANDLER) to catch write/read on specific I/O address and send notification. With this new IOCTL, when the guest writes on specific register, the vmm.ko invokes wakeup() on the parameter (chan) specified from bhyve user-space application. The same parameter is passed to the ptnetmap kthreads that call tsleep(chan, ...) to wait the event. Added: soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/README.network Modified: soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/net_backends.c soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/pci_ptnetmap_memdev.c soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/pci_virtio_ptnetmap.h soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/ptnetmap.h Added: soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/README.network ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/README.network Tue Aug 4 15:22:52 2015 (r289212) @@ -0,0 +1,122 @@ +Network frontends and backends in bhyve + +20140804 + +The following is a proposal on how to implement network frontends (FE) +and backends (BE) in bhyve, and how to interface them. + +We need to address the following requirements: +1. Depending on the type of FE and BE, one may need zero or more + additional threads (iothreads) in charge of sending or receiving + packets, implementing one side of paravirtualized devices, etc. + + The requirements for an intermediate thread are the following: + + --- transmit --- + Frontend Backend Operations + non-PV non block* (1) all in VCPU + other cases (2) notify_tx() in VCPU, I/O in thread + + case 1: VCPU executes (autonomously or on kick_tx) + fe->fe2be(); // fill the ring + be->transmit(); + fe->fe2be(); // reclaim buffers + + case 2: VCPU executes (autonomously) + be->notify_tx(); + + iothread executes + for (;;) { + + fe->fe2be(); // fill the ring + be->transmit(); // e.g. txsync, write + fe->fe2be(); // reclaim buffers + } + + non blocking means that either the BE tx function is non + blocking, or that we have an independent notification mechanism + (e.g. an event loop, kevent, epoll...) to notify the FE when + transmit will be possible and issue a kick_tx() to the VCPU + + --- receive --- + Backend Operations + non block* (1) all in VCPU + other cases (2) all in thread + + case 1: VCPU executes (autonomously or on kick_rx) + if (needed) fe->be2fe(); // release buffers from FE + be->receive(); // read or rxsync + if (needed) fe->be2fe(); // pass packets to FE + main thread does fe->kick_rx() when data available + + case 2: i/o thread executes (autonomously) + for (;;) { + + fe->be2fe(); // reclaim buffers from FE + be->receive(); // read or rxsync + fe->be2fe(); // pass packets to FE and kick_rx + } + /* note, in netmap be->receive() may be empty because poll() + * will already fill the ring with packets. + */ + + same as above, non blocking means that the BE will use an + existing mechanism to notify the FE when receive will be possible + and issue a kick_rx() to the VCPU + +2. for performance reasons, it is important that the interface between + FE and BE support batched transfers and asynchronous completion + notifications. + + Given that the netmap API has the features required by #2, and that + netmap backends (and possibly even frontends) are going to be used + with bhyve, we suggest to standardize netmap as the FE-BE API + +In practice, the FE will need to call some BE-supplied function +during its operation, and the same goes for the BE. +To implement this, both entities export some information +through descriptors visible to the other entity. + +Frontend descriptor + + struct fe_desc { + ... + int (*be2fe)(struct fe_desc *, struct netmap_ring *); + int (*fe2be)(struct fe_desc *, struct netmap_ring *); + ... + } + + fe->be2fe() + is invoked by the BE (when receiving from the network) + to move packets from the netmap ring into the FE and to release + completed buffers from the FE back into the netmap ring. + The amount of data moved can be determined by the BE by comparing + the ring pointers before and after the call. + + Before returning, be2fe() will likely issue a kick to the VCPU + (e.g. an interrupt) to notify the availability of new data. + + The return value may be used to indicate events that cannot + be represented by the ring pointers. + + The function runs in the context of a thread "owned" by the BE, + and should implement protection against concurrent + activities on the FE's data structures, whereas the netmap_ring + is only used by this function during its execution. + + fe->fe2be() + is it needed ? + +Backend descriptors + + struct be_desc { + ... + int (*notify_tx)(struct re_desc *, struct netmap_ring *); + int (*notify_rx)(struct re_desc *, struct netmap_ring *); + ... + } + + be->notify_tx() + is invoked by the ... + + Modified: soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/net_backends.c ============================================================================== --- soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/net_backends.c Tue Aug 4 15:11:36 2015 (r289211) +++ soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/net_backends.c Tue Aug 4 15:22:52 2015 (r289212) @@ -46,7 +46,7 @@ #include #include "mevent.h" -#include "dev/virtio/network/virtio_net.h" +#include #include "net_backends.h" #include @@ -443,30 +443,38 @@ return 0; } +/* used by netmap and ptnetmap */ static int -netmap_init(struct net_backend *be, const char *devname, - net_backend_cb_t cb, void *param) +netmap_commom_init(struct net_backend *be, struct netmap_priv *priv, uint32_t nr_flags, + const char *devname, net_backend_cb_t cb, void *param) { const char *ndname = "/dev/netmap"; - struct netmap_priv *priv = NULL; + struct nmreq req; char tname[40]; - priv = calloc(1, sizeof(struct netmap_priv)); - if (priv == NULL) { - WPRINTF(("Unable alloc netmap private data\n")); - return -1; - } - strncpy(priv->ifname, devname, sizeof(priv->ifname)); priv->ifname[sizeof(priv->ifname) - 1] = '\0'; - priv->nmd = nm_open(priv->ifname, NULL, NETMAP_NO_TX_POLL, NULL); + memset(&req, 0, sizeof(req)); + req.nr_flags |= nr_flags; + + priv->nmd = nm_open(priv->ifname, &req, NETMAP_NO_TX_POLL, NULL); if (priv->nmd == NULL) { WPRINTF(("Unable to nm_open(): device '%s', " "interface '%s', errno (%s)\n", ndname, devname, strerror(errno))); goto err_open; } +#if 0 + /* check parent (nm_desc with the same allocator already mapped) */ + parent_nmd = netmap_find_parent(nmd); + /* mmap or inherit from parent */ + if (nm_mmap(nmd, parent_nmd)) { + error_report("failed to mmap %s: %s", netmap_opts->ifname, strerror(errno)); + nm_close(nmd); + return -1; + } +#endif priv->tx = NETMAP_TXRING(priv->nmd->nifp, 0); priv->rx = NETMAP_RXRING(priv->nmd->nifp, 0); @@ -476,7 +484,6 @@ priv->rx_continue = 0; be->fd = priv->nmd->fd; - be->priv = priv; /* Create a thread for netmap poll. */ pthread_create(&priv->evloop_tid, NULL, netmap_evloop_thread, (void *)be); @@ -486,6 +493,32 @@ return 0; err_open: + return -1; +} + +static int +netmap_init(struct net_backend *be, const char *devname, + net_backend_cb_t cb, void *param) +{ + const char *ndname = "/dev/netmap"; + struct netmap_priv *priv = NULL; + char tname[40]; + + priv = calloc(1, sizeof(struct netmap_priv)); + if (priv == NULL) { + WPRINTF(("Unable alloc netmap private data\n")); + return -1; + } + + if (netmap_commom_init(be, priv, 0, devname, cb, param)) { + goto err; + } + + be->priv = priv; + + return 0; + +err: free(priv); return -1; @@ -708,9 +741,9 @@ /* * The ptnetmap backend */ -#include -#include "net/netmap.h" -#include "dev/netmap/netmap_virt.h" +#include /* IFNAMSIZ */ +#include +#include #include "ptnetmap.h" struct ptnbe_priv { @@ -721,10 +754,8 @@ unsigned long acked_features; /* ptnetmap acked features */ }; - - /* The virtio-net features supported by ptnetmap. */ -#define VIRTIO_NET_F_PTNETMAP 0x2000000 /* ptnetmap available */ +#define VIRTIO_NET_F_PTNETMAP 0x2000000 /* (25) ptnetmap available */ #define PTNETMAP_FEATURES VIRTIO_NET_F_PTNETMAP @@ -737,10 +768,6 @@ static uint64_t ptnbe_set_features(struct net_backend *be, uint64_t features) { - if (features & PTNETMAP_FEATURES) { - WPRINTF(("ptnbe_set_features\n")); - } - return 0; } @@ -763,48 +790,20 @@ WPRINTF(("Unable alloc netmap private data\n")); return -1; } - WPRINTF(("ptnbe_init(): devname '%s'\n", devname)); npriv = &priv->up; - strncpy(npriv->ifname, devname + PTNETMAP_NAME_HDR, sizeof(npriv->ifname)); - npriv->ifname[sizeof(npriv->ifname) - 1] = '\0'; - memset(&req, 0, sizeof(req)); - req.nr_flags |= NR_PASSTHROUGH_HOST; - - npriv->nmd = nm_open(npriv->ifname, &req, NETMAP_NO_TX_POLL, NULL); - if (npriv->nmd == NULL) { - WPRINTF(("Unable to nm_open(): device '%s', " - "interface '%s', errno (%s)\n", - ndname, devname, strerror(errno))); - goto err_open; - } -#if 0 - /* check parent (nm_desc with the same allocator already mapped) */ - parent_nmd = netmap_find_parent(nmd); - /* mmap or inherit from parent */ - if (nm_mmap(nmd, parent_nmd)) { - error_report("failed to mmap %s: %s", netmap_opts->ifname, strerror(errno)); - nm_close(nmd); - return -1; + if (netmap_commom_init(be, npriv, NR_PTNETMAP_HOST, devname + PTNETMAP_NAME_HDR, cb, param)) { + goto err; } -#endif - - - npriv->tx = NETMAP_TXRING(npriv->nmd->nifp, 0); - npriv->rx = NETMAP_RXRING(npriv->nmd->nifp, 0); - npriv->cb = cb; - npriv->cb_param = param; - - be->fd = npriv->nmd->fd; be->priv = priv; ptnbe_init_ptnetmap(be); return 0; -err_open: +err: free(priv); return -1; @@ -816,6 +815,7 @@ struct ptnbe_priv *priv = be->priv; if (priv) { + ptnetmap_delete(&priv->ptns); nm_close(priv->up.nmd); } be->fd = -1; @@ -903,8 +903,7 @@ if (priv->created) return 0; - /* TODO: ioctl to start kthreads */ -#if 1 + /* ioctl to start ptnetmap kthreads */ memset(&req, 0, sizeof(req)); strncpy(req.nr_name, priv->up.ifname, sizeof(req.nr_name)); req.nr_version = NETMAP_API; @@ -916,8 +915,6 @@ priv->up.ifname, strerror(errno)); } else priv->created = 1; -#endif - return err; } @@ -929,15 +926,15 @@ struct nmreq req; int err; + if (!priv->created) + return 0; + if (!(priv->acked_features & NET_PTN_FEATURES_BASE)) { printf("ptnetmap features not acked\n"); return EFAULT; } - if (!priv->created) - return 0; - - /* TODO: ioctl to stop kthreads */ + /* ioctl to stop ptnetmap kthreads */ memset(&req, 0, sizeof(req)); strncpy(req.nr_name, priv->up.ifname, sizeof(req.nr_name)); req.nr_version = NETMAP_API; @@ -956,6 +953,8 @@ .name = "ptnetmap|ptvale", .init = ptnbe_init, .cleanup = ptnbe_cleanup, + .send = netmap_send, + .recv = netmap_receive, .get_features = ptnbe_get_features, .set_features = ptnbe_set_features, .get_ptnetmap = ptnbe_get_ptnetmap, Modified: soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/pci_ptnetmap_memdev.c ============================================================================== --- soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/pci_ptnetmap_memdev.c Tue Aug 4 15:11:36 2015 (r289211) +++ soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/pci_ptnetmap_memdev.c Tue Aug 4 15:22:52 2015 (r289212) @@ -1,3 +1,29 @@ +/* + * Copyright (C) 2015 Stefano Garzarella (stefano.garzarella@gmail.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + #include __FBSDID("$FreeBSD$"); @@ -17,22 +43,9 @@ #include "pci_emul.h" #include "ptnetmap.h" - -/* ptnetmap memdev PCI-ID and PCI-BARS XXX-ste: remove*/ -#define PTN_MEMDEV_NAME "ptnetmap-memdev" -#define PTNETMAP_PCI_VENDOR_ID 0x3333 /* XXX-ste: set vendor_id */ -#define PTNETMAP_PCI_DEVICE_ID 0x0001 -#define PTNETMAP_IO_PCI_BAR 0 -#define PTNETMAP_MEM_PCI_BAR 1 - -/* ptnetmap memdev register */ -/* 32 bit r/o */ -#define PTNETMAP_IO_PCI_FEATURES 0 -/* 32 bit r/o */ -#define PTNETMAP_IO_PCI_MEMSIZE 4 -/* 16 bit r/o */ -#define PTNETMAP_IO_PCI_HOSTID 8 -#define PTNEMTAP_IO_SIZE 10 +#include /* IFNAMSIZ */ +#include +#include struct ptn_memdev_softc { struct pci_devinst *pi; /* PCI device instance */ @@ -129,8 +142,8 @@ return 0; if (baridx == PTNETMAP_MEM_PCI_BAR) { - printf("ptnetmap_memdev: MEM read\n"); - printf("ptnentmap_memdev: mem_read - offset: %lx size: %d ret: %lx\n", offset, size, ret); + printf("ptnetmap_memdev: unexpected MEM read - offset: %lx size: %d ret: %lx\n", + offset, size, ret); return 0; /* XXX */ } @@ -149,7 +162,6 @@ break; } - printf("ptnentmap_memdev: io_read - offset: %lx size: %d ret: %llu\n", offset, size,(unsigned long long)ret); return ret; } @@ -164,22 +176,16 @@ return; if (baridx == PTNETMAP_MEM_PCI_BAR) { - printf("ptnetmap_memdev: MEM write\n"); - return; /* XXX */ + printf("ptnetmap_memdev: unexpected MEM write - offset: %lx size: %d value: %lx\n", + offset, size, value); + return; } - /* XXX probably should do something better than just assert() */ - assert(baridx == PTNETMAP_IO_PCI_BAR); - switch (offset) { - default: printf("ptnentmap_memdev: write io reg unexpected\n"); break; } - - - printf("ptnentmap_memdev: io_write - offset: %lx size: %d val: %lx\n", offset, size, value); } static int @@ -187,12 +193,9 @@ { int ret; - printf("ptnetmap_memdev: configuring\n"); - if (sc->pi == NULL || sc->mem_ptr == NULL) return 0; - /* init iobar */ ret = pci_emul_alloc_bar(sc->pi, PTNETMAP_IO_PCI_BAR, PCIBAR_IO, PTNEMTAP_IO_SIZE); if (ret) { @@ -209,10 +212,6 @@ return ret; } - printf("ptnetmap_memdev: pci_addr: %llx, mem_size: %llu, mem_ptr: %p\n", - (unsigned long long) sc->pi->pi_bar[PTNETMAP_MEM_PCI_BAR].addr, - (unsigned long long) sc->mem_size, sc->mem_ptr); - ret = vm_map_user_buf(sc->pi->pi_vmctx, sc->pi->pi_bar[PTNETMAP_MEM_PCI_BAR].addr, sc->mem_size, sc->mem_ptr); if (ret) { @@ -220,8 +219,6 @@ return ret; } - printf("ptnetmap_memdev: configured\n"); - return 0; } @@ -232,8 +229,6 @@ uint64_t size; int ret; - printf("ptnetmap_memdev: loading\n"); - sc = ptn_memdev_find_empty_pi(); if (sc == NULL) { sc = ptn_memdev_create(); @@ -260,8 +255,6 @@ goto err; } - printf("ptnetmap_memdev: loaded\n"); - return (0); err: ptn_memdev_delete(sc); @@ -274,7 +267,6 @@ { struct ptn_memdev_softc *sc; int ret; - printf("ptnetmap_memdev: attaching\n"); /* if a device with the same mem_id is already attached, we are done */ if (ptn_memdev_find_memid(mem_id)) { @@ -295,17 +287,13 @@ sc->mem_size = mem_size; sc->mem_id = mem_id; - printf("ptnetmap_memdev_attach: mem_id: %u, mem_size: %lu, mem_ptr: %p\n", mem_id, - (unsigned long) mem_size, mem_ptr); - - /* TODO: configure device BARs */ + /* configure device BARs */ ret = ptn_memdev_configure(sc); if (ret) { printf("ptnetmap_memdev: configure error\n"); goto err; } - printf("ptnetmap_memdev: attached\n"); return 0; err: Modified: soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/pci_virtio_ptnetmap.h ============================================================================== --- soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/pci_virtio_ptnetmap.h Tue Aug 4 15:11:36 2015 (r289211) +++ soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/pci_virtio_ptnetmap.h Tue Aug 4 15:22:52 2015 (r289212) @@ -1,12 +1,41 @@ +/* + * Copyright (C) 2015 Stefano Garzarella (stefano.garzarella@gmail.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + #ifndef __PCI_VIRTIO_PTNETMAP_H__ #define __PCI_VIRTIO_PTNETMAP_H__ -/* XXX-ste: move in other file and split in .c .h? */ #ifdef BHYVE_VIRTIO_PTNETMAP +#include +#include /* VM_LAPIC_MSI */ +#include + +#include "ptnetmap.h" /* ptnetmap virtio register BASE */ #define PTNETMAP_VIRTIO_IO_BASE sizeof(struct virtio_net_config) -#include "ptnetmap.h" static void ptnetmap_configure_csb(struct vmctx *ctx, struct paravirt_csb** csb, uint32_t csbbal, @@ -23,7 +52,6 @@ * The CSB is then remapped if the new pointer is != 0 */ if (*csb) { - /* TODO: unmap */ *csb = NULL; } if (base) { @@ -56,8 +84,6 @@ /* extend cfgsize. virtio creates PCIBAR for us */ vc->vc_cfgsize += PTNEMTAP_VIRTIO_IO_SIZE; - - printf("ptnetmap-virtio init END\n"); } static int @@ -75,17 +101,12 @@ printf("ERROR ptnetmap: csb not initialized\n"); return ret; } + /* share netmap_if info to the guest through CSB */ csb->nifp_offset = ptns->offset; csb->num_tx_rings = ptns->num_tx_rings; csb->num_rx_rings = ptns->num_rx_rings; csb->num_tx_slots = ptns->num_tx_slots; csb->num_rx_slots = ptns->num_rx_slots; - printf("txr %u rxr %u txd %u rxd %u nifp_offset %u\n", - csb->num_tx_rings, - csb->num_rx_rings, - csb->num_tx_slots, - csb->num_rx_slots, - csb->nifp_offset); return ret; } @@ -95,6 +116,12 @@ { struct ptnetmap_state *ptns = sc->ptn.state; struct paravirt_csb *csb = sc->ptn.csb; + struct pci_devinst *pi; + struct vmctx *vmctx; + struct vqueue_info *vq; + struct msix_table_entry *mte; + struct iovec iov[1]; + uint16_t idx; int ret; if (sc->ptn.up) { @@ -107,22 +134,59 @@ return -1; } - /* TODO-ste: add support for multiqueue */ + /* TODO: add support for multiqueue */ + pi = sc->vsc_vs.vs_pi; + vmctx = pi->pi_vmctx; - /* TODO: Stop processing guest/host IO notifications in qemu. + /* Configure the RX ring */ + sc->ptn.cfg.rx_ring.irqfd = vm_get_fd(vmctx); + sc->ptn.cfg.rx_ioctl.com = VM_LAPIC_MSI; + vq = &sc->vsc_queues[VTNET_RXQ]; + mte = &pi->pi_msix.table[vq->vq_msix_idx]; + sc->ptn.cfg.rx_ioctl.data.msg = mte->msg_data; + sc->ptn.cfg.rx_ioctl.data.addr = mte->addr; + /* push fake-elem in the rx queue to enable interrupts */ + if (vq_getchain(vq, &idx, iov, 1, NULL) > 0) { + vq_relchain(vq, idx, 0); + } + /* enable rx notification from guest */ + vq->vq_used->vu_flags &= ~VRING_USED_F_NO_NOTIFY; + /* + * Stop processing guest/host IO notifications in bhyve. * Start processing them in ptnetmap. */ - - - /* Configure the RX ring */ - sc->ptn.cfg.rx_ring.ioeventfd = -1; - sc->ptn.cfg.rx_ring.irqfd = -1; + ret = vm_io_reg_handler(vmctx, pi->pi_bar[0].addr + VTCFG_R_QNOTIFY, 0, + 0xFFFFFFFF, VTNET_RXQ, VM_IO_REGH_KWEVENTS, (void *) vq); + if (ret != 0) { + printf("ERROR ptnetmap: vm_io_reg_handler %d\n", ret); + goto err_reg_rx; + } + sc->ptn.cfg.rx_ring.ioeventfd = (uint64_t) vq; /* Configure the TX ring */ - sc->ptn.cfg.tx_ring.ioeventfd = -1; - sc->ptn.cfg.tx_ring.irqfd = -1; - - /* TODO: push fake-elem in the tx/rx queue to enable interrupts */ + sc->ptn.cfg.tx_ring.irqfd = vm_get_fd(vmctx); + sc->ptn.cfg.tx_ioctl.com = VM_LAPIC_MSI; + vq = &sc->vsc_queues[VTNET_TXQ]; + mte = &pi->pi_msix.table[vq->vq_msix_idx]; + sc->ptn.cfg.tx_ioctl.data.msg = mte->msg_data; + sc->ptn.cfg.tx_ioctl.data.addr = mte->addr; + /* push fake-elem in the tx queue to enable interrupts */ + if (vq_getchain(vq, &idx, iov, 1, NULL) > 0) { + vq_relchain(vq, idx, 0); + } + /* enable tx notification from guest */ + vq->vq_used->vu_flags &= ~VRING_USED_F_NO_NOTIFY; + /* + * Stop processing guest/host IO notifications in bhyve. + * Start processing them in ptnetmap. + */ + ret = vm_io_reg_handler(vmctx, pi->pi_bar[0].addr + VTCFG_R_QNOTIFY, 0, + 0xFFFFFFFF, VTNET_TXQ, VM_IO_REGH_KWEVENTS, (void *) vq); + if (ret != 0) { + printf("ERROR ptnetmap: vm_io_reg_handler %d\n", ret); + goto err_reg_tx; + } + sc->ptn.cfg.tx_ring.ioeventfd = (uint64_t) vq; /* Initialize CSB */ sc->ptn.cfg.csb = sc->ptn.csb; @@ -131,7 +195,8 @@ sc->ptn.csb->guest_need_rxkick = 1; sc->ptn.csb->host_need_rxkick = 1; - sc->ptn.cfg.features = PTNETMAP_CFG_FEAT_CSB | PTNETMAP_CFG_FEAT_EVENTFD; + sc->ptn.cfg.features = PTNETMAP_CFG_FEAT_CSB | PTNETMAP_CFG_FEAT_EVENTFD | + PTNETMAP_CFG_FEAT_IOCTL; /* Configure the net backend. */ ret = ptnetmap_create(sc->ptn.state, &sc->ptn.cfg); @@ -143,22 +208,38 @@ return (0); err_ptn_create: + vm_io_reg_handler(vmctx, pi->pi_bar[0].addr + VTCFG_R_QNOTIFY, 0, + 0xFFFFFFFF, VTNET_TXQ, VM_IO_REGH_DELETE, 0); +err_reg_tx: + vm_io_reg_handler(vmctx, pi->pi_bar[0].addr + VTCFG_R_QNOTIFY, 0, + 0xFFFFFFFF, VTNET_RXQ, VM_IO_REGH_DELETE, 0); +err_reg_rx: return (ret); } static int pci_vtnet_ptnetmap_down(struct pci_vtnet_softc *sc) { + struct pci_devinst *pi; + struct vmctx *vmctx; int ret; if (!sc->ptn.state || !sc->ptn.up) { return (0); } - sc->ptn.up = 0; + pi = sc->vsc_vs.vs_pi; + vmctx = pi->pi_vmctx; + /* - * TODO: Start processing guest/host IO notifications in qemu. + * Start processing guest/host IO notifications in bhyve. */ + vm_io_reg_handler(vmctx, pi->pi_bar[0].addr + VTCFG_R_QNOTIFY, 0, + 0xFFFFFFFF, VTNET_RXQ, VM_IO_REGH_DELETE, 0); + vm_io_reg_handler(vmctx, pi->pi_bar[0].addr + VTCFG_R_QNOTIFY, 0, + 0xFFFFFFFF, VTNET_TXQ, VM_IO_REGH_DELETE, 0); + + sc->ptn.up = 0; return (ptnetmap_delete(sc->ptn.state)); } @@ -177,53 +258,50 @@ memcpy(&sc->ptn.reg[offset], &value, size); switch (offset) { - case PTNETMAP_VIRTIO_IO_PTFEAT: - val = (uint32_t *)(sc->ptn.reg + offset); - ret = (sc->ptn.features &= *val); - ptnetmap_ack_features(sc->ptn.state, sc->ptn.features); - printf("ptnetmap acked features: %x\n", sc->ptn.features); - - sc->ptn.reg[PTNETMAP_VIRTIO_IO_PTFEAT] = ret; + case PTNETMAP_VIRTIO_IO_PTFEAT: + val = (uint32_t *)(sc->ptn.reg + offset); + ret = (sc->ptn.features &= *val); + ptnetmap_ack_features(sc->ptn.state, sc->ptn.features); + + sc->ptn.reg[PTNETMAP_VIRTIO_IO_PTFEAT] = ret; + break; + case PTNETMAP_VIRTIO_IO_PTCTL: + val = (uint32_t *)(sc->ptn.reg + offset); + + ret = EINVAL; + switch(*val) { + case NET_PARAVIRT_PTCTL_CONFIG: + ret = pci_vtnet_ptnetmap_get_mem(sc); break; - case PTNETMAP_VIRTIO_IO_PTCTL: - val = (uint32_t *)(sc->ptn.reg + offset); - - ret = EINVAL; - switch(*val) { - case NET_PARAVIRT_PTCTL_CONFIG: - ret = pci_vtnet_ptnetmap_get_mem(sc); - break; - case NET_PARAVIRT_PTCTL_REGIF: - ret = pci_vtnet_ptnetmap_up(sc); - break; - case NET_PARAVIRT_PTCTL_UNREGIF: - ret = pci_vtnet_ptnetmap_down(sc); - break; - case NET_PARAVIRT_PTCTL_HOSTMEMID: - ret = ptnetmap_get_hostmemid(sc->ptn.state); - break; - case NET_PARAVIRT_PTCTL_IFNEW: - case NET_PARAVIRT_PTCTL_IFDELETE: - case NET_PARAVIRT_PTCTL_FINALIZE: - case NET_PARAVIRT_PTCTL_DEREF: - ret = 0; - break; - } - printf("PTSTS - ret %d\n", ret); - sc->ptn.reg[PTNETMAP_VIRTIO_IO_PTSTS] = ret; + case NET_PARAVIRT_PTCTL_REGIF: + ret = pci_vtnet_ptnetmap_up(sc); break; - case PTNETMAP_VIRTIO_IO_CSBBAH: + case NET_PARAVIRT_PTCTL_UNREGIF: + ret = pci_vtnet_ptnetmap_down(sc); break; - case PTNETMAP_VIRTIO_IO_CSBBAL: - ptnetmap_configure_csb(sc->vsc_vs.vs_pi->pi_vmctx, &sc->ptn.csb, *((uint32_t *)(sc->ptn.reg + PTNETMAP_VIRTIO_IO_CSBBAL)), - *((uint32_t *)(sc->ptn.reg + PTNETMAP_VIRTIO_IO_CSBBAH))); + case NET_PARAVIRT_PTCTL_HOSTMEMID: + ret = ptnetmap_get_hostmemid(sc->ptn.state); break; - default: + case NET_PARAVIRT_PTCTL_IFNEW: + case NET_PARAVIRT_PTCTL_IFDELETE: + case NET_PARAVIRT_PTCTL_FINALIZE: + case NET_PARAVIRT_PTCTL_DEREF: + ret = 0; break; + } + sc->ptn.reg[PTNETMAP_VIRTIO_IO_PTSTS] = ret; + break; + case PTNETMAP_VIRTIO_IO_CSBBAH: + break; + case PTNETMAP_VIRTIO_IO_CSBBAL: + ptnetmap_configure_csb(sc->vsc_vs.vs_pi->pi_vmctx, &sc->ptn.csb, + *((uint32_t *)(sc->ptn.reg + PTNETMAP_VIRTIO_IO_CSBBAL)), + *((uint32_t *)(sc->ptn.reg + PTNETMAP_VIRTIO_IO_CSBBAH))); + break; + default: + break; } - printf("ptnentmap_vtnet: io_write - offset: %d size: %d val: %u\n", offset, size, value); - return (0); } @@ -240,14 +318,14 @@ memcpy(value, &sc->ptn.reg[offset], size); #if 0 switch (offset) { - case PTNETMAP_VIRTIO_IO_PTFEAT: - case PTNETMAP_VIRTIO_IO_PTSTS: - break; - default: - break; + case PTNETMAP_VIRTIO_IO_PTFEAT: + case PTNETMAP_VIRTIO_IO_PTSTS: + break; + default: + printf("pci_vtnet_ptnentmap: write io reg unexpected\n"); + break; } #endif - printf("ptnentmap_vtnet: io_read - offset: %d size: %d ret: %u\n", offset, size, *value); return (0); } Modified: soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/ptnetmap.h ============================================================================== --- soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/ptnetmap.h Tue Aug 4 15:11:36 2015 (r289211) +++ soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/ptnetmap.h Tue Aug 4 15:22:52 2015 (r289212) @@ -1,3 +1,29 @@ +/* + * Copyright (C) 2015 Stefano Garzarella (stefano.garzarella@gmail.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + #ifndef __PTNETMAP_H__ #define __PTNETMAP_H__