ia64/xen-unstable

changeset 1744:afd530477bfd

bitkeeper revision 1.1062.3.2 (40f29f095EmGaaKsbz1zoQ1AZH6dQw)

Integrating save/migrate handling with xfrd.
Add suspend callback to save.
author mjw@wray-m-3.hpl.hp.com
date Mon Jul 12 14:24:09 2004 +0000 (2004-07-12)
parents 982f815497e4
children 3000423a41b1
files tools/libxc/xc_io.h tools/python/xen/xend/XendClient.py tools/python/xen/xend/XendDomain.py tools/python/xen/xend/XendMigrate.py tools/python/xen/xend/server/SrvDomain.py tools/python/xen/xend/server/SrvDomainDir.py tools/xfrd/Makefile tools/xfrd/xen_domain.c tools/xfrd/xfrd.c tools/xfrd/xfrd.h
line diff
     1.1 --- a/tools/libxc/xc_io.h	Mon Jul 12 14:18:52 2004 +0000
     1.2 +++ b/tools/libxc/xc_io.h	Mon Jul 12 14:24:09 2004 +0000
     1.3 @@ -1,6 +1,7 @@
     1.4  #ifndef __XC_XC_IO_H__
     1.5  #define __XC_XC_IO_H__
     1.6  
     1.7 +#include <errno.h>
     1.8  #include "xc_private.h"
     1.9  #include "iostream.h"
    1.10  
    1.11 @@ -12,8 +13,21 @@ typedef struct XcIOContext {
    1.12      IOStream *err;
    1.13      char *vmconfig;
    1.14      int vmconfig_n;
    1.15 +    int (*suspend)(u32 domain, void *data);
    1.16 +    void *data;
    1.17  } XcIOContext;
    1.18  
    1.19 +static inline int xcio_suspend_domain(XcIOContext *ctxt){
    1.20 +    int err = 0;
    1.21 +
    1.22 +    if(ctxt->suspend){
    1.23 +        err = ctxt->suspend(ctxt->domain, ctxt->data);
    1.24 +    } else {
    1.25 +        err = -EINVAL;
    1.26 +    }
    1.27 +    return err;
    1.28 +}
    1.29 +
    1.30  static inline int xcio_read(XcIOContext *ctxt, void *buf, int n){
    1.31      int rc;
    1.32  
     2.1 --- a/tools/python/xen/xend/XendClient.py	Mon Jul 12 14:18:52 2004 +0000
     2.2 +++ b/tools/python/xen/xend/XendClient.py	Mon Jul 12 14:24:09 2004 +0000
     2.3 @@ -225,6 +225,11 @@ class Xend:
     2.4      def xend_domain(self, id):
     2.5          return xend_get(self.domainurl(id))
     2.6  
     2.7 +    def xend_domain_configure(self, id, config):
     2.8 +        return xend_call(self.domainurl(id),
     2.9 +                         {'op'      : 'configure',
    2.10 +                          'config'  : fileof(conf) })
    2.11 +
    2.12      def xend_domain_unpause(self, id):
    2.13          return xend_call(self.domainurl(id),
    2.14                           {'op'      : 'unpause'})
     3.1 --- a/tools/python/xen/xend/XendDomain.py	Mon Jul 12 14:18:52 2004 +0000
     3.2 +++ b/tools/python/xen/xend/XendDomain.py	Mon Jul 12 14:24:09 2004 +0000
     3.3 @@ -311,6 +311,42 @@ class XendDomain:
     3.4              return dominfo
     3.5          deferred.addCallback(fn)
     3.6          return deferred
     3.7 +
     3.8 +    def domain_configure(self, id, config):
     3.9 +        """Configure an existing domain. This is intended for internal
    3.10 +        use by domain restore and migrate.
    3.11 +
    3.12 +        @param id:     domain id
    3.13 +        @param config: configuration
    3.14 +        @return: deferred
    3.15 +        """
    3.16 +        dom = int(id)
    3.17 +        dominfo = self.domain_get(dom)
    3.18 +        if not dominfo:
    3.19 +            raise ValueError("Invalid domain: " + str(id))
    3.20 +        if dominfo.config:
    3.21 +            raise ValueError("Domain already configured: " + str(id))
    3.22 +        def fn(dominfo):
    3.23 +            self._add_domain(dominfo.id, dominfo)
    3.24 +            return dominfo
    3.25 +        deferred = dominfo.construct(config)
    3.26 +        deferred.addCallback(fn)
    3.27 +        return deferred
    3.28 +    
    3.29 +    def domain_restore(self, src, progress=0):
    3.30 +        """Restore a domain from file.
    3.31 +
    3.32 +        @param src:      source file
    3.33 +        @param progress: output progress if true
    3.34 +        @return: deferred
    3.35 +        """
    3.36 +        
    3.37 +        def fn(dominfo):
    3.38 +            self._add_domain(dominfo.id, dominfo)
    3.39 +            return dominfo
    3.40 +        deferred = XendDomainInfo.vm_restore(src, progress=progress)
    3.41 +        deferred.addCallback(fn)
    3.42 +        return deferred
    3.43      
    3.44      def domain_get(self, id):
    3.45          """Get up-to-date info about a domain.
    3.46 @@ -346,6 +382,8 @@ class XendDomain:
    3.47           - reboot: domain will restart.
    3.48           - halt: domain will not restart (even if has autorestart set).
    3.49  
    3.50 +         Returns immediately.
    3.51 +
    3.52          @param id:     domain id
    3.53          @param reason: shutdown type: poweroff, reboot, suspend, halt
    3.54          """
    3.55 @@ -443,7 +481,7 @@ class XendDomain:
    3.56  
    3.57      def domain_destroy(self, id):
    3.58          """Terminate domain immediately.
    3.59 -        Camcels any restart for the domain.
    3.60 +        Cancels any restart for the domain.
    3.61  
    3.62          @param id: domain id
    3.63          """
    3.64 @@ -456,6 +494,7 @@ class XendDomain:
    3.65          """Start domain migration.
    3.66  
    3.67          @param id: domain id
    3.68 +        @return: deferred
    3.69          """
    3.70          # Need a cancel too?
    3.71          # Don't forget to cancel restart for it.
    3.72 @@ -464,41 +503,16 @@ class XendDomain:
    3.73          return xmigrate.migrate_begin(dom, dst)
    3.74  
    3.75      def domain_save(self, id, dst, progress=0):
    3.76 -        """Save domain state to file, destroy domain on success.
    3.77 -        Leave domain running on error.
    3.78 +        """Start saving a domain to file.
    3.79  
    3.80          @param id:       domain id
    3.81          @param dst:      destination file
    3.82          @param progress: output progress if true
    3.83 +        @return: deferred
    3.84          """
    3.85          dom = int(id)
    3.86 -        dominfo = self.domain_get(id)
    3.87 -        if not dominfo:
    3.88 -            return -1
    3.89 -        vmconfig = sxp.to_string(dominfo.sxpr())
    3.90 -        self.domain_pause(id)
    3.91 -        eserver.inject('xend.domain.save', id)
    3.92 -        try:
    3.93 -            rc = xc.linux_save(dom=dom, state_file=dst,
    3.94 -                               vmconfig=vmconfig, progress=progress)
    3.95 -        except:
    3.96 -            rc = -1
    3.97 -        if rc == 0:
    3.98 -            self.domain_destroy(id)
    3.99 -        else:
   3.100 -            self.domain_unpause(id)
   3.101 -        return rc
   3.102 -    
   3.103 -    def domain_restore(self, src, progress=0):
   3.104 -        """Restore domain from file.
   3.105 -
   3.106 -        @param src :     source file
   3.107 -        @param progress: output progress if true
   3.108 -        @return: domain object
   3.109 -        """
   3.110 -        dominfo = XendDomainInfo.vm_restore(src, progress=progress)
   3.111 -        self._add_domain(dominfo.id, dominfo)
   3.112 -        return dominfo
   3.113 +        xmigrate = XendMigrate.instance()
   3.114 +        return xmigrate.save_begin(dom, dst)
   3.115      
   3.116      def domain_pincpu(self, dom, cpu):
   3.117          """Pin a domain to a cpu.
     4.1 --- a/tools/python/xen/xend/XendMigrate.py	Mon Jul 12 14:18:52 2004 +0000
     4.2 +++ b/tools/python/xen/xend/XendMigrate.py	Mon Jul 12 14:24:09 2004 +0000
     4.3 @@ -1,5 +1,6 @@
     4.4  # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
     4.5  
     4.6 +import errno
     4.7  import sys
     4.8  import socket
     4.9  import time
    4.10 @@ -14,9 +15,12 @@ import sxp
    4.11  import XendDB
    4.12  import EventServer; eserver = EventServer.instance()
    4.13  
    4.14 +"""The port for the migrate/save daemon xfrd."""
    4.15  XFRD_PORT = 8002
    4.16  
    4.17 +"""The transfer protocol major version number."""
    4.18  XFR_PROTO_MAJOR = 1
    4.19 +"""The transfer protocol minor version number."""
    4.20  XFR_PROTO_MINOR = 0
    4.21  
    4.22  class Xfrd(Protocol):
    4.23 @@ -55,16 +59,16 @@ class XfrdClientFactory(ClientFactory):
    4.24      """Factory for clients of the migration/save daemon xfrd.
    4.25      """
    4.26  
    4.27 -    def __init__(self, minfo):
    4.28 +    def __init__(self, xinfo):
    4.29          #ClientFactory.__init__(self)
    4.30 -        self.minfo = minfo
    4.31 +        self.xinfo = xinfo
    4.32  
    4.33      def startedConnecting(self, connector):
    4.34          print 'Started to connect', 'self=', self, 'connector=', connector
    4.35  
    4.36      def buildProtocol(self, addr):
    4.37          print 'buildProtocol>', addr
    4.38 -        return Migrate(self.minfo)
    4.39 +        return Xfrd(self.xinfo)
    4.40  
    4.41      def clientConnectionLost(self, connector, reason):
    4.42          print 'clientConnectionLost>', 'connector=', connector, 'reason=', reason
    4.43 @@ -76,13 +80,15 @@ class XfrdInfo:
    4.44      """Abstract class for info about a session with xfrd.
    4.45      Has subclasses for save and migrate.
    4.46      """
    4.47 -    
    4.48 +
    4.49 +    def __init__(self):
    4.50 +        from xen.xend import XendDomain
    4.51 +        self.xd = XendDomain.instance()
    4.52 +        self.deferred = defer.Deferred()
    4.53 +        
    4.54      def vmconfig(self):
    4.55          print 'vmconfig>'
    4.56 -        from xen.xend import XendDomain
    4.57 -        xd = XendDomain.instance()
    4.58 -
    4.59 -        dominfo = xd.domain_get(self.src_dom)
    4.60 +        dominfo = self.xd.domain_get(self.src_dom)
    4.61          print 'vmconfig>', type(dominfo), dominfo
    4.62          if dominfo:
    4.63              val = sxp.to_string(dominfo.sxpr())
    4.64 @@ -93,6 +99,8 @@ class XfrdInfo:
    4.65  
    4.66      def error(self, err):
    4.67          self.state = 'error'
    4.68 +        if not self.deferred.called:
    4.69 +            self.deferred.errback(err)
    4.70  
    4.71      def dispatch(self, xfrd, val):
    4.72          op = sxp.name(val)
    4.73 @@ -100,14 +108,18 @@ class XfrdInfo:
    4.74          if op.startswith('xfr_'):
    4.75              fn = getattr(self, op, self.unknown)
    4.76          else:
    4.77 -            fn = self.unknown()
    4.78 -        fn(xfrd, val)
    4.79 +            fn = self.unknown
    4.80 +        val = fn(xfrd, val)
    4.81 +        if val is not None:
    4.82 +            sxp.show(val, out=self.transport)
    4.83  
    4.84      def unknown(self, xfrd, val):
    4.85          print 'unknown>', val
    4.86 +        xfrd.loseConnection()
    4.87 +        return None
    4.88  
    4.89      def xfr_err(self, xfrd, val):
    4.90 -        # If we get an error with non-zero code the migrate failed.
    4.91 +        # If we get an error with non-zero code the operation failed.
    4.92          # An error with code zero indicates hello success.
    4.93          print 'xfr_err>', val
    4.94          v = sxp.child(val)
    4.95 @@ -116,21 +128,49 @@ class XfrdInfo:
    4.96          if not err: return
    4.97          self.error(err);
    4.98          xfrd.loseConnection()
    4.99 +        #try:
   4.100 +        #    self.xd.domain_unpause(self.src_dom)
   4.101 +        #except:
   4.102 +        #    print >>sys.stdout, "Error unpausing domain:", self.src_dom
   4.103 +        return None
   4.104  
   4.105      def xfr_progress(self, val):
   4.106          print 'xfr_progress>', val
   4.107 +        return None
   4.108  
   4.109 -    def xfr_domain_pause(self, val):
   4.110 -        print 'xfr__domain_pause>', val
   4.111 +    def xfr_vm_pause(self, val):
   4.112 +        print 'xfr_vm_pause>', val
   4.113 +        try:
   4.114 +            vmid = sxp.child0(val)
   4.115 +            val = self.xd.domain_pause(vmid)
   4.116 +        except:
   4.117 +            val = errno.EINVAL
   4.118 +        return ['xfr.err', val]
   4.119  
   4.120 -    def xfr_domain_suspend(self, val):
   4.121 -        print 'xfr_domain_suspend>', val
   4.122 +    def xfr_vm_unpause(self, val):
   4.123 +        print 'xfr_vm_unpause>', val
   4.124 +        try:
   4.125 +            vmid = sxp.child0(val)
   4.126 +            val = self.xd.domain_unpause(vmid)
   4.127 +        except:
   4.128 +            val = errno.EINVAL
   4.129 +        return ['xfr.err', val]
   4.130 +
   4.131 +    def xfr_vm_suspend(self, val):
   4.132 +        print 'xfr_vm_suspend>', val
   4.133 +        try:
   4.134 +            vmid = sxp.child0(val)
   4.135 +            val = self.xd.domain_shutdown(vmid, reason='suspend')
   4.136 +        except:
   4.137 +            val = errno.EINVAL
   4.138 +        return ['xfr.err', val]
   4.139  
   4.140  class XendMigrateInfo(XfrdInfo):
   4.141      """Representation of a migrate in-progress and its interaction with xfrd.
   4.142      """
   4.143  
   4.144      def __init__(self, id, dom, host, port):
   4.145 +        XfrdInfo.__init__(self)
   4.146          self.id = id
   4.147          self.state = 'begin'
   4.148          self.src_host = socket.gethostname()
   4.149 @@ -139,7 +179,6 @@ class XendMigrateInfo(XfrdInfo):
   4.150          self.dst_port = port
   4.151          self.dst_dom = None
   4.152          self.start = 0
   4.153 -        self.deferred = defer.Deferred()
   4.154          
   4.155      def sxpr(self):
   4.156          sxpr = ['migrate', ['id', self.id], ['state', self.state] ]
   4.157 @@ -160,12 +199,15 @@ class XendMigrateInfo(XfrdInfo):
   4.158                        self.src_dom,
   4.159                        vmconfig,
   4.160                        self.dst_host,
   4.161 -                      self.d.dst_port])
   4.162 +                      self.dst_port])
   4.163          
   4.164      def xfr_migrate_ok(self, val):
   4.165          dom = int(sxp.child0(val))
   4.166          self.state = 'ok'
   4.167          self.dst_dom = dom
   4.168 +        self.xd_domain_destroy(self.src_dom)
   4.169 +        if not self.deferred.called:
   4.170 +            self.deferred.callback(self)
   4.171  
   4.172      def connectionLost(self, reason=None):
   4.173          if self.state =='ok':
   4.174 @@ -179,12 +221,12 @@ class XendSaveInfo(XfrdInfo):
   4.175      """
   4.176      
   4.177      def __init__(self, id, dom, file):
   4.178 +        XfrdInfo.__init__(self)
   4.179          self.id = id
   4.180          self.state = 'begin'
   4.181          self.src_dom = dom
   4.182          self.file = file
   4.183          self.start = 0
   4.184 -        self.deferred = defer.Deferred()
   4.185          
   4.186      def sxpr(self):
   4.187          sxpr = ['save',
   4.188 @@ -204,6 +246,9 @@ class XendSaveInfo(XfrdInfo):
   4.189      def xfr_save_ok(self, val):
   4.190          dom = int(sxp.child0(val))
   4.191          self.state = 'ok'
   4.192 +        self.xd_domain_destroy(self.src_dom)
   4.193 +        if not self.deferred.called:
   4.194 +            self.deferred.callback(self)
   4.195  
   4.196      def connectionLost(self, reason=None):
   4.197          if self.state =='ok':
   4.198 @@ -217,7 +262,6 @@ class XendMigrate:
   4.199      """External api for interaction with xfrd for migrate and save.
   4.200      Singleton.
   4.201      """
   4.202 -    # Represents migration in progress.
   4.203      # Use log for indications of begin/end/errors?
   4.204      # Need logging of: domain create/halt, migrate begin/end/fail
   4.205      # Log via event server?
   4.206 @@ -226,8 +270,8 @@ class XendMigrate:
   4.207      
   4.208      def __init__(self):
   4.209          self.db = XendDB.XendDB(self.dbpath)
   4.210 -        self.migrate = {}
   4.211 -        self.migrate_db = self.db.fetchall("")
   4.212 +        self.session = {}
   4.213 +        self.session_db = self.db.fetchall("")
   4.214          self.id = 0
   4.215  
   4.216      def nextid(self):
   4.217 @@ -235,44 +279,67 @@ class XendMigrate:
   4.218          return "%d" % self.id
   4.219  
   4.220      def sync(self):
   4.221 -        self.db.saveall("", self.migrate_db)
   4.222 +        self.db.saveall("", self.session_db)
   4.223  
   4.224 -    def sync_migrate(self, id):
   4.225 -        self.db.save(id, self.migrate_db[id])
   4.226 +    def sync_session(self, id):
   4.227 +        self.db.save(id, self.session_db[id])
   4.228  
   4.229      def close(self):
   4.230          pass
   4.231  
   4.232 -    def _add_migrate(self, id, info):
   4.233 -        self.migrate[id] = info
   4.234 -        self.migrate_db[id] = info.sxpr()
   4.235 -        self.sync_migrate(id)
   4.236 +    def _add_session(self, id, info):
   4.237 +        self.session[id] = info
   4.238 +        self.session_db[id] = info.sxpr()
   4.239 +        self.sync_session(id)
   4.240          #eserver.inject('xend.migrate.begin', info.sxpr())
   4.241  
   4.242 -    def _delete_migrate(self, id):
   4.243 +    def _delete_session(self, id):
   4.244          #eserver.inject('xend.migrate.end', id)
   4.245 -        del self.migrate[id]
   4.246 -        del self.migrate_db[id]
   4.247 +        del self.session[id]
   4.248 +        del self.session_db[id]
   4.249          self.db.delete(id)
   4.250  
   4.251 -    def migrate_ls(self):
   4.252 -        return self.migrate.keys()
   4.253 +    def session_ls(self):
   4.254 +        return self.session.keys()
   4.255 +
   4.256 +    def sessions(self):
   4.257 +        return self.session.values()
   4.258  
   4.259 -    def migrates(self):
   4.260 -        return self.migrate.values()
   4.261 +    def session_get(self, id):
   4.262 +        return self.session.get(id)
   4.263  
   4.264 -    def migrate_get(self, id):
   4.265 -        return self.migrate.get(id)
   4.266 +    def session_begin(self, info):
   4.267 +        self._add_session(id, info)
   4.268 +        mcf = XfrdClientFactory(info)
   4.269 +        reactor.connectTCP('localhost', XFRD_PORT, mcf)
   4.270 +        return info
   4.271      
   4.272      def migrate_begin(self, dom, host, port=XFRD_PORT):
   4.273 +        """Begin to migrate a domain to another host.
   4.274 +
   4.275 +        @param dom:  domain
   4.276 +        @param host: destination host
   4.277 +        @param port: destination port
   4.278 +        @return: deferred
   4.279 +        """
   4.280          # Check dom for existence, not migrating already.
   4.281          # Subscribe to migrate notifications (for updating).
   4.282          id = self.nextid()
   4.283          info = XendMigrateInfo(id, dom, host, port)
   4.284 -        self._add_migrate(id, info)
   4.285 -        mcf = XfrdClientFactory(info)
   4.286 -        reactor.connectTCP('localhost', XFRD_PORT, mcf)
   4.287 -        return info
   4.288 +        self.session_begin(info)
   4.289 +        return info.deferred
   4.290 +
   4.291 +    def save_begin(self, dom, file):
   4.292 +        """Begin saving a domain to file.
   4.293 +
   4.294 +        @param dom:  domain
   4.295 +        @param file: destination file
   4.296 +        @return: deferred
   4.297 +        """
   4.298 +        id = self.nextid()
   4.299 +        info = XendSaveInfo(id, dom, file)
   4.300 +        self.session_begin(info)
   4.301 +        return info.deferred
   4.302  
   4.303  def instance():
   4.304      global inst
     5.1 --- a/tools/python/xen/xend/server/SrvDomain.py	Mon Jul 12 14:18:52 2004 +0000
     5.2 +++ b/tools/python/xen/xend/server/SrvDomain.py	Mon Jul 12 14:24:09 2004 +0000
     5.3 @@ -18,6 +18,14 @@ class SrvDomain(SrvDir):
     5.4          self.xd = XendDomain.instance()
     5.5          self.xconsole = XendConsole.instance()
     5.6  
     5.7 +    def op_configure(self, op, req):
     5.8 +        fn = FormFn(self.xd.domain_configure,
     5.9 +                    [['dom', 'int'],
    5.10 +                     ['config', 'sxp']])
    5.11 +        val = fn(req.args, {'dom': self.dom.id})
    5.12 +        #todo: may need to add ok and err callbacks.
    5.13 +        return val
    5.14 +
    5.15      def op_unpause(self, op, req):
    5.16          val = self.xd.domain_unpause(self.dom.id)
    5.17          return val
    5.18 @@ -27,7 +35,6 @@ class SrvDomain(SrvDir):
    5.19          return val
    5.20  
    5.21      def op_shutdown(self, op, req):
    5.22 -        #val = self.xd.domain_shutdown(self.dom.id)
    5.23          fn = FormFn(self.xd.domain_shutdown,
    5.24                      [['dom', 'int'],
    5.25                       ['reason', 'str']])
    5.26 @@ -202,8 +209,22 @@ class SrvDomain(SrvDir):
    5.27          req.write('<form method="post" action="%s">' % req.prePathURL())
    5.28          req.write('<input type="submit" name="op" value="unpause">')
    5.29          req.write('<input type="submit" name="op" value="pause">')
    5.30 +        req.write('<input type="submit" name="op" value="destroy">')
    5.31 +        req.write('</form>')
    5.32 +
    5.33 +        req.write('<form method="post" action="%s">' % req.prePathURL())
    5.34          req.write('<input type="submit" name="op" value="shutdown">')
    5.35 -        req.write('<input type="submit" name="op" value="destroy">')
    5.36 +        req.write('<input type="radio" name="reason" value="poweroff" checked>Poweroff<br>')
    5.37 +        req.write('<input type="radio" name="reason" value="halt">Halt<br>')
    5.38 +        req.write('<input type="radio" name="reason" value="reboot">Reboot<br>')
    5.39 +        req.write('</form>')
    5.40 +        
    5.41 +        req.write('<form method="post" action="%s">' % req.prePathURL())
    5.42 +        req.write('<br><input type="submit" name="op" value="save">')
    5.43 +        req.write('To file: <input type="text" name="file">')
    5.44 +        req.write('</form>')
    5.45 +        
    5.46 +        req.write('<form method="post" action="%s">' % req.prePathURL())
    5.47          req.write('<br><input type="submit" name="op" value="migrate">')
    5.48 -        req.write('To: <input type="text" name="destination">')
    5.49 +        req.write('To host: <input type="text" name="destination">')
    5.50          req.write('</form>')
     6.1 --- a/tools/python/xen/xend/server/SrvDomainDir.py	Mon Jul 12 14:18:52 2004 +0000
     6.2 +++ b/tools/python/xen/xend/server/SrvDomainDir.py	Mon Jul 12 14:24:09 2004 +0000
     6.3 @@ -105,7 +105,10 @@ class SrvDomainDir(SrvDir):
     6.4  
     6.5      def op_restore(self, op, req):
     6.6          """Restore a domain from file.
     6.7 +
     6.8 +        @return: deferred
     6.9          """
    6.10 +        #todo: return is deferred. May need ok and err callbacks.
    6.11          fn = FormFn(self.xd.domain_restore,
    6.12                      [['file', 'str']])
    6.13          val = fn(req.args)
    6.14 @@ -154,9 +157,10 @@ class SrvDomainDir(SrvDir):
    6.15          req.write('<button type="submit" name="op" value="create">Create Domain</button>')
    6.16          req.write('Config <input type="file" name="config"><br>')
    6.17          req.write('</form>')
    6.18 +        
    6.19          req.write('<form method="post" action="%s" enctype="multipart/form-data">'
    6.20                    % req.prePathURL())
    6.21 -        req.write('<button type="submit" name="op" value="create">Restore Domain</button>')
    6.22 +        req.write('<button type="submit" name="op" value="restore">Restore Domain</button>')
    6.23          req.write('State <input type="string" name="state"><br>')
    6.24          req.write('</form>')
    6.25          
     7.1 --- a/tools/xfrd/Makefile	Mon Jul 12 14:18:52 2004 +0000
     7.2 +++ b/tools/xfrd/Makefile	Mon Jul 12 14:24:09 2004 +0000
     7.3 @@ -18,6 +18,9 @@ INCLUDES += -I $(XEN_LINUX_INCLUDE)
     7.4  vpath %.h      $(XEN_XU)
     7.5  INCLUDES += -I $(XEN_XU)
     7.6  
     7.7 +vpath %.h      $(XEN_LIBXC)
     7.8 +INCLUDES += -I $(XEN_LIBXC)
     7.9 +
    7.10  vpath %c       $(XEN_LIBXUTIL)
    7.11  INCLUDES += -I $(XEN_LIBXUTIL)
    7.12  
    7.13 @@ -28,7 +31,9 @@ UTIL_LIB_OBJ = $(UTIL_LIB_SRC:.c=.o)
    7.14  XFRD_PROG_OBJ = $(XFRD_PROG_SRC:.c=.o)
    7.15  XFRD_PROG_OBJ += $(UTIL_LIB)
    7.16  
    7.17 -CPPFLAGS += -D _XEN_XFR_STUB_
    7.18 +# Flag controlling whether to use stubs.
    7.19 +# Define to use stubs, undefine to use the real Xen functions.
    7.20 +#CPPFLAGS += -D _XEN_XFR_STUB_
    7.21  
    7.22  CFLAGS += -g
    7.23  CFLAGS += -Wall
    7.24 @@ -38,15 +43,31 @@ CFLAGS += $(INCLUDES)
    7.25  CFLAGS += -Wp,-MD,.$(@F).d
    7.26  PROG_DEP = .*.d
    7.27  
    7.28 -#LDFLAGS += -L $(COMPRESS_DIR) -lz
    7.29 +#$(warning XFRD_PROG_OBJ= $(XFRD_PROG_OBJ))
    7.30 +#$(warning UTIL_LIB= $(UTIL_LIB))
    7.31 +#$(warning UTIL_LIB_OBJ= $(UTIL_LIB_OBJ))
    7.32 +
    7.33 +# Libraries for xfrd.
    7.34 +XFRD_LIBS :=
    7.35 +
    7.36 +XFRD_LIBS += -L $(XEN_LIBXC) -lxc
    7.37 +XFRD_LIBS += -L $(XEN_LIBXUTIL) -lxutil
    7.38  
    7.39 -$(warning XFRD_PROG_OBJ= $(XFRD_PROG_OBJ))
    7.40 -$(warning UTIL_LIB= $(UTIL_LIB))
    7.41 -$(warning UTIL_LIB_OBJ= $(UTIL_LIB_OBJ))
    7.42 +# zlib library.
    7.43 +XFRD_LIBS += -lz
    7.44 +
    7.45 +CURL_FLAGS = $(shell curl-config --cflags)
    7.46 +CURL_LIBS  = $(shell curl-config --libs)
    7.47 +CFLAGS     += $(CURL_FLAGS)
    7.48 +# libcurl libraries.
    7.49 +XFRD_LIBS += $(CURL_LIBS)
    7.50 +
    7.51 +#$(warning XFRD_LIBS = $(XFRD_LIBS))
    7.52  
    7.53  all: xfrd
    7.54  
    7.55 -xfrd: $(XFRD_PROG_OBJ) -lz
    7.56 +xfrd: $(XFRD_PROG_OBJ)
    7.57 +	$(CC) -o $@ $^ $(XFRD_LIBS)
    7.58  
    7.59  .PHONY: install
    7.60  install: xfrd
    7.61 @@ -64,5 +85,6 @@ clean:
    7.62  	$(RM) *.o *.a *.so *~ xfrd
    7.63  	$(RM) $(PROG_DEP)
    7.64  
    7.65 +$(XFRD_PROG_OBJ): Makefile
    7.66  -include $(PROG_DEP)
    7.67  
     8.1 --- a/tools/xfrd/xen_domain.c	Mon Jul 12 14:18:52 2004 +0000
     8.2 +++ b/tools/xfrd/xen_domain.c	Mon Jul 12 14:24:09 2004 +0000
     8.3 @@ -3,18 +3,43 @@
     8.4  #include <stdio.h>
     8.5  
     8.6  #ifndef _XEN_XFR_STUB_
     8.7 -#include "dom0_defs.h"
     8.8 -#include "mem_defs.h"
     8.9 +#include "xc.h"
    8.10 +#include "xc_io.h"
    8.11  #endif
    8.12  
    8.13  #include "xen_domain.h"
    8.14  #include "marshal.h"
    8.15  #include "xdr.h"
    8.16 +#include "xfrd.h"
    8.17  
    8.18  #define MODULE_NAME "XFRD"
    8.19  #define DEBUG 1
    8.20  #include "debug.h"
    8.21  
    8.22 +#ifndef _XEN_XFR_STUB_
    8.23 +static int domain_suspend(u32 dom, void *data){
    8.24 +    Conn *xend = data;
    8.25 +
    8.26 +    return xfr_vm_suspend(xend, dom);
    8.27 +}
    8.28 +
    8.29 +static int xc_handle = 0;
    8.30 +
    8.31 +int xcinit(void){
    8.32 +    if(xc_handle <= 0){
    8.33 +        xc_handle = xc_interface_open();
    8.34 +    }
    8.35 +    return xc_handle;
    8.36 +}
    8.37 +
    8.38 +void xcfini(void){
    8.39 +    if(xc_handle > 0){
    8.40 +        xc_interface_close(xc_handle);
    8.41 +        xc_handle = 0;
    8.42 +    }
    8.43 +}
    8.44 +#endif   
    8.45 +
    8.46  /** Write domain state.
    8.47   *
    8.48   * At some point during this the domain is suspended, and then there's no way back.
    8.49 @@ -22,10 +47,10 @@
    8.50   */
    8.51  int xen_domain_snd(Conn *xend, IOStream *io, uint32_t dom, char *vmconfig, int vmconfig_n){
    8.52      int err = 0;
    8.53 +#ifdef _XEN_XFR_STUB_
    8.54      char buf[1024];
    8.55      int n, k, d, buf_n;
    8.56      dprintf("> dom=%d\n", dom);
    8.57 -#ifdef _XEN_XFR_STUB_
    8.58      err = marshal_uint32(io, dom);
    8.59      if(err) goto exit;
    8.60      err = marshal_string(io, vmconfig, vmconfig_n);
    8.61 @@ -43,6 +68,15 @@ int xen_domain_snd(Conn *xend, IOStream 
    8.62      
    8.63    exit:
    8.64  #else 
    8.65 +    XcIOContext _ioctxt = {}, *ioctxt = &_ioctxt;
    8.66 +    dprintf("> dom=%d\n", dom);
    8.67 +    ioctxt->io = io;
    8.68 +    ioctxt->info = iostdout;
    8.69 +    ioctxt->err = iostderr;
    8.70 +    ioctxt->data = xend;
    8.71 +    ioctxt->suspend = domain_suspend;
    8.72 +
    8.73 +    err = xc_linux_save(xcinit(), ioctxt);
    8.74  #endif   
    8.75      dprintf("< err=%d\n", err);
    8.76      return err;
    8.77 @@ -53,10 +87,10 @@ int xen_domain_snd(Conn *xend, IOStream 
    8.78   */
    8.79  int xen_domain_rcv(IOStream *io, uint32_t *dom, char **vmconfig, int *vmconfig_n){
    8.80      int err = 0;
    8.81 +#ifdef _XEN_XFR_STUB_
    8.82      char buf[1024];
    8.83      int n, k, d, buf_n;
    8.84      dprintf(">\n");
    8.85 -#ifdef _XEN_XFR_STUB_
    8.86      err = unmarshal_uint32(io, dom);
    8.87      if(err) goto exit;
    8.88      err = unmarshal_new_string(io, vmconfig, vmconfig_n);
    8.89 @@ -72,19 +106,104 @@ int xen_domain_rcv(IOStream *io, uint32_
    8.90      }
    8.91    exit:
    8.92  #else    
    8.93 +    XcIOContext _ioctxt = {}, *ioctxt = &_ioctxt;
    8.94 +    dprintf(">\n");
    8.95 +    ioctxt->io = io;
    8.96 +    ioctxt->info = iostdout;
    8.97 +    ioctxt->err = iostderr;
    8.98 +
    8.99 +    err = xc_linux_restore(xcinit(), ioctxt);
   8.100  #endif   
   8.101      dprintf("< err=%d\n", err);
   8.102      return err;
   8.103  }
   8.104  
   8.105 -/** Configure a new domain. Talk to xend. Use libcurl?
   8.106 +#include <curl/curl.h>
   8.107 +
   8.108 +static int do_curl_global_init = 1;
   8.109 +
   8.110 +static CURL *curlinit(void){
   8.111 +    if(do_curl_global_init){
   8.112 +        do_curl_global_init = 0;
   8.113 +        curl_global_init(CURL_GLOBAL_ALL);
   8.114 +    }
   8.115 +    return curl_easy_init();
   8.116 +}
   8.117 +
   8.118 +/** Configure a new domain. Talk to xend using libcurl.
   8.119   */
   8.120  int xen_domain_configure(uint32_t dom, char *vmconfig, int vmconfig_n){
   8.121      int err = 0;
   8.122 -    dprintf(">\n");
   8.123 +    CURL *curl = NULL;
   8.124 +    CURLcode curlcode = 0;
   8.125 +    char domainurl[128] = {};
   8.126 +    int domainurl_n = sizeof(domainurl) - 1;
   8.127 +    int n;
   8.128 +    struct curl_httppost *form = NULL, *last = NULL;
   8.129 +    CURLFORMcode formcode = 0;
   8.130 +
   8.131 +    dprintf("> dom=%u\n", dom);
   8.132 +    curl = curlinit();
   8.133 +    if(!curl){
   8.134 +        eprintf("> Could not init libcurl\n");
   8.135 +        err = -ENOMEM;
   8.136 +        goto exit;
   8.137 +    }
   8.138 +    n = snprintf(domainurl, domainurl_n,
   8.139 +                 "http://localhost:%d/xend/domain/%u", XEND_PORT, dom);
   8.140 +    if(n <= 0 || n >= domainurl_n){
   8.141 +        err = -ENOMEM;
   8.142 +        eprintf("Out of memory in url.\n");
   8.143 +        goto exit;
   8.144 +    }
   8.145 +    // Config field - set from vmconfig.
   8.146 +    formcode = curl_formadd(&form, &last,
   8.147 +                            CURLFORM_COPYNAME,     "config",
   8.148 +                            CURLFORM_BUFFER,       "config",
   8.149 +                            CURLFORM_BUFFERPTR,    vmconfig,
   8.150 +                            CURLFORM_BUFFERLENGTH, vmconfig_n,
   8.151 +                            CURLFORM_CONTENTTYPE,  "application/octet-stream",
   8.152 +                            CURLFORM_END);
   8.153 +    if(formcode){
   8.154 +        eprintf("> Error adding config field.\n");
   8.155 +        goto exit;
   8.156 +    }
   8.157 +    // Op field.
   8.158 +    formcode = curl_formadd(&form, &last,
   8.159 +                            CURLFORM_COPYNAME,     "op",
   8.160 +                            CURLFORM_COPYCONTENTS, "configure",
   8.161 +                            CURLFORM_END);
   8.162 +
   8.163 +    if(formcode){
   8.164 +        eprintf("> Error adding op field.\n");
   8.165 +        goto exit;
   8.166 +    }
   8.167 +    // No progress meter.
   8.168 +    //curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
   8.169 +    // Completely quiet.
   8.170 +    //curl_easy_setopt(curl, CURLOPT_MUTE, 1);
   8.171 +    // Set the URL.
   8.172 +    curl_easy_setopt(curl, CURLOPT_URL, domainurl);
   8.173 +    // POST the form.
   8.174 +    curl_easy_setopt(curl, CURLOPT_HTTPPOST, form);
   8.175 +    dprintf("> curl perform...\n");
   8.176  #ifdef _XEN_XFR_STUB_
   8.177 -#else    
   8.178 -#endif   
   8.179 +    dprintf("> _XEN_XFR_STUB_ defined - not calling xend\n");
   8.180 +    curlcode = 0;
   8.181 +#else
   8.182 +    curlcode = curl_easy_perform(curl);
   8.183 +#endif
   8.184 +  exit:
   8.185 +    if(curl) curl_easy_cleanup(curl);
   8.186 +    if(form) curl_formfree(form);
   8.187 +    if(formcode){
   8.188 +        dprintf("> formcode=%d\n", formcode);
   8.189 +        err = -EINVAL;
   8.190 +    }
   8.191 +    if(curlcode){
   8.192 +        dprintf("> curlcode=%d\n", curlcode);
   8.193 +        err = -EINVAL;
   8.194 +    }
   8.195      dprintf("< err=%d\n", err);
   8.196      return err;
   8.197  }
     9.1 --- a/tools/xfrd/xfrd.c	Mon Jul 12 14:18:52 2004 +0000
     9.2 +++ b/tools/xfrd/xfrd.c	Mon Jul 12 14:24:09 2004 +0000
     9.3 @@ -93,22 +93,26 @@ Sxpr oxfr_configure; // (xfr.configure <
     9.4  Sxpr oxfr_err;       // (xfr.err <code>)
     9.5  Sxpr oxfr_hello;     // (xfr.hello <major> <minor>)
     9.6  Sxpr oxfr_migrate;   // (xfr.migrate <vmid> <vmconfig> <host> <port>)
     9.7 -Sxpr oxfr_ok;        // (xfr.ok <value>)
     9.8 +Sxpr oxfr_migrate_ok;// (xfr.migrate.ok <value>)
     9.9  Sxpr oxfr_progress;  // (xfr.progress <percent> <rate: kb/s>)
    9.10  Sxpr oxfr_save;      // (xfr.save <vmid> <vmconfig> <file>)
    9.11 -Sxpr oxfr_suspend;   // (xfr.suspend <vmid>)
    9.12 +Sxpr oxfr_save_ok;   // (xfr.save.ok)
    9.13 +Sxpr oxfr_vm_suspend;// (xfr.vm.suspend <vmid>)
    9.14  Sxpr oxfr_xfr;       // (xfr.xfr <vmid>)
    9.15 +Sxpr oxfr_xfr_ok;    // (xfr.xfr.ok <vmid>)
    9.16  
    9.17  void xfr_init(void){
    9.18 -    oxfr_configure = intern("xfr.configure");
    9.19 -    oxfr_err       = intern("xfr.err");
    9.20 -    oxfr_hello     = intern("xfr.hello");
    9.21 -    oxfr_migrate   = intern("xfr.migrate");
    9.22 -    oxfr_ok        = intern("xfr.ok");
    9.23 -    oxfr_progress  = intern("xfr.progress");
    9.24 -    oxfr_save      = intern("xfr.save");
    9.25 -    oxfr_suspend   = intern("xfr.suspend");
    9.26 -    oxfr_xfr       = intern("xfr.xfr");
    9.27 +    oxfr_configure      = intern("xfr.configure");
    9.28 +    oxfr_err            = intern("xfr.err");
    9.29 +    oxfr_hello          = intern("xfr.hello");
    9.30 +    oxfr_migrate        = intern("xfr.migrate");
    9.31 +    oxfr_migrate_ok     = intern("xfr.migrate.ok");
    9.32 +    oxfr_progress       = intern("xfr.progress");
    9.33 +    oxfr_save           = intern("xfr.save");
    9.34 +    oxfr_save_ok        = intern("xfr.save.ok");
    9.35 +    oxfr_vm_suspend     = intern("xfr.vm.suspend");
    9.36 +    oxfr_xfr            = intern("xfr.xfr");
    9.37 +    oxfr_xfr_ok         = intern("xfr.xfr.ok");
    9.38  }
    9.39  
    9.40  #ifndef TRUE
    9.41 @@ -518,11 +522,27 @@ int xfr_send_xfr(Conn *conn, uint32_t vm
    9.42      return (err < 0 ? err : 0);
    9.43  }
    9.44  
    9.45 -int xfr_send_ok(Conn *conn, uint32_t vmid){
    9.46 +int xfr_send_xfr_ok(Conn *conn, uint32_t vmid){
    9.47      int err = 0;
    9.48  
    9.49      err = IOStream_print(conn->out, "(%s %d)",
    9.50 -                         atom_name(oxfr_ok), vmid);
    9.51 +                         atom_name(oxfr_xfr_ok), vmid);
    9.52 +    return (err < 0 ? err : 0);
    9.53 +}
    9.54 +
    9.55 +int xfr_send_migrate_ok(Conn *conn, uint32_t vmid){
    9.56 +    int err = 0;
    9.57 +
    9.58 +    err = IOStream_print(conn->out, "(%s %d)",
    9.59 +                         atom_name(oxfr_migrate_ok), vmid);
    9.60 +    return (err < 0 ? err : 0);
    9.61 +}
    9.62 +
    9.63 +int xfr_send_save_ok(Conn *conn){
    9.64 +    int err = 0;
    9.65 +
    9.66 +    err = IOStream_print(conn->out, "(%s)",
    9.67 +                         atom_name(oxfr_save_ok));
    9.68      return (err < 0 ? err : 0);
    9.69  }
    9.70  
    9.71 @@ -530,10 +550,22 @@ int xfr_send_suspend(Conn *conn, uint32_
    9.72      int err = 0;
    9.73  
    9.74      err = IOStream_print(conn->out, "(%s %d)",
    9.75 -                         atom_name(oxfr_suspend), vmid);
    9.76 +                         atom_name(oxfr_vm_suspend), vmid);
    9.77      return (err < 0 ? err : 0);
    9.78  }
    9.79  
    9.80 +/** Suspend a vm on behalf of save/migrate.
    9.81 + */
    9.82 +int xfr_vm_suspend(Conn *xend, uint32_t vmid){
    9.83 +    int err = 0;
    9.84 +    err = xfr_send_suspend(xend, vmid);
    9.85 +    if(err) goto exit;
    9.86 +    IOStream_flush(xend->out);
    9.87 +    err = xfr_response(xend);
    9.88 +  exit:
    9.89 +    return err;
    9.90 +}
    9.91 +
    9.92  /** Get vm state. Send transfer message.
    9.93   *
    9.94   * @param peer connection
    9.95 @@ -561,7 +593,7 @@ int xfr_send_state(XfrState *state, Conn
    9.96          int errcode;
    9.97          err = intof(sxpr_childN(sxpr, 0, ONONE), &errcode);
    9.98          if(!err) err = errcode;
    9.99 -    } else if(sxpr_elementp(sxpr, oxfr_ok)){
   9.100 +    } else if(sxpr_elementp(sxpr, oxfr_xfr_ok)){
   9.101          // Ok - get the new domain id.
   9.102          err = intof(sxpr_childN(sxpr, 0, ONONE), &state->vmid_new);
   9.103          xfr_error(peer, err);
   9.104 @@ -592,7 +624,7 @@ int xfr_send_done(XfrState *state, Conn 
   9.105          err = xfr_error(xend, first_err);
   9.106      } else {
   9.107          // Report new domain id to xend.
   9.108 -        err = xfr_send_ok(xend, state->vmid_new);
   9.109 +        err = xfr_send_migrate_ok(xend, state->vmid_new);
   9.110      }  
   9.111  
   9.112      XfrState_set_err(state, err);
   9.113 @@ -683,6 +715,11 @@ int xfr_save(Args *args, XfrState *state
   9.114          goto exit;
   9.115      }
   9.116      err = xen_domain_snd(xend, io, state->vmid, state->vmconfig, state->vmconfig_n);
   9.117 +    if(err){
   9.118 +        err = xfr_error(xend, err);
   9.119 +    } else {
   9.120 +        err = xfr_send_save_ok(xend);
   9.121 +    }
   9.122    exit:
   9.123      if(io){
   9.124          IOStream_close(io);
   9.125 @@ -709,7 +746,7 @@ int xfr_recv(Args *args, XfrState *state
   9.126      if(err) goto exit;
   9.127  
   9.128      // Report new domain id to peer.
   9.129 -    err = xfr_send_ok(peer, state->vmid_new);
   9.130 +    err = xfr_send_xfr_ok(peer, state->vmid_new);
   9.131      if(err) goto exit;
   9.132      // Get the final ok.
   9.133      err = xfr_response(peer);
    10.1 --- a/tools/xfrd/xfrd.h	Mon Jul 12 14:18:52 2004 +0000
    10.2 +++ b/tools/xfrd/xfrd.h	Mon Jul 12 14:24:09 2004 +0000
    10.3 @@ -2,7 +2,7 @@
    10.4  #define _XFRD_XFRD_H_
    10.5  
    10.6  /** Xend port in host order. */
    10.7 -#define XEND_PORT 8001
    10.8 +#define XEND_PORT 8000
    10.9  
   10.10  /** Xfrd port in host order. */
   10.11  #define XFRD_PORT 8002
   10.12 @@ -11,4 +11,6 @@
   10.13  #define XFR_PROTO_MAJOR   1
   10.14  #define XFR_PROTO_MINOR   0
   10.15  
   10.16 +struct Conn;
   10.17 +extern int xfr_vm_suspend(struct Conn *xend, uint32_t vmid);
   10.18  #endif