Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/bouyer-xen2]: src/sys/arch/xen/xen The network device backend is now fun...



details:   https://anonhg.NetBSD.org/src/rev/72a0d057b8ff
branches:  bouyer-xen2
changeset: 571900:72a0d057b8ff
user:      bouyer <bouyer%NetBSD.org@localhost>
date:      Fri Feb 18 18:37:17 2005 +0000

description:
The network device backend is now functionnal enouth to allow ping and
ftp between the domain0 and a guest. If shows up as an ethernet interface
in domain0, which can then be bridged, nated, routed, etc ... to real network
devices, but I didn't try this yet (but there's no reasons it wouldn't work :)
TODO:
- deal with ressources shortages
- properly release ressources on domain shutdown
- load balancing
- try to avoid packet copies in some cases.

diffstat:

 sys/arch/xen/xen/xennetback.c |  551 +++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 545 insertions(+), 6 deletions(-)

diffs (truncated from 650 to 300 lines):

diff -r a7980154919e -r 72a0d057b8ff sys/arch/xen/xen/xennetback.c
--- a/sys/arch/xen/xen/xennetback.c     Wed Feb 16 14:04:49 2005 +0000
+++ b/sys/arch/xen/xen/xennetback.c     Fri Feb 18 18:37:17 2005 +0000
@@ -1,4 +1,4 @@
-/*      $NetBSD: xennetback.c,v 1.1.2.1 2005/02/16 13:48:04 bouyer Exp $      */
+/*      $NetBSD: xennetback.c,v 1.1.2.2 2005/02/18 18:37:17 bouyer Exp $      */
 
 /*
  * Copyright (c) 2005 Manuel Bouyer.
@@ -36,15 +36,44 @@
 #include <sys/malloc.h>
 #include <sys/queue.h>
 #include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/device.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <net/netisr.h>
+#include "bpfilter.h"
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#include <net/if_ether.h>
+
 
 #include <machine/xen.h>
+#include <machine/xen_shm.h>
 #include <machine/evtchn.h>
 #include <machine/ctrl_if.h>
 
 #include <machine/xen-public/io/domain_controller.h>
 
+#include <uvm/uvm.h>
+
+#ifdef XENDEBUG_NET
+#define XENPRINTF(x) printf x
+#else
+#define XENPRINTF(x)
+#endif
+
 /*
- * Backend block device driver for Xen
+ * Backend network device driver for Xen
  */
 
 static void xnetback_ctrlif_rx(ctrl_msg_t *, unsigned long);
@@ -58,24 +87,106 @@
        domid_t domid;          /* attached to this domain */
        uint32_t handle;        /* domain-specific handle */
        xnetback_state_t status;
+
+       /* network interface stuff */
+       struct ethercom xni_ec;
+       struct callout xni_restart;
+       u_int8_t xni_enaddr[ETHER_ADDR_LEN];
+
+       /* remote domain communication stuff */
+       unsigned int xni_evtchn;
+       unsigned int xni_irq;
+       paddr_t xni_ma_rxring; /* machine address of rx shared ring */
+       paddr_t xni_ma_txring; /* machine address of tx shared ring */
+
+       netif_tx_interface_t *xni_txring;
+       netif_rx_interface_t *xni_rxring;
+       NETIF_RING_IDX rxreq_cons; /* our index in the RX request ring */
 };
+#define xni_if    xni_ec.ec_if
+#define xni_bpf   xni_if.if_bpf
+
+static int  xennetback_ifioctl(struct ifnet *, u_long, caddr_t);
+static void xennetback_ifstart(struct ifnet *);
+static void xennetback_ifwatchdog(struct ifnet *);
+static int  xennetback_ifinit(struct ifnet *);
+static void xennetback_ifstop(struct ifnet *, int);
+
 
 SLIST_HEAD(, xnetback_instance) xnetback_instances;
 
 static struct xnetback_instance *xnetif_lookup(domid_t, uint32_t);
+static int  xennetback_evthandler(void *);
 
