From owner-svn-soc-all@freebsd.org Tue Jul 21 13:49:45 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 F209C9A53D0 for ; Tue, 21 Jul 2015 13:49:45 +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 E131C1B44 for ; Tue, 21 Jul 2015 13:49:45 +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 t6LDnjDc014450 for ; Tue, 21 Jul 2015 13:49:45 GMT (envelope-from stefano@FreeBSD.org) Received: (from www@localhost) by socsvn.freebsd.org (8.15.2/8.15.2/Submit) id t6LDnhDl014426 for svn-soc-all@FreeBSD.org; Tue, 21 Jul 2015 13:49:43 GMT (envelope-from stefano@FreeBSD.org) Date: Tue, 21 Jul 2015 13:49:43 GMT Message-Id: <201507211349.t6LDnhDl014426@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: r288612 - 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, 21 Jul 2015 13:49:46 -0000 Author: stefano Date: Tue Jul 21 13:49:42 2015 New Revision: 288612 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=288612 Log: add ptnetmap backend and ptnetmap_memdev Added: 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 Modified: soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/Makefile soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/net_backends.c soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/net_backends.h soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/pci_virtio_net.c Modified: soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/Makefile ============================================================================== --- soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/Makefile Tue Jul 21 13:42:23 2015 (r288611) +++ soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/Makefile Tue Jul 21 13:49:42 2015 (r288612) @@ -27,6 +27,7 @@ pci_irq.c \ pci_lpc.c \ pci_passthru.c \ + pci_ptnetmap_memdev.c \ pci_virtio_block.c \ pci_virtio_net.c \ pci_virtio_rnd.c \ Modified: soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/net_backends.c ============================================================================== --- soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/net_backends.c Tue Jul 21 13:42:23 2015 (r288611) +++ soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/net_backends.c Tue Jul 21 13:49:42 2015 (r288612) @@ -109,6 +109,8 @@ */ uint64_t (*set_features)(struct net_backend *be, uint64_t features); + struct ptnetmap_state * (*get_ptnetmap)(struct net_backend *be); + struct pci_vtnet_softc *sc; int fd; void *priv; /* Pointer to backend-specific data. */ @@ -164,6 +166,12 @@ return -1; /* never called, i believe */ } +static struct ptnetmap_state * +netbe_null_get_ptnetmap(struct net_backend *be) +{ + return NULL; +} + static struct net_backend null_backend = { .name = "null", .init = netbe_null_init, @@ -172,6 +180,7 @@ .recv = netbe_null_recv, .get_features = netbe_null_get_features, .set_features = netbe_null_set_features, + .get_ptnetmap = netbe_null_get_ptnetmap, }; DATA_SET(net_backend_set, null_backend); @@ -697,6 +706,265 @@ /* + * The ptnetmap backend + */ +#include +#include "net/netmap.h" +#include "dev/netmap/netmap_virt.h" +#include "ptnetmap.h" + +struct ptnbe_priv { + struct netmap_priv up; + struct ptnetmap_state ptns; + int created; /* ptnetmap kthreads created */ + unsigned long features; /* ptnetmap features */ + unsigned long acked_features; /* ptnetmap acked features */ +}; + + + +/* The virtio-net features supported by ptnetmap. */ +#define VIRTIO_NET_F_PTNETMAP 0x2000000 /* ptnetmap available */ + +#define PTNETMAP_FEATURES VIRTIO_NET_F_PTNETMAP + +static uint64_t +ptnbe_get_features(struct net_backend *be) +{ + return PTNETMAP_FEATURES; +} + +static uint64_t +ptnbe_set_features(struct net_backend *be, uint64_t features) +{ + if (features & PTNETMAP_FEATURES) { + WPRINTF(("ptnbe_set_features\n")); + } + + return 0; +} + +#define PTNETMAP_NAME_HDR 2 + +static void ptnbe_init_ptnetmap(struct net_backend *be); + +static int +ptnbe_init(struct net_backend *be, const char *devname, + net_backend_cb_t cb, void *param) +{ + const char *ndname = "/dev/netmap"; + struct ptnbe_priv *priv = NULL; + struct netmap_priv *npriv; + struct nmreq req; + char tname[40]; + + priv = calloc(1, sizeof(struct ptnbe_priv)); + if (priv == NULL) { + 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; + } +#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: + free(priv); + + return -1; +} + +static void +ptnbe_cleanup(struct net_backend *be) +{ + struct ptnbe_priv *priv = be->priv; + + if (priv) { + nm_close(priv->up.nmd); + } + be->fd = -1; +} + +struct ptnetmap_state * +ptnbe_get_ptnetmap(struct net_backend *be) +{ + struct ptnbe_priv *priv = be->priv; + + return &priv->ptns; +} + +static void +ptnbe_init_ptnetmap(struct net_backend *be) +{ + struct ptnbe_priv *priv = be->priv; + + ptn_memdev_attach(priv->up.nmd->mem, priv->up.nmd->memsize, priv->up.nmd->req.nr_arg2); + + priv->ptns.ptn_be = be; + priv->created = 0; + priv->features = NET_PTN_FEATURES_BASE; + priv->acked_features = 0; +} + +/* return the subset of requested features that we support */ +uint32_t +ptnetmap_get_features(struct ptnetmap_state *ptns, uint32_t features) +{ + struct ptnbe_priv *priv = ptns->ptn_be->priv; + + return priv->features & features; +} + +/* store the agreed upon features */ +void +ptnetmap_ack_features(struct ptnetmap_state *ptns, uint32_t features) +{ + struct ptnbe_priv *priv = ptns->ptn_be->priv; + + priv->acked_features |= features; +} + +int +ptnetmap_get_mem(struct ptnetmap_state *ptns) +{ + struct netmap_priv *npriv = ptns->ptn_be->priv; + + if (npriv->nmd == NULL) + return EINVAL; + + ptns->offset = npriv->nmd->req.nr_offset; + ptns->num_tx_rings = npriv->nmd->req.nr_tx_rings; + ptns->num_rx_rings = npriv->nmd->req.nr_rx_rings; + ptns->num_tx_slots = npriv->nmd->req.nr_tx_slots; + ptns->num_rx_slots = npriv->nmd->req.nr_rx_slots; + + return 0; +} + +int +ptnetmap_get_hostmemid(struct ptnetmap_state *ptns) +{ + struct netmap_priv *npriv = ptns->ptn_be->priv; + + if (npriv->nmd == NULL) + return EINVAL; + + return npriv->nmd->req.nr_arg2; +} + +int +ptnetmap_create(struct ptnetmap_state *ptns, struct ptnetmap_cfg *conf) +{ + struct ptnbe_priv *priv = ptns->ptn_be->priv; + struct nmreq req; + int err; + + if (!(priv->acked_features & NET_PTN_FEATURES_BASE)) { + printf("ptnetmap features not acked\n"); + return EFAULT; + } + + if (priv->created) + return 0; + + /* TODO: ioctl to start kthreads */ +#if 1 + memset(&req, 0, sizeof(req)); + strncpy(req.nr_name, priv->up.ifname, sizeof(req.nr_name)); + req.nr_version = NETMAP_API; + ptnetmap_write_cfg(&req, conf); + req.nr_cmd = NETMAP_PT_HOST_CREATE; + err = ioctl(priv->up.nmd->fd, NIOCREGIF, &req); + if (err) { + printf("Unable to execute NETMAP_PT_HOST_CREATE on %s: %s\n", + priv->up.ifname, strerror(errno)); + } else + priv->created = 1; +#endif + + + return err; +} + +int +ptnetmap_delete(struct ptnetmap_state *ptns) +{ + struct ptnbe_priv *priv = ptns->ptn_be->priv; + struct nmreq req; + int err; + + 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 */ + memset(&req, 0, sizeof(req)); + strncpy(req.nr_name, priv->up.ifname, sizeof(req.nr_name)); + req.nr_version = NETMAP_API; + req.nr_cmd = NETMAP_PT_HOST_DELETE; + err = ioctl(priv->up.nmd->fd, NIOCREGIF, &req); + if (err) { + printf("Unable to execute NETMAP_PT_HOST_DELETE on %s: %s\n", + priv->up.ifname, strerror(errno)); + } + priv->created = 0; + + return 0; +} + +static struct net_backend ptnbe_backend = { + .name = "ptnetmap|ptvale", + .init = ptnbe_init, + .cleanup = ptnbe_cleanup, + .get_features = ptnbe_get_features, + .set_features = ptnbe_set_features, + .get_ptnetmap = ptnbe_get_ptnetmap, +}; + +DATA_SET(net_backend_set, ptnbe_backend); + + +/* * make sure a backend is properly initialized */ static void @@ -734,6 +1002,11 @@ be, be->name); be->set_features = netbe_null_set_features; } + if (be->get_ptnetmap == NULL) { + /*fprintf(stderr, "missing set_features for %p %s\n", + be, be->name);*/ + be->get_ptnetmap = netbe_null_get_ptnetmap; + } } /* @@ -848,3 +1121,11 @@ return -1; return be->recv(be, iov, iovcnt, more); } + +struct ptnetmap_state * +netbe_get_ptnetmap(struct net_backend *be) +{ + if (be == NULL) + return NULL; + return be->get_ptnetmap(be); +} Modified: soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/net_backends.h ============================================================================== --- soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/net_backends.h Tue Jul 21 13:42:23 2015 (r288611) +++ soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/net_backends.h Tue Jul 21 13:49:42 2015 (r288612) @@ -33,6 +33,8 @@ typedef void (*net_backend_cb_t)(int, enum ev_type, void *param); +struct ptnetmap_state; + /* Interface between virtio-net and the network backend. */ struct net_backend; @@ -45,5 +47,6 @@ int iovcnt, int len, int more); int netbe_recv(struct net_backend *be, struct iovec *iov, int iovcnt, int *more); +struct ptnetmap_state *netbe_get_ptnetmap(struct net_backend *be); #endif /* __NET_BACKENDS_H__ */ Added: soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/pci_ptnetmap_memdev.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/pci_ptnetmap_memdev.c Tue Jul 21 13:49:42 2015 (r288612) @@ -0,0 +1,324 @@ +#include +__FBSDID("$FreeBSD$"); + +#include +//#include +#include +#include +#include +//#include +//#include +//#include +//#include + +#include +#include +#include "bhyverun.h" +#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 + +struct ptn_memdev_softc { + struct pci_devinst *pi; /* PCI device instance */ + + void *mem_ptr; /* netmap shared memory */ + uint64_t mem_size; /* netmap shared memory size */ + uint16_t mem_id; /* netmap memory allocator ID */ + + TAILQ_ENTRY(ptn_memdev_softc) next; +}; +static TAILQ_HEAD(, ptn_memdev_softc) ptn_memdevs = TAILQ_HEAD_INITIALIZER(ptn_memdevs); + +/* + * find ptn_memdev through mem_id + */ +static struct ptn_memdev_softc * +ptn_memdev_find_memid(uint16_t mem_id) +{ + struct ptn_memdev_softc *sc; + + TAILQ_FOREACH(sc, &ptn_memdevs, next) { + if (sc->mem_ptr != NULL && mem_id == sc->mem_id) { + return sc; + } + } + + return NULL; +} + +/* + * find ptn_memdev that has not memory + */ +static struct ptn_memdev_softc * +ptn_memdev_find_empty_mem() +{ + struct ptn_memdev_softc *sc; + + TAILQ_FOREACH(sc, &ptn_memdevs, next) { + if (sc->mem_ptr == NULL) { + return sc; + } + } + + return NULL; +} + +/* + * find ptn_memdev that has not PCI device istance + */ +static struct ptn_memdev_softc * +ptn_memdev_find_empty_pi() +{ + struct ptn_memdev_softc *sc; + + TAILQ_FOREACH(sc, &ptn_memdevs, next) { + if (sc->pi == NULL) { + return sc; + } + } + + return NULL; +} + +static struct ptn_memdev_softc * +ptn_memdev_create() +{ + struct ptn_memdev_softc *sc; + + sc = calloc(1, sizeof(struct ptn_memdev_softc)); + + if (sc != NULL) { + TAILQ_INSERT_TAIL(&ptn_memdevs, sc, next); + } + + return sc; +} + +static void +ptn_memdev_delete(struct ptn_memdev_softc *sc) +{ + TAILQ_REMOVE(&ptn_memdevs, sc, next); + + free(sc); +} + +static uint64_t +ptn_pci_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, + int baridx, uint64_t offset, int size) +{ + struct ptn_memdev_softc *sc = pi->pi_arg; + uint64_t ret = 0; + + if (sc == NULL) + 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); + return 0; /* XXX */ + } + + /* XXX probably should do something better than just assert() */ + assert(baridx == PTNETMAP_IO_PCI_BAR); + + switch (offset) { + case PTNETMAP_IO_PCI_MEMSIZE: + ret = sc->mem_size; + break; + case PTNETMAP_IO_PCI_HOSTID: + ret = sc->mem_id; + break; + default: + printf("ptnentmap_memdev: read io reg unexpected\n"); + break; + } + + printf("ptnentmap_memdev: io_read - offset: %lx size: %d ret: %llu\n", offset, size,(unsigned long long)ret); + + return ret; +} + +static void +ptn_pci_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, + int baridx, uint64_t offset, int size, uint64_t value) +{ + struct ptn_memdev_softc *sc = pi->pi_arg; + + if (sc == NULL) + return; + + if (baridx == PTNETMAP_MEM_PCI_BAR) { + printf("ptnetmap_memdev: MEM write\n"); + return; /* XXX */ + } + + /* 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 +ptn_memdev_configure(struct ptn_memdev_softc *sc) +{ + 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) { + printf("ptnetmap_memdev: iobar allocation error %d\n", ret); + return ret; + } + + + /* init membar */ + /* XXX MEM64 has MEM_PREFETCH */ + ret = pci_emul_alloc_bar(sc->pi, PTNETMAP_MEM_PCI_BAR, PCIBAR_MEM32, sc->mem_size); + if (ret) { + printf("ptnetmap_memdev: membar allocation error %d\n", ret); + 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) { + printf("ptnetmap_memdev: membar map error %d\n", ret); + return ret; + } + + printf("ptnetmap_memdev: configured\n"); + + return 0; +} + +static int +ptn_memdev_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) +{ + struct ptn_memdev_softc *sc; + uint64_t size; + int ret; + + printf("ptnetmap_memdev: loading\n"); + + sc = ptn_memdev_find_empty_pi(); + if (sc == NULL) { + sc = ptn_memdev_create(); + if (sc == NULL) { + printf("ptnetmap_memdev: calloc error\n"); + return (ENOMEM); + } + } + + /* link our softc in pi */ + pi->pi_arg = sc; + sc->pi = pi; + + /* initialize config space */ + pci_set_cfgdata16(pi, PCIR_VENDOR, PTNETMAP_PCI_VENDOR_ID); + pci_set_cfgdata16(pi, PCIR_DEVICE, PTNETMAP_PCI_DEVICE_ID); + pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_NETWORK); + pci_set_cfgdata16(pi, PCIR_SUBDEV_0, 1); /* XXX-ste remove? */ + pci_set_cfgdata16(pi, PCIR_SUBVEND_0, PTNETMAP_PCI_VENDOR_ID); /* XXX-ste remove? */ + + ret = ptn_memdev_configure(sc); + if (ret) { + printf("ptnetmap_memdev: configure error\n"); + goto err; + } + + printf("ptnetmap_memdev: loaded\n"); + + return (0); +err: + ptn_memdev_delete(sc); + pi->pi_arg = NULL; + return ret; +} + +int +ptn_memdev_attach(void *mem_ptr, uint32_t mem_size, uint16_t mem_id) +{ + 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)) { + printf("ptnetmap_memdev: already attched\n"); + return 0; + } + + sc = ptn_memdev_find_empty_mem(); + if (sc == NULL) { + sc = ptn_memdev_create(); + if (sc == NULL) { + printf("ptnetmap_memdev: calloc error\n"); + return (ENOMEM); + } + } + + sc->mem_ptr = mem_ptr; + 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 */ + ret = ptn_memdev_configure(sc); + if (ret) { + printf("ptnetmap_memdev: configure error\n"); + goto err; + } + + printf("ptnetmap_memdev: attached\n"); + + return 0; +err: + ptn_memdev_delete(sc); + sc->pi->pi_arg = NULL; + return ret; +} + + +struct pci_devemu pci_de_ptnetmap = { + .pe_emu = PTN_MEMDEV_NAME, + .pe_init = ptn_memdev_init, + .pe_barwrite = ptn_pci_write, + .pe_barread = ptn_pci_read +}; +PCI_EMUL_SET(pci_de_ptnetmap); Modified: soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/pci_virtio_net.c ============================================================================== --- soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/pci_virtio_net.c Tue Jul 21 13:42:23 2015 (r288611) +++ soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/pci_virtio_net.c Tue Jul 21 13:49:42 2015 (r288612) @@ -93,6 +93,7 @@ struct virtio_net_config { uint8_t mac[6]; uint16_t status; + uint16_t max_virtqueue_pairs; } __packed; /* @@ -124,6 +125,25 @@ #define DPRINTF(params) if (pci_vtnet_debug) printf params #define WPRINTF(params) printf params + +#define BHYVE_VIRTIO_PTNETMAP +#ifdef BHYVE_VIRTIO_PTNETMAP +#include +#include +#include "net/netmap.h" +#include "dev/netmap/netmap_virt.h" + +struct pci_vtnet_ptnetmap { + struct paravirt_csb *csb; /* Communication Status Block. */ + uint32_t features; /* ptnetmap features */ + int up; /* ptnetmap up/down */ + struct ptnetmap_state *state; /* ptnetmap state (shared with backend) */ + struct ptnetmap_cfg cfg; /* ptnetmap configuration */ + + /* ptnetmap register */ + uint8_t reg[PTNEMTAP_VIRTIO_IO_SIZE]; +}; +#endif /* * Per-device softc */ @@ -149,8 +169,15 @@ pthread_mutex_t tx_mtx; pthread_cond_t tx_cond; int tx_in_progress; +#ifdef BHYVE_VIRTIO_PTNETMAP + struct pci_vtnet_ptnetmap ptn; +#endif }; +#ifdef BHYVE_VIRTIO_PTNETMAP +#include "pci_virtio_ptnetmap.h" +#endif + static void pci_vtnet_reset(void *); /* static void pci_vtnet_notify(void *, struct vqueue_info *); */ static int pci_vtnet_cfgread(void *, int, int, uint32_t *); @@ -555,6 +582,9 @@ WPRINTF(("net backend initialization failed\n")); } else { vc->vc_hv_caps |= netbe_get_features(sc->vsc_be); +#ifdef BHYVE_VIRTIO_PTNETMAP + pci_vtnet_ptnetmap_init(sc, vc); +#endif /* BHYVE_VIRTIO_PTNETMAP */ } free(devname); } @@ -633,6 +663,10 @@ */ ptr = &sc->vsc_config.mac[offset]; memcpy(ptr, &value, size); +#ifdef BHYVE_VIRTIO_PTNETMAP + } else if (offset >= PTNETMAP_VIRTIO_IO_BASE) { + pci_vtnet_ptnetmap_write(sc, offset, size, value); +#endif } else { /* silently ignore other writes */ DPRINTF(("vtnet: write to readonly reg %d\n\r", offset)); @@ -647,6 +681,12 @@ struct pci_vtnet_softc *sc = vsc; void *ptr; +#ifdef BHYVE_VIRTIO_PTNETMAP + if (offset >= PTNETMAP_VIRTIO_IO_BASE) { + pci_vtnet_ptnetmap_read(sc, offset, size, retval); + return (0); + } +#endif ptr = (uint8_t *)&sc->vsc_config + offset; memcpy(retval, ptr, size); return (0); Added: soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/pci_virtio_ptnetmap.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ soc2015/stefano/ptnetmap/stable/10/usr.sbin/bhyve/pci_virtio_ptnetmap.h Tue Jul 21 13:49:42 2015 (r288612) @@ -0,0 +1,255 @@ +#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 + +/* 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, + uint32_t csbbah) +{ + uint64_t len = 4096; + uint64_t base = ((uint64_t)csbbah << 32) | csbbal; + + /* + * We require that writes to the CSB address registers + * are in the order CSBBAH , CSBBAL so on the second one + * we have a valid 64-bit memory address. + * Any previous region is unmapped, and handlers terminated. + * The CSB is then remapped if the new pointer is != 0 + */ + if (*csb) { + /* TODO: unmap */ + *csb = NULL; + } + if (base) { + *csb = paddr_guest2host(ctx, base, len); + } + +} + +static void +pci_vtnet_ptnetmap_init(struct pci_vtnet_softc *sc, struct virtio_consts *vc) +{ + sc->ptn.up = 0; + + sc->ptn.state = netbe_get_ptnetmap(sc->vsc_be); + if (sc->ptn.state == NULL) { + printf("ptnetmap not supported by backend\n"); + sc->ptn.features = 0; + return; + } + + sc->ptn.features = ptnetmap_get_features(sc->ptn.state, NET_PTN_FEATURES_BASE); + + /* backend require ptnetmap support? */ + if (!(sc->ptn.features & NET_PTN_FEATURES_BASE)) { + printf("ptnetmap not supported/required\n"); + sc->ptn.state = NULL; + sc->ptn.features = 0; + return; + } + + /* extend cfgsize. virtio creates PCIBAR for us */ + vc->vc_cfgsize += PTNEMTAP_VIRTIO_IO_SIZE; + + printf("ptnetmap-virtio init END\n"); +} + +static int +pci_vtnet_ptnetmap_get_mem(struct pci_vtnet_softc *sc) +{ + struct ptnetmap_state *ptns = sc->ptn.state; + struct paravirt_csb *csb = sc->ptn.csb; + int ret; + + ret = ptnetmap_get_mem(ptns); + if (ret) + return ret; + + if (csb == NULL) { + printf("ERROR ptnetmap: csb not initialized\n"); + return ret; + } + 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; +} + +static int +pci_vtnet_ptnetmap_up(struct pci_vtnet_softc *sc) +{ + struct ptnetmap_state *ptns = sc->ptn.state; + struct paravirt_csb *csb = sc->ptn.csb; + int ret; + + if (sc->ptn.up) { + printf("ERROR ptnetmap: already UP\n"); + return -1; + } + + if (csb == NULL) { + printf("ERROR ptnetmap: CSB undefined\n"); + return -1; + } + + /* TODO-ste: add support for multiqueue */ + + /* TODO: Stop processing guest/host IO notifications in qemu. + * Start processing them in ptnetmap. + */ + + + /* Configure the RX ring */ + sc->ptn.cfg.rx_ring.ioeventfd = -1; + sc->ptn.cfg.rx_ring.irqfd = -1; + + /* 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 */ + + /* Initialize CSB */ + sc->ptn.cfg.csb = sc->ptn.csb; + sc->ptn.csb->host_need_txkick = 1; + sc->ptn.csb->guest_need_txkick = 0; + 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; + + /* Configure the net backend. */ + ret = ptnetmap_create(sc->ptn.state, &sc->ptn.cfg); + if (ret) + goto err_ptn_create; + + sc->ptn.up = 1; + + return (0); + +err_ptn_create: + return (ret); +} + +static int +pci_vtnet_ptnetmap_down(struct pci_vtnet_softc *sc) +{ + int ret; + + if (!sc->ptn.state || !sc->ptn.up) { + return (0); + } + + sc->ptn.up = 0; + /* + * TODO: Start processing guest/host IO notifications in qemu. + */ + + return (ptnetmap_delete(sc->ptn.state)); +} + +static int +pci_vtnet_ptnetmap_write(struct pci_vtnet_softc *sc, int offset, int size, uint32_t value) +{ + uint32_t *val, ret; + + if (sc->ptn.state == NULL) { + printf("ERROR ptnetmap: not supported by backend\n"); + return -1; + } + + offset -= PTNETMAP_VIRTIO_IO_BASE; + 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; + 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; + 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); +} + +static int +pci_vtnet_ptnetmap_read(struct pci_vtnet_softc *sc, int offset, int size, uint32_t *value) +{ + if (sc->ptn.state == NULL) { + printf("ERROR ptnetmap: not supported by backend\n"); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***