aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/examples/defaults15
-rwxr-xr-xtools/examples/xc_dom_create.py17
-rw-r--r--tools/xc/lib/xc.h14
-rw-r--r--tools/xc/lib/xc_domain.c2
-rw-r--r--tools/xc/lib/xc_linux_restore.c86
-rw-r--r--tools/xc/lib/xc_linux_save.c89
-rw-r--r--tools/xc/lib/xc_private.h24
-rw-r--r--tools/xc/py/Xc.c284
-rw-r--r--tools/xend/lib/domain_controller.h211
9 files changed, 582 insertions, 160 deletions
diff --git a/tools/examples/defaults b/tools/examples/defaults
index d5a41eebd5..d391eb1d1e 100644
--- a/tools/examples/defaults
+++ b/tools/examples/defaults
@@ -31,12 +31,15 @@ builder_fn='linux' # this is a linux domain
# STEP 2. The initial memory allocation (in megabytes) for the new domain.
mem_size = 64
-
# STEP 3. A handy name for your new domain.
domain_name = "This is VM %d" % vmid
+# STEP 4. Which CPU to start domain on?
+#cpu = -1 # leave to Xen to pick
+cpu = vmid # set based on vmid (mod number of CPUs)
+
-# STEP 4. Specify IP address(es), for the new domain. You need to
+# STEP 5. Specify IP address(es), for the new domain. You need to
# configure IP addrs within the domain just as you do normally. This
# is just to let Xen know about them so it can route packets
# appropriately.
@@ -46,7 +49,7 @@ vfr_ipaddr = [xenctl.utils.add_offset_to_ip(xenctl.utils.get_current_ipaddr(),v
xenctl.utils.add_offset_to_ip('169.254.1.0',vmid),]
-# STEP 5a. Identify any physcial partitions or virtual disks you want the
+# STEP 6. Identify any physcial partitions or virtual disks you want the
# domain to have access to, and what you want them accessible as
# e.g. vbd_list = [ ('phy:sda1','sda1', 'w'),
# ('phy:sda%d' % (3+vmid), 'hda2', 'r'),
@@ -66,7 +69,7 @@ vbd_list = [ ('phy:sda%d'%(7+vmid),'sda1','w' ),
vbd_expert = 0
-# STEP 6. Build the command line for the new domain. Edit as req'd.
+# STEP 7. Build the command line for the new domain. Edit as req'd.
# You only need the ip= line if you're NFS booting or the root file system
# doesn't set it later e.g. in ifcfg-eth0 or via DHCP
# You can use 'extrabit' to set the runlevel and custom environment
@@ -82,12 +85,12 @@ cmdline_root = "root=/dev/sda1 ro"
cmdline_extra = "4 VMID=%d usr=/dev/sda6" % vmid
-# STEP 7. Set according to whether you want the script to watch the domain
+# STEP 8. Set according to whether you want the script to watch the domain
# and auto-restart it should it die or exit.
auto_restart = False
#auto_restart = True
-# STEP 8. (Optional) Define a console port number for the new domain.
+# STEP 9. (Optional) Define a console port number for the new domain.
# console_port = 9610+vmid
diff --git a/tools/examples/xc_dom_create.py b/tools/examples/xc_dom_create.py
index 0a66613da4..22479a9d14 100755
--- a/tools/examples/xc_dom_create.py
+++ b/tools/examples/xc_dom_create.py
@@ -156,6 +156,7 @@ for opt in opts:
if opt[0] == '-r': ramdisk = opt[1]
if opt[0] == '-b': builder_fn = opt[1]
if opt[0] == '-m': mem_size = int(opt[1])
+ if opt[0] == '-C': cpu = int(opt[1])
if opt[0] == '-N': domain_name = opt[1]
if opt[0] == '-a': auto_restart = answer(opt[1])
if opt[0] == '-e': vbd_expert = answer(opt[1])
@@ -219,7 +220,7 @@ def make_domain():
"""
# set up access to the global variables declared above
- global image, ramdisk, mem_size, domain_name, vfr_ipaddr, netmask
+ global image, ramdisk, mem_size, cpu, domain_name, vfr_ipaddr, netmask
global vbd_list, cmdline, xc, vbd_expert, builder_fn
if not os.path.isfile( image ):
@@ -230,7 +231,7 @@ def make_domain():
print "Ramdisk file '" + ramdisk + "' does not exist"
sys.exit()
- id = xc.domain_create( mem_kb=mem_size*1024, name=domain_name )
+ id = xc.domain_create( mem_kb=mem_size*1024, name=domain_name, cpu=cpu )
if id <= 0:
print "Error creating domain"
sys.exit()
@@ -347,6 +348,18 @@ def make_domain():
else:
print "Enabled PCI access (%d:%d:%d)." % \
(pci_bus,pci_dev,pci_func)
+
+ if restore:
+ # send an unsolicited ARP reply for all non link-local IPs
+ gw=xenctl.utils.get_current_ipgw()
+ if gw == '': gw='255.255.255.255'
+ nlb=open('/proc/sys/net/ipv4/ip_nonlocal_bind','r').read()[0]=='1'
+ if not nlb: print >>open('/proc/sys/net/ipv4/ip_nonlocal_bind','w'), '1'
+ for ip in vfr_ipaddr:
+ if not xenctl.utils.check_subnet(ip,'169.254.0.0','255.255.0.0'):
+ print '/usr/sbin/arping -A -b -I eth0 -c 1 -s %s %s' % (ip,gw)
+ os.system('/usr/sbin/arping -A -b -I eth0 -c 1 -s %s %s' % (ip,gw))
+ if not nlb: print >>open('/proc/sys/net/ipv4/ip_nonlocal_bind','w'), '0'
if xc.domain_start( dom=id ) < 0:
print "Error starting domain"
diff --git a/tools/xc/lib/xc.h b/tools/xc/lib/xc.h
index 9a0fab2257..a0205bcc6b 100644
--- a/tools/xc/lib/xc.h
+++ b/tools/xc/lib/xc.h
@@ -38,6 +38,7 @@ typedef struct {
int xc_domain_create(int xc_handle,
unsigned int mem_kb,
const char *name,
+ int cpu,
u64 *pdomid);
int xc_domain_start(int xc_handle,
u64 domid);
@@ -58,15 +59,20 @@ int xc_shadow_control(int xc_handle,
u64 domid,
unsigned int sop);
+#define XCFLAGS_VERBOSE 1
+#define XCFLAGS_LIVE 2
+
int xc_linux_save(int xc_handle,
u64 domid,
- const char *state_file,
- int verbose);
+ unsigned int flags,
+ int (*writerfn)(void *, const void *, size_t),
+ void *writerst );
int xc_linux_restore(int xc_handle,
u64 domid,
- const char *state_file,
- int verbose,
+ unsigned int flags,
+ int (*readerfn)(void *, void *, size_t),
+ void *readerst,
u64 *pdomid);
int xc_linux_build(int xc_handle,
diff --git a/tools/xc/lib/xc_domain.c b/tools/xc/lib/xc_domain.c
index 1d77bfc016..c26a3f87c3 100644
--- a/tools/xc/lib/xc_domain.c
+++ b/tools/xc/lib/xc_domain.c
@@ -11,6 +11,7 @@
int xc_domain_create(int xc_handle,
unsigned int mem_kb,
const char *name,
+ int cpu,
u64 *pdomid)
{
int err;
@@ -20,6 +21,7 @@ int xc_domain_create(int xc_handle,
op.u.createdomain.memory_kb = mem_kb;
strncpy(op.u.createdomain.name, name, MAX_DOMAIN_NAME);
op.u.createdomain.name[MAX_DOMAIN_NAME-1] = '\0';
+ op.u.createdomain.cpu = cpu;
if ( (err = do_dom0_op(xc_handle, &op)) == 0 )
*pdomid = (u64)op.u.createdomain.domain;
diff --git a/tools/xc/lib/xc_linux_restore.c b/tools/xc/lib/xc_linux_restore.c
index e27221281a..65ba875aef 100644
--- a/tools/xc/lib/xc_linux_restore.c
+++ b/tools/xc/lib/xc_linux_restore.c
@@ -45,25 +45,20 @@ static int get_pfn_list(int xc_handle,
return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
}
-static int checked_read(gzFile fd, void *buf, size_t count)
-{
- int rc;
- while ( ((rc = gzread(fd, buf, count)) == -1) && (errno == EINTR) )
- continue;
- return rc == count;
-}
int xc_linux_restore(int xc_handle,
u64 dom,
- const char *state_file,
- int verbose,
+ unsigned int flags,
+ int (*readerfn)(void *, void *, size_t),
+ void *readerst,
u64 *pdomid)
{
dom0_op_t op;
int rc = 1, i, j, n, k;
unsigned long mfn, pfn, xpfn;
unsigned int prev_pc, this_pc;
-
+ int verbose = flags & XCFLAGS_VERBOSE;
+
/* Number of page frames in use by this Linux session. */
unsigned long nr_pfns;
@@ -98,26 +93,10 @@ int xc_linux_restore(int xc_handle,
mfn_mapper_t *region_mapper, *mapper_handle1;
char *region_base;
- /* The name and descriptor of the file that we are reading from. */
- int fd;
- gzFile gfd;
-
mmu_t *mmu = NULL;
int pm_handle = -1;
- if ( (fd = open(state_file, O_RDONLY)) == -1 )
- {
- PERROR("Could not open state file for reading");
- return 1;
- }
-
- if ( (gfd = gzdopen(fd, "rb")) == NULL )
- {
- ERROR("Could not allocate decompression state for state file");
- close(fd);
- return 1;
- }
if ( mlock(&ctxt, sizeof(ctxt) ) )
{
@@ -128,18 +107,18 @@ int xc_linux_restore(int xc_handle,
}
/* Start writing out the saved-domain record. */
- if ( !checked_read(gfd, signature, 16) ||
+ if ( (*readerfn)(readerst, signature, 16) ||
(memcmp(signature, "LinuxGuestRecord", 16) != 0) )
{
ERROR("Unrecognised state format -- no signature found");
goto out;
}
- if ( !checked_read(gfd, name, sizeof(name)) ||
- !checked_read(gfd, &nr_pfns, sizeof(unsigned long)) ||
- !checked_read(gfd, &ctxt, sizeof(ctxt)) ||
- !checked_read(gfd, shared_info, PAGE_SIZE) ||
- !checked_read(gfd, pfn_to_mfn_frame_list, PAGE_SIZE) )
+ if ( (*readerfn)(readerst, name, sizeof(name)) ||
+ (*readerfn)(readerst, &nr_pfns, sizeof(unsigned long)) ||
+ (*readerfn)(readerst, &ctxt, sizeof(ctxt)) ||
+ (*readerfn)(readerst, shared_info, PAGE_SIZE) ||
+ (*readerfn)(readerst, pfn_to_mfn_frame_list, PAGE_SIZE) )
{
ERROR("Error when reading from state file");
goto out;
@@ -250,7 +229,7 @@ int xc_linux_restore(int xc_handle,
prev_pc = this_pc;
}
- if ( !checked_read(gfd, &j, sizeof(int)) )
+ if ( (*readerfn)(readerst, &j, sizeof(int)) )
{
ERROR("Error when reading from state file");
goto out;
@@ -260,7 +239,7 @@ int xc_linux_restore(int xc_handle,
if(j==0) break; // our work here is done
- if ( !checked_read(gfd, region_pfn_type, j*sizeof(unsigned long)) )
+ if ( (*readerfn)(readerst, region_pfn_type, j*sizeof(unsigned long)) )
{
ERROR("Error when reading from state file");
goto out;
@@ -306,21 +285,31 @@ int xc_linux_restore(int xc_handle,
ppage = (unsigned long*) (region_base + i*PAGE_SIZE);
- if ( !checked_read(gfd, ppage, PAGE_SIZE) )
+ if ( (*readerfn)(readerst, ppage, PAGE_SIZE) )
{
ERROR("Error when reading from state file");
goto out;
}
- if ( region_pfn_type[i] == L1TAB )
+ switch( region_pfn_type[i] )
+ {
+ case 0:
+ break;
+
+ case L1TAB:
{
for ( k = 0; k < 1024; k++ )
{
if ( ppage[k] & _PAGE_PRESENT )
{
- if ( (xpfn = ppage[k] >> PAGE_SHIFT) >= nr_pfns )
+ xpfn = ppage[k] >> PAGE_SHIFT;
+
+/*printf("L1 i=%d pfn=%d mfn=%d k=%d pte=%08lx xpfn=%d\n",
+ i,pfn,mfn,k,ppage[k],xpfn);*/
+
+ if ( xpfn >= nr_pfns )
{
- ERROR("Frame number in type %d page table is out of range. i=%d k=%d pfn=%d nr_pfns=%d",region_pfn_type[i],i,k,xpfn,nr_pfns);
+ ERROR("Frame number in type %d page table is out of range. i=%d k=%d pfn=%d nr_pfns=%d",region_pfn_type[i]>>29,i,k,xpfn,nr_pfns);
goto out;
}
#if 0
@@ -335,15 +324,23 @@ int xc_linux_restore(int xc_handle,
}
}
}
- else if ( region_pfn_type[i] == L2TAB )
+ break;
+
+ case L2TAB:
{
for ( k = 0; k < (HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT); k++ )
{
if ( ppage[k] & _PAGE_PRESENT )
{
- if ( (xpfn = ppage[k] >> PAGE_SHIFT) >= nr_pfns )
+ xpfn = ppage[k] >> PAGE_SHIFT;
+
+/*printf("L2 i=%d pfn=%d mfn=%d k=%d pte=%08lx xpfn=%d\n",
+ i,pfn,mfn,k,ppage[k],xpfn);*/
+
+ if ( xpfn >= nr_pfns )
{
- ERROR("Frame number in page table is out of range");
+ ERROR("Frame number in type %d page table is out of range. i=%d k=%d pfn=%d nr_pfns=%d",region_pfn_type[i]>>29,i,k,xpfn,nr_pfns);
+
goto out;
}
#if 0
@@ -358,6 +355,12 @@ int xc_linux_restore(int xc_handle,
}
}
}
+ break;
+
+ default:
+ ERROR("Bogus page type %x page table is out of range. i=%d nr_pfns=%d",region_pfn_type[i],i,nr_pfns);
+ goto out;
+ }
if ( add_mmu_update(xc_handle, mmu,
(mfn<<PAGE_SHIFT) | MMU_MACHPHYS_UPDATE, pfn) )
@@ -545,7 +548,6 @@ int xc_linux_restore(int xc_handle,
if ( pfn_type != NULL )
free(pfn_type);
- gzclose(gfd);
if ( rc == 0 )
*pdomid = dom;
diff --git a/tools/xc/lib/xc_linux_save.c b/tools/xc/lib/xc_linux_save.c
index 88ed9e15d7..02e3ffc352 100644
--- a/tools/xc/lib/xc_linux_save.c
+++ b/tools/xc/lib/xc_linux_save.c
@@ -8,7 +8,6 @@
#include "xc_private.h"
#include <asm-xen/suspend.h>
-#include <zlib.h>
#define BATCH_SIZE 1024 /* 1024 pages (4MB) at a time */
@@ -41,24 +40,18 @@
})
-
-static int checked_write(gzFile fd, void *buf, size_t count)
-{
- int rc;
- while ( ((rc = gzwrite(fd, buf, count)) == -1) && (errno = EINTR) )
- continue;
- return rc == count;
-}
-
int xc_linux_save(int xc_handle,
u64 domid,
- const char *state_file,
- int verbose)
+ unsigned int flags,
+ int (*writerfn)(void *, const void *, size_t),
+ void *writerst )
{
dom0_op_t op;
int rc = 1, i, j, k, n;
unsigned long mfn;
unsigned int prev_pc, this_pc;
+ int verbose = flags & XCFLAGS_VERBOSE;
+ //int live = flags & XCFLAGS_LIVE;
/* state of the new MFN mapper */
mfn_mapper_t *mapper_handle1, *mapper_handle2;
@@ -99,28 +92,6 @@ int xc_linux_save(int xc_handle,
/* A temporary mapping, and a copy, of the guest's suspend record. */
suspend_record_t *p_srec, srec;
- /* The name and descriptor of the file that we are writing to. */
- int fd;
- gzFile gfd;
-
- int pm_handle = -1;
-
- if ( (fd = open(state_file, O_CREAT|O_EXCL|O_WRONLY, 0644)) == -1 )
- {
- PERROR("Could not open file for writing");
- return 1;
- }
-
- /*
- * Compression rate 1: we want speed over compression. We're mainly going
- * for those zero pages, after all.
- */
- if ( (gfd = gzdopen(fd, "wb1")) == NULL )
- {
- ERROR("Could not allocate compression state for state file");
- close(fd);
- return 1;
- }
if ( mlock(&ctxt, sizeof(ctxt) ) )
{
@@ -324,14 +295,14 @@ int xc_linux_save(int xc_handle,
goto out;
}
- if ( !checked_write(gfd, "LinuxGuestRecord", 16) ||
- !checked_write(gfd, name, sizeof(name)) ||
- !checked_write(gfd, &srec.nr_pfns, sizeof(unsigned long)) ||
- !checked_write(gfd, &ctxt, sizeof(ctxt)) ||
- !checked_write(gfd, live_shinfo, PAGE_SIZE) ||
- !checked_write(gfd, pfn_to_mfn_frame_list, PAGE_SIZE) )
+ if ( (*writerfn)(writerst, "LinuxGuestRecord", 16) ||
+ (*writerfn)(writerst, name, sizeof(name)) ||
+ (*writerfn)(writerst, &srec.nr_pfns, sizeof(unsigned long)) ||
+ (*writerfn)(writerst, &ctxt, sizeof(ctxt)) ||
+ (*writerfn)(writerst, live_shinfo, PAGE_SIZE) ||
+ (*writerfn)(writerst, pfn_to_mfn_frame_list, PAGE_SIZE) )
{
- ERROR("Error when writing to state file");
+ ERROR("Error when writing to state file (1)");
goto out;
}
munmap(live_shinfo, PAGE_SIZE);
@@ -401,15 +372,15 @@ int xc_linux_save(int xc_handle,
}
- if ( !checked_write(gfd, &j, sizeof(int) ) )
+ if ( (*writerfn)(writerst, &j, sizeof(int) ) )
{
- ERROR("Error when writing to state file");
+ ERROR("Error when writing to state file (2)");
goto out;
}
- if ( !checked_write(gfd, pfn_type, sizeof(unsigned long)*j ) )
+ if ( (*writerfn)(writerst, pfn_type, sizeof(unsigned long)*j ) )
{
- ERROR("Error when writing to state file");
+ ERROR("Error when writing to state file (3)");
goto out;
}
@@ -430,7 +401,8 @@ int xc_linux_save(int xc_handle,
k++ )
{
if ( !(page[k] & _PAGE_PRESENT) ) continue;
- mfn = page[k] >> PAGE_SHIFT;
+ mfn = page[k] >> PAGE_SHIFT;
+
if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) )
{
ERROR("Frame number in pagetable page is invalid");
@@ -439,11 +411,17 @@ int xc_linux_save(int xc_handle,
page[k] &= PAGE_SIZE - 1;
page[k] |= live_mfn_to_pfn_table[mfn] << PAGE_SHIFT;
+ /*
+ printf("L%d i=%d pfn=%d mfn=%d k=%d pte=%08lx xpfn=%d\n",
+ pfn_type[j]>>29,
+ j,i,mfn,k,page[k],page[k]>>PAGE_SHIFT);
+ */
+
}
- if ( !checked_write(gfd, page, PAGE_SIZE) )
+ if ( (*writerfn)(writerst, page, PAGE_SIZE) )
{
- ERROR("Error when writing to state file");
+ ERROR("Error when writing to state file (4)");
goto out;
}
@@ -451,9 +429,9 @@ int xc_linux_save(int xc_handle,
}
else
{
- if ( !checked_write(gfd, region_base + (PAGE_SIZE*j), PAGE_SIZE) )
+ if ( (*writerfn)(writerst, region_base + (PAGE_SIZE*j), PAGE_SIZE) )
{
- ERROR("Error when writing to state file");
+ ERROR("Error when writing to state file (5)");
goto out;
}
}
@@ -468,9 +446,9 @@ int xc_linux_save(int xc_handle,
rc = 0;
/* Zero terminate */
- if ( !checked_write(gfd, &rc, sizeof(int)) )
+ if ( (*writerfn)(writerst, &rc, sizeof(int)) )
{
- ERROR("Error when writing to state file");
+ ERROR("Error when writing to state file (6)");
goto out;
}
@@ -485,16 +463,9 @@ out:
(void)do_dom0_op(xc_handle, &op);
}
- gzclose(gfd);
-
if ( pfn_type != NULL )
free(pfn_type);
-
- /* On error, make sure the file is deleted. */
- if ( rc != 0 )
- unlink(state_file);
return !!rc;
-
}
diff --git a/tools/xc/lib/xc_private.h b/tools/xc/lib/xc_private.h
index eaa301772d..3a2e3ea9f1 100644
--- a/tools/xc/lib/xc_private.h
+++ b/tools/xc/lib/xc_private.h
@@ -246,28 +246,4 @@ void * mfn_mapper_queue_entry(mfn_mapper_t *t, int offset,
/*********************/
-#if 0
-typedef struct mfn_typer {
- domid_t dom;
- int xc_handle;
- int max;
- dom0_op_t op;
-} mfn_typer_t;
-
-
-mfn_typer_t *mfn_typer_init(int xc_handle, domid_t dom, int num );
-
-void mfn_typer_queue_entry(mfn_typer_t *t, unsigned long mfn );
-
-int mfn_typer_flush_queue(mfn_typer_t *t);
-#endif
-
-int get_pfn_type_batch(int xc_handle,
- u64 dom, int num, unsigned long *arr);
-
-unsigned int get_pfn_type(int xc_handle,
- unsigned long mfn,
- u64 dom);
-
-
#endif /* __XC_PRIVATE_H__ */
diff --git a/tools/xc/py/Xc.c b/tools/xc/py/Xc.c
index 6453281a61..974ad994b7 100644
--- a/tools/xc/py/Xc.c
+++ b/tools/xc/py/Xc.c
@@ -6,6 +6,14 @@
#include <Python.h>
#include <xc.h>
+#include <zlib.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <arpa/inet.h>
/* Needed for Python versions earlier than 2.3. */
#ifndef PyMODINIT_FUNC
@@ -31,16 +39,17 @@ static PyObject *pyxc_domain_create(PyObject *self,
unsigned int mem_kb = 0;
char *name = "(anon)";
+ int cpu = -1;
u64 dom;
int ret;
- static char *kwd_list[] = { "mem_kb", "name", NULL };
+ static char *kwd_list[] = { "mem_kb", "name", "cpu", NULL };
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|is", kwd_list,
- &mem_kb, &name) )
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|isi", kwd_list,
+ &mem_kb, &name, &cpu) )
return NULL;
- if ( (ret = xc_domain_create(xc->xc_handle, mem_kb, name, &dom)) < 0 )
+ if ( (ret = xc_domain_create(xc->xc_handle, mem_kb, name, cpu, &dom)) < 0 )
return PyErr_SetFromErrno(xc_error);
return PyLong_FromUnsignedLongLong(dom);
@@ -183,6 +192,7 @@ static PyObject *pyxc_linux_save(PyObject *self,
u64 dom;
char *state_file;
int progress = 1;
+ unsigned int flags = 0;
static char *kwd_list[] = { "dom", "state_file", "progress", NULL };
@@ -190,11 +200,125 @@ static PyObject *pyxc_linux_save(PyObject *self,
&dom, &state_file, &progress) )
return NULL;
- if ( xc_linux_save(xc->xc_handle, dom, state_file, progress) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- Py_INCREF(zero);
- return zero;
+ if ( progress )
+ flags |= XCFLAGS_VERBOSE;
+
+ if ( strncmp(state_file,"tcp:", strlen("tcp:")) == 0 )
+ {
+#define max_namelen 64
+ char server[max_namelen];
+ char *port_s;
+ int port=777;
+ int sd = -1;
+ struct hostent *h;
+ struct sockaddr_in s;
+ int sockbufsize;
+
+ int writerfn(void *fd, const void *buf, size_t count)
+ {
+ int tot = 0, rc;
+ do {
+ rc = write( (int) fd, ((char*)buf)+tot, count-tot );
+ if ( rc < 0 ) { perror("WRITE"); return rc; };
+ tot += rc;
+ }
+ while ( tot < count );
+ return 0;
+ }
+
+ strncpy( server, state_file+strlen("tcp://"), max_namelen);
+ server[max_namelen-1]='\0';
+ if ( (port_s = strchr(server,':')) != NULL )
+ {
+ *port_s = '\0';
+ port = atoi(port_s+1);
+ }
+
+ printf("X server=%s port=%d\n",server,port);
+
+ h = gethostbyname(server);
+ sd = socket (AF_INET,SOCK_STREAM,0);
+ if ( sd < 0 )
+ goto serr;
+ s.sin_family = AF_INET;
+ bcopy ( h->h_addr, &(s.sin_addr.s_addr), h->h_length);
+ s.sin_port = htons(port);
+ if ( connect(sd, (struct sockaddr *) &s, sizeof(s)) )
+ goto serr;
+
+ sockbufsize=128*1024;
+ if ( setsockopt(sd, SOL_SOCKET, SO_SNDBUF,
+ &sockbufsize, sizeof sockbufsize) < 0 )
+ goto serr;
+
+ if ( xc_linux_save(xc->xc_handle, dom, flags,
+ writerfn, (void*)sd) == 0 )
+ {
+ close(sd);
+ Py_INCREF(zero);
+ return zero;
+ }
+
+ serr:
+ PyErr_SetFromErrno(xc_error);
+ if ( sd >= 0 ) close(sd);
+ return NULL;
+ }
+ else
+ {
+ int fd = -1;
+ gzFile gfd = NULL;
+
+ int writerfn(void *fd, const void *buf, size_t count)
+ {
+ int rc;
+ while ( ((rc = gzwrite( (gzFile*)fd, (void*)buf, count)) == -1) &&
+ (errno = EINTR) )
+ continue;
+ return ! (rc == count);
+ }
+
+ if (strncmp(state_file,"file:",strlen("file:")) == 0)
+ state_file += strlen("file:");
+
+ if ( (fd = open(state_file, O_CREAT|O_EXCL|O_WRONLY, 0644)) == -1 )
+ {
+ perror("Could not open file for writing");
+ goto err;
+ }
+
+ /*
+ * Compression rate 1: we want speed over compression.
+ * We're mainly going for those zero pages, after all.
+ */
+
+ if ( (gfd = gzdopen(fd, "wb1")) == NULL )
+ {
+ perror("Could not allocate compression state for state file");
+ close(fd);
+ goto err;
+ }
+
+
+ if ( xc_linux_save(xc->xc_handle, dom, flags, writerfn, gfd) == 0 )
+ {
+ gzclose(gfd);
+ close(fd);
+
+ Py_INCREF(zero);
+ return zero;
+ }
+
+ err:
+ PyErr_SetFromErrno(xc_error);
+ if ( gfd != NULL )
+ gzclose(gfd);
+ if ( fd >= 0 )
+ close(fd);
+ unlink(state_file);
+ return NULL;
+ }
+
}
static PyObject *pyxc_linux_restore(PyObject *self,
@@ -206,6 +330,7 @@ static PyObject *pyxc_linux_restore(PyObject *self,
char *state_file;
int progress = 1;
u64 dom;
+ unsigned int flags = 0;
static char *kwd_list[] = { "dom", "state_file", "progress", NULL };
@@ -213,11 +338,144 @@ static PyObject *pyxc_linux_restore(PyObject *self,
&dom, &state_file, &progress) )
return NULL;
- if ( xc_linux_restore(xc->xc_handle, dom, state_file, progress, &dom) != 0 )
- return PyErr_SetFromErrno(xc_error);
+ if ( progress )
+ flags |= XCFLAGS_VERBOSE;
+
+ if ( strncmp(state_file,"tcp:", strlen("tcp:")) == 0 )
+ {
+#define max_namelen 64
+ char server[max_namelen];
+ char *port_s;
+ int port=777;
+ int ld = -1, sd = -1;
+ struct hostent *h;
+ struct sockaddr_in s, d, p;
+ socklen_t dlen, plen;
+ int sockbufsize;
+ int on = 1;
+
+ int readerfn(void *fd, void *buf, size_t count)
+ {
+ int rc, tot = 0;
+ do {
+ rc = read( (int) fd, ((char*)buf)+tot, count-tot );
+ if ( rc < 0 ) { perror("READ"); return rc; }
+ tot += rc;
+ }
+ while ( tot < count );
+ return 0;
+ }
+
+ strncpy( server, state_file+strlen("tcp://"), max_namelen);
+ server[max_namelen-1]='\0';
+ if ( (port_s = strchr(server,':')) != NULL )
+ {
+ *port_s = '\0';
+ port = atoi(port_s+1);
+ }
+
+ printf("X server=%s port=%d\n",server,port);
+
+ h = gethostbyname(server);
+ ld = socket (AF_INET,SOCK_STREAM,0);
+ if ( ld < 0 ) goto serr;
+ s.sin_family = AF_INET;
+ //bcopy ( h->h_addr, &(s.sin_addr.s_addr), h->h_length);
+ s.sin_addr.s_addr = htonl(INADDR_ANY);
+ s.sin_port = htons(port);
+
+ if ( setsockopt(ld, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0 )
+ goto serr;
+
+ if ( bind(ld, (struct sockaddr *) &s, sizeof(s)) )
+ goto serr;
+
+ if ( listen(ld, 1) )
+ goto serr;
+
+ dlen=sizeof(struct sockaddr);
+ if ( (sd = accept(ld, (struct sockaddr *) &d, &dlen )) < 0 )
+ goto serr;
+
+ plen = sizeof(p);
+ if ( getpeername(sd, (struct sockaddr_in *) &p,
+ &plen) < 0 )
+ goto serr;
+
+ printf("Accepted connection from %s\n", inet_ntoa(p.sin_addr));
+
+ sockbufsize=128*1024;
+ if ( setsockopt(sd, SOL_SOCKET, SO_SNDBUF, &sockbufsize,
+ sizeof sockbufsize) < 0 )
+ goto serr;
+
+ if ( xc_linux_restore(xc->xc_handle, dom, flags,
+ readerfn, (void*)sd, &dom) == 0 )
+ {
+ close(sd);
+ Py_INCREF(zero);
+ return zero;
+ }
+
+ serr:
+ PyErr_SetFromErrno(xc_error);
+ if ( ld >= 0 ) close(ld);
+ if ( sd >= 0 ) close(sd);
+ return NULL;
+ }
+ else
+ {
+ int fd = -1;
+ gzFile gfd = NULL;
+
+ int readerfn(void *fd, void *buf, size_t count)
+ {
+ int rc;
+ while ( ((rc = gzread( (gzFile*)fd, (void*)buf, count)) == -1) &&
+ (errno = EINTR) )
+ continue;
+ return ! (rc == count);
+ }
+
+ if ( strncmp(state_file,"file:",strlen("file:")) == 0 )
+ state_file += strlen("file:");
+
+ if ( (fd = open(state_file, O_RDONLY)) == -1 )
+ {
+ perror("Could not open file for writing");
+ goto err;
+ }
+
+ /*
+ * Compression rate 1: we want speed over compression.
+ * We're mainly going for those zero pages, after all.
+ */
+
+ if ( (gfd = gzdopen(fd, "rb")) == NULL )
+ {
+ perror("Could not allocate compression state for state file");
+ close(fd);
+ goto err;
+ }
+
+
+ if ( xc_linux_restore(xc->xc_handle, dom, flags,
+ readerfn, gfd, &dom) == 0 )
+ {
+ gzclose(gfd);
+ close(fd);
+
+ Py_INCREF(zero);
+ return zero;
+ }
+
+ err:
+ PyErr_SetFromErrno(xc_error);
+ if ( gfd != NULL ) gzclose(gfd);
+ if ( fd >= 0 ) close(fd);
+ return NULL;
+ }
- Py_INCREF(zero);
- return zero;
}
static PyObject *pyxc_linux_build(PyObject *self,
diff --git a/tools/xend/lib/domain_controller.h b/tools/xend/lib/domain_controller.h
index 68d4fac1d2..d5c397fe96 100644
--- a/tools/xend/lib/domain_controller.h
+++ b/tools/xend/lib/domain_controller.h
@@ -52,9 +52,11 @@ typedef struct {
/*
* Top-level command types.
*/
-#define CMSG_CONSOLE 0 /* Console */
-#define CMSG_BLKIF_BE 1 /* Block-device backend */
-#define CMSG_BLKIF_FE 2 /* Block-device frontend */
+#define CMSG_CONSOLE 0 /* Console */
+#define CMSG_BLKIF_BE 1 /* Block-device backend */
+#define CMSG_BLKIF_FE 2 /* Block-device frontend */
+#define CMSG_NETIF_BE 3 /* Network-device backend */
+#define CMSG_NETIF_FE 4 /* Network-device frontend */
/******************************************************************************
@@ -112,7 +114,14 @@ typedef struct {
#define BLKIF_DRIVER_STATUS_DOWN 0
#define BLKIF_DRIVER_STATUS_UP 1
typedef struct {
+ /* IN */
unsigned int status; /* BLKIF_DRIVER_STATUS_??? */
+ /* OUT */
+ /*
+ * Tells driver how many interfaces it should expect to immediately
+ * receive notifications about.
+ */
+ unsigned int nr_interfaces;
} blkif_fe_driver_status_changed_t;
/*
@@ -131,14 +140,7 @@ typedef struct {
* STATUS_DISCONNECTED message.
*/
typedef struct {
- /* IN */
unsigned int handle;
- /* OUT */
- /*
- * Tells driver how many interfaces it should expect to immediately
- * receive notifications about.
- */
- unsigned int nr_interfaces;
} blkif_fe_interface_disconnect_t;
@@ -313,4 +315,193 @@ typedef struct {
unsigned int nr_interfaces;
} blkif_be_driver_status_changed_t;
+
+/******************************************************************************
+ * NETWORK-INTERFACE FRONTEND DEFINITIONS
+ */
+
+/* Messages from domain controller to guest. */
+#define CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED 0
+
+/* Messages from guest to domain controller. */
+#define CMSG_NETIF_FE_DRIVER_STATUS_CHANGED 32
+#define CMSG_NETIF_FE_INTERFACE_CONNECT 33
+#define CMSG_NETIF_FE_INTERFACE_DISCONNECT 34
+
+/*
+ * CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED:
+ * Notify a guest about a status change on one of its network interfaces.
+ * If the interface is DESTROYED or DOWN then the interface is disconnected:
+ * 1. The shared-memory frame is available for reuse.
+ * 2. Any unacknowledged messgaes pending on the interface were dropped.
+ */
+#define NETIF_INTERFACE_STATUS_DESTROYED 0 /* Interface doesn't exist. */
+#define NETIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */
+#define NETIF_INTERFACE_STATUS_CONNECTED 2 /* Exists and is connected. */
+typedef struct {
+ unsigned int handle;
+ unsigned int status;
+ unsigned int evtchn; /* status == NETIF_INTERFACE_STATUS_CONNECTED */
+ u8 mac[6]; /* status == NETIF_INTERFACE_STATUS_CONNECTED */
+} netif_fe_interface_status_changed_t;
+
+/*
+ * CMSG_NETIF_FE_DRIVER_STATUS_CHANGED:
+ * Notify the domain controller that the front-end driver is DOWN or UP.
+ * When the driver goes DOWN then the controller will send no more
+ * status-change notifications. When the driver comes UP then the controller
+ * will send a notification for each interface that currently exists.
+ * If the driver goes DOWN while interfaces are still UP, the domain
+ * will automatically take the interfaces DOWN.
+ */
+#define NETIF_DRIVER_STATUS_DOWN 0
+#define NETIF_DRIVER_STATUS_UP 1
+typedef struct {
+ /* IN */
+ unsigned int status; /* NETIF_DRIVER_STATUS_??? */
+ /* OUT */
+ /*
+ * Tells driver how many interfaces it should expect to immediately
+ * receive notifications about.
+ */
+ unsigned int nr_interfaces;
+} netif_fe_driver_status_changed_t;
+
+/*
+ * CMSG_NETIF_FE_INTERFACE_CONNECT:
+ * If successful, the domain controller will acknowledge with a
+ * STATUS_CONNECTED message.
+ */
+typedef struct {
+ unsigned int handle;
+ unsigned long tx_shmem_frame;
+ unsigned long rx_shmem_frame;
+} netif_fe_interface_connect_t;
+
+/*
+ * CMSG_NETIF_FE_INTERFACE_DISCONNECT:
+ * If successful, the domain controller will acknowledge with a
+ * STATUS_DISCONNECTED message.
+ */
+typedef struct {
+ unsigned int handle;
+} netif_fe_interface_disconnect_t;
+
+
+/******************************************************************************
+ * NETWORK-INTERFACE BACKEND DEFINITIONS
+ */
+
+/* Messages from domain controller. */
+#define CMSG_NETIF_BE_CREATE 0 /* Create a new net-device interface. */
+#define CMSG_NETIF_BE_DESTROY 1 /* Destroy a net-device interface. */
+#define CMSG_NETIF_BE_CONNECT 2 /* Connect i/f to remote driver. */
+#define CMSG_NETIF_BE_DISCONNECT 3 /* Disconnect i/f from remote driver. */
+
+/* Messages to domain controller. */
+#define CMSG_NETIF_BE_DRIVER_STATUS_CHANGED 32
+
+/*
+ * Message request/response definitions for net-device messages.
+ */
+
+/* Non-specific 'okay' return. */
+#define NETIF_BE_STATUS_OKAY 0
+/* Non-specific 'error' return. */
+#define NETIF_BE_STATUS_ERROR 1
+/* The following are specific error returns. */
+#define NETIF_BE_STATUS_INTERFACE_EXISTS 2
+#define NETIF_BE_STATUS_INTERFACE_NOT_FOUND 3
+#define NETIF_BE_STATUS_INTERFACE_CONNECTED 4
+#define NETIF_BE_STATUS_OUT_OF_MEMORY 5
+#define NETIF_BE_STATUS_MAPPING_ERROR 6
+
+/* This macro can be used to create an array of descriptive error strings. */
+#define NETIF_BE_STATUS_ERRORS { \
+ "Okay", \
+ "Non-specific error", \
+ "Interface already exists", \
+ "Interface not found", \
+ "Interface is still connected", \
+ "Out of memory", \
+ "Could not map domain memory" }
+
+/*
+ * CMSG_NETIF_BE_CREATE:
+ * When the driver sends a successful response then the interface is fully
+ * created. The controller will send a DOWN notification to the front-end
+ * driver.
+ */
+typedef struct {
+ /* IN */
+ domid_t domid; /* Domain attached to new interface. */
+ unsigned int netif_handle; /* Domain-specific interface handle. */
+ u8 mac[6];
+ /* OUT */
+ unsigned int status;
+} netif_be_create_t;
+
+/*
+ * CMSG_NETIF_BE_DESTROY:
+ * When the driver sends a successful response then the interface is fully
+ * torn down. The controller will send a DESTROYED notification to the
+ * front-end driver.
+ */
+typedef struct {
+ /* IN */
+ domid_t domid; /* Identify interface to be destroyed. */
+ unsigned int netif_handle; /* ...ditto... */
+ /* OUT */
+ unsigned int status;
+} netif_be_destroy_t;
+
+/*
+ * CMSG_NETIF_BE_CONNECT:
+ * When the driver sends a successful response then the interface is fully
+ * connected. The controller will send a CONNECTED notification to the
+ * front-end driver.
+ */
+typedef struct {
+ /* IN */
+ domid_t domid; /* Domain attached to new interface. */
+ unsigned int netif_handle; /* Domain-specific interface handle. */
+ unsigned int evtchn; /* Event channel for notifications. */
+ unsigned long tx_shmem_frame; /* Page cont. tx shared comms window. */
+ unsigned long rx_shmem_frame; /* Page cont. rx shared comms window. */
+ unsigned long shmem_frame;
+ /* OUT */
+ unsigned int status;
+} netif_be_connect_t;
+
+/*
+ * CMSG_NETIF_BE_DISCONNECT:
+ * When the driver sends a successful response then the interface is fully
+ * disconnected. The controller will send a DOWN notification to the front-end
+ * driver.
+ */
+typedef struct {
+ /* IN */
+ domid_t domid; /* Domain attached to new interface. */
+ unsigned int netif_handle; /* Domain-specific interface handle. */
+ /* OUT */
+ unsigned int status;
+} netif_be_disconnect_t;
+
+/*
+ * CMSG_NETIF_BE_DRIVER_STATUS_CHANGED:
+ * Notify the domain controller that the back-end driver is DOWN or UP.
+ * If the driver goes DOWN while interfaces are still UP, the domain
+ * will automatically send DOWN notifications.
+ */
+typedef struct {
+ /* IN */
+ unsigned int status; /* NETIF_DRIVER_STATUS_??? */
+ /* OUT */
+ /*
+ * Tells driver how many interfaces it should expect to immediately
+ * receive notifications about.
+ */
+ unsigned int nr_interfaces;
+} netif_be_driver_status_changed_t;
+
#endif /* __DOMAIN_CONTROLLER_H__ */