+/* extra pages to give to forein domains on xmit */
+#define NB_XMIT_PAGES_BATCH 64 /* number of pages to allocate at once */
+static unsigned long xmit_pages[NB_XMIT_PAGES_BATCH]; /* our physical pages */
+vaddr_t xmit_pages_vaddr_base; /* vm space we map it to */
+int xmit_pages_alloc; /* current index in xmit_pages */
+
+int  xennetback_get_xmit_page(vaddr_t *, paddr_t *);
+static void xennetback_get_new_xmit_pages(void);
+
+/* arrays used in xennetback_ifstart(), too large to allocate on stack */
+static mmu_update_t xstart_mmu[NB_XMIT_PAGES_BATCH * 3];
+static multicall_entry_t xstart_mcl[NB_XMIT_PAGES_BATCH * 2];
 
 void
 xennetback_init()
 {
        ctrl_msg_t cmsg;
        netif_be_driver_status_t st;
+       int i;
+       struct vm_page *pg;
+       paddr_t pa;
+       multicall_entry_t mcl[NB_XMIT_PAGES_BATCH];
 
        if ( !(xen_start_info.flags & SIF_INITDOMAIN) &&
             !(xen_start_info.flags & SIF_NET_BE_DOMAIN))
                return;
 
-       printf("xennetback_init\n");
+       XENPRINTF(("xennetback_init\n"));
+
+       xmit_pages_vaddr_base = uvm_km_valloc(kernel_map,
+           NB_XMIT_PAGES_BATCH * PAGE_SIZE);
+       xmit_pages_vaddr_base = xmit_pages_vaddr_base >> PAGE_SHIFT;
+       xmit_pages_alloc = -1;
+       if (xmit_pages_vaddr_base == 0)
+               panic("xennetback_init: no VM space");
+
+       XENPRINTF(("xmit_pages_vaddr_base=0x%x\n", (u_int)xmit_pages_vaddr_base));
+
+       /* 
+        * I don't like this much, but it seems we can't get MEMOP_increase
+        * to work until we've given back a few pages first.
+        * So prime transmit pages pool with some uvm-managed pages.
+        */
+       for (i = 0; i < NB_XMIT_PAGES_BATCH; i++) {
+               pg = uvm_pagealloc(NULL, 0, NULL, 0);
+               if (pg == NULL)
+                       panic("xennetback_init: no page\n");
+               pa = VM_PAGE_TO_PHYS(pg);
+               xmit_pages[i] = xpmap_ptom(pa) >> PAGE_SHIFT;
+               xpmap_phys_to_machine_mapping[
+                   (pa - XPMAP_OFFSET) >> PAGE_SHIFT] = INVALID_P2M_ENTRY;
+               XENPRINTF(("got page pa 0x%x machine_pa 0x%x\n",
+                   (u_int)pa, (u_int)xmit_pages[i]));
+               mcl[i].op = __HYPERVISOR_update_va_mapping;
+               mcl[i].args[0] = (xmit_pages_vaddr_base + i);
+               mcl[i].args[1] = (xmit_pages[i] << PAGE_SHIFT) |
+                   PG_V | PG_RW | PG_U | PG_M;
+               mcl[i].args[2] = 0;
+       }
+       if (HYPERVISOR_multicall(mcl, NB_XMIT_PAGES_BATCH) != 0)
+               panic("xennetback_init: HYPERVISOR_multicall");
+       for (i = 0; i < NB_XMIT_PAGES_BATCH; i++) {
+               if ((mcl[i].args[5] != 0)) {
+                       printf("xennetback_init: "
+                           "mcl[%d] failed\n", i);
+                       panic("xennetback_init");
+               }
+       }
+       xmit_pages_alloc = NB_XMIT_PAGES_BATCH - 1;
 
        /*
         * initialize the backend driver, register the control message handler
@@ -97,8 +208,9 @@
 xnetback_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
 {
        struct xnetback_instance *xneti;
+       struct ifnet *ifp;
 
-       printf("xnetback msg %d\n", msg->subtype);
+       XENPRINTF(("xnetback msg %d\n", msg->subtype));
        switch (msg->subtype) {
        case CMSG_NETIF_BE_CREATE:
        {
@@ -118,6 +230,29 @@
                xneti->domid = req->domid;
                xneti->handle = req->netif_handle;
                xneti->status = DISCONNECTED;
+               ifp = &xneti->xni_if;
+               ifp->if_softc = xneti;
+
+               /* create pseudo-interface */
+               memcpy(xneti->xni_enaddr, req->mac, ETHER_ADDR_LEN);
+               /* we can't use the same MAC addr as our guest */
+               xneti->xni_enaddr[3]++;
+               snprintf(ifp->if_xname, IFNAMSIZ, "xvif%d.%d",
+                   req->domid, req->netif_handle);
+               printf("%s: Ethernet address %s\n", ifp->if_xname,
+                   ether_sprintf(xneti->xni_enaddr));
+               ifp->if_flags =
+                   IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST;
+               ifp->if_ioctl = xennetback_ifioctl;
+               ifp->if_start = xennetback_ifstart;
+               ifp->if_watchdog = xennetback_ifwatchdog;
+               ifp->if_init = xennetback_ifinit;
+               ifp->if_stop = xennetback_ifstop;
+               ifp->if_timer = 0;
+               IFQ_SET_READY(&ifp->if_snd);
+               if_attach(ifp);
+               ether_ifattach(&xneti->xni_if, xneti->xni_enaddr);
+
                req->status = NETIF_BE_STATUS_OKAY;
                SLIST_INSERT_HEAD(&xnetback_instances, xneti, next);
                break;
@@ -138,6 +273,10 @@
                }
                SLIST_REMOVE(&xnetback_instances,
                    xneti, xnetback_instance, next);
