diff --git a/linux-2.4.26-xen-sparse/arch/xen/defconfig-xen0 b/linux-2.4.26-xen-sparse/arch/xen/defconfig-xen0 index a8297dda0d..2463ab1bf5 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/defconfig-xen0 +++ b/linux-2.4.26-xen-sparse/arch/xen/defconfig-xen0 @@ -387,9 +387,22 @@ CONFIG_CHR_DEV_SG=y # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set CONFIG_SCSI_AACRAID=y -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_AIC79XX is not set -# CONFIG_SCSI_AIC7XXX_OLD is not set +CONFIG_SCSI_AIC7XXX=y +CONFIG_AIC7XXX_CMDS_PER_DEVICE=32 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC7XXX_PROBE_EISA_VL is not set +# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set +# CONFIG_AIC7XXX_DEBUG_ENABLE is not set +CONFIG_AIC7XXX_DEBUG_MASK=0 +# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set +CONFIG_SCSI_AIC79XX=y +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +# CONFIG_AIC79XX_BUILD_FIRMWARE is not set +# CONFIG_AIC79XX_ENABLE_RD_STRM is not set +# CONFIG_AIC79XX_DEBUG_ENABLE is not set +CONFIG_AIC79XX_DEBUG_MASK=0 +# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set # CONFIG_SCSI_DPT_I2O is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set @@ -412,9 +425,11 @@ CONFIG_SCSI_BUSLOGIC=y # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_SYM53C8XX_2 is not set -# CONFIG_SCSI_NCR53C8XX is not set -# CONFIG_SCSI_SYM53C8XX is not set +CONFIG_SCSI_SYM53C8XX_2=y +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set diff --git a/tools/libxc/xc_io.h b/tools/libxc/xc_io.h index 37febb52f1..00ed66dc24 100644 --- a/tools/libxc/xc_io.h +++ b/tools/libxc/xc_io.h @@ -1,6 +1,7 @@ #ifndef __XC_XC_IO_H__ #define __XC_XC_IO_H__ +#include #include "xc_private.h" #include "iostream.h" @@ -12,8 +13,21 @@ typedef struct XcIOContext { IOStream *err; char *vmconfig; int vmconfig_n; + int (*suspend)(u32 domain, void *data); + void *data; } XcIOContext; +static inline int xcio_suspend_domain(XcIOContext *ctxt){ + int err = 0; + + if(ctxt->suspend){ + err = ctxt->suspend(ctxt->domain, ctxt->data); + } else { + err = -EINVAL; + } + return err; +} + static inline int xcio_read(XcIOContext *ctxt, void *buf, int n){ int rc; diff --git a/tools/python/xen/xend/XendClient.py b/tools/python/xen/xend/XendClient.py index 534b163cc1..f62d07d4c8 100644 --- a/tools/python/xen/xend/XendClient.py +++ b/tools/python/xen/xend/XendClient.py @@ -231,6 +231,11 @@ class Xend: def xend_domain(self, id): return xend_get(self.domainurl(id)) + def xend_domain_configure(self, id, config): + return xend_call(self.domainurl(id), + {'op' : 'configure', + 'config' : fileof(conf) }) + def xend_domain_unpause(self, id): return xend_call(self.domainurl(id), {'op' : 'unpause'}) diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index a106a273a4..7a9ab8d7f3 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -311,6 +311,42 @@ class XendDomain: return dominfo deferred.addCallback(fn) return deferred + + def domain_configure(self, id, config): + """Configure an existing domain. This is intended for internal + use by domain restore and migrate. + + @param id: domain id + @param config: configuration + @return: deferred + """ + dom = int(id) + dominfo = self.domain_get(dom) + if not dominfo: + raise ValueError("Invalid domain: " + str(id)) + if dominfo.config: + raise ValueError("Domain already configured: " + str(id)) + def fn(dominfo): + self._add_domain(dominfo.id, dominfo) + return dominfo + deferred = dominfo.construct(config) + deferred.addCallback(fn) + return deferred + + def domain_restore(self, src, progress=0): + """Restore a domain from file. + + @param src: source file + @param progress: output progress if true + @return: deferred + """ + + def fn(dominfo): + self._add_domain(dominfo.id, dominfo) + return dominfo + deferred = XendDomainInfo.vm_restore(src, progress=progress) + deferred.addCallback(fn) + return deferred def domain_get(self, id): """Get up-to-date info about a domain. @@ -346,6 +382,8 @@ class XendDomain: - reboot: domain will restart. - halt: domain will not restart (even if has autorestart set). + Returns immediately. + @param id: domain id @param reason: shutdown type: poweroff, reboot, suspend, halt """ @@ -443,7 +481,7 @@ class XendDomain: def domain_destroy(self, id): """Terminate domain immediately. - Camcels any restart for the domain. + Cancels any restart for the domain. @param id: domain id """ @@ -456,6 +494,7 @@ class XendDomain: """Start domain migration. @param id: domain id + @return: deferred """ # Need a cancel too? # Don't forget to cancel restart for it. @@ -464,41 +503,16 @@ class XendDomain: return xmigrate.migrate_begin(dom, dst) def domain_save(self, id, dst, progress=0): - """Save domain state to file, destroy domain on success. - Leave domain running on error. + """Start saving a domain to file. @param id: domain id @param dst: destination file @param progress: output progress if true + @return: deferred """ dom = int(id) - dominfo = self.domain_get(id) - if not dominfo: - return -1 - vmconfig = sxp.to_string(dominfo.sxpr()) - self.domain_pause(id) - eserver.inject('xend.domain.save', id) - try: - rc = xc.linux_save(dom=dom, state_file=dst, - vmconfig=vmconfig, progress=progress) - except: - rc = -1 - if rc == 0: - self.domain_destroy(id) - else: - self.domain_unpause(id) - return rc - - def domain_restore(self, src, progress=0): - """Restore domain from file. - - @param src : source file - @param progress: output progress if true - @return: domain object - """ - dominfo = XendDomainInfo.vm_restore(src, progress=progress) - self._add_domain(dominfo.id, dominfo) - return dominfo + xmigrate = XendMigrate.instance() + return xmigrate.save_begin(dom, dst) def domain_pincpu(self, dom, cpu): """Pin a domain to a cpu. diff --git a/tools/python/xen/xend/XendMigrate.py b/tools/python/xen/xend/XendMigrate.py index 29cb4bb616..543c1cbd42 100644 --- a/tools/python/xen/xend/XendMigrate.py +++ b/tools/python/xen/xend/XendMigrate.py @@ -1,5 +1,6 @@ # Copyright (C) 2004 Mike Wray +import errno import sys import socket import time @@ -14,9 +15,12 @@ import sxp import XendDB import EventServer; eserver = EventServer.instance() +"""The port for the migrate/save daemon xfrd.""" XFRD_PORT = 8002 +"""The transfer protocol major version number.""" XFR_PROTO_MAJOR = 1 +"""The transfer protocol minor version number.""" XFR_PROTO_MINOR = 0 class Xfrd(Protocol): @@ -46,7 +50,7 @@ class Xfrd(Protocol): self.parser.input(data) if self.parser.ready(): val = self.parser.get_val() - self.xinfo.dispatch(val) + self.xinfo.dispatch(self, val) if self.parser.at_eof(): self.loseConnection() @@ -55,16 +59,16 @@ class XfrdClientFactory(ClientFactory): """Factory for clients of the migration/save daemon xfrd. """ - def __init__(self, minfo): + def __init__(self, xinfo): #ClientFactory.__init__(self) - self.minfo = minfo + self.xinfo = xinfo def startedConnecting(self, connector): print 'Started to connect', 'self=', self, 'connector=', connector def buildProtocol(self, addr): print 'buildProtocol>', addr - return Migrate(self.minfo) + return Xfrd(self.xinfo) def clientConnectionLost(self, connector, reason): print 'clientConnectionLost>', 'connector=', connector, 'reason=', reason @@ -76,13 +80,15 @@ class XfrdInfo: """Abstract class for info about a session with xfrd. Has subclasses for save and migrate. """ - + + def __init__(self): + from xen.xend import XendDomain + self.xd = XendDomain.instance() + self.deferred = defer.Deferred() + def vmconfig(self): print 'vmconfig>' - from xen.xend import XendDomain - xd = XendDomain.instance() - - dominfo = xd.domain_get(self.src_dom) + dominfo = self.xd.domain_get(self.src_dom) print 'vmconfig>', type(dominfo), dominfo if dominfo: val = sxp.to_string(dominfo.sxpr()) @@ -93,6 +99,8 @@ class XfrdInfo: def error(self, err): self.state = 'error' + if not self.deferred.called: + self.deferred.errback(err) def dispatch(self, xfrd, val): op = sxp.name(val) @@ -100,38 +108,70 @@ class XfrdInfo: if op.startswith('xfr_'): fn = getattr(self, op, self.unknown) else: - fn = self.unknown() - fn(xfrd, val) + fn = self.unknown + val = fn(xfrd, val) + if val is not None: + sxp.show(val, out=self.transport) def unknown(self, xfrd, val): print 'unknown>', val + xfrd.loseConnection() + return None def xfr_err(self, xfrd, val): - # If we get an error with non-zero code the migrate failed. + # If we get an error with non-zero code the operation failed. # An error with code zero indicates hello success. print 'xfr_err>', val - v = sxp.child(val) + v = sxp.child0(val) print 'xfr_err>', type(v), v - err = int(sxp.child(val)) + err = int(sxp.child0(val)) if not err: return self.error(err); xfrd.loseConnection() + #try: + # self.xd.domain_unpause(self.src_dom) + #except: + # print >>sys.stdout, "Error unpausing domain:", self.src_dom + return None def xfr_progress(self, val): print 'xfr_progress>', val + return None - def xfr_domain_pause(self, val): - print 'xfr__domain_pause>', val + def xfr_vm_pause(self, val): + print 'xfr_vm_pause>', val + try: + vmid = sxp.child0(val) + val = self.xd.domain_pause(vmid) + except: + val = errno.EINVAL + return ['xfr.err', val] - def xfr_domain_suspend(self, val): - print 'xfr_domain_suspend>', val + def xfr_vm_unpause(self, val): + print 'xfr_vm_unpause>', val + try: + vmid = sxp.child0(val) + val = self.xd.domain_unpause(vmid) + except: + val = errno.EINVAL + return ['xfr.err', val] + + def xfr_vm_suspend(self, val): + print 'xfr_vm_suspend>', val + try: + vmid = sxp.child0(val) + val = self.xd.domain_shutdown(vmid, reason='suspend') + except: + val = errno.EINVAL + return ['xfr.err', val] class XendMigrateInfo(XfrdInfo): """Representation of a migrate in-progress and its interaction with xfrd. """ - def __init__(self, id, dom, host, port): - self.id = id + def __init__(self, xid, dom, host, port): + XfrdInfo.__init__(self) + self.xid = xid self.state = 'begin' self.src_host = socket.gethostname() self.src_dom = dom @@ -139,10 +179,9 @@ class XendMigrateInfo(XfrdInfo): self.dst_port = port self.dst_dom = None self.start = 0 - self.deferred = defer.Deferred() def sxpr(self): - sxpr = ['migrate', ['id', self.id], ['state', self.state] ] + sxpr = ['migrate', ['id', self.xid], ['state', self.state] ] sxpr_src = ['src', ['host', self.src_host], ['domain', self.src_dom] ] sxpr.append(sxpr_src) sxpr_dst = ['dst', ['host', self.dst_host] ] @@ -160,12 +199,15 @@ class XendMigrateInfo(XfrdInfo): self.src_dom, vmconfig, self.dst_host, - self.d.dst_port]) + self.dst_port]) def xfr_migrate_ok(self, val): dom = int(sxp.child0(val)) self.state = 'ok' self.dst_dom = dom + self.xd_domain_destroy(self.src_dom) + if not self.deferred.called: + self.deferred.callback(self) def connectionLost(self, reason=None): if self.state =='ok': @@ -178,17 +220,17 @@ class XendSaveInfo(XfrdInfo): """Representation of a save in-progress and its interaction with xfrd. """ - def __init__(self, id, dom, file): - self.id = id + def __init__(self, xid, dom, file): + XfrdInfo.__init__(self) + self.xid = xid self.state = 'begin' self.src_dom = dom self.file = file self.start = 0 - self.deferred = defer.Deferred() def sxpr(self): sxpr = ['save', - ['id', self.id], + ['id', self.xid], ['state', self.state], ['domain', self.src_dom], ['file', self.file] ] @@ -204,6 +246,9 @@ class XendSaveInfo(XfrdInfo): def xfr_save_ok(self, val): dom = int(sxp.child0(val)) self.state = 'ok' + self.xd_domain_destroy(self.src_dom) + if not self.deferred.called: + self.deferred.callback(self) def connectionLost(self, reason=None): if self.state =='ok': @@ -217,7 +262,6 @@ class XendMigrate: """External api for interaction with xfrd for migrate and save. Singleton. """ - # Represents migration in progress. # Use log for indications of begin/end/errors? # Need logging of: domain create/halt, migrate begin/end/fail # Log via event server? @@ -226,53 +270,77 @@ class XendMigrate: def __init__(self): self.db = XendDB.XendDB(self.dbpath) - self.migrate = {} - self.migrate_db = self.db.fetchall("") - self.id = 0 + self.session = {} + self.session_db = self.db.fetchall("") + self.xid = 0 def nextid(self): - self.id += 1 - return "%d" % self.id + self.xid += 1 + return "%d" % self.xid def sync(self): - self.db.saveall("", self.migrate_db) + self.db.saveall("", self.session_db) - def sync_migrate(self, id): - self.db.save(id, self.migrate_db[id]) + def sync_session(self, xid): + print 'sync_session>', type(xid), xid, self.session_db[xid] + self.db.save(xid, self.session_db[xid]) def close(self): pass - def _add_migrate(self, id, info): - self.migrate[id] = info - self.migrate_db[id] = info.sxpr() - self.sync_migrate(id) + def _add_session(self, xid, info): + self.session[xid] = info + self.session_db[xid] = info.sxpr() + self.sync_session(xid) #eserver.inject('xend.migrate.begin', info.sxpr()) - def _delete_migrate(self, id): - #eserver.inject('xend.migrate.end', id) - del self.migrate[id] - del self.migrate_db[id] - self.db.delete(id) + def _delete_session(self, xid): + #eserver.inject('xend.migrate.end', xid) + del self.session[xid] + del self.session_db[xid] + self.db.delete(xid) - def migrate_ls(self): - return self.migrate.keys() + def session_ls(self): + return self.session.keys() - def migrates(self): - return self.migrate.values() + def sessions(self): + return self.session.values() - def migrate_get(self, id): - return self.migrate.get(id) - - def migrate_begin(self, dom, host, port=XFRD_PORT): - # Check dom for existence, not migrating already. - # Subscribe to migrate notifications (for updating). - id = self.nextid() - info = XendMigrateInfo(id, dom, host, port) - self._add_migrate(id, info) + def session_get(self, xid): + return self.session.get(xid) + + def session_begin(self, info): + self._add_session(info.xid, info) mcf = XfrdClientFactory(info) reactor.connectTCP('localhost', XFRD_PORT, mcf) return info + + def migrate_begin(self, dom, host, port=XFRD_PORT): + """Begin to migrate a domain to another host. + + @param dom: domain + @param host: destination host + @param port: destination port + @return: deferred + """ + # Check dom for existence, not migrating already. + # Subscribe to migrate notifications (for updating). + xid = self.nextid() + info = XendMigrateInfo(xid, dom, host, port) + self.session_begin(info) + return info.deferred + + def save_begin(self, dom, file): + """Begin saving a domain to file. + + @param dom: domain + @param file: destination file + @return: deferred + """ + xid = self.nextid() + info = XendSaveInfo(xid, dom, file) + self.session_begin(info) + return info.deferred def instance(): global inst diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py index b71dd63161..cb70cf41bc 100644 --- a/tools/python/xen/xend/server/SrvDomain.py +++ b/tools/python/xen/xend/server/SrvDomain.py @@ -18,6 +18,14 @@ class SrvDomain(SrvDir): self.xd = XendDomain.instance() self.xconsole = XendConsole.instance() + def op_configure(self, op, req): + fn = FormFn(self.xd.domain_configure, + [['dom', 'int'], + ['config', 'sxp']]) + val = fn(req.args, {'dom': self.dom.id}) + #todo: may need to add ok and err callbacks. + return val + def op_unpause(self, op, req): val = self.xd.domain_unpause(self.dom.id) return val @@ -27,7 +35,6 @@ class SrvDomain(SrvDir): return val def op_shutdown(self, op, req): - #val = self.xd.domain_shutdown(self.dom.id) fn = FormFn(self.xd.domain_shutdown, [['dom', 'int'], ['reason', 'str']]) @@ -202,8 +209,22 @@ class SrvDomain(SrvDir): req.write('
' % req.prePathURL()) req.write('') req.write('') - req.write('') req.write('') - req.write('
') - req.write('To: ') + req.write('
') + + req.write('
' % req.prePathURL()) + req.write('') + req.write('Poweroff
') + req.write('Halt
') + req.write('Reboot
') + req.write('
') + + req.write('
' % req.prePathURL()) + req.write('
') + req.write('To file: ') + req.write('
') + + req.write('
' % req.prePathURL()) + req.write('
') + req.write('To host: ') req.write('
') diff --git a/tools/python/xen/xend/server/SrvDomainDir.py b/tools/python/xen/xend/server/SrvDomainDir.py index 719ea612ff..8ca6239850 100644 --- a/tools/python/xen/xend/server/SrvDomainDir.py +++ b/tools/python/xen/xend/server/SrvDomainDir.py @@ -105,7 +105,10 @@ class SrvDomainDir(SrvDir): def op_restore(self, op, req): """Restore a domain from file. + + @return: deferred """ + #todo: return is deferred. May need ok and err callbacks. fn = FormFn(self.xd.domain_restore, [['file', 'str']]) val = fn(req.args) @@ -154,9 +157,10 @@ class SrvDomainDir(SrvDir): req.write('') req.write('Config
') req.write('') + req.write('
' % req.prePathURL()) - req.write('') + req.write('') req.write('State
') req.write('
') diff --git a/tools/xfrd/Makefile b/tools/xfrd/Makefile index fe84120471..6e9b4b6681 100644 --- a/tools/xfrd/Makefile +++ b/tools/xfrd/Makefile @@ -18,6 +18,9 @@ INCLUDES += -I $(XEN_LINUX_INCLUDE) vpath %.h $(XEN_XU) INCLUDES += -I $(XEN_XU) +vpath %.h $(XEN_LIBXC) +INCLUDES += -I $(XEN_LIBXC) + vpath %c $(XEN_LIBXUTIL) INCLUDES += -I $(XEN_LIBXUTIL) @@ -28,7 +31,9 @@ UTIL_LIB_OBJ = $(UTIL_LIB_SRC:.c=.o) XFRD_PROG_OBJ = $(XFRD_PROG_SRC:.c=.o) XFRD_PROG_OBJ += $(UTIL_LIB) -CPPFLAGS += -D _XEN_XFR_STUB_ +# Flag controlling whether to use stubs. +# Define to use stubs, undefine to use the real Xen functions. +#CPPFLAGS += -D _XEN_XFR_STUB_ CFLAGS += -g CFLAGS += -Wall @@ -38,15 +43,31 @@ CFLAGS += $(INCLUDES) CFLAGS += -Wp,-MD,.$(@F).d PROG_DEP = .*.d -#LDFLAGS += -L $(COMPRESS_DIR) -lz +#$(warning XFRD_PROG_OBJ= $(XFRD_PROG_OBJ)) +#$(warning UTIL_LIB= $(UTIL_LIB)) +#$(warning UTIL_LIB_OBJ= $(UTIL_LIB_OBJ)) -$(warning XFRD_PROG_OBJ= $(XFRD_PROG_OBJ)) -$(warning UTIL_LIB= $(UTIL_LIB)) -$(warning UTIL_LIB_OBJ= $(UTIL_LIB_OBJ)) +# Libraries for xfrd. +XFRD_LIBS := + +XFRD_LIBS += -L $(XEN_LIBXC) -lxc +XFRD_LIBS += -L $(XEN_LIBXUTIL) -lxutil + +# zlib library. +XFRD_LIBS += -lz + +CURL_FLAGS = $(shell curl-config --cflags) +CURL_LIBS = $(shell curl-config --libs) +CFLAGS += $(CURL_FLAGS) +# libcurl libraries. +XFRD_LIBS += $(CURL_LIBS) + +#$(warning XFRD_LIBS = $(XFRD_LIBS)) all: xfrd -xfrd: $(XFRD_PROG_OBJ) -lz +xfrd: $(XFRD_PROG_OBJ) + $(CC) -o $@ $^ $(XFRD_LIBS) .PHONY: install install: xfrd @@ -64,5 +85,6 @@ clean: $(RM) *.o *.a *.so *~ xfrd $(RM) $(PROG_DEP) +$(XFRD_PROG_OBJ): Makefile -include $(PROG_DEP) diff --git a/tools/xfrd/xen_domain.c b/tools/xfrd/xen_domain.c index 4c197e8396..adef919af1 100644 --- a/tools/xfrd/xen_domain.c +++ b/tools/xfrd/xen_domain.c @@ -3,18 +3,48 @@ #include #ifndef _XEN_XFR_STUB_ -#include "dom0_defs.h" -#include "mem_defs.h" +#include "xc.h" +#include "xc_io.h" #endif #include "xen_domain.h" #include "marshal.h" #include "xdr.h" +#include "xfrd.h" #define MODULE_NAME "XFRD" #define DEBUG 1 #include "debug.h" +#ifndef _XEN_XFR_STUB_ +static int domain_suspend(u32 dom, void *data){ + int err = 0; + Conn *xend = data; + + dprintf("> dom=%lu data=%p\n", dom, data); + err = xfr_vm_suspend(xend, dom); + dprintf("< err=%d\n", err); + return err; +} + +static int xc_handle = 0; + +int xcinit(void){ + if(xc_handle <= 0){ + xc_handle = xc_interface_open(); + } + dprintf("< xc_handle=%d\n", xc_handle); + return xc_handle; +} + +void xcfini(void){ + if(xc_handle > 0){ + xc_interface_close(xc_handle); + xc_handle = 0; + } +} +#endif + /** Write domain state. * * At some point during this the domain is suspended, and then there's no way back. @@ -22,10 +52,10 @@ */ int xen_domain_snd(Conn *xend, IOStream *io, uint32_t dom, char *vmconfig, int vmconfig_n){ int err = 0; +#ifdef _XEN_XFR_STUB_ char buf[1024]; int n, k, d, buf_n; dprintf("> dom=%d\n", dom); -#ifdef _XEN_XFR_STUB_ err = marshal_uint32(io, dom); if(err) goto exit; err = marshal_string(io, vmconfig, vmconfig_n); @@ -41,8 +71,20 @@ int xen_domain_snd(Conn *xend, IOStream *io, uint32_t dom, char *vmconfig, int v dprintf("> k=%d n=%d\n", k, n); } + dom = 99; + err = xfr_vm_suspend(xend, dom); exit: #else + XcIOContext _ioctxt = {}, *ioctxt = &_ioctxt; + dprintf("> dom=%d\n", dom); + ioctxt->domain = dom; + ioctxt->io = io; + ioctxt->info = iostdout; + ioctxt->err = iostderr; + ioctxt->data = xend; + ioctxt->suspend = domain_suspend; + + err = xc_linux_save(xcinit(), ioctxt); #endif dprintf("< err=%d\n", err); return err; @@ -53,10 +95,10 @@ int xen_domain_snd(Conn *xend, IOStream *io, uint32_t dom, char *vmconfig, int v */ int xen_domain_rcv(IOStream *io, uint32_t *dom, char **vmconfig, int *vmconfig_n){ int err = 0; +#ifdef _XEN_XFR_STUB_ char buf[1024]; int n, k, d, buf_n; dprintf(">\n"); -#ifdef _XEN_XFR_STUB_ err = unmarshal_uint32(io, dom); if(err) goto exit; err = unmarshal_new_string(io, vmconfig, vmconfig_n); @@ -72,19 +114,104 @@ int xen_domain_rcv(IOStream *io, uint32_t *dom, char **vmconfig, int *vmconfig_n } exit: #else + XcIOContext _ioctxt = {}, *ioctxt = &_ioctxt; + dprintf(">\n"); + ioctxt->io = io; + ioctxt->info = iostdout; + ioctxt->err = iostderr; + + err = xc_linux_restore(xcinit(), ioctxt); #endif dprintf("< err=%d\n", err); return err; } -/** Configure a new domain. Talk to xend. Use libcurl? +#include + +static int do_curl_global_init = 1; + +static CURL *curlinit(void){ + if(do_curl_global_init){ + do_curl_global_init = 0; + curl_global_init(CURL_GLOBAL_ALL); + } + return curl_easy_init(); +} + +/** Configure a new domain. Talk to xend using libcurl. */ int xen_domain_configure(uint32_t dom, char *vmconfig, int vmconfig_n){ int err = 0; - dprintf(">\n"); + CURL *curl = NULL; + CURLcode curlcode = 0; + char domainurl[128] = {}; + int domainurl_n = sizeof(domainurl) - 1; + int n; + struct curl_httppost *form = NULL, *last = NULL; + CURLFORMcode formcode = 0; + + dprintf("> dom=%u\n", dom); + curl = curlinit(); + if(!curl){ + eprintf("> Could not init libcurl\n"); + err = -ENOMEM; + goto exit; + } + n = snprintf(domainurl, domainurl_n, + "http://localhost:%d/xend/domain/%u", XEND_PORT, dom); + if(n <= 0 || n >= domainurl_n){ + err = -ENOMEM; + eprintf("Out of memory in url.\n"); + goto exit; + } + // Config field - set from vmconfig. + formcode = curl_formadd(&form, &last, + CURLFORM_COPYNAME, "config", + CURLFORM_BUFFER, "config", + CURLFORM_BUFFERPTR, vmconfig, + CURLFORM_BUFFERLENGTH, vmconfig_n, + CURLFORM_CONTENTTYPE, "application/octet-stream", + CURLFORM_END); + if(formcode){ + eprintf("> Error adding config field.\n"); + goto exit; + } + // Op field. + formcode = curl_formadd(&form, &last, + CURLFORM_COPYNAME, "op", + CURLFORM_COPYCONTENTS, "configure", + CURLFORM_END); + + if(formcode){ + eprintf("> Error adding op field.\n"); + goto exit; + } + // No progress meter. + //curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + // Completely quiet. + //curl_easy_setopt(curl, CURLOPT_MUTE, 1); + // Set the URL. + curl_easy_setopt(curl, CURLOPT_URL, domainurl); + // POST the form. + curl_easy_setopt(curl, CURLOPT_HTTPPOST, form); + dprintf("> curl perform...\n"); #ifdef _XEN_XFR_STUB_ -#else -#endif + dprintf("> _XEN_XFR_STUB_ defined - not calling xend\n"); + curlcode = 0; +#else + curlcode = curl_easy_perform(curl); +#endif + exit: + if(curl) curl_easy_cleanup(curl); + if(form) curl_formfree(form); + if(formcode){ + dprintf("> formcode=%d\n", formcode); + err = -EINVAL; + } + if(curlcode){ + dprintf("> curlcode=%d\n", curlcode); + err = -EINVAL; + } dprintf("< err=%d\n", err); return err; } diff --git a/tools/xfrd/xfrd.c b/tools/xfrd/xfrd.c index 5dac7be0ba..301674b1fe 100644 --- a/tools/xfrd/xfrd.c +++ b/tools/xfrd/xfrd.c @@ -93,22 +93,26 @@ Sxpr oxfr_configure; // (xfr.configure ) Sxpr oxfr_err; // (xfr.err ) Sxpr oxfr_hello; // (xfr.hello ) Sxpr oxfr_migrate; // (xfr.migrate ) -Sxpr oxfr_ok; // (xfr.ok ) +Sxpr oxfr_migrate_ok;// (xfr.migrate.ok ) Sxpr oxfr_progress; // (xfr.progress ) Sxpr oxfr_save; // (xfr.save ) -Sxpr oxfr_suspend; // (xfr.suspend ) +Sxpr oxfr_save_ok; // (xfr.save.ok) +Sxpr oxfr_vm_suspend;// (xfr.vm.suspend ) Sxpr oxfr_xfr; // (xfr.xfr ) +Sxpr oxfr_xfr_ok; // (xfr.xfr.ok ) void xfr_init(void){ - oxfr_configure = intern("xfr.configure"); - oxfr_err = intern("xfr.err"); - oxfr_hello = intern("xfr.hello"); - oxfr_migrate = intern("xfr.migrate"); - oxfr_ok = intern("xfr.ok"); - oxfr_progress = intern("xfr.progress"); - oxfr_save = intern("xfr.save"); - oxfr_suspend = intern("xfr.suspend"); - oxfr_xfr = intern("xfr.xfr"); + oxfr_configure = intern("xfr.configure"); + oxfr_err = intern("xfr.err"); + oxfr_hello = intern("xfr.hello"); + oxfr_migrate = intern("xfr.migrate"); + oxfr_migrate_ok = intern("xfr.migrate.ok"); + oxfr_progress = intern("xfr.progress"); + oxfr_save = intern("xfr.save"); + oxfr_save_ok = intern("xfr.save.ok"); + oxfr_vm_suspend = intern("xfr.vm.suspend"); + oxfr_xfr = intern("xfr.xfr"); + oxfr_xfr_ok = intern("xfr.xfr.ok"); } #ifndef TRUE @@ -518,11 +522,27 @@ int xfr_send_xfr(Conn *conn, uint32_t vmid){ return (err < 0 ? err : 0); } -int xfr_send_ok(Conn *conn, uint32_t vmid){ +int xfr_send_xfr_ok(Conn *conn, uint32_t vmid){ int err = 0; err = IOStream_print(conn->out, "(%s %d)", - atom_name(oxfr_ok), vmid); + atom_name(oxfr_xfr_ok), vmid); + return (err < 0 ? err : 0); +} + +int xfr_send_migrate_ok(Conn *conn, uint32_t vmid){ + int err = 0; + + err = IOStream_print(conn->out, "(%s %d)", + atom_name(oxfr_migrate_ok), vmid); + return (err < 0 ? err : 0); +} + +int xfr_send_save_ok(Conn *conn){ + int err = 0; + + err = IOStream_print(conn->out, "(%s)", + atom_name(oxfr_save_ok)); return (err < 0 ? err : 0); } @@ -530,10 +550,24 @@ int xfr_send_suspend(Conn *conn, uint32_t vmid){ int err = 0; err = IOStream_print(conn->out, "(%s %d)", - atom_name(oxfr_suspend), vmid); + atom_name(oxfr_vm_suspend), vmid); return (err < 0 ? err : 0); } +/** Suspend a vm on behalf of save/migrate. + */ +int xfr_vm_suspend(Conn *xend, uint32_t vmid){ + int err = 0; + dprintf("> vmid=%u\n", vmid); + err = xfr_send_suspend(xend, vmid); + if(err) goto exit; + IOStream_flush(xend->out); + err = xfr_response(xend); + exit: + dprintf("< err=%d\n", err); + return err; +} + /** Get vm state. Send transfer message. * * @param peer connection @@ -561,7 +595,7 @@ int xfr_send_state(XfrState *state, Conn *xend, Conn *peer){ int errcode; err = intof(sxpr_childN(sxpr, 0, ONONE), &errcode); if(!err) err = errcode; - } else if(sxpr_elementp(sxpr, oxfr_ok)){ + } else if(sxpr_elementp(sxpr, oxfr_xfr_ok)){ // Ok - get the new domain id. err = intof(sxpr_childN(sxpr, 0, ONONE), &state->vmid_new); xfr_error(peer, err); @@ -592,7 +626,7 @@ int xfr_send_done(XfrState *state, Conn *xend){ err = xfr_error(xend, first_err); } else { // Report new domain id to xend. - err = xfr_send_ok(xend, state->vmid_new); + err = xfr_send_migrate_ok(xend, state->vmid_new); } XfrState_set_err(state, err); @@ -677,17 +711,25 @@ int xfr_save(Args *args, XfrState *state, Conn *xend, char *file){ int err = 0; IOStream *io = NULL; + dprintf("> file=%s\n", file); io = file_stream_fopen(file, "wb"); if(!io){ + dprintf("> Failed to open %s\n", file); err = -EIO; goto exit; } err = xen_domain_snd(xend, io, state->vmid, state->vmconfig, state->vmconfig_n); + if(err){ + err = xfr_error(xend, err); + } else { + err = xfr_send_save_ok(xend); + } exit: if(io){ IOStream_close(io); IOStream_free(io); } + dprintf("< err=%d\n", err); return err; } @@ -709,7 +751,7 @@ int xfr_recv(Args *args, XfrState *state, Conn *peer){ if(err) goto exit; // Report new domain id to peer. - err = xfr_send_ok(peer, state->vmid_new); + err = xfr_send_xfr_ok(peer, state->vmid_new); if(err) goto exit; // Get the final ok. err = xfr_response(peer); diff --git a/tools/xfrd/xfrd.h b/tools/xfrd/xfrd.h index 2537fd67ab..9de464549b 100644 --- a/tools/xfrd/xfrd.h +++ b/tools/xfrd/xfrd.h @@ -2,7 +2,7 @@ #define _XFRD_XFRD_H_ /** Xend port in host order. */ -#define XEND_PORT 8001 +#define XEND_PORT 8000 /** Xfrd port in host order. */ #define XFRD_PORT 8002 @@ -11,4 +11,6 @@ #define XFR_PROTO_MAJOR 1 #define XFR_PROTO_MINOR 0 +struct Conn; +extern int xfr_vm_suspend(struct Conn *xend, uint32_t vmid); #endif