diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/examples/defaults | 15 | ||||
-rwxr-xr-x | tools/examples/xc_dom_create.py | 17 | ||||
-rw-r--r-- | tools/xc/lib/xc.h | 14 | ||||
-rw-r--r-- | tools/xc/lib/xc_domain.c | 2 | ||||
-rw-r--r-- | tools/xc/lib/xc_linux_restore.c | 86 | ||||
-rw-r--r-- | tools/xc/lib/xc_linux_save.c | 89 | ||||
-rw-r--r-- | tools/xc/lib/xc_private.h | 24 | ||||
-rw-r--r-- | tools/xc/py/Xc.c | 284 | ||||
-rw-r--r-- | tools/xend/lib/domain_controller.h | 211 |
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__ */ |