+
+               ether_ifdetach(&xneti->xni_if);
+               if_detach(&xneti->xni_if);
+
                free(xneti, M_DEVBUF);
                req->status = NETIF_BE_STATUS_OKAY;
                break;
@@ -145,9 +284,67 @@
        case CMSG_NETIF_BE_CONNECT:
        {
                netif_be_connect_t *req = (netif_be_connect_t *)&msg->msg[0];
+               vaddr_t ring_rxaddr, ring_txaddr;
+               int error;
+
                if (msg->length != sizeof(netif_be_connect_t))
                        goto error;
-               req->status = NETIF_BE_STATUS_ERROR;
+               xneti = xnetif_lookup(req->domid, req->netif_handle);
+               if (xneti == NULL) {
+                       req->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
+                       goto end;
+               }
+               if (xneti->status == CONNECTED) {
+                       req->status = NETIF_BE_STATUS_INTERFACE_CONNECTED;
+                       goto end;
+               }
+               ring_rxaddr = uvm_km_alloc(kernel_map, PAGE_SIZE);
+               if (ring_rxaddr == 0) {
+                       printf("%s: can't alloc ring VM\n",
+                           xneti->xni_if.if_xname);
+                       req->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
+                       goto end;
+               }
+               ring_txaddr = uvm_km_alloc(kernel_map, PAGE_SIZE);
+               if (ring_txaddr == 0) {
+                       printf("%s: can't alloc ring VM\n",
+                           xneti->xni_if.if_xname);
+                       uvm_km_free(kernel_map, ring_rxaddr, PAGE_SIZE);
+                       req->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
+                       goto end;
+               }
+               xneti->xni_ma_rxring = req->rx_shmem_frame << PAGE_SHIFT;
+               xneti->xni_ma_txring = req->tx_shmem_frame << PAGE_SHIFT;
+               error = pmap_remap_pages(pmap_kernel(), ring_rxaddr,
+                  xneti->xni_ma_rxring, 1, PMAP_WIRED | PMAP_CANFAIL,
+                  req->domid);
+               if (error == 0)
+                       error = pmap_remap_pages(pmap_kernel(), ring_txaddr,
+                          xneti->xni_ma_txring, 1, PMAP_WIRED | PMAP_CANFAIL,
+                          req->domid);
+               if (error) {
+                       uvm_km_free(kernel_map, ring_rxaddr, PAGE_SIZE);
+                       uvm_km_free(kernel_map, ring_txaddr, PAGE_SIZE);
+                       printf("%s: can't remap ring: error %d\n",
+                           xneti->xni_if.if_xname, error);
+                       if (error == ENOMEM)
+                               req->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
+                       else if (error == EFAULT)
+                               req->status = NETIF_BE_STATUS_MAPPING_ERROR;
+                       else
+                               req->status = NETIF_BE_STATUS_ERROR;
+                       goto end;
+               }
+               xneti->xni_rxring = (void *)ring_rxaddr;
+               xneti->xni_txring = (void *)ring_txaddr;
+               xneti->xni_evtchn = req->evtchn;
+               xneti->xni_irq = bind_evtchn_to_irq(req->evtchn);
+               event_set_handler(xneti->xni_irq, xennetback_evthandler,
+                   xneti, IPL_NET);
+               printf("%s interrupting at irq %d\n",
+                   xneti->xni_if.if_xname, xneti->xni_irq);
+               hypervisor_enable_irq(xneti->xni_irq);
+               req->status = NETIF_BE_STATUS_OKAY;
                break;
        }
        case CMSG_NETIF_BE_DISCONNECT:
@@ -156,6 +353,11 @@
                    (netif_be_disconnect_t *)&msg->msg[0];
                if (msg->length != sizeof(netif_be_disconnect_t))
                        goto error;
+               xneti = xnetif_lookup(req->domid, req->netif_handle);
+               if (xneti == NULL) {
+                       req->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
+                       goto end;
+               }
                req->status = NETIF_BE_STATUS_ERROR;
                break;
        }
@@ -166,11 +368,12 @@
                msg->length = 0;
        }
 end:



Home | Main Index | Thread Index | Old Index