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