direct-io.hg

changeset 4580:c69fbe48a357

bitkeeper revision 1.1327.2.1 (4266169fT9qqykPCJWENnvnqwf71kQ)

Refactor domain construction and device controllers to
remove use of twisted. Use threads to dispatch channel
input. Move device controllers into domains.

Signed-off-by: Mike Wray <mike.wray@hp.com>
author mjw@wray-m-3.hpl.hp.com
date Wed Apr 20 08:45:19 2005 +0000 (2005-04-20)
parents dfe18db08708
children a838a908e38e
files .rootkeys tools/python/xen/lowlevel/xu/xu.c tools/python/xen/xend/XendConsole.py tools/python/xen/xend/XendDomain.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/scheduler.py tools/python/xen/xend/server/SrvDaemon.py tools/python/xen/xend/server/SrvDomainDir.py tools/python/xen/xend/server/blkif.py tools/python/xen/xend/server/channel.py tools/python/xen/xend/server/console.py tools/python/xen/xend/server/controller.py tools/python/xen/xend/server/event.py tools/python/xen/xend/server/messages.py tools/python/xen/xend/server/netif.py tools/python/xen/xend/server/pciif.py tools/python/xen/xend/server/usbif.py
line diff
     1.1 --- a/.rootkeys	Tue Apr 19 13:48:05 2005 +0000
     1.2 +++ b/.rootkeys	Wed Apr 20 08:45:19 2005 +0000
     1.3 @@ -902,6 +902,7 @@ 40c9c4686jruMyZIqiaZRMiMoqMJtg tools/pyt
     1.4  40c9c468xzANp6o2D_MeCYwNmOIUsQ tools/python/xen/xend/XendVnet.py
     1.5  40c9c468x191zetrVlMnExfsQWHxIQ tools/python/xen/xend/__init__.py
     1.6  40c9c468S2YnCEKmk4ey8XQIST7INg tools/python/xen/xend/encode.py
     1.7 +4266169ezWIlXSfY50n6HSoVFbosmw tools/python/xen/xend/scheduler.py
     1.8  40c9c468DCpMe542varOolW1Xc68ew tools/python/xen/xend/server/SrvBase.py
     1.9  40c9c468IxQabrKJSWs0aEjl-27mRQ tools/python/xen/xend/server/SrvConsole.py
    1.10  40c9c4689Io5bxfbYIfRiUvsiLX0EQ tools/python/xen/xend/server/SrvConsoleDir.py
    1.11 @@ -924,9 +925,11 @@ 40c9c469N2-b3GqpLHHHPZykJPLVvA tools/pyt
    1.12  40c9c469hJ_IlatRne-9QEa0-wlquw tools/python/xen/xend/server/console.py
    1.13  40c9c469UcNJh_NuLU0ytorM0Lk5Ow tools/python/xen/xend/server/controller.py
    1.14  40d83983OXjt-y3HjSCcuoPp9rzvmw tools/python/xen/xend/server/domain.py
    1.15 +4266169exkN9o3hA8vxe8Er0BZv1Xw tools/python/xen/xend/server/event.py
    1.16  40c9c469yrm31i60pGKslTi2Zgpotg tools/python/xen/xend/server/messages.py
    1.17  40c9c46925x-Rjb0Cv2f1-l2jZrPYg tools/python/xen/xend/server/netif.py
    1.18  40c9c469ZqILEQ8x6yWy0_51jopiCg tools/python/xen/xend/server/params.py
    1.19 +4266169eI_oX3YBjwaeC0V-THBRnjg tools/python/xen/xend/server/pciif.py
    1.20  41ee5e8dq9NtihbL4nWKjuSLOhXPUg tools/python/xen/xend/server/usbif.py
    1.21  40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/python/xen/xend/sxp.py
    1.22  4189125cL90jKSOcBJ3Vx4nWGiXXvA tools/python/xen/xend/util.py
     2.1 --- a/tools/python/xen/lowlevel/xu/xu.c	Tue Apr 19 13:48:05 2005 +0000
     2.2 +++ b/tools/python/xen/lowlevel/xu/xu.c	Wed Apr 20 08:45:19 2005 +0000
     2.3 @@ -304,20 +304,6 @@ static PyObject *xu_notifier_read(PyObje
     2.4      return Py_None;
     2.5  }
     2.6  
     2.7 -/* this is now a NOOP */
     2.8 -static PyObject *xu_notifier_unmask(PyObject *self, PyObject *args)
     2.9 -{
    2.10 -    Py_INCREF(Py_None);
    2.11 -    return Py_None;
    2.12 -}
    2.13 -
    2.14 -/* this is now a NOOP */
    2.15 -static PyObject *xu_notifier_bind(PyObject *self, PyObject *args)
    2.16 -{
    2.17 -    Py_INCREF(Py_None);
    2.18 -    return Py_None;
    2.19 -}
    2.20 -
    2.21  static PyObject *xu_notifier_bind_virq(PyObject *self, 
    2.22              PyObject *args, PyObject *kwds)
    2.23  {
    2.24 @@ -366,13 +352,6 @@ static PyObject *xu_notifier_virq_send(P
    2.25      return PyInt_FromLong(kmsg.u.virq.port);
    2.26  }
    2.27  
    2.28 -/* this is now a NOOP */
    2.29 -static PyObject *xu_notifier_unbind(PyObject *self, PyObject *args)
    2.30 -{
    2.31 -    Py_INCREF(Py_None);
    2.32 -    return Py_None;
    2.33 -}
    2.34 -
    2.35  static PyObject *xu_notifier_fileno(PyObject *self, PyObject *args)
    2.36  {
    2.37      return PyInt_FromLong(xcs_data_fd);
    2.38 @@ -384,21 +363,6 @@ static PyMethodDef xu_notifier_methods[]
    2.39        METH_VARARGS,
    2.40        "Read a @port with pending notifications.\n" },
    2.41  
    2.42 -    { "unmask", 
    2.43 -      (PyCFunction)xu_notifier_unmask,
    2.44 -      METH_VARARGS,
    2.45 -      "Unmask notifications for a @port.\n" },
    2.46 -
    2.47 -    { "bind", 
    2.48 -      (PyCFunction)xu_notifier_bind,
    2.49 -      METH_VARARGS,
    2.50 -      "Get notifications for a @port.\n" },
    2.51 -
    2.52 -    { "unbind", 
    2.53 -      (PyCFunction)xu_notifier_unbind,
    2.54 -      METH_VARARGS,
    2.55 -      "No longer get notifications for a @port.\n" },
    2.56 -      
    2.57      { "bind_virq",
    2.58        (PyCFunction)xu_notifier_bind_virq,
    2.59        METH_VARARGS | METH_KEYWORDS,
    2.60 @@ -1054,13 +1018,6 @@ typedef struct xu_port_object {
    2.61  
    2.62  static PyObject *port_error;
    2.63  
    2.64 -/* now a NOOP */
    2.65 -static PyObject *xu_port_notify(PyObject *self, PyObject *args)
    2.66 -{
    2.67 -    Py_INCREF(Py_None);
    2.68 -    return Py_None;
    2.69 -}
    2.70 -
    2.71  static PyObject *xu_port_read_request(PyObject *self, PyObject *args)
    2.72  {
    2.73      xu_port_object    *xup = (xu_port_object *)self;
    2.74 @@ -1212,14 +1169,6 @@ static PyObject *xu_port_request_to_read
    2.75      return PyInt_FromLong(found);
    2.76  }
    2.77  
    2.78 -static PyObject *xu_port_space_to_write_request(PyObject *self, PyObject *args)
    2.79 -{
    2.80 -    if ( !PyArg_ParseTuple(args, "") )
    2.81 -        return NULL;
    2.82 -
    2.83 -    return PyInt_FromLong(1);
    2.84 -}
    2.85 -
    2.86  static PyObject *xu_port_response_to_read(PyObject *self, PyObject *args)
    2.87  {
    2.88      xu_port_object   *xup = (xu_port_object *)self;
    2.89 @@ -1243,25 +1192,27 @@ static PyObject *xu_port_response_to_rea
    2.90      return PyInt_FromLong(found);
    2.91  }
    2.92  
    2.93 -static PyObject *xu_port_space_to_write_response(
    2.94 -    PyObject *self, PyObject *args)
    2.95 +static void _xu_port_close(xu_port_object *xup )
    2.96  {
    2.97 -    if ( !PyArg_ParseTuple(args, "") )
    2.98 -        return NULL;
    2.99 -
   2.100 -    return PyInt_FromLong(1);
   2.101 +    if ( xup->connected && xup->remote_dom != 0 )
   2.102 +    {  
   2.103 +        xcs_msg_t kmsg;
   2.104 +        kmsg.type = XCS_CIF_FREE_CC;
   2.105 +        kmsg.u.interface.dom         = xup->remote_dom;
   2.106 +        kmsg.u.interface.local_port  = xup->local_port; 
   2.107 +        kmsg.u.interface.remote_port = xup->remote_port;
   2.108 +        xcs_ctrl_send(&kmsg);
   2.109 +        xcs_ctrl_read(&kmsg);
   2.110 +        xup->connected = 0;
   2.111 +    }
   2.112  }
   2.113  
   2.114 -/* NOOP */
   2.115 -static PyObject *xu_port_connect(PyObject *self, PyObject *args)
   2.116 +static PyObject *xu_port_close(PyObject *self, PyObject *args)
   2.117  {
   2.118 -    Py_INCREF(Py_None);
   2.119 -    return Py_None;
   2.120 -}
   2.121 +    xu_port_object *xup = (xu_port_object *)self;
   2.122  
   2.123 -/* NOOP */
   2.124 -static PyObject *xu_port_disconnect(PyObject *self, PyObject *args)
   2.125 -{
   2.126 +    _xu_port_close(xup);
   2.127 +
   2.128      Py_INCREF(Py_None);
   2.129      return Py_None;
   2.130  }
   2.131 @@ -1278,6 +1229,11 @@ static PyObject *xu_port_register(PyObje
   2.132                                        &type) )
   2.133          return NULL;
   2.134      
   2.135 +    if (!xup->connected)
   2.136 +    {
   2.137 +        return PyInt_FromLong(0);
   2.138 +    }
   2.139 +    
   2.140      msg.type = XCS_MSG_BIND;
   2.141      msg.u.bind.port = xup->local_port;
   2.142      msg.u.bind.type = type;
   2.143 @@ -1303,6 +1259,11 @@ static PyObject *xu_port_deregister(PyOb
   2.144      if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list,
   2.145                                        &type) )
   2.146          return NULL;
   2.147 +
   2.148 +    if (!xup->connected)
   2.149 +    {
   2.150 +        return PyInt_FromLong(0);
   2.151 +    }
   2.152      
   2.153      msg.type = XCS_MSG_UNBIND;
   2.154      msg.u.bind.port = xup->local_port;
   2.155 @@ -1319,10 +1280,6 @@ static PyObject *xu_port_deregister(PyOb
   2.156  }
   2.157  
   2.158  static PyMethodDef xu_port_methods[] = {
   2.159 -    { "notify",
   2.160 -      (PyCFunction)xu_port_notify,
   2.161 -      METH_VARARGS,
   2.162 -      "Send a notification to the remote end.\n" },
   2.163  
   2.164      { "read_request",
   2.165        (PyCFunction)xu_port_read_request,
   2.166 @@ -1349,21 +1306,12 @@ static PyMethodDef xu_port_methods[] = {
   2.167        METH_VARARGS,
   2.168        "Returns TRUE if there is a request message to read.\n" },
   2.169  
   2.170 -    { "space_to_write_request",
   2.171 -      (PyCFunction)xu_port_space_to_write_request,
   2.172 -      METH_VARARGS,
   2.173 -      "Returns TRUE if there is space to write a request message.\n" },
   2.174  
   2.175      { "response_to_read",
   2.176        (PyCFunction)xu_port_response_to_read,
   2.177        METH_VARARGS,
   2.178        "Returns TRUE if there is a response message to read.\n" },
   2.179  
   2.180 -    { "space_to_write_response",
   2.181 -      (PyCFunction)xu_port_space_to_write_response,
   2.182 -      METH_VARARGS,
   2.183 -      "Returns TRUE if there is space to write a response message.\n" },
   2.184 -      
   2.185      { "register",
   2.186        (PyCFunction)xu_port_register,
   2.187        METH_VARARGS | METH_KEYWORDS,
   2.188 @@ -1374,15 +1322,10 @@ static PyMethodDef xu_port_methods[] = {
   2.189        METH_VARARGS | METH_KEYWORDS,
   2.190        "Stop receiving a type of message on this port.\n" },
   2.191  
   2.192 -    { "connect",
   2.193 -      (PyCFunction)xu_port_connect,
   2.194 +    { "close",
   2.195 +      (PyCFunction)xu_port_close,
   2.196        METH_VARARGS,
   2.197 -      "Synchronously connect to remote domain.\n" },
   2.198 -
   2.199 -    { "disconnect",
   2.200 -      (PyCFunction)xu_port_disconnect,
   2.201 -      METH_VARARGS,
   2.202 -      "Synchronously disconnect from remote domain.\n" },
   2.203 +      "Close the port.\n" },
   2.204  
   2.205      { NULL, NULL, 0, NULL }
   2.206  };
   2.207 @@ -1431,31 +1374,32 @@ static PyObject *xu_port_new(PyObject *s
   2.208  static PyObject *xu_port_getattr(PyObject *obj, char *name)
   2.209  {
   2.210      xu_port_object *xup = (xu_port_object *)obj;
   2.211 +
   2.212      if ( strcmp(name, "local_port") == 0 )
   2.213 -        return PyInt_FromLong(xup->local_port);
   2.214 +    {
   2.215 +        return PyInt_FromLong(xup->connected ? xup->local_port : -1);
   2.216 +    }
   2.217      if ( strcmp(name, "remote_port") == 0 )
   2.218 -        return PyInt_FromLong(xup->remote_port);
   2.219 +    {
   2.220 +        return PyInt_FromLong(xup->connected ? xup->remote_port : -1);
   2.221 +    }
   2.222      if ( strcmp(name, "remote_dom") == 0 )
   2.223 +    {
   2.224          return PyInt_FromLong(xup->remote_dom);
   2.225 +    }
   2.226 +    if ( strcmp(name, "connected") == 0 )
   2.227 +    {
   2.228 +        return PyInt_FromLong(xup->connected);
   2.229 +    }
   2.230      return Py_FindMethod(xu_port_methods, obj, name);
   2.231  }
   2.232  
   2.233  static void xu_port_dealloc(PyObject *self)
   2.234  {
   2.235 -
   2.236      xu_port_object *xup = (xu_port_object *)self;
   2.237 -    xcs_msg_t kmsg;
   2.238  
   2.239 -    if ( xup->remote_dom != 0 )
   2.240 -    {  
   2.241 -        kmsg.type = XCS_CIF_FREE_CC;
   2.242 -        kmsg.u.interface.dom         = xup->remote_dom;
   2.243 -        kmsg.u.interface.local_port  = xup->local_port; 
   2.244 -        kmsg.u.interface.remote_port = xup->remote_port;
   2.245 -        xcs_ctrl_send(&kmsg);
   2.246 -        xcs_ctrl_read(&kmsg);
   2.247 -    }
   2.248 -            
   2.249 +    _xu_port_close(xup);
   2.250 +
   2.251      PyObject_Del(self);
   2.252  }
   2.253  
   2.254 @@ -1638,6 +1582,26 @@ static PyObject *xu_buffer_full(PyObject
   2.255      return PyInt_FromLong(0);
   2.256  }
   2.257  
   2.258 +static PyObject *xu_buffer_size(PyObject *self, PyObject *args)
   2.259 +{
   2.260 +    xu_buffer_object *xub = (xu_buffer_object *)self;
   2.261 +
   2.262 +    if ( !PyArg_ParseTuple(args, "") )
   2.263 +        return NULL;
   2.264 +
   2.265 +    return PyInt_FromLong(xub->prod - xub->cons);
   2.266 +}
   2.267 +
   2.268 +static PyObject *xu_buffer_space(PyObject *self, PyObject *args)
   2.269 +{
   2.270 +    xu_buffer_object *xub = (xu_buffer_object *)self;
   2.271 +
   2.272 +    if ( !PyArg_ParseTuple(args, "") )
   2.273 +        return NULL;
   2.274 +
   2.275 +    return PyInt_FromLong(BUFSZ - (xub->prod - xub->cons));
   2.276 +}
   2.277 +
   2.278  static PyMethodDef xu_buffer_methods[] = {
   2.279      { "peek", 
   2.280        (PyCFunction)xu_buffer_peek,
   2.281 @@ -1669,6 +1633,16 @@ static PyMethodDef xu_buffer_methods[] =
   2.282        METH_VARARGS,
   2.283        "Return TRUE if the buffer is full.\n" },
   2.284  
   2.285 +    { "size", 
   2.286 +      (PyCFunction)xu_buffer_size,
   2.287 +      METH_VARARGS,
   2.288 +      "Return number of bytes in the buffer.\n" },
   2.289 +
   2.290 +    { "space", 
   2.291 +      (PyCFunction)xu_buffer_space,
   2.292 +      METH_VARARGS,
   2.293 +      "Return space left in the buffer.\n" },
   2.294 +
   2.295      { NULL, NULL, 0, NULL }
   2.296  };
   2.297  
     3.1 --- a/tools/python/xen/xend/XendConsole.py	Tue Apr 19 13:48:05 2005 +0000
     3.2 +++ b/tools/python/xen/xend/XendConsole.py	Wed Apr 20 08:45:19 2005 +0000
     3.3 @@ -1,40 +1,29 @@
     3.4  # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
     3.5  
     3.6 -import socket
     3.7  import xen.lowlevel.xc
     3.8  xc = xen.lowlevel.xc.new()
     3.9  
    3.10 -import sxp
    3.11 -import XendRoot
    3.12 -xroot = XendRoot.instance()
    3.13 -import XendDB
    3.14 +import XendRoot; xroot = XendRoot.instance()
    3.15  from XendError import XendError
    3.16  
    3.17 -import EventServer
    3.18 -eserver = EventServer.instance()
    3.19 -
    3.20 -from xen.xend.server import SrvDaemon
    3.21 -daemon = SrvDaemon.instance()
    3.22 -
    3.23  class XendConsole:
    3.24  
    3.25      def  __init__(self):
    3.26          pass
    3.27 -        eserver.subscribe('xend.domain.died', self.onDomainDied)
    3.28 -        eserver.subscribe('xend.domain.destroy', self.onDomainDied)
    3.29 -
    3.30 -    def onDomainDied(self, event, val):
    3.31 -        pass
    3.32  
    3.33      def console_ls(self):
    3.34          return [ c.console_port for c in self.consoles() ]
    3.35  
    3.36      def consoles(self):
    3.37 -        return daemon.get_consoles()
    3.38 -    
    3.39 -    def console_create(self, dom, console_port=None):
    3.40 -        consinfo = daemon.console_create(dom, console_port=console_port)
    3.41 -        return consinfo
    3.42 +        l = []
    3.43 +        xd = XendRoot.get_component('xen.xend.XendDomain')
    3.44 +        for vm in xd.domains():
    3.45 +            ctrl = vm.getDeviceController("console", error=False)
    3.46 +            if (not ctrl): continue
    3.47 +            console = ctrl.getDevice(0)
    3.48 +            if (not console): continue
    3.49 +            l.append(console)
    3.50 +        return l
    3.51      
    3.52      def console_get(self, id):
    3.53          id = int(id)
     4.1 --- a/tools/python/xen/xend/XendDomain.py	Tue Apr 19 13:48:05 2005 +0000
     4.2 +++ b/tools/python/xen/xend/XendDomain.py	Wed Apr 20 08:45:19 2005 +0000
     4.3 @@ -6,30 +6,68 @@
     4.4  """
     4.5  import sys
     4.6  import traceback
     4.7 -
     4.8 -from twisted.internet import defer
     4.9 -#defer.Deferred.debug = 1
    4.10 -from twisted.internet import reactor
    4.11 +import time
    4.12  
    4.13  import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
    4.14  
    4.15  import sxp
    4.16 -import XendRoot
    4.17 -xroot = XendRoot.instance()
    4.18 +import XendRoot; xroot = XendRoot.instance()
    4.19  import XendDB
    4.20  import XendDomainInfo
    4.21  import XendMigrate
    4.22 -import EventServer
    4.23 +import EventServer; eserver = EventServer.instance()
    4.24  from XendError import XendError
    4.25  from XendLogging import log
    4.26  
    4.27 +from scheduler import Scheduler
    4.28  
    4.29 -from xen.xend.server import SrvDaemon
    4.30 -xend = SrvDaemon.instance()
    4.31 +from xen.xend.server import channel
    4.32  
    4.33 -eserver = EventServer.instance()
    4.34  
    4.35  __all__ = [ "XendDomain" ]
    4.36 +
    4.37 +SHUTDOWN_TIMEOUT = 30
    4.38 +
    4.39 +class DomainShutdown:
    4.40 +    """A pending domain shutdown. The domain is asked to shut down,
    4.41 +    if it has not terminated or rebooted when the timeout expires it
    4.42 +    is destroyed.
    4.43 +    """
    4.44 +
    4.45 +    def __init__(self, dominfo, reason, key, timeout=None):
    4.46 +        if timeout is None:
    4.47 +            timeout = SHUTDOWN_TIMEOUT
    4.48 +        self.start = time.time()
    4.49 +        self.timeout = timeout
    4.50 +        self.dominfo = dominfo
    4.51 +        self.last_restart_time = dominfo.restart_time
    4.52 +        self.last_restart_count = dominfo.restart_count
    4.53 +        self.reason = reason
    4.54 +        self.key = key
    4.55 +
    4.56 +    def getDomain(self):
    4.57 +        return self.dominfo.id
    4.58 +
    4.59 +    def getDomainName(self):
    4.60 +        return self.dominfo.name
    4.61 +
    4.62 +    def getReason(self):
    4.63 +        return self.reason
    4.64 +
    4.65 +    def getTimeout(self):
    4.66 +        return self.timeout
    4.67 +
    4.68 +    def isTerminated(self):
    4.69 +        return self.dominfo.is_terminated()
    4.70 +
    4.71 +    def isRestarted(self):
    4.72 +        return (self.dominfo.restart_count > self.last_restart_count)
    4.73 +
    4.74 +    def isShutdown(self):
    4.75 +        return self.isTerminated() or self.isRestarted()
    4.76 +
    4.77 +    def isExpired(self):
    4.78 +        return (time.time() - self.start) > self.timeout
    4.79          
    4.80  class XendDomain:
    4.81      """Index of all domains. Singleton.
    4.82 @@ -46,8 +84,11 @@ class XendDomain:
    4.83      restarts_by_id = {}
    4.84      restarts_by_name = {}
    4.85  
    4.86 +    """Table of pending domain shutdowns, indexed by domain id."""
    4.87 +    shutdowns_by_id = {}
    4.88 +
    4.89      """Table of delayed calls."""
    4.90 -    schedule = {}
    4.91 +    scheduler = Scheduler()
    4.92      
    4.93      def __init__(self):
    4.94          # Hack alert. Python does not support mutual imports, but XendDomainInfo
    4.95 @@ -67,6 +108,7 @@ class XendDomain:
    4.96      def onVirq(self, event, val):
    4.97          """Event handler for virq.
    4.98          """
    4.99 +        print 'onVirq>', val
   4.100          self.reap()
   4.101  
   4.102      def schedule_later(self, _delay, _name, _fn, *args):
   4.103 @@ -77,22 +119,16 @@ class XendDomain:
   4.104          @param _fn:    function
   4.105          @param args:   arguments
   4.106          """
   4.107 -        if self.schedule.get(_name): return
   4.108 -        self.schedule[_name] = reactor.callLater(_delay, _fn, *args)
   4.109 +        self.scheduler.later(_delay, _name, _fn, args)
   4.110          
   4.111      def schedule_cancel(self, name):
   4.112          """Cancel a scheduled function call.
   4.113          
   4.114          @param name: schedule name to cancel
   4.115          """
   4.116 -        callid = self.schedule.get(name)
   4.117 -        if not callid:
   4.118 -            return
   4.119 -        if callid.active():
   4.120 -            callid.cancel()
   4.121 -        del self.schedule[name]
   4.122 +        self.scheduler.cancel(name)
   4.123  
   4.124 -    def reap_schedule(self, delay=0):
   4.125 +    def reap_schedule(self, delay=1):
   4.126          """Schedule reap to be called later.
   4.127  
   4.128          @param delay: delay in seconds
   4.129 @@ -104,7 +140,7 @@ class XendDomain:
   4.130          """
   4.131          self.schedule_cancel('reap')
   4.132  
   4.133 -    def refresh_schedule(self, delay=0):
   4.134 +    def refresh_schedule(self, delay=1):
   4.135          """Schedule refresh to be called later.
   4.136          
   4.137          @param delay: delay in seconds
   4.138 @@ -116,7 +152,7 @@ class XendDomain:
   4.139          """
   4.140          self.schedule_cancel('refresh')
   4.141  
   4.142 -    def domain_restarts_schedule(self, delay=0):
   4.143 +    def domain_restarts_schedule(self, delay=1):
   4.144          """Schedule domain_restarts to be called later.
   4.145          
   4.146          @param delay: delay in seconds
   4.147 @@ -132,30 +168,45 @@ class XendDomain:
   4.148          """Remove all domain info. Used after reboot.
   4.149          """
   4.150          for (k, v) in self.domain_db.items():
   4.151 -            self._delete_domain(k, notify=0)
   4.152 -            
   4.153 -    def initial_refresh(self):
   4.154 -        """Refresh initial domain info from domain_db.
   4.155 +            self._delete_domain(k, notify=False)
   4.156 +
   4.157 +    def xen_domains(self):
   4.158 +        """Get table of domains indexed by id from xc.
   4.159          """
   4.160 -            
   4.161 -        def cb_all_ok(val):
   4.162 -            self.refresh()
   4.163 -
   4.164          domlist = xc.domain_getinfo()
   4.165          doms = {}
   4.166          for d in domlist:
   4.167              domid = str(d['dom'])
   4.168              doms[domid] = d
   4.169 -        dlist = []
   4.170 +        return doms
   4.171 +
   4.172 +    def xen_domain(self, dom):
   4.173 +        """Get info about a single domain from xc.
   4.174 +        Returns None if not found.
   4.175 +        """
   4.176 +        dom = int(dom)
   4.177 +        dominfo = xc.domain_getinfo(dom, 1)
   4.178 +        if dominfo == [] or dominfo[0]['dom'] != dom:
   4.179 +            dominfo = None
   4.180 +        else:
   4.181 +            dominfo = dominfo[0]
   4.182 +        return dominfo
   4.183 +            
   4.184 +    def initial_refresh(self):
   4.185 +        """Refresh initial domain info from domain_db.
   4.186 +        """
   4.187 +        doms = self.xen_domains()
   4.188          for config in self.domain_db.values():
   4.189              domid = str(sxp.child_value(config, 'id'))
   4.190              if domid in doms:
   4.191 -                d_dom = self._new_domain(config, doms[domid])
   4.192 -                dlist.append(d_dom)
   4.193 +                try:
   4.194 +                    self._new_domain(config, doms[domid])
   4.195 +                except Exception, ex:
   4.196 +                    log.exception("Error recreating domain info: id=%s", domid)
   4.197 +                    self._delete_domain(domid)
   4.198              else:
   4.199                  self._delete_domain(domid)
   4.200 -        d_all = defer.DeferredList(dlist, fireOnOneErrback=1)
   4.201 -        d_all.addCallback(cb_all_ok)
   4.202 +        self.refresh()
   4.203  
   4.204      def sync(self):
   4.205          """Sync domain db to disk.
   4.206 @@ -177,35 +228,45 @@ class XendDomain:
   4.207  
   4.208          @param savedinfo: saved info from the db
   4.209          @param info:      domain info from xen
   4.210 -        @return: deferred
   4.211 +        @return: domain
   4.212          """
   4.213 -        def cbok(dominfo):
   4.214 -            self.domain_by_id[dominfo.id] = dominfo
   4.215 -            self.domain_by_name[dominfo.name] = dominfo
   4.216 -            if dominfo.restart_pending():
   4.217 -                self.domain_restart_add(dominfo)
   4.218 -        
   4.219 -        deferred = XendDomainInfo.vm_recreate(savedinfo, info)
   4.220 -        deferred.addCallback(cbok)
   4.221 -        return deferred
   4.222 +        dominfo = XendDomainInfo.vm_recreate(savedinfo, info)
   4.223 +        self.domain_by_id[dominfo.id] = dominfo
   4.224 +        self.domain_by_name[dominfo.name] = dominfo
   4.225 +        if dominfo.restart_pending():
   4.226 +            self.domain_restart_add(dominfo)
   4.227 +        return dominfo
   4.228  
   4.229 -    def _add_domain(self, info, notify=1):
   4.230 +    def _add_domain(self, info, notify=True):
   4.231          """Add a domain entry to the tables.
   4.232  
   4.233          @param info:   domain info object
   4.234          @param notify: send a domain created event if true
   4.235          """
   4.236 +        # Remove entries under the wrong id.
   4.237 +        for i, d in self.domain_by_id.items():
   4.238 +            if i != d.id:
   4.239 +                del self.domain_by_id[i]
   4.240 +                if i in self.domain_db:
   4.241 +                    del self.domain_db[i]
   4.242 +                self.db.delete(i)
   4.243 +        # Remove entries under the wrong name.
   4.244 +        for n, d in self.domain_by_name.items():
   4.245 +            if n != d.name:
   4.246 +                del self.domain_by_name[n]
   4.247 +        # But also need to make sure are indexed under correct name.
   4.248 +        # What about entries under info.name ?
   4.249 +        if info.id in self.domain_by_id:
   4.250 +            notify = False
   4.251          self.domain_by_id[info.id] = info
   4.252          self.domain_db[info.id] = info.sxpr()
   4.253 -        for k, d in self.domain_by_name.items():
   4.254 -            if k != d.name:
   4.255 -                del self.domain_by_name[k]
   4.256          if info.name:
   4.257              self.domain_by_name[info.name] = info
   4.258          self.sync_domain(info.id)
   4.259 -        if notify: eserver.inject('xend.domain.create', [info.name, info.id])
   4.260 +        if notify:
   4.261 +            eserver.inject('xend.domain.create', [info.name, info.id])
   4.262  
   4.263 -    def _delete_domain(self, id, notify=1):
   4.264 +    def _delete_domain(self, id, notify=True):
   4.265          """Remove a domain from the tables.
   4.266  
   4.267          @param id:     domain id
   4.268 @@ -214,10 +275,11 @@ class XendDomain:
   4.269          for (k, info) in self.domain_by_name.items():
   4.270              if info.id == id:
   4.271                  del self.domain_by_name[k]
   4.272 -        if id in self.domain_by_id:
   4.273 -            info = self.domain_by_id[id]
   4.274 +        info = self.domain_by_id.get(id)
   4.275 +        if info:
   4.276              del self.domain_by_id[id]
   4.277 -            if notify: eserver.inject('xend.domain.died', [info.name, info.id])
   4.278 +            if notify:
   4.279 +                eserver.inject('xend.domain.died', [info.name, info.id])
   4.280          if id in self.domain_db:
   4.281              del self.domain_db[id]
   4.282              self.db.delete(id)
   4.283 @@ -227,9 +289,9 @@ class XendDomain:
   4.284          Tidy them up.
   4.285          """
   4.286          self.reap_cancel()
   4.287 -        domlist = xc.domain_getinfo()
   4.288          casualties = []
   4.289 -        for d in domlist:
   4.290 +        doms = self.xen_domains()
   4.291 +        for d in doms.values():
   4.292              dead = 0
   4.293              dead = dead or (d['crashed'] or d['shutdown'])
   4.294              dead = dead or (d['dying'] and
   4.295 @@ -239,8 +301,12 @@ class XendDomain:
   4.296          destroyed = 0
   4.297          for d in casualties:
   4.298              id = str(d['dom'])
   4.299 +            print 'reap>', id
   4.300              dominfo = self.domain_by_id.get(id)
   4.301              name = (dominfo and dominfo.name) or '??'
   4.302 +            if dominfo and dominfo.is_terminated():
   4.303 +                print 'reap> already terminated:', id
   4.304 +                continue
   4.305              log.debug('XendDomain>reap> domain died name=%s id=%s', name, id)
   4.306              if d['shutdown']:
   4.307                  reason = XendDomainInfo.shutdown_reason(d['shutdown_reason'])
   4.308 @@ -255,36 +321,34 @@ class XendDomain:
   4.309                      eserver.inject('xend.domain.exit', [name, id, reason])
   4.310                      self.domain_restart_schedule(id, reason)
   4.311              else:
   4.312 -               eserver.inject('xend.domain.exit', [name, id, 'crash']) 
   4.313 +               eserver.inject('xend.domain.exit', [name, id, 'crash'])
   4.314              destroyed += 1
   4.315              self.final_domain_destroy(id)
   4.316          if self.domain_restarts_exist():
   4.317              self.domain_restarts_schedule()
   4.318          if destroyed:
   4.319 -            self.refresh_schedule(delay=1)
   4.320 +            self.refresh_schedule(delay=5)
   4.321  
   4.322      def refresh(self):
   4.323          """Refresh domain list from Xen.
   4.324          """
   4.325          self.refresh_cancel()
   4.326 -        domlist = xc.domain_getinfo()
   4.327 -        # Index the domlist by id.
   4.328 +        doms = self.xen_domains()
   4.329          # Add entries for any domains we don't know about.
   4.330 -        doms = {}
   4.331 -        for d in domlist:
   4.332 -            id = str(d['dom'])
   4.333 -            doms[id] = d
   4.334 +        for (id, d) in doms.items():
   4.335              if id not in self.domain_by_id:
   4.336 +                log.warning("Created entry for unknown domain: %s", id)
   4.337                  savedinfo = None
   4.338 -                deferred = XendDomainInfo.vm_recreate(savedinfo, d)
   4.339 -                def cbok(dominfo):
   4.340 -                    self._add_domain(dominfo)
   4.341 -                deferred.addCallback(cbok)
   4.342 +                dominfo = XendDomainInfo.vm_recreate(savedinfo, d)
   4.343 +                self._add_domain(dominfo)
   4.344          # Remove entries for domains that no longer exist.
   4.345 +        # Update entries for existing domains.
   4.346          for d in self.domain_by_id.values():
   4.347              info = doms.get(d.id)
   4.348              if info:
   4.349                  d.update(info)
   4.350 +            elif d.restart_pending():
   4.351 +                pass
   4.352              else:
   4.353                  self._delete_domain(d.id)
   4.354          self.reap_schedule(delay=1)
   4.355 @@ -304,19 +368,13 @@ class XendDomain:
   4.356  
   4.357          @param id: domain id
   4.358          """
   4.359 -        dom = int(id)
   4.360 -        dominfo = xc.domain_getinfo(dom, 1)
   4.361 -        if dominfo == [] or dominfo[0]['dom'] != dom:
   4.362 -            try:
   4.363 -                self._delete_domain(id)
   4.364 -            except:
   4.365 -                log.exception('refresh_domain> error')
   4.366 -                raise
   4.367 -                pass
   4.368 -        else:
   4.369 +        dominfo = xen_domain(id)
   4.370 +        if dominfo:
   4.371              d = self.domain_by_id.get(id)
   4.372              if d:
   4.373 -                d.update(dominfo[0])
   4.374 +                d.update(dominfo)
   4.375 +        else:
   4.376 +            self._delete_domain(id)
   4.377  
   4.378      def domain_ls(self):
   4.379          """Get list of domain names.
   4.380 @@ -346,30 +404,33 @@ class XendDomain:
   4.381          """Create a domain from a configuration.
   4.382  
   4.383          @param config: configuration
   4.384 -        @return: deferred
   4.385 +        @return: domain
   4.386          """
   4.387 -        def cbok(dominfo):
   4.388 -            self._add_domain(dominfo)
   4.389 -            return dominfo
   4.390 -        deferred = XendDomainInfo.vm_create(config)
   4.391 -        deferred.addCallback(cbok)
   4.392 -        return deferred
   4.393 +        dominfo = XendDomainInfo.vm_create(config)
   4.394 +        self._add_domain(dominfo)
   4.395 +        return dominfo
   4.396  
   4.397      def domain_restart(self, dominfo):
   4.398          """Restart a domain.
   4.399  
   4.400          @param dominfo: domain object
   4.401 -        @return: deferred
   4.402          """
   4.403 -        def cbok(dominfo):
   4.404 -            self._add_domain(dominfo)
   4.405 -            return dominfo
   4.406          log.info("Restarting domain: id=%s name=%s", dominfo.id, dominfo.name)
   4.407          eserver.inject("xend.domain.restart",
   4.408                         [dominfo.name, dominfo.id, "begin"])
   4.409 -        deferred = dominfo.restart()
   4.410 -        deferred.addCallback(cbok)
   4.411 -        return deferred        
   4.412 +        try:
   4.413 +            dominfo.restart()
   4.414 +            self._add_domain(dominfo)
   4.415 +            log.info('Restarted domain name=%s id=%s', dominfo.name, dominfo.id)
   4.416 +            eserver.inject("xend.domain.restart",
   4.417 +                           [dominfo.name, dominfo.id, "success"])
   4.418 +            self.domain_unpause(dominfo.id)
   4.419 +        except Exception, ex:
   4.420 +            log.exception("Exception restarting domain: name=%s id=%s",
   4.421 +                          dominfo.name, dominfo.id)
   4.422 +            eserver.inject("xend.domain.restart",
   4.423 +                           [dominfo.name, dominfo.id, "fail"])
   4.424 +        return dominfo
   4.425  
   4.426      def domain_configure(self, id, vmconfig):
   4.427          """Configure an existing domain. This is intended for internal
   4.428 @@ -377,38 +438,25 @@ class XendDomain:
   4.429  
   4.430          @param id:       domain id
   4.431          @param vmconfig: vm configuration
   4.432 -        @return: deferred
   4.433          """
   4.434          config = sxp.child_value(vmconfig, 'config')
   4.435          dominfo = self.domain_lookup(id)
   4.436          log.debug('domain_configure> id=%s config=%s', str(id), str(config))
   4.437          if dominfo.config:
   4.438              raise XendError("Domain already configured: " + dominfo.id)
   4.439 -        def cbok(dominfo):
   4.440 -            self._add_domain(dominfo)
   4.441 -            return dominfo
   4.442 -        deferred = dominfo.dom_construct(dominfo.dom, config)
   4.443 -        deferred.addCallback(cbok)
   4.444 -        return deferred
   4.445 +        dominfo.dom_construct(dominfo.dom, config)
   4.446 +        self._add_domain(dominfo)
   4.447 +        return dominfo
   4.448      
   4.449 -    def domain_restore(self, src, progress=0):
   4.450 +    def domain_restore(self, src, progress=False):
   4.451          """Restore a domain from file.
   4.452  
   4.453          @param src:      source file
   4.454          @param progress: output progress if true
   4.455          @return: deferred
   4.456          """
   4.457 -        
   4.458 -        if 0:
   4.459 -            def cbok(dominfo):
   4.460 -                self._add_domain(dominfo)
   4.461 -                return dominfo
   4.462 -            deferred = XendDomainInfo.vm_restore(src, progress=progress)
   4.463 -            deferred.addCallback(cbok)
   4.464 -        else:
   4.465 -            xmigrate = XendMigrate.instance()
   4.466 -            deferred = xmigrate.restore_begin(src)
   4.467 -        return deferred
   4.468 +        xmigrate = XendMigrate.instance()
   4.469 +        return xmigrate.restore_begin(src)
   4.470      
   4.471      def domain_get(self, id):
   4.472          """Get up-to-date info about a domain.
   4.473 @@ -425,7 +473,7 @@ class XendDomain:
   4.474          dominfo = self.domain_by_name.get(name) or self.domain_by_id.get(name)
   4.475          if dominfo:
   4.476              return dominfo
   4.477 -        raise XendError('invalid domain:' + name)
   4.478 +        raise XendError('invalid domain: ' + name)
   4.479  
   4.480      def domain_exists(self, name):
   4.481          name = str(name)
   4.482 @@ -470,15 +518,54 @@ class XendDomain:
   4.483          if reason == 'halt':
   4.484              self.domain_restart_cancel(dominfo.id)
   4.485          else:
   4.486 -            self.domain_restart_schedule(dominfo.id, reason, force=1)
   4.487 +            self.domain_restart_schedule(dominfo.id, reason, force=True)
   4.488          eserver.inject('xend.domain.shutdown', [dominfo.name, dominfo.id, reason])
   4.489          if reason == 'halt':
   4.490              reason = 'poweroff'
   4.491 -        val = xend.domain_shutdown(dominfo.id, reason, key)
   4.492 -        self.refresh_schedule()
   4.493 +        val = dominfo.shutdown(reason, key=key)
   4.494 +        self.add_shutdown(dominfo, reason, key)
   4.495 +        self.refresh_schedule(delay=10)
   4.496          return val
   4.497  
   4.498 -    def domain_restart_schedule(self, id, reason, force=0):
   4.499 +    def add_shutdown(self, dominfo, reason, key):
   4.500 +        """Add a pending shutdown for a domain.
   4.501 +        This will destroy the domain if the shutdown times out.
   4.502 +        """
   4.503 +        if dominfo.id in self.shutdowns_by_id:
   4.504 +            return
   4.505 +        self.shutdowns_by_id[dominfo.id] = DomainShutdown(dominfo, reason, key)
   4.506 +        self.domain_shutdowns()
   4.507 +
   4.508 +    def domain_shutdowns(self):
   4.509 +        """Process pending domain shutdowns.
   4.510 +        Destroys domains whose shutdowns have timed out.
   4.511 +        """
   4.512 +        self.schedule_cancel('domain_shutdowns')
   4.513 +        timeout = SHUTDOWN_TIMEOUT
   4.514 +        for shutdown in self.shutdowns_by_id.values():
   4.515 +            id = shutdown.getDomain()
   4.516 +            if shutdown.isShutdown():
   4.517 +                # Shutdown done - remove.
   4.518 +                print 'domain_shutdowns> done: ', id
   4.519 +                del self.shutdowns_by_id[id]
   4.520 +            elif shutdown.isExpired():
   4.521 +                # Shutdown expired - remove and destroy domain.
   4.522 +                del self.shutdowns_by_id[id]
   4.523 +                try:
   4.524 +                    log.info("Domain shutdown timeout expired: name=%s id=%s",
   4.525 +                             shutdown.getDomainName(), id)
   4.526 +                    self.domain_destroy(id, reason=shutdown.getReason())
   4.527 +                except Exception:
   4.528 +                    pass
   4.529 +            else:
   4.530 +                # Shutdown still pending.
   4.531 +                print 'domain_shutdowns> pending: ', id
   4.532 +                timeout = min(timeout, shutdown.getTimeout())
   4.533 +        if self.shutdowns_by_id:
   4.534 +            # Pending shutdowns remain - reschedule.
   4.535 +            self.schedule_later(timeout, 'domain_shutdowns', self.domain_shutdowns)
   4.536 +
   4.537 +    def domain_restart_schedule(self, id, reason, force=False):
   4.538          """Schedule a restart for a domain if it needs one.
   4.539  
   4.540          @param id:     domain id
   4.541 @@ -510,7 +597,8 @@ class XendDomain:
   4.542          """
   4.543          dominfo = self.restarts_by_id.get(id) or self.restarts_by_name.get(id)
   4.544          if dominfo:
   4.545 -            log.info('Cancelling restart for domain: name=%s id=%s', dominfo.name, dominfo.id)
   4.546 +            log.info('Cancelling restart for domain: name=%s id=%s',
   4.547 +                     dominfo.name, dominfo.id)
   4.548              eserver.inject("xend.domain.restart",
   4.549                             [dominfo.name, dominfo.id, "cancel"])
   4.550              dominfo.restart_cancel()
   4.551 @@ -521,36 +609,22 @@ class XendDomain:
   4.552          """Execute any scheduled domain restarts for domains that have gone.
   4.553          """
   4.554          self.domain_restarts_cancel()
   4.555 +        doms = self.xen_domains()
   4.556          for dominfo in self.restarts_by_id.values():
   4.557 -            if dominfo.id in self.domain_by_id:
   4.558 +            print 'domain_restarts>', dominfo.name, dominfo.id
   4.559 +            info = doms.get(dominfo.id)
   4.560 +            if info:
   4.561                  # Don't execute restart for domains still running.
   4.562 +                print 'domain_restarts> still runnning: ', dominfo.name
   4.563                  continue
   4.564              # Remove it from the restarts.
   4.565              del self.restarts_by_id[dominfo.id]
   4.566              del self.restarts_by_name[dominfo.name]
   4.567 -            try:
   4.568 -                def cbok(dominfo):
   4.569 -                    log.info('Restarted domain name=%s id=%s', dominfo.name, dominfo.id)
   4.570 -                    eserver.inject("xend.domain.restart",
   4.571 -                                   [dominfo.name, dominfo.id, "success"])
   4.572 -                    self.domain_unpause(dominfo.id)
   4.573 -                def cberr(err):
   4.574 -                    log.exception("Delayed exception restarting domain: name=%s id=%s",
   4.575 -                                  dominfo.name, dominfo.id)
   4.576 -                    eserver.inject("xend.domain.restart",
   4.577 -                                   [dominfo.name, dominfo.id, "fail"])
   4.578 -                    
   4.579 -                deferred = self.domain_restart(dominfo)
   4.580 -                deferred.addCallback(cbok)
   4.581 -                deferred.addErrback(cberr)
   4.582 -            except:
   4.583 -                log.exception("Exception restarting domain: name=%s id=%s",
   4.584 -                              dominfo.name, dominfo.id)
   4.585 -                eserver.inject("xend.domain.restart",
   4.586 -                               [dominfo.name, dominfo.id, "fail"])
   4.587 +            print 'domain_restarts> restarting: ', dominfo.name
   4.588 +            self.domain_restart(dominfo)
   4.589          if self.domain_restarts_exist():
   4.590              # Run again later if any restarts remain.
   4.591 -            self.refresh_schedule(delay=5)
   4.592 +            self.refresh_schedule(delay=10)
   4.593  
   4.594      def domain_restarts_exist(self):
   4.595          return len(self.restarts_by_id)
   4.596 @@ -560,14 +634,17 @@ class XendDomain:
   4.597  
   4.598          @param id: domain id
   4.599          """
   4.600 -        dominfo = self.domain_lookup(id)
   4.601 -        log.info('Destroying domain: name=%s', dominfo.name)
   4.602 -        eserver.inject('xend.domain.destroy', [dominfo.name, dominfo.id])
   4.603 -        if dominfo:
   4.604 +        try:
   4.605 +            dominfo = self.domain_lookup(id)
   4.606 +            log.info('Destroying domain: name=%s', dominfo.name)
   4.607 +            eserver.inject('xend.domain.destroy', [dominfo.name, dominfo.id])
   4.608              val = dominfo.destroy()
   4.609 -        else:
   4.610 +        except:
   4.611              #todo
   4.612 -            val = xc.domain_destroy(dom=dominfo.dom)
   4.613 +            try:
   4.614 +                val = xc.domain_destroy(dom=int(id))
   4.615 +            except Exception, ex:
   4.616 +                raise XendError(str(ex))
   4.617          return val       
   4.618  
   4.619      def domain_destroy(self, id, reason='halt'):
   4.620 @@ -580,12 +657,12 @@ class XendDomain:
   4.621          if reason == 'halt':
   4.622              self.domain_restart_cancel(id)
   4.623          elif reason == 'reboot':
   4.624 -            self.domain_restart_schedule(id, reason, force=1)
   4.625 +            self.domain_restart_schedule(id, reason, force=True)
   4.626          val = self.final_domain_destroy(id)
   4.627          self.refresh_schedule()
   4.628          return val
   4.629  
   4.630 -    def domain_migrate(self, id, dst, live=0, resource=0):
   4.631 +    def domain_migrate(self, id, dst, live=False, resource=0):
   4.632          """Start domain migration.
   4.633  
   4.634          @param id: domain id
   4.635 @@ -595,10 +672,9 @@ class XendDomain:
   4.636          # Don't forget to cancel restart for it.
   4.637          dominfo = self.domain_lookup(id)
   4.638          xmigrate = XendMigrate.instance()
   4.639 -        val = xmigrate.migrate_begin(dominfo, dst, live=live, resource=resource)
   4.640 -        return val
   4.641 +        return xmigrate.migrate_begin(dominfo, dst, live=live, resource=resource)
   4.642  
   4.643 -    def domain_save(self, id, dst, progress=0):
   4.644 +    def domain_save(self, id, dst, progress=False):
   4.645          """Start saving a domain to file.
   4.646  
   4.647          @param id:       domain id
   4.648 @@ -647,7 +723,6 @@ class XendDomain:
   4.649  
   4.650          @param id:       domain id
   4.651          @param devconfig: device configuration
   4.652 -        @return: deferred
   4.653          """
   4.654          dominfo = self.domain_lookup(id)
   4.655          self.refresh_schedule()
   4.656 @@ -703,8 +778,7 @@ class XendDomain:
   4.657          @return: device indexes
   4.658          """
   4.659          dominfo = self.domain_lookup(id)
   4.660 -        devs = dominfo.get_devices(type)
   4.661 -        return devs
   4.662 +        return dominfo.get_devices(type)
   4.663  
   4.664      def domain_devtype_get(self, id, type, idx):
   4.665          """Get a device from a domain.
   4.666 @@ -787,7 +861,8 @@ class XendDomain:
   4.667              raise XendError(str(ex))
   4.668  
   4.669      def domain_mem_target_set(self, id, target):
   4.670 -        return xend.domain_mem_target_set(id, target)
   4.671 +        dominfo = self.domain_lookup(id)
   4.672 +        return dominfo.mem_target_set(target)
   4.673          
   4.674  
   4.675  
     5.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Tue Apr 19 13:48:05 2005 +0000
     5.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Wed Apr 20 08:45:19 2005 +0000
     5.3 @@ -9,30 +9,25 @@ Author: Mike Wray <mike.wray@hpl.hp.com>
     5.4  """
     5.5  
     5.6  import string
     5.7 -import types
     5.8 -import re
     5.9 -import sys
    5.10  import os
    5.11  import time
    5.12  
    5.13 -from twisted.internet import defer
    5.14 -
    5.15  import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
    5.16  import xen.util.ip
    5.17  from xen.util.ip import _readline, _readlines
    5.18 -from xen.xend.server import channel
    5.19 +from xen.xend.server import channel, controller
    5.20 +
    5.21 +from server.channel import channelFactory
    5.22 +import server.SrvDaemon; xend = server.SrvDaemon.instance()
    5.23 +from server import messages
    5.24  
    5.25  import sxp
    5.26 -
    5.27 -import XendConsole
    5.28 -xendConsole = XendConsole.instance()
    5.29  from XendLogging import log
    5.30 +from XendError import VmError
    5.31  from XendRoot import get_component
    5.32 +#import XendConsole; xendConsole = XendConsole.instance()
    5.33  
    5.34 -import server.SrvDaemon
    5.35 -xend = server.SrvDaemon.instance()
    5.36 -
    5.37 -from XendError import VmError
    5.38 +from PrettyPrint import prettyprint
    5.39  
    5.40  """The length of domain names that Xen can handle.
    5.41  The names stored in Xen itself are not used for much, and
    5.42 @@ -48,8 +43,10 @@ SIF_NET_BE_DOMAIN = (1<<5)
    5.43  
    5.44  """Shutdown code for poweroff."""
    5.45  DOMAIN_POWEROFF = 0
    5.46 +
    5.47  """Shutdown code for reboot."""
    5.48  DOMAIN_REBOOT   = 1
    5.49 +
    5.50  """Shutdown code for suspend."""
    5.51  DOMAIN_SUSPEND  = 2
    5.52  
    5.53 @@ -59,6 +56,15 @@ shutdown_reasons = {
    5.54      DOMAIN_REBOOT  : "reboot",
    5.55      DOMAIN_SUSPEND : "suspend" }
    5.56  
    5.57 +"""Map shutdown reasons to the message type to use.
    5.58 +"""
    5.59 +shutdown_messages = {
    5.60 +    'poweroff' : 'shutdown_poweroff_t',
    5.61 +    'reboot'   : 'shutdown_reboot_t',
    5.62 +    'suspend'  : 'shutdown_suspend_t',
    5.63 +    'sysrq'    : 'shutdown_sysrq_t',
    5.64 +    }
    5.65 +
    5.66  RESTART_ALWAYS   = 'always'
    5.67  RESTART_ONREBOOT = 'onreboot'
    5.68  RESTART_NEVER    = 'never'
    5.69 @@ -164,21 +170,12 @@ Indexed by device type.
    5.70  """
    5.71  device_handlers = {}
    5.72  
    5.73 -def add_device_handler(name, h):
    5.74 -    """Add a handler for a device type.
    5.75 -
    5.76 -    @param name:     device type
    5.77 -    @param h:        handler: fn(vm, dev)
    5.78 -    """
    5.79 -    device_handlers[name] = h
    5.80 +def add_device_handler(name, type):
    5.81 +    device_handlers[name] = type
    5.82  
    5.83  def get_device_handler(name):
    5.84 -    """Get the handler for a device type.
    5.85 -
    5.86 -    @param name :     device type
    5.87 -    @return; handler or None
    5.88 -    """
    5.89 -    return device_handlers.get(name)
    5.90 +    return device_handlers[name]
    5.91 +    
    5.92  
    5.93  def vm_create(config):
    5.94      """Create a VM from a configuration.
    5.95 @@ -186,11 +183,11 @@ def vm_create(config):
    5.96      is destroyed.
    5.97  
    5.98      @param config    configuration
    5.99 -    @return: Deferred
   5.100      @raise: VmError for invalid configuration
   5.101      """
   5.102      vm = XendDomainInfo()
   5.103 -    return vm.construct(config)
   5.104 +    vm.construct(config)
   5.105 +    return vm
   5.106  
   5.107  def vm_recreate(savedinfo, info):
   5.108      """Create the VM object for an existing domain.
   5.109 @@ -199,37 +196,37 @@ def vm_recreate(savedinfo, info):
   5.110      @type  savedinfo: sxpr
   5.111      @param info:      domain info from xc
   5.112      @type  info:      xc domain dict
   5.113 -    @return: deferred
   5.114      """
   5.115 +    print 'vm_recreate>'
   5.116 +    print 'savedinfo=' ; prettyprint(savedinfo)
   5.117 +    print 'info=', info
   5.118      vm = XendDomainInfo()
   5.119 -    vm.recreate = 1
   5.120 +    vm.recreate = True
   5.121      vm.savedinfo = savedinfo
   5.122      vm.setdom(info['dom'])
   5.123 -    #vm.name = info['name']
   5.124      vm.memory = info['mem_kb']/1024
   5.125      start_time = sxp.child_value(savedinfo, 'start_time')
   5.126      if start_time is not None:
   5.127          vm.start_time = float(start_time)
   5.128      vm.restart_state = sxp.child_value(savedinfo, 'restart_state')
   5.129 +    vm.restart_count = int(sxp.child_value(savedinfo, 'restart_count', 0))
   5.130      restart_time = sxp.child_value(savedinfo, 'restart_time')
   5.131      if restart_time is not None:
   5.132          vm.restart_time = float(restart_time)
   5.133      config = sxp.child_value(savedinfo, 'config')
   5.134      if config:
   5.135 -        d = vm.construct(config)
   5.136 +        vm.construct(config)
   5.137      else:
   5.138          vm.name = sxp.child_value(savedinfo, 'name', "Domain-%d" % info['dom'])
   5.139 -        d = defer.succeed(vm)
   5.140 -    vm.recreate = 0
   5.141 +    vm.recreate = False
   5.142      vm.savedinfo = None
   5.143 -    return d
   5.144 +    return vm
   5.145  
   5.146 -def vm_restore(src, progress=0):
   5.147 +def vm_restore(src, progress=False):
   5.148      """Restore a VM from a disk image.
   5.149  
   5.150      src      saved state to restore
   5.151      progress progress reporting flag
   5.152 -    returns  deferred
   5.153      raises   VmError for invalid configuration
   5.154      """
   5.155      vm = XendDomainInfo()
   5.156 @@ -244,12 +241,9 @@ def vm_restore(src, progress=0):
   5.157          config = sxp.child_value(vmconfig, 'config')
   5.158      except Exception, ex:
   5.159          raise VmError('config error: ' + str(ex))
   5.160 -    deferred = vm.dom_construct(dom, config)
   5.161 -    def vifs_cb(val, vm):
   5.162 -        vif_up(vm.ipaddrs)
   5.163 -        return vm
   5.164 -    deferred.addCallback(vifs_cb, vm)
   5.165 -    return deferred
   5.166 +    vm.dom_construct(dom, config)
   5.167 +    vif_up(vm.ipaddrs)
   5.168 +    return vm
   5.169      
   5.170  def dom_get(dom):
   5.171      """Get info from xen for an existing domain.
   5.172 @@ -262,27 +256,6 @@ def dom_get(dom):
   5.173          return domlist[0]
   5.174      return None
   5.175      
   5.176 -def append_deferred(dlist, v):
   5.177 -    """Append a value to a deferred list if it is a deferred.
   5.178 -
   5.179 -    @param dlist: list of deferreds
   5.180 -    @param v: value to add
   5.181 -    """
   5.182 -    if isinstance(v, defer.Deferred):
   5.183 -        dlist.append(v)
   5.184 -
   5.185 -def dlist_err(val):
   5.186 -    """Error callback suitable for a deferred list.
   5.187 -    In a deferred list the error callback is called with with Failure((error, index)).
   5.188 -    This callback extracts the error and returns it.
   5.189 -
   5.190 -    @param val: Failure containing (error, index)
   5.191 -    @type val: twisted.internet.failure.Failure 
   5.192 -    """
   5.193 -    
   5.194 -    (error, index) = val.value
   5.195 -    return error
   5.196 -
   5.197  class XendDomainInfo:
   5.198      """Virtual machine object."""
   5.199  
   5.200 @@ -303,25 +276,31 @@ class XendDomainInfo:
   5.201          self.image = None
   5.202          self.ramdisk = None
   5.203          self.cmdline = None
   5.204 -        self.console = None
   5.205 +
   5.206 +        self.channel = None
   5.207 +        self.controllers = {}
   5.208          self.devices = {}
   5.209 -        self.device_index = {}
   5.210 +        
   5.211          self.configs = []
   5.212 +        
   5.213          self.info = None
   5.214          self.ipaddrs = []
   5.215 -        self.blkif_backend = 0
   5.216 -        self.netif_backend = 0
   5.217 +        self.blkif_backend = False
   5.218 +        self.netif_backend = False
   5.219          #todo: state: running, suspended
   5.220          self.state = STATE_VM_OK
   5.221          #todo: set to migrate info if migrating
   5.222          self.migrate = None
   5.223 +        
   5.224          self.restart_mode = RESTART_ONREBOOT
   5.225          self.restart_state = None
   5.226          self.restart_time = None
   5.227 +        self.restart_count = 0
   5.228 +        
   5.229          self.console_port = None
   5.230          self.savedinfo = None
   5.231          self.image_handler = None
   5.232 -        self.is_vmx = 0
   5.233 +        self.is_vmx = False
   5.234          self.vcpus = 1
   5.235  
   5.236      def setdom(self, dom):
   5.237 @@ -332,6 +311,15 @@ class XendDomainInfo:
   5.238          self.dom = int(dom)
   5.239          self.id = str(dom)
   5.240  
   5.241 +    def getDomain(self):
   5.242 +        return self.dom
   5.243 +
   5.244 +    def getName(self):
   5.245 +        return self.name
   5.246 +
   5.247 +    def getChannel(self):
   5.248 +        return self.channel
   5.249 +
   5.250      def update(self, info):
   5.251          """Update with  info from xc.domain_getinfo().
   5.252          """
   5.253 @@ -343,8 +331,9 @@ class XendDomainInfo:
   5.254          s += " id=" + self.id
   5.255          s += " name=" + self.name
   5.256          s += " memory=" + str(self.memory)
   5.257 -        if self.console:
   5.258 -            s += " console=" + str(self.console.console_port)
   5.259 +        console = self.getConsole()
   5.260 +        if console:
   5.261 +            s += " console=" + str(console.console_port)
   5.262          if self.image:
   5.263              s += " image=" + self.image
   5.264          s += ""
   5.265 @@ -352,6 +341,71 @@ class XendDomainInfo:
   5.266  
   5.267      __repr__ = __str__
   5.268  
   5.269 +    def getDeviceTypes(self):
   5.270 +        return self.controllers.keys()
   5.271 +
   5.272 +    def getDeviceControllers(self):
   5.273 +        return self.controllers.values()
   5.274 +
   5.275 +    def getDeviceController(self, type, error=True):
   5.276 +        ctrl = self.controllers.get(type)
   5.277 +        if not ctrl and error:
   5.278 +            raise XendError("invalid device type:" + type)
   5.279 +        return ctrl
   5.280 +    
   5.281 +    def findDeviceController(self, type):
   5.282 +        return (self.getDeviceController(type, error=False)
   5.283 +                or self.createDeviceController(type))
   5.284 +
   5.285 +    def createDeviceController(self, type):
   5.286 +        ctrl = controller.createDevController(type, self, recreate=self.recreate)
   5.287 +        self.controllers[type] = ctrl
   5.288 +        return ctrl
   5.289 +
   5.290 +    def createDevice(self, type, devconfig, recreate=False):
   5.291 +        ctrl = self.findDeviceController(type)
   5.292 +        return ctrl.createDevice(devconfig, recreate=self.recreate)
   5.293 +
   5.294 +    def configureDevice(self, type, id, devconfig):
   5.295 +        ctrl = self.getDeviceController(type)
   5.296 +        return ctrl.configureDevice(id, devconfig)
   5.297 +
   5.298 +    def destroyDevice(self, type, id, change=False, reboot=False):
   5.299 +        ctrl = self.getDeviceController(type)
   5.300 +        return ctrl.destroyDevice(id, change=change, reboot=reboot)
   5.301 +
   5.302 +    def deleteDevice(self, type, id):
   5.303 +        ctrl = self.getDeviceController(type)
   5.304 +        return ctrl.deleteDevice(id)
   5.305 +
   5.306 +    def getDevice(self, type, id):
   5.307 +        ctrl = self.getDeviceController(type)
   5.308 +        return ctrl.getDevice(id)
   5.309 +        
   5.310 +    def getDeviceByIndex(self, type, idx):
   5.311 +        ctrl = self.getDeviceController(type)
   5.312 +        return ctrl.getDeviceByIndex(idx)
   5.313 +
   5.314 +    def getDeviceIndex(self, type, dev):
   5.315 +        ctrl = self.getDeviceController(type)
   5.316 +        return ctrl.getDeviceIndex(dev)
   5.317 +    
   5.318 +    def getDeviceConfig(self, type, id):
   5.319 +        ctrl = self.getDeviceController(type)
   5.320 +        return ctrl.getDeviceConfig(id)
   5.321 +
   5.322 +    def getDeviceIds(self, type):
   5.323 +        ctrl = self.getDeviceController(type)
   5.324 +        return ctrl.getDeviceIds()
   5.325 +    
   5.326 +    def getDeviceConfigs(self, type):
   5.327 +        ctrl = self.getDeviceController(type)
   5.328 +        return ctrl.getDeviceConfigs()
   5.329 +
   5.330 +    def getDeviceSxprs(self, type):
   5.331 +        ctrl = self.getDeviceController(type)
   5.332 +        return ctrl.getDeviceSxprs()
   5.333 +
   5.334      def sxpr(self):
   5.335          sxpr = ['domain',
   5.336                  ['id', self.id],
   5.337 @@ -378,8 +432,13 @@ class XendDomainInfo:
   5.338              sxpr.append(['up_time', str(up_time) ])
   5.339              sxpr.append(['start_time', str(self.start_time) ])
   5.340  
   5.341 -        if self.console:
   5.342 -            sxpr.append(self.console.sxpr())
   5.343 +        if self.channel:
   5.344 +            sxpr.append(self.channel.sxpr())
   5.345 +        console = self.getConsole()
   5.346 +        if console:
   5.347 +            sxpr.append(console.sxpr())
   5.348 +        if self.restart_count:
   5.349 +            sxpr.append(['restart_count', self.restart_count])
   5.350          if self.restart_state:
   5.351              sxpr.append(['restart_state', self.restart_state])
   5.352          if self.restart_time:
   5.353 @@ -393,10 +452,10 @@ class XendDomainInfo:
   5.354  
   5.355      def sxpr_devices(self):
   5.356          sxpr = ['devices']
   5.357 -        for devs in self.devices.values():
   5.358 -            for dev in devs:
   5.359 -                if hasattr(dev, 'sxpr'):
   5.360 -                    sxpr.append(dev.sxpr())
   5.361 +        for ty in self.getDeviceTypes():
   5.362 +            devs = [ ty ]
   5.363 +            devs += self.getDeviceSxprs(ty)
   5.364 +            sxpr.append(devs)
   5.365          return sxpr
   5.366  
   5.367      def check_name(self, name):
   5.368 @@ -432,46 +491,55 @@ class XendDomainInfo:
   5.369          """Construct the vm instance from its configuration.
   5.370  
   5.371          @param config: configuration
   5.372 -        @return: deferred
   5.373          @raise: VmError on error
   5.374          """
   5.375          # todo - add support for scheduling params?
   5.376          self.config = config
   5.377          try:
   5.378 +            # Initial domain create.
   5.379              self.name = sxp.child_value(config, 'name')
   5.380              self.check_name(self.name)
   5.381 -            try:
   5.382 -                self.cpu_weight = float(sxp.child_value(config, 'cpu_weight', '1'))
   5.383 -            except:
   5.384 -                raise VmError('invalid cpu weight')
   5.385 -            self.memory = int(sxp.child_value(config, 'memory'))
   5.386 -            if self.memory is None:
   5.387 -                raise VmError('missing memory size')
   5.388 -            cpu = sxp.child_value(config, 'cpu')
   5.389 -            if self.recreate and self.dom and cpu is not None:
   5.390 -                xc.domain_pincpu(self.dom, int(cpu))
   5.391 -            try:
   5.392 -                image = sxp.child_value(self.config, 'image')
   5.393 -                self.vcpus = int(sxp.child_value(image, 'vcpus'))
   5.394 -            except:
   5.395 -                raise VmError('invalid vcpus value')
   5.396 -
   5.397 +            self.configure_cpus(config)
   5.398              self.find_image_handler()
   5.399              self.init_domain()
   5.400 -            self.configure_console()
   5.401 +            self.register_domain()
   5.402 +
   5.403 +            # Create domain devices.
   5.404              self.configure_backends()
   5.405 -            self.construct_image()
   5.406 +            self.configure_console()
   5.407              self.configure_restart()
   5.408 -            deferred = self.configure()
   5.409 -            def cberr(err):
   5.410 -                self.destroy()
   5.411 -                return err
   5.412 -            deferred.addErrback(cberr)
   5.413 -        except StandardError, ex:
   5.414 +            self.construct_image()
   5.415 +            self.configure()
   5.416 +        except Exception, ex:
   5.417              # Catch errors, cleanup and re-raise.
   5.418 +            print 'Domain construction error:', ex
   5.419 +            import traceback
   5.420 +            traceback.print_exc()
   5.421              self.destroy()
   5.422              raise
   5.423 -        return deferred
   5.424 +
   5.425 +    def register_domain(self):
   5.426 +        xd = get_component('xen.xend.XendDomain')
   5.427 +        xd._add_domain(self)
   5.428 +
   5.429 +    def configure_cpus(self, config):
   5.430 +        try:
   5.431 +            self.cpu_weight = float(sxp.child_value(config, 'cpu_weight', '1'))
   5.432 +        except:
   5.433 +            raise VmError('invalid cpu weight')
   5.434 +        self.memory = int(sxp.child_value(config, 'memory'))
   5.435 +        if self.memory is None:
   5.436 +            raise VmError('missing memory size')
   5.437 +        cpu = sxp.child_value(config, 'cpu')
   5.438 +        if self.recreate and self.dom and cpu is not None:
   5.439 +            xc.domain_pincpu(self.dom, int(cpu))
   5.440 +        try:
   5.441 +            image = sxp.child_value(self.config, 'image')
   5.442 +            vcpus = sxp.child_value(image, 'vcpus')
   5.443 +            if vcpus:
   5.444 +                self.vcpus = int(vcpus)
   5.445 +        except:
   5.446 +            raise VmError('invalid vcpus value')
   5.447  
   5.448      def find_image_handler(self):
   5.449          """Construct the boot image for the domain.
   5.450 @@ -485,7 +553,7 @@ class XendDomainInfo:
   5.451          if image_name is None:
   5.452              raise VmError('missing image name')
   5.453          if image_name == "vmx":
   5.454 -            self.is_vmx = 1
   5.455 +            self.is_vmx = True
   5.456          image_handler = get_image_handler(image_name)
   5.457          if image_handler is None:
   5.458              raise VmError('unknown image type: ' + image_name)
   5.459 @@ -513,107 +581,18 @@ class XendDomainInfo:
   5.460                  devices.append(dev)
   5.461          return devices
   5.462  
   5.463 -    def config_device(self, type, idx):
   5.464 -        """Get a device config from the device nodes of a given type
   5.465 -        from the config.
   5.466 -
   5.467 -        @param type: device type
   5.468 -        @type  type: string
   5.469 -        @param idx: index
   5.470 -        @type  idx: int
   5.471 -        @return config or None
   5.472 -        """
   5.473 -        devs = self.config_devices(type)
   5.474 -        if 0 <= idx < len(devs):
   5.475 -            return devs[idx]
   5.476 -        else:
   5.477 -            return None
   5.478 -
   5.479 -    def next_device_index(self, type):
   5.480 -        """Get the next index for a given device type.
   5.481 -
   5.482 -        @param type: device type
   5.483 -        @type  type: string
   5.484 -        @return device index
   5.485 -        @rtype: int
   5.486 -        """
   5.487 -        idx = self.device_index.get(type, 0)
   5.488 -        self.device_index[type] = idx + 1
   5.489 -        return idx
   5.490 -
   5.491 -    def add_device(self, type, dev):
   5.492 -        """Add a device to a virtual machine.
   5.493 -
   5.494 -        @param type: device type
   5.495 -        @param dev:  device to add
   5.496 -        """
   5.497 -        dl = self.devices.get(type, [])
   5.498 -        dl.append(dev)
   5.499 -        self.devices[type] = dl
   5.500 -
   5.501 -    def refresh_device(self, type, dev):
   5.502 -        """Refresh a device to a virtual machine.
   5.503 -
   5.504 -        @param type: device type
   5.505 -        @param dev:  device
   5.506 -        """
   5.507 -        dl = self.devices.get(type, [])
   5.508 -        if dev in dl:
   5.509 -            dl.refresh(dev)
   5.510 -
   5.511 -    def remove_device(self, type, dev):
   5.512 -        """Remove a device from a virtual machine.
   5.513 -
   5.514 -        @param type: device type
   5.515 -        @param dev:  device
   5.516 -        """
   5.517 -        dl = self.devices.get(type, [])
   5.518 -        if dev in dl:
   5.519 -            dl.remove(dev)
   5.520 -
   5.521 -    def get_devices(self, type):
   5.522 -        """Get a list of the devices of a given type.
   5.523 -
   5.524 -        @param type: device type
   5.525 -        @return: devices
   5.526 -        """
   5.527 -        val = self.devices.get(type, [])
   5.528 -        return val
   5.529 -
   5.530 -    def get_device_by_id(self, type, id):
   5.531 -        """Get the device with the given id.
   5.532 -
   5.533 -        @param id:       device id
   5.534 -        @return:  device or None
   5.535 -        """
   5.536 -        dl = self.get_devices(type)
   5.537 -        for d in dl:
   5.538 -            if d.getprop('id') == id:
   5.539 -                return d
   5.540 -        return None
   5.541 -
   5.542 -    def get_device_by_index(self, type, idx):
   5.543 -        """Get the device with the given index.
   5.544 -
   5.545 -        @param idx: device index
   5.546 -        @return:  device or None
   5.547 -        """
   5.548 -        idx = str(idx)
   5.549 -        dl = self.get_devices(type)
   5.550 -        for d in dl:
   5.551 -            if d.getidx() == idx:
   5.552 -                return d
   5.553 -        return None
   5.554 -
   5.555      def get_device_savedinfo(self, type, index):
   5.556          val = None
   5.557          if self.savedinfo is None:
   5.558              return val
   5.559 -        index = str(index)
   5.560          devinfo = sxp.child(self.savedinfo, 'devices')
   5.561          if devinfo is None:
   5.562              return val
   5.563 -        for d in sxp.children(devinfo, type):
   5.564 +        devs = sxp.child(devinfo, type)
   5.565 +        if devs is None:
   5.566 +            return val
   5.567 +        index = str(index)
   5.568 +        for d in sxp.children(devs):
   5.569              dindex = sxp.child_value(d, 'index')
   5.570              if dindex is None: continue
   5.571              if str(dindex) == index:
   5.572 @@ -631,10 +610,11 @@ class XendDomainInfo:
   5.573          @param period:    vif period in uSec
   5.574          @return: 0 on success
   5.575          """
   5.576 -    
   5.577 -        ctrl = xend.netif_create(self.dom, recreate=self.recreate)
   5.578 -        d = ctrl.limitDevice(vif, credit, period)
   5.579 -        return d
   5.580 +        #todo: all wrong
   5.581 +        #ctrl = xend.netif_create(self.dom, recreate=self.recreate)
   5.582 +        #d = ctrl.limitDevice(vif, credit, period)
   5.583 +        #return d
   5.584 +        pass
   5.585      
   5.586      def add_config(self, val):
   5.587          """Add configuration data to a virtual machine.
   5.588 @@ -654,25 +634,15 @@ class XendDomainInfo:
   5.589          The domain will not finally go away unless all vm
   5.590          devices have been released.
   5.591          """
   5.592 +        if self.channel:
   5.593 +            self.channel.close()
   5.594 +            self.channel = None
   5.595          if self.dom is None: return 0
   5.596 -        self.destroy_console()
   5.597 -        chan = xend.getDomChannel(self.dom)
   5.598 -        if chan:
   5.599 -            log.debug("Closing channel to domain %d", self.dom)
   5.600 -            chan.close()
   5.601          try:
   5.602              return xc.domain_destroy(dom=self.dom)
   5.603          except Exception, err:
   5.604              log.exception("Domain destroy failed: %s", self.name)
   5.605  
   5.606 -    def destroy_console(self):
   5.607 -        if self.console:
   5.608 -            if self.restart_pending():
   5.609 -                self.console.deregisterChannel()
   5.610 -            else:
   5.611 -                log.debug('Closing console, domain %s', self.id)
   5.612 -                self.console.close()
   5.613 -
   5.614      def cleanup(self):
   5.615          """Cleanup vm resources: release devices.
   5.616          """
   5.617 @@ -687,41 +657,15 @@ class XendDomainInfo:
   5.618      def release_devices(self):
   5.619          """Release all vm devices.
   5.620          """
   5.621 -        self.release_vifs()
   5.622 -        self.release_vbds()
   5.623 -        self.release_usbifs()
   5.624 -        
   5.625 -        self.devices = {}
   5.626 -        self.device_index = {}
   5.627 -        self.configs = []
   5.628 -        self.ipaddrs = []
   5.629 -
   5.630 -    def release_vifs(self):
   5.631 -        """Release vm virtual network devices (vifs).
   5.632 -        """
   5.633 -        if self.dom is None: return
   5.634 -        ctrl = xend.netif_get(self.dom)
   5.635 -        if ctrl:
   5.636 -            log.debug("Destroying vifs for domain %d", self.dom)
   5.637 -            ctrl.destroy()
   5.638 -
   5.639 -    def release_vbds(self):
   5.640 -        """Release vm virtual block devices (vbds).
   5.641 -        """
   5.642 -        if self.dom is None: return
   5.643 -        ctrl = xend.blkif_get(self.dom)
   5.644 -        if ctrl:
   5.645 -            log.debug("Destroying vbds for domain %d", self.dom)
   5.646 -            ctrl.destroy()
   5.647 -
   5.648 -    def release_usbifs(self):
   5.649 -        """Release vm virtual USB devices (usbifs).
   5.650 -        """
   5.651 -        if self.dom is None: return
   5.652 -        ctrl = xend.usbif_get(self.dom)
   5.653 -        if ctrl:
   5.654 -            log.debug("Destroying usbifs for domain %d", self.dom)
   5.655 -            ctrl.destroy()
   5.656 +        reboot = self.restart_pending()
   5.657 +        for ctrl in self.getDeviceControllers():
   5.658 +            if ctrl.isDestroyed(): continue
   5.659 +            ctrl.destroyController(reboot=reboot)
   5.660 +        if not reboot:
   5.661 +            self.devices = {}
   5.662 +            self.device_index = {}
   5.663 +            self.configs = []
   5.664 +            self.ipaddrs = []
   5.665  
   5.666      def show(self):
   5.667          """Print virtual machine info.
   5.668 @@ -752,10 +696,6 @@ class XendDomainInfo:
   5.669              return
   5.670          dom = self.dom or 0
   5.671          memory = self.memory
   5.672 -        name = self.name
   5.673 -        # If the name is over the xen limit, use the end of it.
   5.674 -        if len(name) > MAX_DOMAIN_NAME:
   5.675 -            name = name[-MAX_DOMAIN_NAME:]
   5.676          try:
   5.677              cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
   5.678          except:
   5.679 @@ -766,8 +706,8 @@ class XendDomainInfo:
   5.680                                 cpu= cpu, cpu_weight= cpu_weight)
   5.681          if dom <= 0:
   5.682              raise VmError('Creating domain failed: name=%s memory=%d'
   5.683 -                          % (name, memory))
   5.684 -        log.debug('init_domain> Created domain=%d name=%s memory=%d', dom, name, memory)
   5.685 +                          % (self.name, memory))
   5.686 +        log.debug('init_domain> Created domain=%d name=%s memory=%d', dom, self.name, memory)
   5.687          self.setdom(dom)
   5.688  
   5.689      def build_domain(self, ostype, kernel, ramdisk, cmdline, memmap):
   5.690 @@ -785,28 +725,29 @@ class XendDomainInfo:
   5.691          flags = 0
   5.692          if self.netif_backend: flags |= SIF_NET_BE_DOMAIN
   5.693          if self.blkif_backend: flags |= SIF_BLK_BE_DOMAIN
   5.694 -	if ostype == "vmx":
   5.695 -        	err = buildfn(dom      = dom,
   5.696 -               	      	image          = kernel,
   5.697 -                      	control_evtchn = 0,
   5.698 -                        memsize        = self.memory,
   5.699 -			memmap	       = memmap,
   5.700 -                      	cmdline        = cmdline,
   5.701 -                      	ramdisk        = ramdisk,
   5.702 -                      	flags          = flags)
   5.703 -	else:
   5.704 -        	log.warning('building dom with %d vcpus', self.vcpus)
   5.705 -        	err = buildfn(dom            = dom,
   5.706 -               	      	image          = kernel,
   5.707 -                      	control_evtchn = self.console.getRemotePort(),
   5.708 -                      	cmdline        = cmdline,
   5.709 -                      	ramdisk        = ramdisk,
   5.710 -                      	flags          = flags,
   5.711 -                      	vcpus          = self.vcpus)
   5.712 -        if err != 0:
   5.713 -            raise VmError('Building domain failed: type=%s dom=%d err=%d'
   5.714 -                          % (ostype, dom, err))
   5.715 -
   5.716 +        #todo generalise this
   5.717 +        if ostype == "vmx":
   5.718 +            err = buildfn(dom            = dom,
   5.719 +                          image          = kernel,
   5.720 +                          control_evtchn = 0,
   5.721 +                          memsize        = self.memory,
   5.722 +                          memmap         = memmap,
   5.723 +                          cmdline        = cmdline,
   5.724 +                          ramdisk        = ramdisk,
   5.725 +                          flags          = flags)
   5.726 +        else:
   5.727 +            log.warning('building dom with %d vcpus', self.vcpus)
   5.728 +            err = buildfn(dom            = dom,
   5.729 +                          image          = kernel,
   5.730 +                          control_evtchn = self.channel.getRemotePort(),
   5.731 +                          cmdline        = cmdline,
   5.732 +                          ramdisk        = ramdisk,
   5.733 +                          flags          = flags,
   5.734 +                          vcpus          = self.vcpus)
   5.735 +            if err != 0:
   5.736 +                raise VmError('Building domain failed: type=%s dom=%d err=%d'
   5.737 +                              % (ostype, dom, err))
   5.738 +            
   5.739      def create_domain(self, ostype, kernel, ramdisk, cmdline, memmap=''):
   5.740          """Create a domain. Builds the image but does not configure it.
   5.741  
   5.742 @@ -817,87 +758,87 @@ class XendDomainInfo:
   5.743          """
   5.744  
   5.745          self.create_channel()
   5.746 -        if self.console:
   5.747 -            self.console.registerChannel()
   5.748 -        else:
   5.749 -            self.console = xendConsole.console_create(
   5.750 -                self.dom, console_port=self.console_port)
   5.751          self.build_domain(ostype, kernel, ramdisk, cmdline, memmap)
   5.752          self.image = kernel
   5.753          self.ramdisk = ramdisk
   5.754          self.cmdline = cmdline
   5.755  
   5.756      def create_channel(self):
   5.757 -        """Create the channel to the domain.
   5.758 +        """Create the control channel to the domain.
   5.759          If saved info is available recreate the channel using the saved ports.
   5.760 -
   5.761 -        @return: channel
   5.762          """
   5.763          local = 0
   5.764          remote = 1
   5.765          if self.savedinfo:
   5.766 -            consinfo = sxp.child(self.savedinfo, "console")
   5.767 -            if consinfo:
   5.768 -                local = int(sxp.child_value(consinfo, "local_port", 0))
   5.769 -                remote = int(sxp.child_value(consinfo, "remote_port", 1))
   5.770 -        return xend.createDomChannel(self.dom, local_port=local,
   5.771 -                                     remote_port=remote)
   5.772 +            info = sxp.child(self.savedinfo, "channel")
   5.773 +            if info:
   5.774 +                local = int(sxp.child_value(info, "local_port", 0))
   5.775 +                remote = int(sxp.child_value(info, "remote_port", 1))
   5.776 +        self.channel = channelFactory().openChannel(self.dom,
   5.777 +                                                    local_port=local,
   5.778 +                                                    remote_port=remote)
   5.779  
   5.780 +    def create_configured_devices(self):
   5.781 +        devices = sxp.children(self.config, 'device')
   5.782 +        indexes = {}
   5.783 +        for d in devices:
   5.784 +            dev_config = sxp.child0(d)
   5.785 +            if dev_config is None:
   5.786 +                raise VmError('invalid device')
   5.787 +            dev_type = sxp.name(dev_config)
   5.788 +            ctrl_type = get_device_handler(dev_type)
   5.789 +            if ctrl_type is None:
   5.790 +                raise VmError('unknown device type: ' + dev_type)
   5.791 +            # Keep track of device indexes by type, so we can fish
   5.792 +            # out saved info for recreation.
   5.793 +            idx = indexes.get(dev_type, -1)
   5.794 +            idx += 1
   5.795 +            indexes[ctrl_type] = idx
   5.796 +            recreate = self.get_device_recreate(dev_type, idx)
   5.797 +            self.createDevice(ctrl_type, dev_config, recreate=recreate)
   5.798 +        
   5.799      def create_devices(self):
   5.800          """Create the devices for a vm.
   5.801  
   5.802 -        @return: Deferred
   5.803          @raise: VmError for invalid devices
   5.804          """
   5.805 -        dlist = []
   5.806 -        devices = sxp.children(self.config, 'device')
   5.807 -        index = {}
   5.808 -        for d in devices:
   5.809 -            dev = sxp.child0(d)
   5.810 -            if dev is None:
   5.811 -                raise VmError('invalid device')
   5.812 -            dev_name = sxp.name(dev)
   5.813 -            dev_index = index.get(dev_name, 0)
   5.814 -            dev_handler = get_device_handler(dev_name)
   5.815 -            if dev_handler is None:
   5.816 -                raise VmError('unknown device type: ' + dev_name)
   5.817 -            v = dev_handler(self, dev, dev_index)
   5.818 -            append_deferred(dlist, v)
   5.819 -            index[dev_name] = dev_index + 1
   5.820 -        deferred = defer.DeferredList(dlist, fireOnOneErrback=1)
   5.821 -        deferred.addErrback(dlist_err)
   5.822 +        if self.rebooting():
   5.823 +            for ctrl in self.getDeviceControllers():
   5.824 +                ctrl.initController(reboot=True)
   5.825 +        else:
   5.826 +            self.create_configured_devices()
   5.827          if self.is_vmx:
   5.828 -            device_model = sxp.child_value(self.config, 'device_model')
   5.829 -            device_config = sxp.child_value(self.config, 'device_config')
   5.830 -            memory = sxp.child_value(self.config, "memory")
   5.831 -            # Create an event channel
   5.832 -            device_channel = channel.eventChannel(0, self.dom)
   5.833 -            # Fork and exec device_model -f device_config <port>
   5.834 -            os.system(device_model
   5.835 -                      + " -f %s" % device_config
   5.836 -                      + " -d %d" % self.dom
   5.837 -                      + " -p %d" % device_channel['port1']
   5.838 -                      + " -m %s" % memory)
   5.839 -        return deferred
   5.840 +            self.create_vmx_model()
   5.841 +
   5.842 +    def create_vmx_model(self):
   5.843 +        #todo: remove special case for vmx
   5.844 +        device_model = sxp.child_value(self.config, 'device_model')
   5.845 +        if not device_model:
   5.846 +            raise VmError("vmx: missing device model")
   5.847 +        device_config = sxp.child_value(self.config, 'device_config')
   5.848 +        if not device_config:
   5.849 +            raise VmError("vmx: missing device config")
   5.850 +        #todo: self.memory?
   5.851 +        memory = sxp.child_value(self.config, "memory")
   5.852 +        # Create an event channel
   5.853 +        device_channel = channel.eventChannel(0, self.dom)
   5.854 +        # Execute device model.
   5.855 +        #todo: Error handling
   5.856 +        os.system(device_model
   5.857 +                  + " -f %s" % device_config
   5.858 +                  + " -d %d" % self.dom
   5.859 +                  + " -p %d" % device_channel['port1']
   5.860 +                  + " -m %s" % memory)
   5.861  
   5.862      def device_create(self, dev_config):
   5.863          """Create a new device.
   5.864  
   5.865          @param dev_config: device configuration
   5.866 -        @return: deferred
   5.867          """
   5.868 -        dev_name = sxp.name(dev_config)
   5.869 -        dev_handler = get_device_handler(dev_name)
   5.870 -        if dev_handler is None:
   5.871 -            raise VmError('unknown device type: ' + dev_name)
   5.872 -        devs = self.get_devices(dev_name)
   5.873 -        dev_index = len(devs)
   5.874 -        self.config.append(['device', dev_config])
   5.875 -        d = dev_handler(self, dev_config, dev_index, change=1)
   5.876 -        def cbok(dev):
   5.877 -            return dev.sxpr()
   5.878 -        d.addCallback(cbok)
   5.879 -        return d
   5.880 +        dev_type = sxp.name(dev_config)
   5.881 +        dev = self.createDevice(self, dev_config, change=True)
   5.882 +        self.config.append(['device', dev.getConfig()])
   5.883 +        return dev.sxpr()
   5.884  
   5.885      def device_configure(self, dev_config, idx):
   5.886          """Configure an existing device.
   5.887 @@ -906,16 +847,11 @@ class XendDomainInfo:
   5.888          @param idx:  device index
   5.889          """
   5.890          type = sxp.name(dev_config)
   5.891 -        dev = self.get_device_by_index(type, idx)
   5.892 +        dev = self.getDeviceByIndex(type, idx)
   5.893          if not dev:
   5.894              raise VmError('invalid device: %s %s' % (type, idx))
   5.895 -        new_config = dev.configure(dev_config, change=1)
   5.896 -        devs = self.devices.get(type)
   5.897 -        index = devs.index(dev)
   5.898 -        # Patch new config into device configs.
   5.899 -        dev_configs = self.config_devices(type)
   5.900 -        old_config = dev_configs[index]
   5.901 -        dev_configs[index] = new_config
   5.902 +        old_config = dev.getConfig()
   5.903 +        new_config = dev.configure(dev_config, change=True)
   5.904          # Patch new config into vm config.
   5.905          new_full_config = ['device', new_config]
   5.906          old_full_config = ['device', old_config]
   5.907 @@ -929,37 +865,24 @@ class XendDomainInfo:
   5.908          @param type: device type
   5.909          @param idx:  device index
   5.910          """
   5.911 -        dev = self.get_device_by_index(type, idx)
   5.912 +        dev = self.getDeviceByIndex(type, idx)
   5.913          if not dev:
   5.914              raise VmError('invalid device: %s %s' % (type, idx))
   5.915 -        devs = self.devices.get(type)
   5.916          dev.refresh()
   5.917 -        #self.refresh_device(type, dev)
   5.918          
   5.919 -    def device_destroy(self, type, idx):
   5.920 -        """Destroy a device.
   5.921 +    def device_delete(self, type, idx):
   5.922 +        """Destroy and remove a device.
   5.923  
   5.924          @param type: device type
   5.925          @param idx:  device index
   5.926          """
   5.927 -        dev = self.get_device_by_index(type, idx)
   5.928 +        dev = self.getDeviceByIndex(type, idx)
   5.929          if not dev:
   5.930              raise VmError('invalid device: %s %s' % (type, idx))
   5.931 -        devs = self.devices.get(type)
   5.932 -        index = devs.index(dev)
   5.933 -        dev_config = self.config_device(type, index)
   5.934 +        dev_config = dev.getConfig()
   5.935          if dev_config:
   5.936              self.config.remove(['device', dev_config])
   5.937 -        dev.destroy(change=1)
   5.938 -        self.remove_device(type, dev)
   5.939 -
   5.940 -    def configure_memory(self):
   5.941 -        """Configure vm memory limit.
   5.942 -        """
   5.943 -        maxmem = sxp.child_value(self.config, "maxmem")
   5.944 -        if maxmem is None:
   5.945 -            maxmem = self.memory
   5.946 -        xc.domain_setmaxmem(self.dom, maxmem_kb = maxmem * 1024)
   5.947 +        self.deleteDevice(type, dev.getId())
   5.948  
   5.949      def configure_console(self):
   5.950          """Configure the vm console port.
   5.951 @@ -985,15 +908,15 @@ class XendDomainInfo:
   5.952          for the given reason.
   5.953  
   5.954          @param reason: shutdown reason
   5.955 -        @return 1 if needs restaert, 0 otherwise
   5.956 +        @return True if needs restart, False otherwise
   5.957          """
   5.958          if self.restart_mode == RESTART_NEVER:
   5.959 -            return 0
   5.960 +            return False
   5.961          if self.restart_mode == RESTART_ALWAYS:
   5.962 -            return 1
   5.963 +            return True
   5.964          if self.restart_mode == RESTART_ONREBOOT:
   5.965              return reason == 'reboot'
   5.966 -        return 0
   5.967 +        return False
   5.968  
   5.969      def restart_cancel(self):
   5.970          """Cancel a vm restart.
   5.971 @@ -1010,6 +933,9 @@ class XendDomainInfo:
   5.972          """
   5.973          return self.restart_state == STATE_RESTART_PENDING
   5.974  
   5.975 +    def rebooting(self):
   5.976 +        return self.restart_state == STATE_RESTART_BOOTING
   5.977 +
   5.978      def restart_check(self):
   5.979          """Check if domain restart is OK.
   5.980          To prevent restart loops, raise an error if it is
   5.981 @@ -1024,20 +950,20 @@ class XendDomainInfo:
   5.982                  log.error(msg)
   5.983                  raise VmError(msg)
   5.984          self.restart_time = tnow
   5.985 +        self.restart_count += 1
   5.986  
   5.987      def restart(self):
   5.988          """Restart the domain after it has exited.
   5.989          Reuses the domain id and console port.
   5.990  
   5.991 -        @return: deferred
   5.992          """
   5.993          try:
   5.994 +            self.state = STATE_VM_OK
   5.995              self.restart_check()
   5.996              self.restart_state = STATE_RESTART_BOOTING
   5.997 -            d = self.construct(self.config)
   5.998 +            self.construct(self.config)
   5.999          finally:
  5.1000              self.restart_state = None
  5.1001 -        return d
  5.1002  
  5.1003      def configure_backends(self):
  5.1004          """Set configuration flags if the vm is a backend for netif or blkif.
  5.1005 @@ -1047,73 +973,70 @@ class XendDomainInfo:
  5.1006              v = sxp.child0(c)
  5.1007              name = sxp.name(v)
  5.1008              if name == 'blkif':
  5.1009 -                self.blkif_backend = 1
  5.1010 +                self.blkif_backend = True
  5.1011              elif name == 'netif':
  5.1012 -                self.netif_backend = 1
  5.1013 +                self.netif_backend = True
  5.1014              elif name == 'usbif':
  5.1015 -                self.usbif_backend = 1
  5.1016 +                self.usbif_backend = True
  5.1017              else:
  5.1018                  raise VmError('invalid backend type:' + str(name))
  5.1019  
  5.1020      def configure(self):
  5.1021          """Configure a vm.
  5.1022  
  5.1023 -        @return: deferred - calls callback with vm
  5.1024          """
  5.1025 -        d = self.create_devices()
  5.1026 -        d.addCallback(lambda x: self.create_blkif())
  5.1027 -        d.addCallback(self._configure)
  5.1028 -        return d
  5.1029 +        self.configure_fields()
  5.1030 +        self.create_console()
  5.1031 +        self.create_devices()
  5.1032 +        self.create_blkif()
  5.1033  
  5.1034 -    def _configure(self, val):
  5.1035 -        d = self.configure_fields()
  5.1036 -        def cbok(results):
  5.1037 -            return self
  5.1038 -        def cberr(err):
  5.1039 -            self.destroy()
  5.1040 -            return err
  5.1041 -        d.addCallback(cbok)
  5.1042 -        d.addErrback(cberr)
  5.1043 -        return d
  5.1044 +    def create_console(self):
  5.1045 +        console = self.getConsole()
  5.1046 +        if not console:
  5.1047 +            config = ['console']
  5.1048 +            if self.console_port:
  5.1049 +                config.append(['console_port', self.console_port])
  5.1050 +            console = self.createDevice('console', config)
  5.1051 +        return console
  5.1052 +
  5.1053 +    def getConsole(self):
  5.1054 +        console_ctrl = self.getDeviceController("console", error=False)
  5.1055 +        if console_ctrl:
  5.1056 +            return console_ctrl.getDevice(0)
  5.1057 +        return None
  5.1058  
  5.1059      def create_blkif(self):
  5.1060          """Create the block device interface (blkif) for the vm.
  5.1061          The vm needs a blkif even if it doesn't have any disks
  5.1062          at creation time, for example when it uses NFS root.
  5.1063  
  5.1064 -        @return: deferred
  5.1065          """
  5.1066 -        if self.get_devices("vbd") == []:
  5.1067 -            ctrl = xend.blkif_create(self.dom, recreate=self.recreate)
  5.1068 -            back = ctrl.getBackendInterface(0)
  5.1069 -            return back.connect(recreate=self.recreate)
  5.1070 -        else:
  5.1071 -            return None
  5.1072 +        blkif = self.getDeviceController("blkif", error=False)
  5.1073 +        if not blkif:
  5.1074 +            blkif = self.createDeviceController("blkif")
  5.1075 +            backend = blkif.getBackend(0)
  5.1076 +            backend.connect(recreate=self.recreate)
  5.1077  
  5.1078      def dom_construct(self, dom, config):
  5.1079          """Construct a vm for an existing domain.
  5.1080  
  5.1081          @param dom: domain id
  5.1082          @param config: domain configuration
  5.1083 -        @return: deferred
  5.1084          """
  5.1085          d = dom_get(dom)
  5.1086          if not d:
  5.1087              raise VmError("Domain not found: %d" % dom)
  5.1088          try:
  5.1089 -            self.restore = 1
  5.1090 +            self.restore = True
  5.1091              self.setdom(dom)
  5.1092 -            #self.name = d['name']
  5.1093              self.memory = d['mem_kb']/1024
  5.1094 -            deferred = self.construct(config)
  5.1095 +            self.construct(config)
  5.1096          finally:
  5.1097 -            self.restore = 0
  5.1098 -        return deferred
  5.1099 +            self.restore = False
  5.1100  
  5.1101      def configure_fields(self):
  5.1102          """Process the vm configuration fields using the registered handlers.
  5.1103          """
  5.1104 -        dlist = []
  5.1105          index = {}
  5.1106          for field in sxp.children(self.config):
  5.1107              field_name = sxp.name(field)
  5.1108 @@ -1122,13 +1045,9 @@ class XendDomainInfo:
  5.1109              # Ignore unknown fields. Warn?
  5.1110              if field_handler:
  5.1111                  v = field_handler(self, self.config, field, field_index)
  5.1112 -                append_deferred(dlist, v)
  5.1113              else:
  5.1114                  log.warning("Unknown config field %s", field_name)
  5.1115              index[field_name] = field_index + 1
  5.1116 -        d = defer.DeferredList(dlist, fireOnOneErrback=1)
  5.1117 -        d.addErrback(dlist_err)
  5.1118 -        return d
  5.1119  
  5.1120      def pgtable_size(self, memory):
  5.1121          """Return the size of memory needed for 1:1 page tables for physical
  5.1122 @@ -1143,6 +1062,25 @@ class XendDomainInfo:
  5.1123              return (1 + ((memory + 3) >> 2)) * 4
  5.1124          return 0
  5.1125  
  5.1126 +    def mem_target_set(self, target):
  5.1127 +        """Set domain memory target in pages.
  5.1128 +        """
  5.1129 +        if self.channel:
  5.1130 +            msg = messages.packMsg('mem_request_t', { 'target' : target * (1 << 8)} )
  5.1131 +            self.channel.writeRequest(msg)
  5.1132 +
  5.1133 +    def shutdown(self, reason, key=0):
  5.1134 +        msgtype = shutdown_messages.get(reason)
  5.1135 +        if not msgtype:
  5.1136 +            raise XendError('invalid reason:' + reason)
  5.1137 +        extra = {}
  5.1138 +        if reason == 'sysrq':
  5.1139 +            extra['key'] = key
  5.1140 +        if self.channel:
  5.1141 +            msg = messages.packMsg(msgtype, extra)
  5.1142 +            self.channel.writeRequest(msg)
  5.1143 +
  5.1144 +
  5.1145  def vm_image_linux(vm, image):
  5.1146      """Create a VM for a linux image.
  5.1147  
  5.1148 @@ -1175,7 +1113,6 @@ def vm_image_plan9(vm, image):
  5.1149  
  5.1150      returns vm 
  5.1151      """
  5.1152 -    #todo: Same as for linux. Is that right? If so can unify them.
  5.1153      kernel = sxp.child_value(image, "kernel")
  5.1154      cmdline = ""
  5.1155      ip = sxp.child_value(image, "ip", "dhcp")
  5.1156 @@ -1188,7 +1125,6 @@ def vm_image_plan9(vm, image):
  5.1157      if args:
  5.1158          cmdline += " " + args
  5.1159      ramdisk = sxp.child_value(image, "ramdisk", '')
  5.1160 -    vifs = vm.config_devices("vif")
  5.1161      vm.create_domain("plan9", kernel, ramdisk, cmdline)
  5.1162      return vm
  5.1163      
  5.1164 @@ -1219,115 +1155,6 @@ def vm_image_vmx(vm, image):
  5.1165      vm.create_domain("vmx", kernel, ramdisk, cmdline, memmap)
  5.1166      return vm
  5.1167  
  5.1168 -def vm_dev_vif(vm, val, index, change=0):
  5.1169 -    """Create a virtual network interface (vif).
  5.1170 -
  5.1171 -    @param vm:        virtual machine
  5.1172 -    @param val:       vif config
  5.1173 -    @param index:     vif index
  5.1174 -    @return: deferred
  5.1175 -    """
  5.1176 -    vif = vm.next_device_index('vif')
  5.1177 -    vmac = sxp.child_value(val, "mac")
  5.1178 -    ctrl = xend.netif_create(vm.dom, recreate=vm.recreate)
  5.1179 -    log.debug("Creating vif dom=%d vif=%d mac=%s", vm.dom, vif, str(vmac))
  5.1180 -    recreate = vm.get_device_recreate('vif', index)
  5.1181 -    defer = ctrl.attachDevice(vif, val, recreate=recreate)
  5.1182 -    def cbok(dev):
  5.1183 -        dev.vifctl('up', vmname=vm.name)
  5.1184 -        dev.setIndex(index)
  5.1185 -        vm.add_device('vif', dev)
  5.1186 -        if change:
  5.1187 -            dev.interfaceChanged()
  5.1188 -        return dev
  5.1189 -    defer.addCallback(cbok)
  5.1190 -    return defer
  5.1191 -
  5.1192 -def vm_dev_usb(vm, val, index):
  5.1193 -    """Attach the relevant physical ports to the domains' USB interface.
  5.1194 -
  5.1195 -    @param vm:    virtual machine
  5.1196 -    @param val:   USB interface config
  5.1197 -    @param index: USB interface index
  5.1198 -    @return: deferred
  5.1199 -    """
  5.1200 -    ctrl = xend.usbif_create(vm.dom, recreate=vm.recreate)
  5.1201 -    log.debug("Creating USB interface dom=%d", vm.dom)
  5.1202 -    defer = ctrl.attachDevice(val, recreate=vm.recreate)
  5.1203 -    def cbok(path):
  5.1204 -        vm.add_device('usb', val[1][1])
  5.1205 -        return path
  5.1206 -    defer.addCallback(cbok)
  5.1207 -    return defer
  5.1208 -
  5.1209 -def vm_dev_vbd(vm, val, index, change=0):
  5.1210 -    """Create a virtual block device (vbd).
  5.1211 -
  5.1212 -    @param vm:        virtual machine
  5.1213 -    @param val:       vbd config
  5.1214 -    @param index:     vbd index
  5.1215 -    @return: deferred
  5.1216 -    """
  5.1217 -    idx = vm.next_device_index('vbd')
  5.1218 -    uname = sxp.child_value(val, 'uname')
  5.1219 -    log.debug("Creating vbd dom=%d uname=%s", vm.dom, uname)
  5.1220 -    ctrl = xend.blkif_create(vm.dom, recreate=vm.recreate)
  5.1221 -    recreate = vm.get_device_recreate('vbd', index)
  5.1222 -    defer = ctrl.attachDevice(idx, val, recreate=recreate)
  5.1223 -    def cbok(dev):
  5.1224 -        dev.setIndex(index)
  5.1225 -        vm.add_device('vbd', dev)
  5.1226 -        if change:
  5.1227 -            dev.interfaceChanged()
  5.1228 -        return dev
  5.1229 -    defer.addCallback(cbok)
  5.1230 -    return defer
  5.1231 -
  5.1232 -def parse_pci(val):
  5.1233 -    """Parse a pci field.
  5.1234 -    """
  5.1235 -    if isinstance(val, types.StringType):
  5.1236 -        radix = 10
  5.1237 -        if val.startswith('0x') or val.startswith('0X'):
  5.1238 -            radix = 16
  5.1239 -        v = int(val, radix)
  5.1240 -    else:
  5.1241 -        v = val
  5.1242 -    return v
  5.1243 -
  5.1244 -def vm_dev_pci(vm, val, index, change=0):
  5.1245 -    """Add a pci device.
  5.1246 -
  5.1247 -    @param vm: virtual machine
  5.1248 -    @param val: device configuration
  5.1249 -    @param index: device index
  5.1250 -    @return: 0 on success
  5.1251 -    """
  5.1252 -    bus = sxp.child_value(val, 'bus')
  5.1253 -    if not bus:
  5.1254 -        raise VmError('pci: Missing bus')
  5.1255 -    dev = sxp.child_value(val, 'dev')
  5.1256 -    if not dev:
  5.1257 -        raise VmError('pci: Missing dev')
  5.1258 -    func = sxp.child_value(val, 'func')
  5.1259 -    if not func:
  5.1260 -        raise VmError('pci: Missing func')
  5.1261 -    try:
  5.1262 -        bus = parse_pci(bus)
  5.1263 -        dev = parse_pci(dev)
  5.1264 -        func = parse_pci(func)
  5.1265 -    except:
  5.1266 -        raise VmError('pci: invalid parameter')
  5.1267 -    log.debug("Creating pci device dom=%d bus=%x dev=%x func=%x", vm.dom, bus, dev, func)
  5.1268 -    rc = xc.physdev_pci_access_modify(dom=vm.dom, bus=bus, dev=dev,
  5.1269 -                                      func=func, enable=1)
  5.1270 -    if rc < 0:
  5.1271 -        #todo non-fatal
  5.1272 -        raise VmError('pci: Failed to configure device: bus=%s dev=%s func=%s' %
  5.1273 -                      (bus, dev, func))
  5.1274 -    return rc
  5.1275 -    
  5.1276 -
  5.1277  def vm_field_ignore(vm, config, val, index):
  5.1278      """Dummy config field handler used for fields with built-in handling.
  5.1279  
  5.1280 @@ -1355,16 +1182,11 @@ def vm_field_maxmem(vm, config, val, ind
  5.1281          raise VmError("invalid maxmem: " + str(maxmem))
  5.1282      xc.domain_setmaxmem(vm.dom, maxmem_kb = maxmem * 1024)
  5.1283  
  5.1284 +#============================================================================
  5.1285  # Register image handlers.
  5.1286 -add_image_handler('linux',  vm_image_linux)
  5.1287 -add_image_handler('plan9',  vm_image_plan9)
  5.1288 -add_image_handler('vmx',  vm_image_vmx)
  5.1289 -
  5.1290 -# Register device handlers.
  5.1291 -add_device_handler('vif',  vm_dev_vif)
  5.1292 -add_device_handler('vbd',  vm_dev_vbd)
  5.1293 -add_device_handler('pci',  vm_dev_pci)
  5.1294 -add_device_handler('usb',  vm_dev_usb)
  5.1295 +add_image_handler('linux', vm_image_linux)
  5.1296 +add_image_handler('plan9', vm_image_plan9)
  5.1297 +add_image_handler('vmx',   vm_image_vmx)
  5.1298  
  5.1299  # Ignore the fields we already handle.
  5.1300  add_config_handler('name',       vm_field_ignore)
  5.1301 @@ -1380,3 +1202,27 @@ add_config_handler('vcpus',      vm_fiel
  5.1302  
  5.1303  # Register other config handlers.
  5.1304  add_config_handler('maxmem',     vm_field_maxmem)
  5.1305 +
  5.1306 +#============================================================================
  5.1307 +# Register device controllers and their device config types.
  5.1308 +
  5.1309 +from server import console
  5.1310 +controller.addDevControllerClass("console", console.ConsoleController)
  5.1311 +
  5.1312 +from server import blkif
  5.1313 +controller.addDevControllerClass("blkif", blkif.BlkifController)
  5.1314 +add_device_handler("vbd", "blkif")
  5.1315 +
  5.1316 +from server import netif
  5.1317 +controller.addDevControllerClass("netif", netif.NetifController)
  5.1318 +add_device_handler("vif", "netif")
  5.1319 +
  5.1320 +from server import pciif
  5.1321 +controller.addDevControllerClass("pciif", pciif.PciController)
  5.1322 +add_device_handler("pci", "pciif")
  5.1323 +
  5.1324 +from xen.xend.server import usbif
  5.1325 +controller.addDevControllerClass("usbif", usbif.UsbifController)
  5.1326 +add_device_handler("usb", "usbif")
  5.1327 +
  5.1328 +#============================================================================
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/tools/python/xen/xend/scheduler.py	Wed Apr 20 08:45:19 2005 +0000
     6.3 @@ -0,0 +1,41 @@
     6.4 +import threading
     6.5 +
     6.6 +class Scheduler:
     6.7 +
     6.8 +    def __init__(self):
     6.9 +        self.lock = threading.Lock()
    6.10 +        self.schedule = {}
    6.11 +
    6.12 +    def later(self, _delay, _name, _fn, args):
    6.13 +        """Schedule a function to be called later (if not already scheduled).
    6.14 +
    6.15 +        @param _delay: delay in seconds
    6.16 +        @param _name:  schedule name
    6.17 +        @param _fn:    function
    6.18 +        @param args:   arguments
    6.19 +        """
    6.20 +        try:
    6.21 +            self.lock.acquire()
    6.22 +            if self.schedule.get(_name): return
    6.23 +            timer = threading.Timer(_delay, _fn, args=args)
    6.24 +            self.schedule[_name] = timer
    6.25 +        finally:
    6.26 +            self.lock.release()
    6.27 +        timer.start()
    6.28 +
    6.29 +    def cancel(self, name):
    6.30 +        """Cancel a scheduled function call.
    6.31 +        
    6.32 +        @param name: schedule name to cancel
    6.33 +        """
    6.34 +        try:
    6.35 +            self.lock.acquire()
    6.36 +            timer = self.schedule.get(name)
    6.37 +            if not timer:
    6.38 +                return
    6.39 +            del self.schedule[name]
    6.40 +        finally:
    6.41 +            self.lock.release()
    6.42 +        timer.cancel()
    6.43 +
    6.44 +        
     7.1 --- a/tools/python/xen/xend/server/SrvDaemon.py	Tue Apr 19 13:48:05 2005 +0000
     7.2 +++ b/tools/python/xen/xend/server/SrvDaemon.py	Wed Apr 20 08:45:19 2005 +0000
     7.3 @@ -39,294 +39,13 @@ from xen.xend.XendLogging import log
     7.4  from xen.util.ip import _readline, _readlines
     7.5  
     7.6  import channel
     7.7 -import blkif
     7.8 -import netif
     7.9 -import usbif
    7.10 -import console
    7.11 -import domain
    7.12 +import controller
    7.13 +import event
    7.14  from params import *
    7.15  
    7.16 -DAEMONIZE = 1
    7.17 +DAEMONIZE = 0
    7.18  DEBUG = 1
    7.19  
    7.20 -class NotifierProtocol(protocol.Protocol):
    7.21 -    """Asynchronous handler for i/o on the notifier (event channel).
    7.22 -    """
    7.23 -
    7.24 -    def __init__(self, channelFactory):
    7.25 -        self.channelFactory = channelFactory
    7.26 -
    7.27 -    def notificationReceived(self, idx):
    7.28 -        channel = self.channelFactory.getChannel(idx)
    7.29 -        if channel:
    7.30 -            channel.notificationReceived()
    7.31 -
    7.32 -    def connectionLost(self, reason=None):
    7.33 -        pass
    7.34 -
    7.35 -    def doStart(self):
    7.36 -        pass
    7.37 -
    7.38 -    def doStop(self):
    7.39 -        pass
    7.40 -
    7.41 -    def startProtocol(self):
    7.42 -        pass
    7.43 -
    7.44 -    def stopProtocol(self):
    7.45 -        pass
    7.46 -
    7.47 -class NotifierPort(abstract.FileDescriptor):
    7.48 -    """Transport class for the event channel.
    7.49 -    """
    7.50 -
    7.51 -    def __init__(self, daemon, notifier, proto, reactor=None):
    7.52 -        assert isinstance(proto, NotifierProtocol)
    7.53 -        abstract.FileDescriptor.__init__(self, reactor)
    7.54 -        self.daemon = daemon
    7.55 -        self.notifier = notifier
    7.56 -        self.protocol = proto
    7.57 -
    7.58 -    def startListening(self):
    7.59 -        self._bindNotifier()
    7.60 -        self._connectToProtocol()
    7.61 -
    7.62 -    def stopListening(self):
    7.63 -        if self.connected:
    7.64 -            result = self.d = defer.Deferred()
    7.65 -        else:
    7.66 -            result = None
    7.67 -        self.loseConnection()
    7.68 -        return result
    7.69 -
    7.70 -    def fileno(self):
    7.71 -        return self.notifier.fileno()
    7.72 -
    7.73 -    def _bindNotifier(self):
    7.74 -        self.connected = 1
    7.75 -
    7.76 -    def _connectToProtocol(self):
    7.77 -        self.protocol.makeConnection(self)
    7.78 -        self.startReading()
    7.79 -
    7.80 -    def loseConnection(self):
    7.81 -        if self.connected:
    7.82 -            self.stopReading()
    7.83 -            self.disconnecting = 1
    7.84 -            reactor.callLater(0, self.connectionLost)
    7.85 -
    7.86 -    def connectionLost(self, reason=None):
    7.87 -        abstract.FileDescriptor.connectionLost(self, reason)
    7.88 -        if hasattr(self, 'protocol'):
    7.89 -            self.protocol.doStop()
    7.90 -        self.connected = 0
    7.91 -        #self.notifier.close()   # (this said:) Not implemented.
    7.92 -        #os.close(self.fileno()) # But yes it is...
    7.93 -        del self.notifier        # ...as _dealloc!
    7.94 -        if hasattr(self, 'd'):
    7.95 -            self.d.callback(None)
    7.96 -            del self.d
    7.97 -        
    7.98 -    def doRead(self):
    7.99 -        count = 0
   7.100 -        while 1:            
   7.101 -            notification = self.notifier.read()
   7.102 -            if not notification:
   7.103 -                break
   7.104 -            self.protocol.notificationReceived(notification)
   7.105 -            self.notifier.unmask(notification)
   7.106 -            count += 1
   7.107 -
   7.108 -class EventProtocol(protocol.Protocol):
   7.109 -    """Asynchronous handler for a connected event socket.
   7.110 -    """
   7.111 -
   7.112 -    def __init__(self, daemon):
   7.113 -        #protocol.Protocol.__init__(self)
   7.114 -        self.daemon = daemon
   7.115 -        # Event queue.
   7.116 -        self.queue = []
   7.117 -        # Subscribed events.
   7.118 -        self.events = []
   7.119 -        self.parser = sxp.Parser()
   7.120 -        self.pretty = 0
   7.121 -
   7.122 -        # For debugging subscribe to everything and make output pretty.
   7.123 -        self.subscribe(['*'])
   7.124 -        self.pretty = 1
   7.125 -
   7.126 -    def dataReceived(self, data):
   7.127 -        try:
   7.128 -            self.parser.input(data)
   7.129 -            if self.parser.ready():
   7.130 -                val = self.parser.get_val()
   7.131 -                res = self.dispatch(val)
   7.132 -                self.send_result(res)
   7.133 -            if self.parser.at_eof():
   7.134 -                self.loseConnection()
   7.135 -        except SystemExit:
   7.136 -            raise
   7.137 -        except:
   7.138 -            if DEBUG:
   7.139 -                raise
   7.140 -            else:
   7.141 -                self.send_error()
   7.142 -
   7.143 -    def loseConnection(self):
   7.144 -        if self.transport:
   7.145 -            self.transport.loseConnection()
   7.146 -        if self.connected:
   7.147 -            reactor.callLater(0, self.connectionLost)
   7.148 -
   7.149 -    def connectionLost(self, reason=None):
   7.150 -        self.unsubscribe()
   7.151 -
   7.152 -    def send_reply(self, sxpr):
   7.153 -        io = StringIO.StringIO()
   7.154 -        if self.pretty:
   7.155 -            PrettyPrint.prettyprint(sxpr, out=io)
   7.156 -        else:
   7.157 -            sxp.show(sxpr, out=io)
   7.158 -        print >> io
   7.159 -        io.seek(0)
   7.160 -        return self.transport.write(io.getvalue())
   7.161 -
   7.162 -    def send_result(self, res):
   7.163 -        return self.send_reply(['ok', res])
   7.164 -
   7.165 -    def send_error(self):
   7.166 -        (extype, exval) = sys.exc_info()[:2]
   7.167 -        return self.send_reply(['err',
   7.168 -                                ['type', str(extype)],
   7.169 -                                ['value', str(exval)]])
   7.170 -
   7.171 -    def send_event(self, val):
   7.172 -        return self.send_reply(['event', val[0], val[1]])
   7.173 -
   7.174 -    def unsubscribe(self):
   7.175 -        for event in self.events:
   7.176 -            eserver.unsubscribe(event, self.queue_event)
   7.177 -
   7.178 -    def subscribe(self, events):
   7.179 -        self.unsubscribe()
   7.180 -        for event in events:
   7.181 -            eserver.subscribe(event, self.queue_event)
   7.182 -        self.events = events
   7.183 -
   7.184 -    def queue_event(self, name, v):
   7.185 -        # Despite the name we don't queue the event here.
   7.186 -        # We send it because the transport will queue it.
   7.187 -        self.send_event([name, v])
   7.188 -        
   7.189 -    def opname(self, name):
   7.190 -         return 'op_' + name.replace('.', '_')
   7.191 -
   7.192 -    def operror(self, name, req):
   7.193 -        raise XendError('Invalid operation: ' +name)
   7.194 -
   7.195 -    def dispatch(self, req):
   7.196 -        op_name = sxp.name(req)
   7.197 -        op_method_name = self.opname(op_name)
   7.198 -        op_method = getattr(self, op_method_name, self.operror)
   7.199 -        return op_method(op_name, req)
   7.200 -
   7.201 -    def op_help(self, name, req):
   7.202 -        def nameop(x):
   7.203 -            if x.startswith('op_'):
   7.204 -                return x[3:].replace('_', '.')
   7.205 -            else:
   7.206 -                return x
   7.207 -        
   7.208 -        l = [ nameop(k) for k in dir(self) if k.startswith('op_') ]
   7.209 -        return l
   7.210 -
   7.211 -    def op_quit(self, name, req):
   7.212 -        self.loseConnection()
   7.213 -
   7.214 -    def op_exit(self, name, req):
   7.215 -        sys.exit(0)
   7.216 -
   7.217 -    def op_pretty(self, name, req):
   7.218 -        self.pretty = 1
   7.219 -        return ['ok']
   7.220 -
   7.221 -    def op_console_disconnect(self, name, req):
   7.222 -        id = sxp.child_value(req, 'id')
   7.223 -        if not id:
   7.224 -            raise XendError('Missing console id')
   7.225 -        id = int(id)
   7.226 -        self.daemon.console_disconnect(id)
   7.227 -        return ['ok']
   7.228 -
   7.229 -    def op_info(self, name, req):
   7.230 -        val = ['info']
   7.231 -        val += self.daemon.consoles()
   7.232 -        val += self.daemon.blkifs()
   7.233 -        val += self.daemon.netifs()
   7.234 -        val += self.daemon.usbifs()
   7.235 -        return val
   7.236 -
   7.237 -    def op_sys_subscribe(self, name, v):
   7.238 -        # (sys.subscribe event*)
   7.239 -        # Subscribe to the events:
   7.240 -        self.subscribe(v[1:])
   7.241 -        return ['ok']
   7.242 -
   7.243 -    def op_sys_inject(self, name, v):
   7.244 -        # (sys.inject event)
   7.245 -        event = v[1]
   7.246 -        eserver.inject(sxp.name(event), event)
   7.247 -        return ['ok']
   7.248 -
   7.249 -    def op_trace(self, name, v):
   7.250 -        mode = (v[1] == 'on')
   7.251 -        self.daemon.tracing(mode)
   7.252 -
   7.253 -    def op_log_stderr(self, name, v):
   7.254 -        mode = v[1]
   7.255 -        logging = XendRoot.instance().get_logging()
   7.256 -        if mode == 'on':
   7.257 -            logging.addLogStderr()
   7.258 -        else:
   7.259 -            logging.removeLogStderr()
   7.260 -
   7.261 -    def op_debug_msg(self, name, v):
   7.262 -        mode = v[1]
   7.263 -        import messages
   7.264 -        messages.DEBUG = (mode == 'on')
   7.265 -
   7.266 -    def op_debug_controller(self, name, v):
   7.267 -        mode = v[1]
   7.268 -        import controller
   7.269 -        controller.DEBUG = (mode == 'on')
   7.270 -
   7.271 -
   7.272 -class EventFactory(protocol.Factory):
   7.273 -    """Asynchronous handler for the event server socket.
   7.274 -    """
   7.275 -    protocol = EventProtocol
   7.276 -    service = None
   7.277 -
   7.278 -    def __init__(self, daemon):
   7.279 -        #protocol.Factory.__init__(self)
   7.280 -        self.daemon = daemon
   7.281 -
   7.282 -    def buildProtocol(self, addr):
   7.283 -        proto = self.protocol(self.daemon)
   7.284 -        proto.factory = self
   7.285 -        return proto
   7.286 -
   7.287 -class VirqClient:
   7.288 -    def __init__(self, daemon):
   7.289 -        self.daemon = daemon
   7.290 -
   7.291 -    def virqReceived(self, virq):
   7.292 -        print 'VirqClient.virqReceived>', virq
   7.293 -        eserver.inject('xend.virq', virq)
   7.294 -
   7.295 -    def lostChannel(self, channel):
   7.296 -        print 'VirqClient.lostChannel>', channel
   7.297 -        
   7.298  class Daemon:
   7.299      """The xend daemon.
   7.300      """
   7.301 @@ -469,6 +188,7 @@ class Daemon:
   7.302              pass
   7.303          else:
   7.304              # Child
   7.305 +            self.daemonize()
   7.306              os.execl("/usr/sbin/xfrd", "xfrd")
   7.307  
   7.308      def daemonize(self):
   7.309 @@ -504,8 +224,6 @@ class Daemon:
   7.310          xfrd_pid = self.cleanup_xfrd()
   7.311  
   7.312  
   7.313 -        self.daemonize()
   7.314 -        
   7.315          if self.set_user():
   7.316              return 4
   7.317          os.chdir("/")
   7.318 @@ -608,146 +326,43 @@ class Daemon:
   7.319          return self.cleanup(kill=True)
   7.320  
   7.321      def run(self):
   7.322 -        xroot = XendRoot.instance()
   7.323 -        log.info("Xend Daemon started")
   7.324 -        self.createFactories()
   7.325 -        self.listenEvent(xroot)
   7.326 -        self.listenNotifier()
   7.327 -        self.listenVirq()
   7.328 -        SrvServer.create(bridge=1)
   7.329 -        reactor.run()
   7.330 +        try:
   7.331 +            xroot = XendRoot.instance()
   7.332 +            log.info("Xend Daemon started")
   7.333 +            self.createFactories()
   7.334 +            self.listenEvent(xroot)
   7.335 +            self.listenVirq()
   7.336 +            self.listenChannels()
   7.337 +            SrvServer.create(bridge=1)
   7.338 +            self.daemonize()
   7.339 +            reactor.run()
   7.340 +        except Exception, ex:
   7.341 +            print >>sys.stderr, 'Exception starting xend:', ex
   7.342 +            self.exit(1)
   7.343 +            
   7.344  
   7.345      def createFactories(self):
   7.346          self.channelF = channel.channelFactory()
   7.347 -        self.domainCF = domain.DomainControllerFactory()
   7.348 -        self.blkifCF = blkif.BlkifControllerFactory()
   7.349 -        self.netifCF = netif.NetifControllerFactory()
   7.350 -        self.usbifCF = usbif.UsbifControllerFactory()
   7.351 -        self.consoleCF = console.ConsoleControllerFactory()
   7.352  
   7.353      def listenEvent(self, xroot):
   7.354 -        protocol = EventFactory(self)
   7.355          port = xroot.get_xend_event_port()
   7.356          interface = xroot.get_xend_address()
   7.357 -        return reactor.listenTCP(port, protocol, interface=interface)
   7.358 +        return event.listenEvent(self, port, interface)
   7.359  
   7.360 -    def listenNotifier(self):
   7.361 -        protocol = NotifierProtocol(self.channelF)
   7.362 -        p = NotifierPort(self, self.channelF.notifier, protocol, reactor)
   7.363 -        p.startListening()
   7.364 -        return p
   7.365 +    def listenChannels(self):
   7.366 +        self.channelF.start()
   7.367  
   7.368      def listenVirq(self):
   7.369 -        virqChan = self.channelF.virqChannel(channel.VIRQ_DOM_EXC)
   7.370 -        virqChan.registerClient(VirqClient(self))
   7.371 -
   7.372 -    def exit(self):
   7.373 -        reactor.disconnectAll()
   7.374 -        sys.exit(0)
   7.375 -
   7.376 -    def getDomChannel(self, dom):
   7.377 -        """Get the channel to a domain.
   7.378 -
   7.379 -        @param dom: domain
   7.380 -        @return: channel (or None)
   7.381 -        """
   7.382 -        return self.channelF.getDomChannel(dom)
   7.383 -
   7.384 -    def createDomChannel(self, dom, local_port=0, remote_port=0):
   7.385 -        """Get the channel to a domain, creating if necessary.
   7.386 -
   7.387 -        @param dom: domain
   7.388 -        @param local_port: optional local port to re-use
   7.389 -        @param remote_port: optional remote port to re-use
   7.390 -        @return: channel
   7.391 -        """
   7.392 -        return self.channelF.domChannel(dom, local_port=local_port,
   7.393 -                                        remote_port=remote_port)
   7.394 -
   7.395 -    def blkif_create(self, dom, recreate=0):
   7.396 -        """Create or get a block device interface controller.
   7.397 -        
   7.398 -        Returns controller
   7.399 -        """
   7.400 -        blkif = self.blkifCF.getController(dom)
   7.401 -        blkif.daemon = self
   7.402 -        return blkif
   7.403 -
   7.404 -    def blkifs(self):
   7.405 -        return [ x.sxpr() for x in self.blkifCF.getControllers() ]
   7.406 -
   7.407 -    def blkif_get(self, dom):
   7.408 -        return self.blkifCF.getControllerByDom(dom)
   7.409 -
   7.410 -    def netif_create(self, dom, recreate=0):
   7.411 -        """Create or get a network interface controller.
   7.412 -        
   7.413 -        """
   7.414 -        return self.netifCF.getController(dom)
   7.415 -
   7.416 -    def netifs(self):
   7.417 -        return [ x.sxpr() for x in self.netifCF.getControllers() ]
   7.418 -
   7.419 -    def netif_get(self, dom):
   7.420 -        return self.netifCF.getControllerByDom(dom)
   7.421 +        def virqReceived(virq):
   7.422 +            print 'virqReceived>', virq
   7.423 +            eserver.inject('xend.virq', virq)
   7.424 +        self.channelF.setVirqHandler(virqReceived)
   7.425  
   7.426 -    def usbif_create(self, dom, recreate=0):
   7.427 -        return self.usbifCF.getController(dom)
   7.428 -    
   7.429 -    def usbifs(self):
   7.430 -        return [ x.sxpr() for x in self.usbifCF.getControllers() ]
   7.431 -
   7.432 -    def usbif_get(self, dom):
   7.433 -        return self.usbifCF.getControllerByDom(dom)
   7.434 -
   7.435 -    def console_create(self, dom, console_port=None):
   7.436 -        """Create a console for a domain.
   7.437 -        """
   7.438 -        console = self.consoleCF.getControllerByDom(dom)
   7.439 -        if console is None:
   7.440 -            console = self.consoleCF.createController(dom, console_port)
   7.441 -        return console
   7.442 -
   7.443 -    def consoles(self):
   7.444 -        return [ c.sxpr() for c in self.consoleCF.getControllers() ]
   7.445 -
   7.446 -    def get_consoles(self):
   7.447 -        return self.consoleCF.getControllers()
   7.448 -
   7.449 -    def get_console(self, id):
   7.450 -        return self.consoleCF.getControllerByIndex(id)
   7.451 -
   7.452 -    def get_domain_console(self, dom):
   7.453 -        return self.consoleCF.getControllerByDom(dom)
   7.454 +    def exit(self, rc=0):
   7.455 +        reactor.disconnectAll()
   7.456 +        self.channelF.stop()
   7.457 +        sys.exit(rc)
   7.458  
   7.459 -    def console_disconnect(self, id):
   7.460 -        """Disconnect any connected console client.
   7.461 -        """
   7.462 -        console = self.get_console(id)
   7.463 -        if not console:
   7.464 -            raise XendError('Invalid console id')
   7.465 -        console.disconnect()
   7.466 -
   7.467 -    def domain_shutdown(self, dom, reason, key=0):
   7.468 -        """Shutdown a domain.
   7.469 -        """
   7.470 -        dom = int(dom)
   7.471 -        ctrl = self.domainCF.getController(dom)
   7.472 -        if not ctrl:
   7.473 -            raise XendError('No domain controller: %s' % dom)
   7.474 -        ctrl.shutdown(reason, key)
   7.475 -        return 0
   7.476 -
   7.477 -    def domain_mem_target_set(self, dom, target):
   7.478 -        """Set memory target for a domain.
   7.479 -        """
   7.480 -        dom = int(dom)
   7.481 -        ctrl = self.domainCF.getController(dom)
   7.482 -        if not ctrl:
   7.483 -            raise XendError('No domain controller: %s' % dom)
   7.484 -        ctrl.mem_target_set(target)
   7.485 -        return 0
   7.486 -        
   7.487  def instance():
   7.488      global inst
   7.489      try:
     8.1 --- a/tools/python/xen/xend/server/SrvDomainDir.py	Tue Apr 19 13:48:05 2005 +0000
     8.2 +++ b/tools/python/xen/xend/server/SrvDomainDir.py	Wed Apr 20 08:45:19 2005 +0000
     8.3 @@ -62,9 +62,8 @@ class SrvDomainDir(SrvDir):
     8.4          if not ok:
     8.5              raise XendError(errmsg)
     8.6          try:
     8.7 -            deferred = self.xd.domain_create(config)
     8.8 -            deferred.addCallback(self._op_create_cb, configstring, req)
     8.9 -            return deferred
    8.10 +            dominfo = self.xd.domain_create(config)
    8.11 +            return self._op_create_cb(dominfo, configstring, req)
    8.12          except Exception, ex:
    8.13              print 'op_create> Exception creating domain:'
    8.14              traceback.print_exc()
    8.15 @@ -97,9 +96,8 @@ class SrvDomainDir(SrvDir):
    8.16          """
    8.17          fn = FormFn(self.xd.domain_restore,
    8.18                      [['file', 'str']])
    8.19 -        deferred = fn(req.args)
    8.20 -        deferred.addCallback(self._op_restore_cb, req)
    8.21 -        return deferred
    8.22 +        dominfo = fn(req.args)
    8.23 +        return self._op_restore_cb(dominfo, req)
    8.24  
    8.25      def _op_restore_cb(self, dominfo, req):
    8.26          dom = dominfo.name
     9.1 --- a/tools/python/xen/xend/server/blkif.py	Tue Apr 19 13:48:05 2005 +0000
     9.2 +++ b/tools/python/xen/xend/server/blkif.py	Wed Apr 20 08:45:19 2005 +0000
     9.3 @@ -2,54 +2,29 @@
     9.4  """Support for virtual block devices.
     9.5  """
     9.6  
     9.7 -from twisted.internet import defer
     9.8 -
     9.9 -from xen.xend import sxp
    9.10 -from xen.xend import Blkctl
    9.11 -from xen.xend.XendLogging import log
    9.12 -from xen.xend.XendError import XendError, VmError
    9.13 -
    9.14  import os
    9.15  import re
    9.16  import string
    9.17 +
    9.18 +from xen.xend.XendError import XendError, VmError
    9.19 +from xen.xend import XendRoot
    9.20 +from xen.xend.XendLogging import log
    9.21 +from xen.xend import sxp
    9.22 +from xen.xend import Blkctl
    9.23 +
    9.24  import channel
    9.25 -import controller
    9.26 +from controller import CtrlMsgRcvr, Dev, DevController
    9.27  from messages import *
    9.28  
    9.29  from xen.util.ip import _readline, _readlines
    9.30  
    9.31  def expand_dev_name(name):
    9.32 +    if not name:
    9.33 +        return name
    9.34      if re.match( '^/dev/', name ):
    9.35 -	return name
    9.36 +        return name
    9.37      else:
    9.38 -	return '/dev/' + name
    9.39 -
    9.40 -def check_mounted(self, name):
    9.41 -    mode = None
    9.42 -    name = expand_dev_name(name)
    9.43 -    lines = _readlines(os.popen('mount 2>/dev/null'))
    9.44 -    exp = re.compile('^' + name + ' .*[\(,]r(?P<mode>[ow])[,\)]')
    9.45 -    for line in lines:
    9.46 -        pm = exp.match(line)
    9.47 -        if not pm: continue
    9.48 -        mode = pm.group('mode')
    9.49 -        break
    9.50 -    if mode is 'w':
    9.51 -        return mode
    9.52 -    if mode is 'o':
    9.53 -        mode = 'r'
    9.54 -    blkifs = self.ctrl.daemon.blkifs()
    9.55 -    for blkif in blkifs:
    9.56 -        if blkif[1][1] is self.ctrl.dom:
    9.57 -            continue
    9.58 -        for dev in self.ctrl.daemon.blkif_get(blkif[1][1]).getDevices():
    9.59 -            if dev.type == 'phy' and name == expand_dev_name(dev.params):
    9.60 -                mode = dev.mode
    9.61 -                if 'w' in mode:
    9.62 -                    return 'w'
    9.63 -    if mode and 'r' in mode:
    9.64 -        return 'r'
    9.65 -    return None
    9.66 +        return '/dev/' + name
    9.67  
    9.68  def blkdev_name_to_number(name):
    9.69      """Take the given textual block-device name (e.g., '/dev/sda1',
    9.70 @@ -58,10 +33,10 @@ def blkdev_name_to_number(name):
    9.71      n = expand_dev_name(name)
    9.72  
    9.73      try:
    9.74 -	return os.stat(n).st_rdev
    9.75 +        return os.stat(n).st_rdev
    9.76      except Exception, ex:
    9.77          log.debug("exception looking up device number for %s: %s", name, ex)
    9.78 -	pass
    9.79 +        pass
    9.80  
    9.81      if re.match( '/dev/sd[a-p]([0-9]|1[0-5])', n):
    9.82          return 8 * 256 + 16 * (ord(n[7:8]) - ord('a')) + int(n[8:])
    9.83 @@ -74,8 +49,8 @@ def blkdev_name_to_number(name):
    9.84  
    9.85      # see if this is a hex device number
    9.86      if re.match( '^(0x)?[0-9a-fA-F]+$', name ):
    9.87 -	return string.atoi(name,16)
    9.88 -	
    9.89 +        return string.atoi(name,16)
    9.90 +        
    9.91      return None
    9.92  
    9.93  def blkdev_segment(name):
    9.94 @@ -90,50 +65,70 @@ def blkdev_segment(name):
    9.95      val = None
    9.96      n = blkdev_name_to_number(name)
    9.97      if n:
    9.98 -	val = { 'device' : n,
    9.99 +        val = { 'device'       : n,
   9.100                  'start_sector' : long(0),
   9.101 -                'nr_sectors' : long(1L<<63),
   9.102 -                'type' : 'Disk' }
   9.103 +                'nr_sectors'   : long(1L<<63),
   9.104 +                'type'         : 'Disk' }
   9.105      return val
   9.106  
   9.107 -class BlkifBackendController(controller.BackendController):
   9.108 -    """ Handler for the 'back-end' channel to a block device driver domain.
   9.109 -    """
   9.110 -
   9.111 -    def __init__(self, factory, dom):
   9.112 -        controller.BackendController.__init__(self, factory, dom)
   9.113 -        self.addMethod(CMSG_BLKIF_BE,
   9.114 -                       CMSG_BLKIF_BE_DRIVER_STATUS,
   9.115 -                       self.recv_be_driver_status)
   9.116 -        self.registerChannel()
   9.117 -
   9.118 -    def recv_be_driver_status(self, msg, req):
   9.119 -        """Request handler for be_driver_status messages.
   9.120 -        
   9.121 -        @param msg: message
   9.122 -        @type  msg: xu message
   9.123 -        @param req: request flag (true if the msg is a request)
   9.124 -        @type  req: bool
   9.125 -        """
   9.126 -        val = unpackMsg('blkif_be_driver_status_t', msg)
   9.127 -        status = val['status']
   9.128 -
   9.129 -class BlkifBackendInterface(controller.BackendInterface):
   9.130 +def mount_mode(name):
   9.131 +    mode = None
   9.132 +    name = expand_dev_name(name)
   9.133 +    lines = _readlines(os.popen('mount 2>/dev/null'))
   9.134 +    exp = re.compile('^' + name + ' .*[\(,]r(?P<mode>[ow])[,\)]')
   9.135 +    for line in lines:
   9.136 +        pm = exp.match(line)
   9.137 +        if not pm: continue
   9.138 +        mode = pm.group('mode')
   9.139 +        break
   9.140 +    if mode == 'w':
   9.141 +        return mode
   9.142 +    if mode == 'o':
   9.143 +        mode = 'r'
   9.144 +    return mode
   9.145 +    
   9.146 +class BlkifBackend:
   9.147      """ Handler for the 'back-end' channel to a block device driver domain
   9.148      on behalf of a front-end domain.
   9.149      Must be connected using connect() before it can be used.
   9.150 -    Do not create directly - use getBackendInterface() on the BlkifController.
   9.151      """
   9.152  
   9.153 -    def __init__(self, ctrl, dom, handle):
   9.154 -        controller.BackendInterface.__init__(self, ctrl, dom, handle)
   9.155 -        self.connected = 0
   9.156 +    def __init__(self, controller, id, dom, recreate=False):
   9.157 +        self.controller = controller
   9.158 +        self.id = id
   9.159 +        self.frontendDomain = self.controller.getDomain()
   9.160 +        self.frontendChannel = None
   9.161 +        self.backendDomain = dom
   9.162 +        self.backendChannel = None
   9.163 +        self.destroyed = False
   9.164 +        self.connected = False
   9.165          self.evtchn = None
   9.166          self.status = BLKIF_INTERFACE_STATUS_DISCONNECTED
   9.167  
   9.168 +    def init(self, recreate=False, reboot=False):
   9.169 +        self.destroyed = False
   9.170 +        self.frontendDomain = self.controller.getDomain()
   9.171 +        self.frontendChannel = self.controller.getChannel()
   9.172 +        cf = channel.channelFactory()
   9.173 +        self.backendChannel = cf.openChannel(self.backendDomain)
   9.174 +
   9.175      def __str__(self):
   9.176 -        return '<BlkifBackendInterface %d %d>' % (self.controller.dom, self.dom)
   9.177 +        return ('<BlkifBackend frontend=%d backend=%d id=%d>'
   9.178 +                % (self.frontendDomain,
   9.179 +                   self.backendDomain,
   9.180 +                   self.id))
   9.181 +
   9.182 +    def getId(self):
   9.183 +        return self.id
   9.184  
   9.185 +    def closeEvtchn(self):
   9.186 +        if self.evtchn:
   9.187 +            channel.eventChannelClose(self.evtchn)
   9.188 +            self.evtchn = None
   9.189 +
   9.190 +    def openEvtchn(self):
   9.191 +        self.evtchn = channel.eventChannel(self.backendDomain, self.frontendDomain)
   9.192 +        
   9.193      def getEventChannelBackend(self):
   9.194          val = 0
   9.195          if self.evtchn:
   9.196 @@ -146,91 +141,76 @@ class BlkifBackendInterface(controller.B
   9.197              val = self.evtchn['port2']
   9.198          return val
   9.199  
   9.200 -    def connect(self, recreate=0):
   9.201 +    def connect(self, recreate=False):
   9.202          """Connect to the blkif control interface.
   9.203  
   9.204          @param recreate: true if after xend restart
   9.205 -        @return: deferred
   9.206          """
   9.207          log.debug("Connecting blkif %s", str(self))
   9.208          if recreate or self.connected:
   9.209 -            d = defer.succeed(self)
   9.210 +            self.connected = True
   9.211 +            pass
   9.212          else:
   9.213 -            d = self.send_be_create()
   9.214 -            d.addCallback(self.respond_be_create)
   9.215 -        return d
   9.216 +            self.send_be_create()
   9.217          
   9.218      def send_be_create(self):
   9.219 -        d = defer.Deferred()
   9.220 +        log.debug("send_be_create %s", str(self))
   9.221          msg = packMsg('blkif_be_create_t',
   9.222 -                      { 'domid'        : self.controller.dom,
   9.223 -                        'blkif_handle' : self.handle })
   9.224 -        self.writeRequest(msg, response=d)
   9.225 -        return d
   9.226 +                      { 'domid'        : self.frontendDomain,
   9.227 +                        'blkif_handle' : self.id })
   9.228 +        msg = self.backendChannel.requestResponse(msg)
   9.229 +        #todo: check return status
   9.230 +        self.connected = True
   9.231  
   9.232 -    def respond_be_create(self, msg):
   9.233 -        val = unpackMsg('blkif_be_create_t', msg)
   9.234 -        self.connected = 1
   9.235 -        return self
   9.236 -    
   9.237 -    def destroy(self):
   9.238 +    def destroy(self, change=False, reboot=False):
   9.239          """Disconnect from the blkif control interface and destroy it.
   9.240          """
   9.241 -        def cb_destroy(val):
   9.242 -            self.send_be_destroy()
   9.243 -            self.close()
   9.244 -        d = defer.Deferred()
   9.245 -        d.addCallback(cb_destroy)
   9.246 -        if self.evtchn:
   9.247 -            channel.eventChannelClose(self.evtchn)
   9.248 -        self.send_be_disconnect(response=d)
   9.249 -        
   9.250 -    def send_be_disconnect(self, response=None):
   9.251 +        self.send_be_disconnect()
   9.252 +        self.send_be_destroy()
   9.253 +        self.closeEvtchn()
   9.254 +        self.destroyed = True
   9.255 +        # For change true need to notify front-end, or back-end will do it?
   9.256 +
   9.257 +    def send_be_disconnect(self):
   9.258          msg = packMsg('blkif_be_disconnect_t',
   9.259 -                      { 'domid'        : self.controller.dom,
   9.260 -                        'blkif_handle' : self.handle })
   9.261 -        self.writeRequest(msg, response=response)
   9.262 +                      { 'domid'        : self.frontendDomain,
   9.263 +                        'blkif_handle' : self.id })
   9.264 +        self.backendChannel.writeRequest(msg)
   9.265 +        self.connected = False
   9.266  
   9.267 -    def send_be_destroy(self, response=None):
   9.268 +    def send_be_destroy(self):
   9.269          msg = packMsg('blkif_be_destroy_t',
   9.270 -                      { 'domid'        : self.controller.dom,
   9.271 -                        'blkif_handle' : self.handle })
   9.272 -        self.writeRequest(msg, response=response)
   9.273 +                      { 'domid'        : self.frontendDomain,
   9.274 +                        'blkif_handle' : self.id })
   9.275 +        self.backendChannel.writeRequest(msg)
   9.276  
   9.277      def connectInterface(self, val):
   9.278 -        self.evtchn = channel.eventChannel(self.dom, self.controller.dom)
   9.279 +        self.openEvtchn()
   9.280          log.debug("Connecting blkif to event channel %s ports=%d:%d",
   9.281                    str(self), self.evtchn['port1'], self.evtchn['port2'])
   9.282          msg = packMsg('blkif_be_connect_t',
   9.283 -                      { 'domid'        : self.controller.dom,
   9.284 -                        'blkif_handle' : self.handle,
   9.285 +                      { 'domid'        : self.frontendDomain,
   9.286 +                        'blkif_handle' : self.id,
   9.287                          'evtchn'       : self.getEventChannelBackend(),
   9.288                          'shmem_frame'  : val['shmem_frame'] })
   9.289 -        d = defer.Deferred()
   9.290 -        d.addCallback(self.respond_be_connect)
   9.291 -        self.writeRequest(msg, response=d)
   9.292 -
   9.293 -    def respond_be_connect(self, msg):
   9.294 -        """Response handler for a be_connect message.
   9.295 -
   9.296 -        @param msg: message
   9.297 -        @type  msg: xu message
   9.298 -        """
   9.299 +        msg = self.backendChannel.requestResponse(msg)
   9.300 +        #todo: check return status
   9.301          val = unpackMsg('blkif_be_connect_t', msg)
   9.302          self.status = BLKIF_INTERFACE_STATUS_CONNECTED
   9.303          self.send_fe_interface_status()
   9.304              
   9.305 -    def send_fe_interface_status(self, response=None):
   9.306 +    def send_fe_interface_status(self):
   9.307          msg = packMsg('blkif_fe_interface_status_t',
   9.308 -                      { 'handle' : self.handle,
   9.309 +                      { 'handle' : self.id,
   9.310                          'status' : self.status,
   9.311 -                        'domid'  : self.dom,
   9.312 +                        'domid'  : self.backendDomain,
   9.313                          'evtchn' : self.getEventChannelFrontend() })
   9.314 -        self.controller.writeRequest(msg, response=response)
   9.315 +        self.frontendChannel.writeRequest(msg)
   9.316  
   9.317      def interfaceDisconnected(self):
   9.318          self.status = BLKIF_INTERFACE_STATUS_DISCONNECTED
   9.319 -        #todo?: Do this: self.evtchn = None
   9.320 +        #todo?: Close evtchn:
   9.321 +        #self.closeEvtchn()
   9.322          self.send_fe_interface_status()
   9.323          
   9.324      def interfaceChanged(self):
   9.325 @@ -238,83 +218,18 @@ class BlkifBackendInterface(controller.B
   9.326          The front-end should then probe for devices.
   9.327          """
   9.328          msg = packMsg('blkif_fe_interface_status_t',
   9.329 -                      { 'handle' : self.handle,
   9.330 +                      { 'handle' : self.id,
   9.331                          'status' : BLKIF_INTERFACE_STATUS_CHANGED,
   9.332 -                        'domid'  : self.dom,
   9.333 +                        'domid'  : self.backendDomain,
   9.334                          'evtchn' : 0 })
   9.335 -        self.controller.writeRequest(msg)
   9.336 -        
   9.337 -class BlkifControllerFactory(controller.SplitControllerFactory):
   9.338 -    """Factory for creating block device interface controllers.
   9.339 -    """
   9.340 -
   9.341 -    def __init__(self):
   9.342 -        controller.SplitControllerFactory.__init__(self)
   9.343 -
   9.344 -    def createController(self, dom, recreate=0):
   9.345 -        """Create a block device controller for a domain.
   9.346 -
   9.347 -        @param dom: domain
   9.348 -        @type  dom: int
   9.349 -        @param recreate: if true it's a recreate (after xend restart)
   9.350 -        @type  recreate: bool
   9.351 -        @return: block device controller
   9.352 -        @rtype: BlkifController
   9.353 -        """
   9.354 -        blkif = self.getControllerByDom(dom)
   9.355 -        if blkif is None:
   9.356 -            blkif = BlkifController(self, dom)
   9.357 -            self.addController(blkif)
   9.358 -        return blkif
   9.359 -
   9.360 -    def createBackendController(self, dom):
   9.361 -        """Create a block device backend controller.
   9.362 +        self.frontendChannel.writeRequest(msg)
   9.363  
   9.364 -        @param dom: backend domain
   9.365 -        @return: backend controller
   9.366 -        """
   9.367 -        return BlkifBackendController(self, dom)
   9.368 -
   9.369 -    def createBackendInterface(self, ctrl, dom, handle):
   9.370 -        """Create a block device backend interface.
   9.371 -
   9.372 -        @param ctrl: controller
   9.373 -        @param dom: backend domain
   9.374 -        @param handle: interface handle
   9.375 -        @return: backend interface
   9.376 -        """
   9.377 -        return BlkifBackendInterface(ctrl, dom, handle)
   9.378 -
   9.379 -    def getDomainDevices(self, dom):
   9.380 -        """Get the block devices for a domain.
   9.381 -
   9.382 -        @param dom: domain
   9.383 -        @type  dom: int
   9.384 -        @return: devices
   9.385 -        @rtype:  [device]
   9.386 -        """
   9.387 -        blkif = self.getControllerByDom(dom)
   9.388 -        return (blkif and blkif.getDevices()) or []
   9.389 -
   9.390 -    def getDomainDevice(self, dom, idx):
   9.391 -        """Get a block device from a domain.
   9.392 -
   9.393 -        @param dom: domain
   9.394 -        @type  dom: int
   9.395 -        @param idx: device index
   9.396 -        @type  idx: int
   9.397 -        @return: device
   9.398 -        @rtype:  device
   9.399 -        """
   9.400 -        blkif = self.getControllerByDom(dom)
   9.401 -        return (blkif and blkif.getDevice(idx)) or None
   9.402 -
   9.403 -class BlkDev(controller.SplitDev):
   9.404 +class BlkDev(Dev):
   9.405      """Info record for a block device.
   9.406      """
   9.407  
   9.408 -    def __init__(self, idx, ctrl, config):
   9.409 -        controller.SplitDev.__init__(self, idx, ctrl)
   9.410 +    def __init__(self, controller, id, config, recreate=False):
   9.411 +        Dev.__init__(self, controller, id, config, recreate=recreate)
   9.412          self.dev = None
   9.413          self.uname = None
   9.414          self.vdev = None
   9.415 @@ -325,10 +240,27 @@ class BlkDev(controller.SplitDev):
   9.416          self.device = None
   9.417          self.start_sector = None
   9.418          self.nr_sectors = None
   9.419 -        self.ctrl = ctrl
   9.420 -        self.configure(config)
   9.421 +        
   9.422 +        self.frontendDomain = self.getDomain()
   9.423 +        self.frontendChannel = None
   9.424 +        self.backendDomain = None
   9.425 +        self.backendChannel = None
   9.426 +        self.backendId = 0
   9.427 +        self.configure(self.config, recreate=recreate)
   9.428  
   9.429 -    def configure(self, config):
   9.430 +    def init(self, recreate=False, reboot=False):
   9.431 +        print 'BlkDev>init>'
   9.432 +        self.frontendDomain = self.getDomain()
   9.433 +        self.frontendChannel = self.getChannel()
   9.434 +        backend = self.getBackend()
   9.435 +        self.backendChannel = backend.backendChannel
   9.436 +        self.backendId = backend.id
   9.437 +        print 'BlkDev>init<'
   9.438 +
   9.439 +    def configure(self, config, change=False, recreate=False):
   9.440 +        print 'BlkDev>configure>'
   9.441 +        if change:
   9.442 +            raise XendError("cannot reconfigure vbd")
   9.443          self.config = config
   9.444          self.uname = sxp.child_value(config, 'uname')
   9.445          if not self.uname:
   9.446 @@ -340,23 +272,33 @@ class BlkDev(controller.SplitDev):
   9.447          if not self.dev:
   9.448              raise VmError('vbd: Missing dev')
   9.449          self.mode = sxp.child_value(config, 'mode', 'r')
   9.450 -        # todo: The 'dev' should be looked up in the context of the domain.
   9.451 +        
   9.452          self.vdev = blkdev_name_to_number(self.dev)
   9.453          if not self.vdev:
   9.454              raise VmError('vbd: Device not found: %s' % self.dev)
   9.455 +        
   9.456          try:
   9.457              self.backendDomain = int(sxp.child_value(config, 'backend', '0'))
   9.458          except:
   9.459              raise XendError('invalid backend domain')
   9.460  
   9.461 -    def recreate(self, savedinfo):
   9.462 -        node = sxp.child_value(savedinfo, 'node')
   9.463 -        self.setNode(node)
   9.464 +        print 'BlkDev>configure<'
   9.465 +        return self.config
   9.466  
   9.467 -    def attach(self):
   9.468 -        node = Blkctl.block('bind', self.type, self.params)
   9.469 -        self.setNode(node)
   9.470 -        return self.attachBackend()
   9.471 +    def attach(self, recreate=False, change=False):
   9.472 +        print 'BlkDev>attach>', self
   9.473 +        if recreate:
   9.474 +            print 'attach>', 'recreate=', recreate
   9.475 +            node = sxp.child_value(recreate, 'node')
   9.476 +            print 'attach>', 'node=', node
   9.477 +            self.setNode(node)
   9.478 +        else:
   9.479 +            node = Blkctl.block('bind', self.type, self.params)
   9.480 +            self.setNode(node)
   9.481 +            self.attachBackend()
   9.482 +        if change:
   9.483 +            self.interfaceChanged()
   9.484 +        print 'BlkDev>attach<', self
   9.485  
   9.486      def unbind(self):
   9.487          if self.node is None: return
   9.488 @@ -379,14 +321,15 @@ class BlkDev(controller.SplitDev):
   9.489              return
   9.490          # done.
   9.491              
   9.492 -        mounted_mode = check_mounted(self, node)
   9.493 +        mounted_mode = self.check_mounted(node)
   9.494          if not '!' in self.mode and mounted_mode:
   9.495 -            if mounted_mode is "w":
   9.496 +            if mounted_mode == "w":
   9.497                  raise VmError("vbd: Segment %s is in writable use" %
   9.498                                self.uname)
   9.499              elif 'w' in self.mode:
   9.500                  raise VmError("vbd: Segment %s is in read-only use" %
   9.501                                self.uname)
   9.502 +            
   9.503          segment = blkdev_segment(node)
   9.504          if not segment:
   9.505              raise VmError("vbd: Segment not found: uname=%s" % self.uname)
   9.506 @@ -395,12 +338,28 @@ class BlkDev(controller.SplitDev):
   9.507          self.start_sector = segment['start_sector']
   9.508          self.nr_sectors = segment['nr_sectors']
   9.509  
   9.510 +    def check_mounted(self, name):
   9.511 +        mode = mount_mode(name)
   9.512 +        xd = XendRoot.get_component('xen.xend.XendDomain')
   9.513 +        for vm in xd.domains():
   9.514 +            ctrl = vm.getDeviceController(self.getType(), error=False)
   9.515 +            if (not ctrl): continue
   9.516 +            for dev in ctrl.getDevices():
   9.517 +                if dev is self: continue
   9.518 +                if dev.type == 'phy' and name == expand_dev_name(dev.params):
   9.519 +                    mode = dev.mode
   9.520 +                    if 'w' in mode:
   9.521 +                        return 'w'
   9.522 +        if mode and 'r' in mode:
   9.523 +            return 'r'
   9.524 +        return None
   9.525 +
   9.526      def readonly(self):
   9.527          return 'w' not in self.mode
   9.528  
   9.529      def sxpr(self):
   9.530          val = ['vbd',
   9.531 -               ['idx', self.idx],
   9.532 +               ['id', self.id],
   9.533                 ['vdev', self.vdev],
   9.534                 ['device', self.device],
   9.535                 ['mode', self.mode]]
   9.536 @@ -410,163 +369,162 @@ class BlkDev(controller.SplitDev):
   9.537              val.append(['uname', self.uname])
   9.538          if self.node:
   9.539              val.append(['node', self.node])
   9.540 -        if self.index is not None:
   9.541 -            val.append(['index', self.index])
   9.542 +        val.append(['index', self.getIndex()])
   9.543          return val
   9.544  
   9.545 +    def getBackend(self):
   9.546 +        return self.controller.getBackend(self.backendDomain)
   9.547 +
   9.548      def refresh(self):
   9.549 -        log.debug("Refreshing vbd domain=%d idx=%s", self.controller.dom, self.idx)
   9.550 +        log.debug("Refreshing vbd domain=%d id=%s", self.frontendDomain, self.id)
   9.551          self.interfaceChanged()
   9.552  
   9.553 -    def destroy(self, change=0):
   9.554 +    def destroy(self, change=False, reboot=False):
   9.555          """Destroy the device. If 'change' is true notify the front-end interface.
   9.556  
   9.557          @param change: change flag
   9.558          """
   9.559 -        log.debug("Destroying vbd domain=%d idx=%s", self.controller.dom, self.idx)
   9.560 -        d = self.send_be_vbd_destroy()
   9.561 +        self.destroyed = True
   9.562 +        log.debug("Destroying vbd domain=%d id=%s", self.frontendDomain, self.id)
   9.563 +        self.send_be_vbd_destroy()
   9.564          if change:
   9.565 -            d.addCallback(lambda val: self.interfaceChanged())
   9.566 -        d.addCallback(lambda val: self.unbind())
   9.567 +            self.interfaceChanged()
   9.568 +        self.unbind()
   9.569  
   9.570      def interfaceChanged(self):
   9.571          """Tell the back-end to notify the front-end that a device has been
   9.572          added or removed.
   9.573          """
   9.574 -        self.getBackendInterface().interfaceChanged()
   9.575 +        self.getBackend().interfaceChanged()
   9.576  
   9.577      def attachBackend(self):
   9.578          """Attach the device to its controller.
   9.579  
   9.580          """
   9.581 -        backend = self.getBackendInterface()
   9.582 -        d1 = backend.connect()
   9.583 -        d2 = defer.Deferred()
   9.584 -        d2.addCallback(self.send_be_vbd_create)
   9.585 -        d1.chainDeferred(d2)
   9.586 -        return d2
   9.587 +        print 'BlkDev>attachBackend>'
   9.588 +        self.getBackend().connect()
   9.589 +        self.send_be_vbd_create()
   9.590 +        print 'BlkDev>attachBackend<'
   9.591          
   9.592 -    def send_be_vbd_create(self, val):
   9.593 -        d = defer.Deferred()
   9.594 -        d.addCallback(self.respond_be_vbd_create)
   9.595 -        backend = self.getBackendInterface()
   9.596 +    def send_be_vbd_create(self):
   9.597 +        print 'BlkDev>send_be_vbd_create>'
   9.598          msg = packMsg('blkif_be_vbd_create_t',
   9.599 -                      { 'domid'        : self.controller.dom,
   9.600 -                        'blkif_handle' : backend.handle,
   9.601 +                      { 'domid'        : self.frontendDomain,
   9.602 +                        'blkif_handle' : self.backendId,
   9.603                          'pdevice'      : self.device,
   9.604                          'vdevice'      : self.vdev,
   9.605                          'readonly'     : self.readonly() })
   9.606 -        backend.writeRequest(msg, response=d)
   9.607 -        return d
   9.608 +        msg = self.backendChannel.requestResponse(msg)
   9.609          
   9.610 -    def respond_be_vbd_create(self, msg):
   9.611          val = unpackMsg('blkif_be_vbd_create_t', msg)
   9.612 -	status = val['status']
   9.613 -	if status != BLKIF_BE_STATUS_OKAY:
   9.614 +        status = val['status']
   9.615 +        if status != BLKIF_BE_STATUS_OKAY:
   9.616              raise XendError("Creating vbd failed: device %s, error %d"
   9.617                              % (sxp.to_string(self.config), status))
   9.618 -        return self
   9.619  
   9.620      def send_be_vbd_destroy(self):
   9.621 -        d = defer.Deferred()
   9.622 -        backend = self.getBackendInterface()
   9.623          msg = packMsg('blkif_be_vbd_destroy_t',
   9.624 -                      { 'domid'                : self.controller.dom,
   9.625 -                        'blkif_handle'         : backend.handle,
   9.626 +                      { 'domid'                : self.frontendDomain,
   9.627 +                        'blkif_handle'         : self.backendId,
   9.628                          'vdevice'              : self.vdev })
   9.629 -        self.controller.delDevice(self.vdev)
   9.630 -        backend.writeRequest(msg, response=d)
   9.631 -        return d
   9.632 +        return self.backendChannel.writeRequest(msg)
   9.633          
   9.634 -
   9.635 -class BlkifController(controller.SplitController):
   9.636 +class BlkifController(DevController):
   9.637      """Block device interface controller. Handles all block devices
   9.638      for a domain.
   9.639      """
   9.640      
   9.641 -    def __init__(self, factory, dom):
   9.642 +    def __init__(self, dctype, vm, recreate=False):
   9.643          """Create a block device controller.
   9.644 -        Do not call directly - use createController() on the factory instead.
   9.645          """
   9.646 -        controller.SplitController.__init__(self, factory, dom)
   9.647 -        self.addMethod(CMSG_BLKIF_FE,
   9.648 -                       CMSG_BLKIF_FE_DRIVER_STATUS,
   9.649 -                       self.recv_fe_driver_status)
   9.650 -        self.addMethod(CMSG_BLKIF_FE,
   9.651 -                       CMSG_BLKIF_FE_INTERFACE_CONNECT,
   9.652 -                       self.recv_fe_interface_connect)
   9.653 -        self.registerChannel()
   9.654 +        DevController.__init__(self, dctype, vm, recreate=recreate)
   9.655 +        self.backends = {}
   9.656 +        self.backendId = 0
   9.657 +        self.rcvr = None
   9.658 +
   9.659 +    def initController(self, recreate=False, reboot=False):
   9.660 +        print 'BlkifController>initController>'
   9.661 +        self.destroyed = False
   9.662 +        # Add our handlers for incoming requests.
   9.663 +        self.rcvr = CtrlMsgRcvr(self.getChannel())
   9.664 +        self.rcvr.addHandler(CMSG_BLKIF_FE,
   9.665 +                             CMSG_BLKIF_FE_DRIVER_STATUS,
   9.666 +                             self.recv_fe_driver_status)
   9.667 +        self.rcvr.addHandler(CMSG_BLKIF_FE,
   9.668 +                             CMSG_BLKIF_FE_INTERFACE_CONNECT,
   9.669 +                             self.recv_fe_interface_connect)
   9.670 +        self.rcvr.registerChannel()
   9.671 +        if reboot:
   9.672 +            self.rebootBackends()
   9.673 +            self.rebootDevices()
   9.674 +        print 'BlkifController>initController<'
   9.675  
   9.676      def sxpr(self):
   9.677 -        val = ['blkif', ['dom', self.dom]]
   9.678 +        val = ['blkif', ['dom', self.getDomain()]]
   9.679          return val
   9.680  
   9.681 -    def addDevice(self, idx, config):
   9.682 -        """Add a device to the device table.
   9.683 +    def rebootBackends(self):
   9.684 +        for backend in self.backends.values():
   9.685 +            backend.init(reboot=True)
   9.686 +
   9.687 +    def getBackendById(self, id):
   9.688 +        return self.backends.get(id)
   9.689 +
   9.690 +    def getBackendByDomain(self, dom):
   9.691 +        for backend in self.backends.values():
   9.692 +            if backend.backendDomain == dom:
   9.693 +                return backend
   9.694 +        return None
   9.695  
   9.696 -        @param vdev:     device index
   9.697 -        @type  vdev:     int
   9.698 -        @param config: device configuration
   9.699 -        @return: device
   9.700 -        @rtype:  BlkDev
   9.701 -        """
   9.702 -        if idx in self.devices:
   9.703 -            raise XendError('device exists: ' + str(idx))
   9.704 -        dev = BlkDev(idx, self, config )
   9.705 -        self.devices[idx] = dev
   9.706 -        return dev
   9.707 +    def getBackend(self, dom):
   9.708 +        backend = self.getBackendByDomain(dom)
   9.709 +        if backend: return backend
   9.710 +        backend = BlkifBackend(self, self.backendId, dom)
   9.711 +        self.backendId += 1
   9.712 +        self.backends[backend.getId()] = backend
   9.713 +        backend.init()
   9.714 +        return backend
   9.715  
   9.716 -    def attachDevice(self, idx, config, recreate=0):
   9.717 -        """Attach a device to the specified interface.
   9.718 -        On success the returned deferred will be called with the device.
   9.719 +    def newDevice(self, id, config, recreate=False):
   9.720 +        """Create a device..
   9.721  
   9.722 -        @param idx:      device id
   9.723 +        @param id:      device id
   9.724          @param config:   device configuration
   9.725          @param recreate: if true it's being recreated (after xend restart)
   9.726          @type  recreate: bool
   9.727 -        @return: deferred
   9.728 -        @rtype:  Deferred
   9.729 +        @return: device
   9.730 +        @rtype:  BlkDev
   9.731          """
   9.732 -        dev = self.addDevice(idx, config)
   9.733 -        if recreate:
   9.734 -            dev.recreate(recreate)
   9.735 -            d = defer.succeed(dev)
   9.736 -        else:
   9.737 -            d = dev.attach()
   9.738 -        return d
   9.739 -
   9.740 -    def destroy(self):
   9.741 +        return BlkDev(self, id, config, recreate=recreate)
   9.742 +        
   9.743 +    def destroyController(self, reboot=False):
   9.744          """Destroy the controller and all devices.
   9.745          """
   9.746 -        log.debug("Destroying blkif domain=%d", self.dom)
   9.747 -        self.destroyDevices()
   9.748 -        self.destroyBackends()
   9.749 +        self.destroyed = True
   9.750 +        log.debug("Destroying blkif domain=%d", self.getDomain())
   9.751 +        self.destroyDevices(reboot=reboot)
   9.752 +        self.destroyBackends(reboot=reboot)
   9.753 +        self.rcvr.deregisterChannel()
   9.754  
   9.755 -    def destroyDevices(self):
   9.756 -        """Destroy all devices.
   9.757 -        """
   9.758 -        for dev in self.getDevices():
   9.759 -            dev.destroy()
   9.760 +    def destroyBackends(self, reboot=False):
   9.761 +        for backend in self.backends.values():
   9.762 +            backend.destroy(reboot=reboot)
   9.763  
   9.764 -    def destroyBackends(self):
   9.765 -        for backend in self.getBackendInterfaces():
   9.766 -            backend.destroy()
   9.767 -
   9.768 -    def recv_fe_driver_status(self, msg, req):
   9.769 +    def recv_fe_driver_status(self, msg):
   9.770          val = unpackMsg('blkif_fe_driver_status_t', msg)
   9.771 -        print 'recv_fe_driver_status>', val
   9.772 -        for backend in self.getBackendInterfaces():
   9.773 +        for backend in self.backends.values():
   9.774              backend.interfaceDisconnected()
   9.775  
   9.776 -    def recv_fe_interface_connect(self, msg, req):
   9.777 +    def recv_fe_interface_connect(self, msg):
   9.778          val = unpackMsg('blkif_fe_interface_connect_t', msg)
   9.779 -        handle = val['handle']
   9.780 -        backend = self.getBackendInterfaceByHandle(handle)
   9.781 +        id = val['handle']
   9.782 +        backend = self.getBackendById(id)
   9.783          if backend:
   9.784 -            backend.connectInterface(val)
   9.785 +            try:
   9.786 +                backend.connectInterface(val)
   9.787 +            except IOError, ex:
   9.788 +                log.error("Exception connecting backend: %s", ex)
   9.789          else:
   9.790 -            log.error('interface connect on unknown interface: handle=%d', handle)
   9.791 -
   9.792 -
   9.793 +            log.error('interface connect on unknown interface: id=%d', id)
   9.794      
   9.795  
    10.1 --- a/tools/python/xen/xend/server/channel.py	Tue Apr 19 13:48:05 2005 +0000
    10.2 +++ b/tools/python/xen/xend/server/channel.py	Wed Apr 20 08:45:19 2005 +0000
    10.3 @@ -1,8 +1,12 @@
    10.4  # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    10.5  
    10.6 +import threading
    10.7 +import select
    10.8 +
    10.9  import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
   10.10  from xen.lowlevel import xu
   10.11 -from messages import msgTypeName, printMsg
   10.12 +
   10.13 +from messages import *
   10.14  
   10.15  VIRQ_MISDIRECT  = 0  # Catch-all interrupt for unbound VIRQs.
   10.16  VIRQ_TIMER      = 1  # Timebase update, and/or requested timeout.
   10.17 @@ -10,6 +14,10 @@ VIRQ_DEBUG      = 2  # Request guest to 
   10.18  VIRQ_CONSOLE    = 3  # (DOM0) bytes received on emergency console.
   10.19  VIRQ_DOM_EXC    = 4  # (DOM0) Exceptional event for some domain.
   10.20  
   10.21 +DEBUG = 0
   10.22 +
   10.23 +RESPONSE_TIMEOUT = 20.0
   10.24 +
   10.25  def eventChannel(dom1, dom2):
   10.26      """Create an event channel between domains.
   10.27      The returned dict contains dom1, dom2, port1 and port2 on success.
   10.28 @@ -33,6 +41,7 @@ def eventChannelClose(evtchn):
   10.29              pass
   10.30          
   10.31      if not evtchn: return
   10.32 +    print 'eventChannelClose>', evtchn
   10.33      evtchn_close(evtchn.get('dom1'), evtchn.get('port1'))
   10.34      evtchn_close(evtchn.get('dom2'), evtchn.get('port2'))
   10.35      
   10.36 @@ -45,76 +54,135 @@ class ChannelFactory:
   10.37      """ Channels indexed by index. """
   10.38      channels = {}
   10.39  
   10.40 +    thread = None
   10.41 +
   10.42 +    notifier = None
   10.43 +
   10.44 +    """Map of ports to the virq they signal."""
   10.45 +    virqPorts = {}
   10.46 +
   10.47      def __init__(self):
   10.48          """Constructor - do not use. Use the channelFactory function."""
   10.49          self.notifier = xu.notifier()
   10.50 +        self.bind_virq(VIRQ_MISDIRECT)
   10.51 +        self.bind_virq(VIRQ_TIMER)
   10.52 +        self.bind_virq(VIRQ_DEBUG)
   10.53 +        self.bind_virq(VIRQ_CONSOLE)
   10.54 +        self.bind_virq(VIRQ_DOM_EXC)
   10.55 +        self.virqHandler = None
   10.56 +
   10.57 +    def bind_virq(self, virq):
   10.58 +        port = self.notifier.bind_virq(virq)
   10.59 +        self.virqPorts[port] = virq
   10.60 +
   10.61 +    def virq(self):
   10.62 +        self.notifier.virq_send(self.virqPort)
   10.63 +
   10.64 +    def start(self):
   10.65 +        """Fork a thread to read messages.
   10.66 +        """
   10.67 +        if self.thread: return
   10.68 +        self.thread = threading.Thread(name="ChannelFactory",
   10.69 +                                       target=self.main)
   10.70 +        self.thread.setDaemon(True)
   10.71 +        self.thread.start()
   10.72 +
   10.73 +    def stop(self):
   10.74 +        """Signal the thread to stop.
   10.75 +        """
   10.76 +        self.thread = None
   10.77 +
   10.78 +    def main(self):
   10.79 +        """Main routine for the thread.
   10.80 +        """
   10.81 +        while True:
   10.82 +            if self.thread == None: return
   10.83 +            port = self.notifier.read()
   10.84 +            if port:
   10.85 +                virq = self.virqPorts.get(port)
   10.86 +                if virq is not None:
   10.87 +                    self.virqReceived(virq)
   10.88 +                else:
   10.89 +                    self.msgReceived(port)
   10.90 +            else:
   10.91 +                select.select([self.notifier], [], [], 1.0)
   10.92 +
   10.93 +    def msgReceived(self, port):
   10.94 +        # We run the message handlers in their own threads.
   10.95 +        # Note we use keyword args to lambda to save the values -
   10.96 +        # otherwise lambda will use the variables, which will get
   10.97 +        # assigned by the loop and the lambda will get the changed values.
   10.98 +        for chan in self.channels.values():
   10.99 +            if self.thread == None: return
  10.100 +            msg = chan.readResponse()
  10.101 +            if msg:
  10.102 +                chan.responseReceived(msg)
  10.103 +        for chan in self.channels.values():
  10.104 +            if self.thread == None: return
  10.105 +            msg = chan.readRequest()
  10.106 +            if msg:
  10.107 +                self.runInThread(lambda chan=chan, msg=msg: chan.requestReceived(msg))
  10.108 +
  10.109 +    def runInThread(self, thunk):
  10.110 +        thread = threading.Thread(target = thunk)
  10.111 +        thread.setDaemon(True)
  10.112 +        thread.start()
  10.113 +
  10.114 +    def setVirqHandler(self, virqHandler):
  10.115 +        self.virqHandler = virqHandler
  10.116 +
  10.117 +    def virqReceived(self, virq):
  10.118 +        if 1 or DEBUG:
  10.119 +            print 'virqReceived>', virq
  10.120 +        if not self.virqHandler: return
  10.121 +        self.runInThread(lambda virq=virq: self.virqHandler(virq))
  10.122 +
  10.123 +    def newChannel(self, dom, local_port, remote_port):
  10.124 +        """Create a new channel.
  10.125 +        """
  10.126 +        return self.addChannel(Channel(self, dom, local_port, remote_port))
  10.127      
  10.128      def addChannel(self, channel):
  10.129 -        """Add a channel. Registers with the notifier.
  10.130 +        """Add a channel.
  10.131          """
  10.132 -        idx = channel.idx
  10.133 -        self.channels[idx] = channel
  10.134 -        self.notifier.bind(idx)
  10.135 -
  10.136 -    def getChannel(self, idx):
  10.137 -        """Get the channel with the given index (if any).
  10.138 -        """
  10.139 -        return self.channels.get(idx)
  10.140 +        self.channels[channel.getKey()] = channel
  10.141 +        return channel
  10.142  
  10.143 -    def delChannel(self, idx):
  10.144 -        """Remove the channel with the given index (if any).
  10.145 -        Deregisters with the notifier.
  10.146 +    def delChannel(self, channel):
  10.147 +        """Remove the channel.
  10.148          """
  10.149 -        if idx in self.channels:
  10.150 -            del self.channels[idx]
  10.151 -            self.notifier.unbind(idx)
  10.152 +        key = channel.getKey()
  10.153 +        if key in self.channels:
  10.154 +            del self.channels[key]
  10.155  
  10.156 -    def domChannel(self, dom, local_port=0, remote_port=0):
  10.157 -        """Get the channel for the given domain.
  10.158 -        Construct if necessary.
  10.159 +    def getChannel(self, dom, local_port, remote_port):
  10.160 +        """Get the channel with the given domain and ports (if any).
  10.161 +        """
  10.162 +        key = (dom, local_port, remote_port)
  10.163 +        return self.channels.get(key)
  10.164 +
  10.165 +    def findChannel(self, dom, local_port=0, remote_port=0):
  10.166 +        """Find a channel. Ports given as zero are wildcards.
  10.167  
  10.168          dom domain
  10.169  
  10.170          returns channel
  10.171          """
  10.172 -        chan = self.getDomChannel(dom)
  10.173 -        if not chan:
  10.174 -            chan = Channel(self, dom, local_port=local_port,
  10.175 -                           remote_port=remote_port)
  10.176 -            self.addChannel(chan)
  10.177 -        return chan
  10.178 -
  10.179 -    def getDomChannel(self, dom):
  10.180 -        """Get the channel for the given domain.
  10.181 -
  10.182 -        dom domain
  10.183 +        chan = self.getChannel(dom, local_port, remote_port)
  10.184 +        if chan: return chan
  10.185 +        if local_port and remote_port:
  10.186 +            return None
  10.187 +        for c in self.channels.values():
  10.188 +            if c.dom != dom: continue
  10.189 +            if local_port and local_port != c.getLocalPort(): continue
  10.190 +            if remote_port and remote_port != c.getRemotePort(): continue
  10.191 +            return c
  10.192 +        return None
  10.193  
  10.194 -        returns channel (or None)
  10.195 -        """
  10.196 -        dom = int(dom)
  10.197 -        for chan in self.channels.values():
  10.198 -            if not isinstance(chan, Channel): continue
  10.199 -            if chan.dom == dom:
  10.200 -                return chan
  10.201 -        return None
  10.202 -        
  10.203 -
  10.204 -    def virqChannel(self, virq):
  10.205 -        """Get the channel for the given virq.
  10.206 -        Construct if necessary.
  10.207 -        """
  10.208 -        for chan in self.channels.values():
  10.209 -            if not isinstance(chan, VirqChannel): continue
  10.210 -            if chan.virq == virq:
  10.211 -                return chan
  10.212 -        chan = VirqChannel(self, virq)
  10.213 -        self.addChannel(chan)
  10.214 -        return chan
  10.215 -
  10.216 -    def channelClosed(self, channel):
  10.217 -        """The given channel has been closed - remove it.
  10.218 -        """
  10.219 -        self.delChannel(channel.idx)
  10.220 +    def openChannel(self, dom, local_port=0, remote_port=0):
  10.221 +        return (self.findChannel(dom, local_port=local_port, remote_port=remote_port)
  10.222 +                or
  10.223 +                self.newChannel(dom, local_port, remote_port))
  10.224  
  10.225      def createPort(self, dom, local_port=0, remote_port=0):
  10.226          """Create a port for a channel to the given domain.
  10.227 @@ -147,122 +215,54 @@ def channelFactory():
  10.228          inst = ChannelFactory()
  10.229      return inst
  10.230  
  10.231 -class BaseChannel:
  10.232 -    """Abstract superclass for channels.
  10.233 -
  10.234 -    The subclass constructor must set idx to the port to use.
  10.235 -    """
  10.236 -
  10.237 -    def __init__(self, factory):
  10.238 -        self.factory = factory
  10.239 -        self.idx = -1
  10.240 -        self.closed = 0
  10.241 -
  10.242 -    def getIndex(self):
  10.243 -        """Get the channel index.
  10.244 -        """
  10.245 -        return self.idx
  10.246 -
  10.247 -    def notificationReceived(self):
  10.248 -        """Called when a notification is received.
  10.249 -        Calls handleNotification(), which should be defined
  10.250 -        in a subclass.
  10.251 -        """
  10.252 -        if self.closed: return
  10.253 -        self.handleNotification()
  10.254 +class Channel:
  10.255  
  10.256 -    def close(self):
  10.257 -        """Close the channel. Calls channelClosed() on the factory.
  10.258 -        Override in subclass.
  10.259 -        """
  10.260 -        self.factory.channelClosed(self)
  10.261 -
  10.262 -    def handleNotification(self):
  10.263 -        """Handle notification.
  10.264 -        Define in subclass.
  10.265 -        """
  10.266 -        pass
  10.267 -        
  10.268 -
  10.269 -class VirqChannel(BaseChannel):
  10.270 -    """A channel for handling a virq.
  10.271 -    """
  10.272 -    
  10.273 -    def __init__(self, factory, virq):
  10.274 -        """Create a channel for the given virq using the given factory.
  10.275 -
  10.276 -        Do not call directly, use virqChannel on the factory.
  10.277 -        """
  10.278 -        BaseChannel.__init__(self, factory)
  10.279 -        self.virq = virq
  10.280 +    def __init__(self, factory, dom, local_port, remote_port):
  10.281          self.factory = factory
  10.282 -        # Notification port (int).
  10.283 -        #self.port = xc.evtchn_bind_virq(virq)
  10.284 -        self.port = factory.notifier.bind_virq(virq)
  10.285 -        self.idx = self.port
  10.286 -        # Clients to call when a virq arrives.
  10.287 -        self.clients = []
  10.288 -
  10.289 -    def __repr__(self):
  10.290 -        return ('<VirqChannel virq=%d port=%d>'
  10.291 -                % (self.virq, self.port))
  10.292 -
  10.293 -    def getVirq(self):
  10.294 -        """Get the channel's virq.
  10.295 -        """
  10.296 -        return self.virq
  10.297 -
  10.298 -    def close(self):
  10.299 -        """Close the channel. Calls lostChannel(self) on all its clients and
  10.300 -        channelClosed() on the factory.
  10.301 -        """
  10.302 -        for c in self.clients[:]:
  10.303 -            c.lostChannel(self)
  10.304 -        self.clients = []
  10.305 -        BaseChannel.close(self)
  10.306 -
  10.307 -    def registerClient(self, client):
  10.308 -        """Register a client. The client will be called with
  10.309 -        client.virqReceived(virq) when a virq is received.
  10.310 -        The client will be called with client.lostChannel(self) if the
  10.311 -        channel is closed.
  10.312 -        """
  10.313 -        self.clients.append(client)
  10.314 -
  10.315 -    def handleNotification(self):
  10.316 -        for c in self.clients:
  10.317 -            c.virqReceived(self.virq)
  10.318 -
  10.319 -    def notify(self):
  10.320 -        # xc.evtchn_send(self.port)
  10.321 -        self.factory.notifier.virq_send(self.port)
  10.322 -
  10.323 -
  10.324 -class Channel(BaseChannel):
  10.325 -    """A control channel to a domain. Messages for the domain device controllers
  10.326 -    are multiplexed over the channel (console, block devs, net devs).
  10.327 -    """
  10.328 -
  10.329 -    def __init__(self, factory, dom, local_port=0, remote_port=0):
  10.330 -        """Create a channel to the given domain using the given factory.
  10.331 -
  10.332 -        Do not call directly, use domChannel on the factory.
  10.333 -        """
  10.334 -        BaseChannel.__init__(self, factory)
  10.335 -        # Domain.
  10.336          self.dom = int(dom)
  10.337 -        # Domain port (object).
  10.338 -        self.port = self.factory.createPort(dom, local_port=local_port,
  10.339 -                                            remote_port=remote_port)
  10.340 -        # Channel port (int).
  10.341 -        self.idx = self.port.local_port
  10.342          # Registered devices.
  10.343          self.devs = []
  10.344          # Devices indexed by the message types they handle.
  10.345          self.devs_by_type = {}
  10.346 -        # Output queue.
  10.347 -        self.queue = []
  10.348 -        self.closed = 0
  10.349 +        self.port = self.factory.createPort(self.dom,
  10.350 +                                            local_port=local_port,
  10.351 +                                            remote_port=remote_port)
  10.352 +        self.closed = False
  10.353 +        self.queue = ResponseQueue(self)
  10.354 +        # Make sure the port will deliver all the messages.
  10.355 +        self.port.register(TYPE_WILDCARD)
  10.356 +
  10.357 +    def getKey(self):
  10.358 +        """Get the channel key.
  10.359 +        """
  10.360 +        return (self.dom, self.getLocalPort(), self.getRemotePort())
  10.361 +
  10.362 +    def sxpr(self):
  10.363 +        val = ['channel']
  10.364 +        val.append(['domain', self.dom])
  10.365 +        if self.port:
  10.366 +            val.append(['local_port', self.port.local_port])
  10.367 +            val.append(['remote_port', self.port.remote_port])
  10.368 +        return val
  10.369 +
  10.370 +    def close(self):
  10.371 +        """Close the channel.
  10.372 +        """
  10.373 +        if DEBUG:
  10.374 +            print 'Channel>close>', self
  10.375 +        if self.closed: return
  10.376 +        self.closed = True
  10.377 +        self.factory.delChannel(self)
  10.378 +        for d in self.devs[:]:
  10.379 +            d.lostChannel(self)
  10.380 +        self.devs = []
  10.381 +        self.devs_by_type = {}
  10.382 +        if self.port:
  10.383 +            self.port.close()
  10.384 +            #self.port = None
  10.385 +
  10.386 +    def getDomain(self):
  10.387 +        return self.dom
  10.388  
  10.389      def getLocalPort(self):
  10.390          """Get the local port.
  10.391 @@ -282,18 +282,12 @@ class Channel(BaseChannel):
  10.392          if self.closed: return -1
  10.393          return self.port.remote_port
  10.394  
  10.395 -    def close(self):
  10.396 -        """Close the channel. Calls lostChannel() on all its devices and
  10.397 -        channelClosed() on the factory.
  10.398 -        """
  10.399 -        if self.closed: return
  10.400 -        self.closed = 1
  10.401 -        for d in self.devs[:]:
  10.402 -            d.lostChannel()
  10.403 -        self.factory.channelClosed(self)
  10.404 -        self.devs = []
  10.405 -        self.devs_by_type = {}
  10.406 -        self.port.disconnect()
  10.407 +    def __repr__(self):
  10.408 +        return ('<Channel dom=%d ports=%d:%d>'
  10.409 +                % (self.dom,
  10.410 +                   self.getLocalPort(),
  10.411 +                   self.getRemotePort()))
  10.412 +
  10.413  
  10.414      def registerDevice(self, types, dev):
  10.415          """Register a device controller.
  10.416 @@ -306,7 +300,6 @@ class Channel(BaseChannel):
  10.417          self.devs.append(dev)
  10.418          for ty in types:
  10.419              self.devs_by_type[ty] = dev
  10.420 -        self.port.register(ty)
  10.421  
  10.422      def deregisterDevice(self, dev):
  10.423          """Remove the registration for a device controller.
  10.424 @@ -318,7 +311,6 @@ class Channel(BaseChannel):
  10.425          types = [ ty for (ty, d) in self.devs_by_type.items() if d == dev ]
  10.426          for ty in types:
  10.427              del self.devs_by_type[ty]
  10.428 -            self.port.deregister(ty)
  10.429  
  10.430      def getDevice(self, type):
  10.431          """Get the device controller handling a message type.
  10.432 @@ -330,130 +322,160 @@ class Channel(BaseChannel):
  10.433          """
  10.434          return self.devs_by_type.get(type)
  10.435  
  10.436 -    def getMessageType(self, msg):
  10.437 -        """Get a 2-tuple of the message type and subtype.
  10.438 -
  10.439 -        @param msg: message
  10.440 -        @type  msg: xu message
  10.441 -        @return: type info
  10.442 -        @rtype:  (int, int)
  10.443 -        """
  10.444 -        hdr = msg.get_header()
  10.445 -        return (hdr['type'], hdr.get('subtype'))
  10.446 -
  10.447 -    def __repr__(self):
  10.448 -        return ('<Channel dom=%d ports=%d:%d>'
  10.449 -                % (self.dom,
  10.450 -                   self.getLocalPort(),
  10.451 -                   self.getRemotePort()))
  10.452 -
  10.453 -    def handleNotification(self):
  10.454 -        """Process outstanding messages in repsonse to notification on the port.
  10.455 -        """
  10.456 -        if self.closed:
  10.457 -            print 'handleNotification> Notification on closed channel', self
  10.458 -            return
  10.459 -        work = 0
  10.460 -        work += self.handleRequests()
  10.461 -        work += self.handleResponses()
  10.462 -        work += self.handleWrites()
  10.463 -        if work:
  10.464 -            self.notify()
  10.465 -
  10.466 -    def notify(self):
  10.467 -        """Notify the other end of the port that messages have been processed.
  10.468 -        """
  10.469 -        if self.closed: return
  10.470 -        self.port.notify()
  10.471 -
  10.472 -    def handleRequests(self):
  10.473 -        work = 0
  10.474 -        while 1:
  10.475 -            msg = self.readRequest()
  10.476 -            if not msg: break
  10.477 -            self.requestReceived(msg)
  10.478 -            work += 1
  10.479 -        return work
  10.480 -
  10.481      def requestReceived(self, msg):
  10.482 -        (ty, subty) = self.getMessageType(msg)
  10.483 -        #todo:  Must respond before writing any more messages.
  10.484 -        #todo:  Should automate this (respond on write)
  10.485 -        responded = 0
  10.486 +        if DEBUG:
  10.487 +            print 'Channel>requestReceived>', self,
  10.488 +            printMsg(msg)
  10.489 +        (ty, subty) = getMessageType(msg)
  10.490 +        responded = False
  10.491          dev = self.getDevice(ty)
  10.492          if dev:
  10.493              responded = dev.requestReceived(msg, ty, subty)
  10.494 +        elif DEBUG:
  10.495 +            print "Channel>requestReceived> No device", self,
  10.496 +            printMsg(msg)
  10.497          else:
  10.498 -            print ("requestReceived> No device: Message type %s %d:%d"
  10.499 -                   % (msgTypeName(ty, subty), ty, subty)), self
  10.500 +            pass
  10.501          if not responded:
  10.502 -            self.port.write_response(msg)
  10.503 -
  10.504 -    def handleResponses(self):
  10.505 -        work = 0
  10.506 -        while 1:
  10.507 -            msg = self.readResponse()
  10.508 -            if not msg: break
  10.509 -            self.responseReceived(msg)
  10.510 -            work += 1
  10.511 -        return work
  10.512 -
  10.513 -    def responseReceived(self, msg):
  10.514 -        (ty, subty) = self.getMessageType(msg)
  10.515 -        dev = self.getDevice(ty)
  10.516 -        if dev:
  10.517 -            dev.responseReceived(msg, ty, subty)
  10.518 -        else:
  10.519 -            print ("responseReceived> No device: Message type %d:%d"
  10.520 -                   % (msgTypeName(ty, subty), ty, subty)), self
  10.521 +            self.writeResponse(msg)
  10.522  
  10.523 -    def handleWrites(self):
  10.524 -        work = 0
  10.525 -        # Pull data from producers.
  10.526 -        for dev in self.devs:
  10.527 -            work += dev.produceRequests()
  10.528 -        # Flush the queue.
  10.529 -        while self.queue and self.port.space_to_write_request():
  10.530 -            msg = self.queue.pop(0)
  10.531 -            self.port.write_request(msg)
  10.532 -            work += 1
  10.533 -        return work
  10.534 -
  10.535 -    def writeRequest(self, msg, notify=1):
  10.536 -        if self.closed:
  10.537 -            val = -1
  10.538 -        elif self.writeReady():
  10.539 -            self.port.write_request(msg)
  10.540 -            if notify: self.notify()
  10.541 -            val = 1
  10.542 -        else:
  10.543 -            self.queue.append(msg)
  10.544 -            val = 0
  10.545 -        return val
  10.546 +    def writeRequest(self, msg):
  10.547 +        if DEBUG:
  10.548 +            print 'Channel>writeRequest>', self,
  10.549 +            printMsg(msg, all=True)
  10.550 +        if self.closed: return -1
  10.551 +        self.port.write_request(msg)
  10.552 +        return 1
  10.553  
  10.554      def writeResponse(self, msg):
  10.555 -        if self.closed: return -1
  10.556 -        self.port.write_response(msg)
  10.557 +        if DEBUG:
  10.558 +            print 'Channel>writeResponse>', self,
  10.559 +            printMsg(msg, all=True)
  10.560 +        if self.port:
  10.561 +            self.port.write_response(msg)
  10.562          return 1
  10.563  
  10.564 -    def writeReady(self):
  10.565 -        if self.closed or self.queue: return 0
  10.566 -        return self.port.space_to_write_request()
  10.567 -
  10.568      def readRequest(self):
  10.569          if self.closed:
  10.570 -            return None
  10.571 -        if self.port.request_to_read():
  10.572 +            val =  None
  10.573 +        else:
  10.574              val = self.port.read_request()
  10.575 -        else:
  10.576 -            val = None
  10.577          return val
  10.578          
  10.579      def readResponse(self):
  10.580          if self.closed:
  10.581 -            return None
  10.582 -        if self.port.response_to_read():
  10.583 +            val = None
  10.584 +        else:
  10.585              val = self.port.read_response()
  10.586 +        if DEBUG and val:
  10.587 +            print 'Channel>readResponse>', self,
  10.588 +            printMsg(val, all=True)
  10.589 +        return val
  10.590 +
  10.591 +    def requestResponse(self, msg, timeout=None):
  10.592 +        """Write a request and wait for a response.
  10.593 +        Raises IOError on timeout.
  10.594 +
  10.595 +        @param msg request message
  10.596 +        @param timeout timeout (0 is forever)
  10.597 +        @return response message
  10.598 +        """
  10.599 +        if self.closed:
  10.600 +            raise IOError("closed")
  10.601 +        if self.closed:
  10.602 +            return None
  10.603 +        if timeout is None:
  10.604 +            timeout = RESPONSE_TIMEOUT
  10.605 +        elif timeout <= 0:
  10.606 +            timeout = None
  10.607 +        return self.queue.call(msg, timeout)
  10.608 +
  10.609 +    def responseReceived(self, msg):
  10.610 +        if DEBUG:
  10.611 +            print 'Channel>responseReceived>', self,
  10.612 +            printMsg(msg)
  10.613 +        self.queue.response(getMessageId(msg), msg)
  10.614 +
  10.615 +    def virq(self):
  10.616 +        self.factory.virq()
  10.617 +
  10.618 +
  10.619 +class Response:
  10.620 +    """Entry in the response queue.
  10.621 +    Used to signal a response to a message.
  10.622 +    """
  10.623 +
  10.624 +    def __init__(self, mid):
  10.625 +        self.mid = mid
  10.626 +        self.msg = None
  10.627 +        self.ready = threading.Event()
  10.628 +
  10.629 +    def response(self, msg):
  10.630 +        """Signal arrival of a response to a waiting thread.
  10.631 +        Passing msg None cancels the wait with an IOError.
  10.632 +        """
  10.633 +        if msg:
  10.634 +            self.msg = msg
  10.635          else:
  10.636 -            val = None
  10.637 -        return val
  10.638 +            self.mid = -1
  10.639 +        self.ready.set()
  10.640 +
  10.641 +    def wait(self, timeout):
  10.642 +        """Wait up to 'timeout' seconds for a response.
  10.643 +        Returns the response or raises an IOError.
  10.644 +        """
  10.645 +        self.ready.wait(timeout)
  10.646 +        if self.mid < 0:
  10.647 +            raise IOError("wait canceled")
  10.648 +        if self.msg is None:
  10.649 +            raise IOError("response timeout")
  10.650 +        return self.msg
  10.651 +
  10.652 +class ResponseQueue:
  10.653 +    """Response queue. Manages waiters for responses to messages.
  10.654 +    """
  10.655 +
  10.656 +    def __init__(self, channel):
  10.657 +        self.channel = channel
  10.658 +        self.lock = threading.Lock()
  10.659 +        self.responses = {}
  10.660 +
  10.661 +    def add(self, mid):
  10.662 +        r = Response(mid)
  10.663 +        self.responses[mid] = r
  10.664 +        return r
  10.665 +
  10.666 +    def get(self, mid):
  10.667 +        return self.responses.get(mid)
  10.668 +
  10.669 +    def remove(self, mid):
  10.670 +        r = self.responses.get(mid)
  10.671 +        if r:
  10.672 +            del self.responses[mid]
  10.673 +        return r
  10.674 +
  10.675 +    def response(self, mid, msg):
  10.676 +        """Process a response.
  10.677 +        """
  10.678 +        try:
  10.679 +            self.lock.acquire()
  10.680 +            r = self.remove(mid)
  10.681 +        finally:
  10.682 +            self.lock.release()
  10.683 +        if r:
  10.684 +            r.response(msg)
  10.685 +
  10.686 +    def call(self, msg, timeout):
  10.687 +        """Send the message and wait for 'timeout' seconds for a response.
  10.688 +        Returns the response.
  10.689 +        Raises IOError on timeout.
  10.690 +        """
  10.691 +        mid = getMessageId(msg)
  10.692 +        try:
  10.693 +            self.lock.acquire()
  10.694 +            r = self.add(mid)
  10.695 +        finally:
  10.696 +            self.lock.release()
  10.697 +        self.channel.writeRequest(msg)
  10.698 +        return r.wait(timeout)
  10.699 +                
    11.1 --- a/tools/python/xen/xend/server/console.py	Tue Apr 19 13:48:05 2005 +0000
    11.2 +++ b/tools/python/xen/xend/server/console.py	Wed Apr 20 08:45:19 2005 +0000
    11.3 @@ -2,19 +2,17 @@
    11.4  
    11.5  import socket
    11.6  
    11.7 -from twisted.internet import reactor
    11.8 -from twisted.internet import protocol
    11.9 +from twisted.internet import reactor, protocol
   11.10  
   11.11  from xen.lowlevel import xu
   11.12  
   11.13  from xen.xend.XendError import XendError
   11.14 -from xen.xend import EventServer
   11.15 -eserver = EventServer.instance()
   11.16 +from xen.xend import EventServer; eserver = EventServer.instance()
   11.17  from xen.xend.XendLogging import log
   11.18 -from xen.xend import XendRoot
   11.19 -xroot = XendRoot.instance()
   11.20 +from xen.xend import XendRoot; xroot = XendRoot.instance()
   11.21 +from xen.xend import sxp
   11.22  
   11.23 -import controller
   11.24 +from controller import CtrlMsgRcvr, Dev, DevController
   11.25  from messages import *
   11.26  from params import *
   11.27  
   11.28 @@ -22,31 +20,28 @@ class ConsoleProtocol(protocol.Protocol)
   11.29      """Asynchronous handler for a console TCP socket.
   11.30      """
   11.31  
   11.32 -    def __init__(self, controller, idx):
   11.33 -        self.controller = controller
   11.34 -        self.idx = idx
   11.35 +    def __init__(self, console, id):
   11.36 +        self.console = console
   11.37 +        self.id = id
   11.38          self.addr = None
   11.39          self.binary = 0
   11.40  
   11.41      def connectionMade(self):
   11.42          peer = self.transport.getPeer()
   11.43          self.addr = (peer.host, peer.port)
   11.44 -        if self.controller.connect(self.addr, self):
   11.45 +        if self.console.connect(self.addr, self):
   11.46              self.transport.write("Cannot connect to console %d on domain %d\n"
   11.47 -                                 % (self.idx, self.controller.dom))
   11.48 +                                 % (self.id, self.console.dom))
   11.49              self.loseConnection()
   11.50              return
   11.51          else:
   11.52 -            # KAF: A nice quiet successful connect.
   11.53 -            #self.transport.write("Connected to console %d on domain %d\n"
   11.54 -            #                     % (self.idx, self.controller.dom))
   11.55              log.info("Console connected %s %s %s",
   11.56 -                     self.idx, str(self.addr[0]), str(self.addr[1]))
   11.57 +                     self.id, str(self.addr[0]), str(self.addr[1]))
   11.58              eserver.inject('xend.console.connect',
   11.59 -                           [self.idx, self.addr[0], self.addr[1]])
   11.60 +                           [self.id, self.addr[0], self.addr[1]])
   11.61  
   11.62      def dataReceived(self, data):
   11.63 -        if self.controller.handleInput(self, data):
   11.64 +        if self.console.receiveInput(self, data):
   11.65              self.loseConnection()
   11.66  
   11.67      def write(self, data):
   11.68 @@ -55,10 +50,10 @@ class ConsoleProtocol(protocol.Protocol)
   11.69  
   11.70      def connectionLost(self, reason=None):
   11.71          log.info("Console disconnected %s %s %s",
   11.72 -                 self.idx, str(self.addr[0]), str(self.addr[1]))
   11.73 +                 str(self.id), str(self.addr[0]), str(self.addr[1]))
   11.74          eserver.inject('xend.console.disconnect',
   11.75 -                       [self.idx, self.addr[0], self.addr[1]])
   11.76 -        self.controller.disconnect(conn=self)
   11.77 +                       [self.id, self.addr[0], self.addr[1]])
   11.78 +        self.console.disconnect(conn=self)
   11.79  
   11.80      def loseConnection(self):
   11.81          self.transport.loseConnection()
   11.82 @@ -68,42 +63,19 @@ class ConsoleFactory(protocol.ServerFact
   11.83      """
   11.84      protocol = ConsoleProtocol
   11.85      
   11.86 -    def __init__(self, controller, idx):
   11.87 +    def __init__(self, console, id):
   11.88          #protocol.ServerFactory.__init__(self)
   11.89 -        self.controller = controller
   11.90 -        self.idx = idx
   11.91 +        self.console = console
   11.92 +        self.id = id
   11.93  
   11.94      def buildProtocol(self, addr):
   11.95 -        proto = self.protocol(self.controller, self.idx)
   11.96 +        proto = self.protocol(self.console, self.id)
   11.97          proto.factory = self
   11.98          return proto
   11.99  
  11.100 -class ConsoleControllerFactory(controller.ControllerFactory):
  11.101 -    """Factory for creating console controllers.
  11.102 -    """
  11.103 -
  11.104 -    def createController(self, dom, console_port=None):
  11.105 -        if console_port is None:
  11.106 -            console_port = xroot.get_console_port_base() + dom
  11.107 -        for c in self.getControllers():
  11.108 -            if c.console_port == console_port:
  11.109 -                raise XendError('console port in use: ' + str(console_port))
  11.110 -        console = ConsoleController(self, dom, console_port)
  11.111 -        self.addController(console)
  11.112 -        log.info("Created console id=%s domain=%d port=%d",
  11.113 -                 console.idx, console.dom, console.console_port)
  11.114 -        eserver.inject('xend.console.create',
  11.115 -                       [console.idx, console.dom, console.console_port])
  11.116 -        return console
  11.117 -        
  11.118 -    def consoleClosed(self, console):
  11.119 -        log.info("Closed console id=%s", console.idx)
  11.120 -        eserver.inject('xend.console.close', console.idx)
  11.121 -        self.delController(console)
  11.122 -
  11.123 -class ConsoleController(controller.Controller):
  11.124 -    """Console controller for a domain.
  11.125 -    Does not poll for i/o itself, but relies on the notifier to post console
  11.126 +class ConsoleDev(Dev):
  11.127 +    """Console device for a domain.
  11.128 +    Does not poll for i/o itself, but relies on the domain to post console
  11.129      output and the connected TCP sockets to post console input.
  11.130      """
  11.131  
  11.132 @@ -112,28 +84,53 @@ class ConsoleController(controller.Contr
  11.133      STATUS_CONNECTED = 'connected'
  11.134      STATUS_LISTENING = 'listening'
  11.135  
  11.136 -    def __init__(self, factory, dom, console_port):
  11.137 -        controller.Controller.__init__(self, factory, dom)
  11.138 -        self.addMethod(CMSG_CONSOLE, 0, None)
  11.139 +    def __init__(self, controller, id, config, recreate=False):
  11.140 +        print 'Console>'
  11.141 +        Dev.__init__(self, controller, id, config)
  11.142          self.status = self.STATUS_NEW
  11.143          self.addr = None
  11.144          self.conn = None
  11.145 -        self.rbuf = xu.buffer()
  11.146 -        self.wbuf = xu.buffer()
  11.147 +        self.console_port = None
  11.148 +        self.obuf = xu.buffer()
  11.149 +        self.ibuf = xu.buffer()
  11.150 +        self.channel = None
  11.151 +        self.listener = None
  11.152 +        
  11.153 +        console_port = sxp.child_value(self.config, "console_port")
  11.154 +        if console_port is None:
  11.155 +            console_port = xroot.get_console_port_base() + self.getDomain()
  11.156 +        self.checkConsolePort(console_port)
  11.157          self.console_port = console_port
  11.158 +        
  11.159 +        log.info("Created console id=%d domain=%d port=%d",
  11.160 +                 self.id, self.getDomain(), self.console_port)
  11.161 +        eserver.inject('xend.console.create',
  11.162 +                       [self.id, self.getDomain(), self.console_port])
  11.163  
  11.164 -        self.registerChannel()
  11.165 -        self.listener = None
  11.166 +    def init(self, recreate=False, reboot=False):
  11.167 +        print 'Console>init>'
  11.168 +        self.destroyed = False
  11.169 +        self.channel = self.getChannel()
  11.170          self.listen()
  11.171  
  11.172 +    def checkConsolePort(self, console_port):
  11.173 +        """Check that a console port is not in use by another console.
  11.174 +        """
  11.175 +        xd = XendRoot.get_component('xen.xend.XendDomain')
  11.176 +        for vm in xd.domains():
  11.177 +            ctrl = vm.getDeviceController(self.getType(), error=False)
  11.178 +            if (not ctrl): continue
  11.179 +            ctrl.checkConsolePort(console_port)
  11.180 +    
  11.181      def sxpr(self):
  11.182          val = ['console',
  11.183                 ['status', self.status ],
  11.184 -               ['id',     self.idx    ],
  11.185 -               ['domain', self.dom    ] ]
  11.186 +               ['id',     self.id    ],
  11.187 +               ['domain', self.getDomain() ] ]
  11.188          val.append(['local_port',   self.getLocalPort()  ])
  11.189          val.append(['remote_port',  self.getRemotePort() ])
  11.190          val.append(['console_port', self.console_port    ])
  11.191 +        val.append(['index', self.getIndex()])
  11.192          if self.addr:
  11.193              val.append(['connected', self.addr[0], self.addr[1]])
  11.194          return val
  11.195 @@ -159,42 +156,33 @@ class ConsoleController(controller.Contr
  11.196          host = socket.gethostname()
  11.197          return "telnet://%s:%d" % (host, self.console_port)
  11.198  
  11.199 -    def ready(self):
  11.200 -        return not (self.closed() or self.rbuf.empty())
  11.201 -
  11.202      def closed(self):
  11.203          return self.status == self.STATUS_CLOSED
  11.204  
  11.205      def connected(self):
  11.206          return self.status == self.STATUS_CONNECTED
  11.207  
  11.208 -    def close(self):
  11.209 -        """Close the console controller.
  11.210 +    def destroy(self, change=False, reboot=False):
  11.211 +        """Close the console.
  11.212          """
  11.213 -        self.lostChannel()
  11.214 -
  11.215 -    def lostChannel(self):
  11.216 -        """The channel to the domain has been lost.
  11.217 -        Cleanup: disconnect TCP connections and listeners, notify the controller.
  11.218 -        """
  11.219 +        if reboot:
  11.220 +            return
  11.221          self.status = self.STATUS_CLOSED
  11.222          if self.conn:
  11.223              self.conn.loseConnection()
  11.224          self.listener.stopListening()
  11.225 -        controller.Controller.lostChannel(self)
  11.226  
  11.227      def listen(self):
  11.228          """Listen for TCP connections to the console port..
  11.229          """
  11.230          if self.closed(): return
  11.231 -        self.status = self.STATUS_LISTENING
  11.232          if self.listener:
  11.233 -            #self.listener.startListening()
  11.234              pass
  11.235          else:
  11.236 -            f = ConsoleFactory(self, self.idx)
  11.237 +            self.status = self.STATUS_LISTENING
  11.238 +            cf = ConsoleFactory(self, self.id)
  11.239              interface = xroot.get_console_address()
  11.240 -            self.listener = reactor.listenTCP(self.console_port, f, interface=interface)
  11.241 +            self.listener = reactor.listenTCP(self.console_port, cf, interface=interface)
  11.242  
  11.243      def connect(self, addr, conn):
  11.244          """Connect a TCP connection to the console.
  11.245 @@ -210,7 +198,7 @@ class ConsoleController(controller.Contr
  11.246          self.addr = addr
  11.247          self.conn = conn
  11.248          self.status = self.STATUS_CONNECTED
  11.249 -        self.handleOutput()
  11.250 +        self.writeOutput()
  11.251          return 0
  11.252  
  11.253      def disconnect(self, conn=None):
  11.254 @@ -221,68 +209,107 @@ class ConsoleController(controller.Contr
  11.255              self.conn.loseConnection()
  11.256          self.addr = None
  11.257          self.conn = None
  11.258 +        self.status = self.STATUS_LISTENING
  11.259          self.listen()
  11.260  
  11.261 -    def requestReceived(self, msg, type, subtype):
  11.262 -        """Receive console data from the console channel.
  11.263 +    def receiveOutput(self, msg):
  11.264 +        """Receive output console data from the console channel.
  11.265  
  11.266          msg     console message
  11.267          type    major message type
  11.268          subtype minor message typ
  11.269          """
  11.270 -        self.rbuf.write(msg.get_payload())
  11.271 -        self.handleOutput()
  11.272 +        # Treat the obuf as a ring buffer.
  11.273 +        data = msg.get_payload()
  11.274 +        data_n = len(data)
  11.275 +        if self.obuf.space() < data_n:
  11.276 +            self.obuf.discard(data_n)
  11.277 +        if self.obuf.space() < data_n:
  11.278 +            data = data[-self.obuf.space():]
  11.279 +        self.obuf.write(data)
  11.280 +        self.writeOutput()
  11.281          
  11.282 -    def responseReceived(self, msg, type, subtype):
  11.283 -        """Handle a response to a request written to the console channel.
  11.284 -        Just ignore it because the return values are not interesting.
  11.285 -
  11.286 -        msg     console message
  11.287 -        type    major message type
  11.288 -        subtype minor message typ
  11.289 +    def writeOutput(self):
  11.290 +        """Handle buffered output from the console device.
  11.291 +        Sends it to the connected TCP connection (if any).
  11.292          """
  11.293 -        pass
  11.294 -
  11.295 -    def produceRequests(self):
  11.296 -        """Write pending console data to the console channel.
  11.297 -        Writes as much to the channel as it can.
  11.298 -        """
  11.299 -        work = 0
  11.300 -        while self.channel and not self.wbuf.empty() and self.channel.writeReady():
  11.301 -            msg = xu.message(CMSG_CONSOLE, 0, 0)
  11.302 -            msg.append_payload(self.wbuf.read(msg.MAX_PAYLOAD))
  11.303 -            work += self.channel.writeRequest(msg, notify=0)
  11.304 -        return work
  11.305 -
  11.306 -    def handleInput(self, conn, data):
  11.307 -        """Handle some external input aimed at the console.
  11.308 -        Called from a TCP connection (conn). Ignores the input
  11.309 -        if the calling connection (conn) is not the one connected
  11.310 -        to the console (self.conn).
  11.311 +        if self.closed():
  11.312 +            return -1
  11.313 +        if not self.conn:
  11.314 +            return 0
  11.315 +        while not self.obuf.empty():
  11.316 +            try:
  11.317 +                bytes = self.conn.write(self.obuf.peek())
  11.318 +                if bytes > 0:
  11.319 +                    self.obuf.discard(bytes)
  11.320 +            except socket.error:
  11.321 +                pass
  11.322 +        return 0
  11.323 +    
  11.324 +    def receiveInput(self, conn, data):
  11.325 +        """Receive console input from a TCP connection.  Ignores the
  11.326 +        input if the calling connection (conn) is not the one
  11.327 +        connected to the console (self.conn).
  11.328  
  11.329          conn connection
  11.330          data input data
  11.331          """
  11.332          if self.closed(): return -1
  11.333          if conn != self.conn: return 0
  11.334 -        self.wbuf.write(data)
  11.335 -        if self.channel and self.produceRequests():
  11.336 -            self.channel.notify()
  11.337 +        self.ibuf.write(data)
  11.338 +        self.writeInput()
  11.339          return 0
  11.340  
  11.341 -    def handleOutput(self):
  11.342 -        """Handle buffered output from the console.
  11.343 -        Sends it to the connected console (if any).
  11.344 +    def writeInput(self):
  11.345 +        """Write pending console input to the console channel.
  11.346 +        Writes as much to the channel as it can.
  11.347          """
  11.348 -        if self.closed():
  11.349 -            return -1
  11.350 -        if not self.conn:
  11.351 -            return 0
  11.352 -        while not self.rbuf.empty():
  11.353 -            try:
  11.354 -                bytes = self.conn.write(self.rbuf.peek())
  11.355 -                if bytes > 0:
  11.356 -                    self.rbuf.discard(bytes)
  11.357 -            except socket.error, error:
  11.358 -                pass
  11.359 -        return 0
  11.360 +        while self.channel and not self.ibuf.empty():
  11.361 +            msg = xu.message(CMSG_CONSOLE, 0, 0)
  11.362 +            msg.append_payload(self.ibuf.read(msg.MAX_PAYLOAD))
  11.363 +            self.channel.writeRequest(msg)
  11.364 +
  11.365 +class ConsoleController(DevController):
  11.366 +    """Device controller for all the consoles for a domain.
  11.367 +    """
  11.368 +
  11.369 +    def __init__(self, dctype, vm, recreate=False):
  11.370 +        DevController.__init__(self, dctype, vm, recreate=recreate)
  11.371 +        self.rcvr = None
  11.372 +
  11.373 +    def initController(self, recreate=False, reboot=False):
  11.374 +        self.destroyed = False
  11.375 +        self.rcvr = CtrlMsgRcvr(self.getChannel())
  11.376 +        self.rcvr.addHandler(CMSG_CONSOLE,
  11.377 +                             0,
  11.378 +                             self.receiveOutput)
  11.379 +        self.rcvr.registerChannel()
  11.380 +        if reboot:
  11.381 +            self.rebootDevices()
  11.382 +
  11.383 +    def destroyController(self, reboot=False):
  11.384 +        self.destroyed = True
  11.385 +        self.destroyDevices(reboot=reboot)
  11.386 +        self.rcvr.deregisterChannel()
  11.387 +
  11.388 +    def newDevice(self, id, config, recreate=False):
  11.389 +        return ConsoleDev(self, id, config, recreate=recreate)
  11.390 +
  11.391 +    def checkConsolePort(self, console_port):
  11.392 +        """Check that a console port is not in use by a console.
  11.393 +        """
  11.394 +        for c in self.getDevices():
  11.395 +            if c.console_port == console_port:
  11.396 +                raise XendError('console port in use: ' + str(console_port))
  11.397 +
  11.398 +    def receiveOutput(self, msg):
  11.399 +        """Handle a control request.
  11.400 +        The CMSG_CONSOLE messages just contain data, and no console id,
  11.401 +        so just send to console 0 (if there is one).
  11.402 +
  11.403 +        todo: extend CMSG_CONSOLE to support more than one console?
  11.404 +        """
  11.405 +        console = self.getDevice(0)
  11.406 +        if console:
  11.407 +            console.receiveOutput(msg)
  11.408 +
    12.1 --- a/tools/python/xen/xend/server/controller.py	Tue Apr 19 13:48:05 2005 +0000
    12.2 +++ b/tools/python/xen/xend/server/controller.py	Wed Apr 20 08:45:19 2005 +0000
    12.3 @@ -3,84 +3,29 @@
    12.4  for a domain.
    12.5  """
    12.6  
    12.7 -from twisted.internet import defer
    12.8 -#defer.Deferred.debug = 1
    12.9 -
   12.10 -import channel
   12.11 -from messages import msgTypeName, printMsg
   12.12 +from xen.xend.XendError import XendError
   12.13 +from messages import msgTypeName, printMsg, getMessageType
   12.14  
   12.15  DEBUG = 0
   12.16  
   12.17 -class Responder:
   12.18 -    """Handler for a response to a message with a specified id.
   12.19 +class CtrlMsgRcvr:
   12.20 +    """Dispatcher class for messages on a control channel.
   12.21 +    Once I{registerChannel} has been called, our message types are registered
   12.22 +    with the channel. The channel will call I{requestReceived}
   12.23 +    when a request arrives if it has one of our message types.
   12.24 +
   12.25 +    @ivar channel: channel to a domain
   12.26 +    @type channel: Channel
   12.27 +    @ivar majorTypes: major message types we are interested in
   12.28 +    @type majorTypes: {int:{int:method}}
   12.29 +    
   12.30      """
   12.31  
   12.32 -    def __init__(self, mid, deferred):
   12.33 -        """Create a responder.
   12.34 -
   12.35 -        @param mid: message id of response to handle
   12.36 -        @type  mid: int
   12.37 -        @param deferred: deferred object holding the callbacks
   12.38 -        @type  deferred: Deferred
   12.39 -        """
   12.40 -        self.mid = mid
   12.41 -        self.deferred = deferred
   12.42 -
   12.43 -    def responseReceived(self, msg):
   12.44 -        """Entry point called when a response message with the right id arrives.
   12.45 -        Calls callback on I{self.deferred} with the message.
   12.46 -
   12.47 -        @param msg: response message
   12.48 -        @type  msg: xu message
   12.49 -        """
   12.50 -        if self.deferred.called: return
   12.51 -        self.deferred.callback(msg)
   12.52 -
   12.53 -    def error(self, err):
   12.54 -        """Entry point called when there has been an error.
   12.55 -        Calls errback on I{self.deferred} with the error.
   12.56 -
   12.57 -        @param err: error
   12.58 -        @type  err: Exception
   12.59 -        """
   12.60 -        if self.deferred.called: return
   12.61 -        self.deferred.errback(err)
   12.62 +    def __init__(self, channel):
   12.63 +        self.majorTypes = {}
   12.64 +        self.channel = channel
   12.65  
   12.66 -class CtrlMsgRcvr:
   12.67 -    """Abstract class for things that deal with a control interface to a domain.
   12.68 -    Once I{registerChannel} has been called, our message types are registered
   12.69 -    with the channel to the domain. The channel will call I{requestReceived}
   12.70 -    when a request arrives, or I{responseReceived} when a response arrives,
   12.71 -    if they have one of our message types.
   12.72 -
   12.73 -    @ivar dom: the domain we are a control interface for
   12.74 -    @type dom: int
   12.75 -    @ivar majorTypes: major message types we are interested in
   12.76 -    @type majorTypes: {int:{int:method}}
   12.77 -    @ivar timeout: timeout (in seconds) for message handlers
   12.78 -    @type timeout: int
   12.79 -    
   12.80 -    @ivar channel: channel to the domain
   12.81 -    @type channel: Channel
   12.82 -    @ivar idx: channel index
   12.83 -    @ivar idx: string
   12.84 -    @ivar responders: table of message response handlers
   12.85 -    @type responders: {int:Responder}
   12.86 -    """
   12.87 -
   12.88 -    def __init__(self):
   12.89 -        self.channelFactory = channel.channelFactory()
   12.90 -        self.majorTypes = {}
   12.91 -        self.dom = None
   12.92 -        self.channel = None
   12.93 -        self.idx = None
   12.94 -        self.responders = {}
   12.95 -        self.timeout = 10
   12.96 -
   12.97 -    def setTimeout(self, timeout):
   12.98 -        self.timeout = timeout
   12.99 -
  12.100 -    def getMethod(self, type, subtype):
  12.101 +    def getHandler(self, type, subtype):
  12.102          """Get the method for a type and subtype.
  12.103  
  12.104          @param type: major message type
  12.105 @@ -93,7 +38,7 @@ class CtrlMsgRcvr:
  12.106              method = subtypes.get(subtype)
  12.107          return method
  12.108  
  12.109 -    def addMethod(self, type, subtype, method):
  12.110 +    def addHandler(self, type, subtype, method):
  12.111          """Add a method to handle a message type and subtype.
  12.112          
  12.113          @param type: major message type
  12.114 @@ -124,102 +69,31 @@ class CtrlMsgRcvr:
  12.115          """
  12.116          if DEBUG:
  12.117              print 'requestReceived>',
  12.118 -            printMsg(msg, all=1)
  12.119 +            printMsg(msg, all=True)
  12.120          responded = 0
  12.121 -        method = self.getMethod(type, subtype)
  12.122 +        method = self.getHandler(type, subtype)
  12.123          if method:
  12.124 -            responded = method(msg, 1)
  12.125 +            responded = method(msg)
  12.126          elif DEBUG:
  12.127              print ('requestReceived> No handler: Message type %s %d:%d'
  12.128                     % (msgTypeName(type, subtype), type, subtype)), self
  12.129          return responded
  12.130          
  12.131 -    def responseReceived(self, msg, type, subtype):
  12.132 -        """Dispatch a response to handlers.
  12.133 -        Called by the channel for responses with one of our types.
  12.134 -        
  12.135 -        First looks for a message responder for the message's id.
  12.136 -        See L{callResponders}, L{addResponder}.
  12.137 -        If there is no responder, looks for a message handler for
  12.138 -        the message type/subtype.
  12.139 -
  12.140 -        @param msg:     message
  12.141 -        @type  msg:     xu message
  12.142 -        @param type:    major message type
  12.143 -        @type  type:    int
  12.144 -        @param subtype: minor message type
  12.145 -        @type  subtype: int
  12.146 -        """
  12.147 -        if DEBUG:
  12.148 -            print 'responseReceived>',
  12.149 -            printMsg(msg, all=1)
  12.150 -        if self.callResponders(msg):
  12.151 -            return
  12.152 -        method = self.getMethod(type, subtype)
  12.153 -        if method:
  12.154 -            method(msg, 0)
  12.155 -        elif DEBUG:
  12.156 -            print ('responseReceived> No handler: Message type %s %d:%d'
  12.157 -                   % (msgTypeName(type, subtype), type, subtype)), self
  12.158 -
  12.159 -    def addResponder(self, mid, deferred):
  12.160 -        """Add a responder for a message id.
  12.161 -        The I{deferred} is called with callback(msg) when a response
  12.162 -        with message id I{mid} arrives.
  12.163 -
  12.164 -        Responders have a timeout set and I{deferred} will error
  12.165 -        on expiry.
  12.166 -
  12.167 -        @param mid:      message id of response expected
  12.168 -        @type  mid:      int
  12.169 -        @param deferred: handler for the response
  12.170 -        @type  deferred: Deferred
  12.171 -        @return: responder
  12.172 -        @rtype:  Responder
  12.173 -        """
  12.174 -        resp = Responder(mid, deferred)
  12.175 -        self.responders[resp.mid] = resp
  12.176 -        if self.timeout > 0:
  12.177 -            deferred.setTimeout(self.timeout)
  12.178 -        return resp
  12.179 -
  12.180 -    def callResponders(self, msg):
  12.181 -        """Call any waiting responders for a response message.
  12.182 -        Looks for a responder registered for the message's id.
  12.183 -        See L{addResponder}.
  12.184 -
  12.185 -        @param msg: response message
  12.186 -        @type  msg: xu message
  12.187 -        @return: 1 if there was a responder for the message, 0 otherwise
  12.188 -        @rtype : bool
  12.189 -        """
  12.190 -        hdr = msg.get_header()
  12.191 -        mid = hdr['id']
  12.192 -        handled = 0
  12.193 -        resp = self.responders.get(mid)
  12.194 -        if resp:
  12.195 -            handled = 1
  12.196 -            resp.responseReceived(msg)
  12.197 -            del self.responders[mid]
  12.198 -        # Clean up called responders.
  12.199 -        for resp in self.responders.values():
  12.200 -            if resp.deferred.called:
  12.201 -                del self.responders[resp.mid]
  12.202 -        return handled
  12.203  
  12.204      def lostChannel(self):
  12.205          """Called when the channel to the domain is lost.
  12.206          """
  12.207 -        pass
  12.208 +        print 'CtrlMsgRcvr>lostChannel>',
  12.209 +        self.channel = None
  12.210      
  12.211      def registerChannel(self):
  12.212          """Register interest in our major message types with the
  12.213          channel to our domain. Once we have registered, the channel
  12.214 -        will call requestReceived or responseReceived for our messages.
  12.215 +        will call requestReceived for our messages.
  12.216          """
  12.217 -        self.channel = self.channelFactory.domChannel(self.dom)
  12.218 -        self.idx = self.channel.getIndex()
  12.219 -        if self.majorTypes:
  12.220 +        if DEBUG:
  12.221 +            print 'CtrlMsgRcvr>registerChannel>', self.channel, self.getMajorTypes()
  12.222 +        if self.channel:
  12.223              self.channel.registerDevice(self.getMajorTypes(), self)
  12.224          
  12.225      def deregisterChannel(self):
  12.226 @@ -229,470 +103,340 @@ class CtrlMsgRcvr:
  12.227          """
  12.228          if self.channel:
  12.229              self.channel.deregisterDevice(self)
  12.230 -            self.channel = None
  12.231  
  12.232 -    def produceRequests(self):
  12.233 -        """Produce any queued requests.
  12.234 -
  12.235 -        @return: number produced
  12.236 -        @rtype:  int
  12.237 -        """
  12.238 -        return 0
  12.239 -
  12.240 -    def writeRequest(self, msg, response=None):
  12.241 -        """Write a request to the channel.
  12.242 -
  12.243 -        @param msg:      request message
  12.244 -        @type  msg:      xu message
  12.245 -        @param response: response handler
  12.246 -        @type  response: Deferred
  12.247 -        """
  12.248 -        if self.channel:
  12.249 -            if DEBUG:
  12.250 -                print 'CtrlMsgRcvr>writeRequest>',
  12.251 -                printMsg(msg, all=1)
  12.252 -            if response:
  12.253 -                self.addResponder(msg.get_header()['id'], response)
  12.254 -            self.channel.writeRequest(msg)
  12.255 -        else:
  12.256 -            print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self
  12.257 -
  12.258 -    def writeResponse(self, msg):
  12.259 -        """Write a response to the channel. This acknowledges
  12.260 -        a request message.
  12.261 -
  12.262 -        @param msg:      message
  12.263 -        @type  msg:      xu message
  12.264 -        """
  12.265 -        if self.channel:
  12.266 -            if DEBUG:
  12.267 -                print 'CtrlMsgRcvr>writeResponse>',
  12.268 -                printMsg(msg, all=0)
  12.269 -            self.channel.writeResponse(msg)
  12.270 -        else:
  12.271 -            print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self
  12.272 -            
  12.273 -class ControllerFactory:
  12.274 -    """Abstract class for factories creating controllers for a domain.
  12.275 -    Maintains a table of controllers.
  12.276 -
  12.277 -    @ivar controllers: mapping of index to controller instance
  12.278 -    @type controllers: {String: Controller}
  12.279 -    @ivar dom: domain
  12.280 -    @type dom: int
  12.281 +class DevControllerType:
  12.282 +    """Abstract class for device controller types.
  12.283      """
  12.284  
  12.285 -    def __init__(self):
  12.286 -        self.controllers = {}
  12.287 -        
  12.288 -    def addController(self, controller):
  12.289 -        """Add a controller instance (under its index).
  12.290 -        """
  12.291 -        self.controllers[controller.idx] = controller
  12.292 +    def __init__(self, type):
  12.293 +        self.type = type
  12.294  
  12.295 -    def getControllers(self):
  12.296 -        """Get a list of all controllers.
  12.297 -        """
  12.298 -        return self.controllers.values()
  12.299 -
  12.300 -    def getControllerByIndex(self, idx):
  12.301 -        """Get a controller from its index.
  12.302 -        """
  12.303 -        return self.controllers.get(idx)
  12.304 -
  12.305 -    def getControllerByDom(self, dom):
  12.306 -        """Get the controller for the given domain.
  12.307 -
  12.308 -        @param dom: domain id
  12.309 -        @type  dom: int
  12.310 -        @return: controller or None
  12.311 +    def getType(self):
  12.312 +        """Get the device controller type name.
  12.313          """
  12.314 -        for inst in self.controllers.values():
  12.315 -            if inst.dom == dom:
  12.316 -                return inst
  12.317 -        return None
  12.318 -
  12.319 -    def getController(self, dom):
  12.320 -        """Create or find the controller for a domain.
  12.321 +        return self.type
  12.322  
  12.323 -        @param dom:      domain
  12.324 -        @return: controller
  12.325 -        """
  12.326 -        ctrl = self.getControllerByDom(dom)
  12.327 -        if ctrl is None:
  12.328 -            ctrl = self.createController(dom)
  12.329 -            self.addController(ctrl)
  12.330 -        return ctrl
  12.331 -    
  12.332 -    def createController(self, dom):
  12.333 -        """Create a controller. Define in a subclass.
  12.334 -
  12.335 -        @param dom: domain
  12.336 -        @type  dom: int
  12.337 -        @return: controller instance
  12.338 -        @rtype:  Controller (or subclass)
  12.339 +    def createDevController(self, vm, recreate=False):
  12.340 +        """Create a device controller for a domain.
  12.341 +           Must be implemented in subclass.
  12.342          """
  12.343          raise NotImplementedError()
  12.344  
  12.345 -    def delController(self, controller):
  12.346 -        """Delete a controller instance from the table.
  12.347 -
  12.348 -        @param controller: controller instance
  12.349 -        """
  12.350 -        if controller.idx in self.controllers:
  12.351 -            del self.controllers[controller.idx]
  12.352 -
  12.353 -    def controllerClosed(self, controller):
  12.354 -        """Callback called when a controller is closed (usually by the controller).
  12.355 -        
  12.356 -        @param controller: controller instance
  12.357 -        """
  12.358 -        self.delController(controller)
  12.359 -
  12.360 -class Controller(CtrlMsgRcvr):
  12.361 -    """Abstract class for a device controller attached to a domain.
  12.362 +class SimpleDevControllerType(DevControllerType):
  12.363 +    """Device controller type that simply wraps a controller
  12.364 +    class and uses its constructor to create instances.
  12.365 +    """
  12.366 +    
  12.367 +    def __init__(self, type, devControllerClass):
  12.368 +        DevControllerType.__init__(self, type)
  12.369 +        self.devControllerClass = devControllerClass
  12.370  
  12.371 -    @ivar factory: controller factory
  12.372 -    @type factory: ControllerFactory
  12.373 -    @ivar dom:     domain
  12.374 -    @type dom:     int
  12.375 -    @ivar channel: channel to the domain
  12.376 -    @type channel: Channel
  12.377 -    @ivar idx:     channel index
  12.378 -    @type idx:     String
  12.379 -    """
  12.380 +    def createDevController(self, vm, recreate=False):
  12.381 +        """Create a device controller for a domain.
  12.382 +        """
  12.383 +        ctrl = self.devControllerClass(self, vm, recreate=recreate)
  12.384 +        ctrl.initController(recreate=recreate)
  12.385 +        return ctrl
  12.386  
  12.387 -    def __init__(self, factory, dom):
  12.388 -        CtrlMsgRcvr.__init__(self)
  12.389 -        self.factory = factory
  12.390 -        self.dom = int(dom)
  12.391 -        self.channel = None
  12.392 -        self.idx = None
  12.393 -
  12.394 -    def close(self):
  12.395 -        """Close the controller.
  12.396 -        """
  12.397 -        self.lostChannel()
  12.398 -
  12.399 -    def lostChannel(self):
  12.400 -        """The controller channel has been lost.
  12.401 -        """
  12.402 -        self.deregisterChannel()
  12.403 -        self.factory.controllerClosed(self)
  12.404 -
  12.405 -class SplitControllerFactory(ControllerFactory):
  12.406 -    """Abstract class for factories creating split controllers for a domain.
  12.407 -    Maintains a table of backend controllers.
  12.408 +class DevControllerTable:
  12.409 +    """Table of device controller types, indexed by type name.
  12.410      """
  12.411  
  12.412      def __init__(self):
  12.413 -        ControllerFactory.__init__(self)
  12.414 -        self.backendControllers = {}
  12.415 +        self.controllerTypes = {}
  12.416 +
  12.417 +    def getDevControllerType(self, type):
  12.418 +        return self.controllerTypes.get(type)
  12.419 +
  12.420 +    def addDevControllerType(self, dctype):
  12.421 +        self.controllerTypes[dctype.getType()] = dctype
  12.422 +        return dctype
  12.423  
  12.424 -    def getBackendControllers(self):
  12.425 -        return self.backendControllers.values()
  12.426 +    def delDevControllerType(self, type):
  12.427 +        if type in self.controllerTypes:
  12.428 +            del self.controllerTypes[type]
  12.429  
  12.430 -    def getBackendControllerByDomain(self, dom):
  12.431 -        """Get the backend controller for a domain if there is one.
  12.432 +    def createDevController(self, type, vm, recreate=False):
  12.433 +        dctype = self.getDevControllerType(type)
  12.434 +        if not dctype:
  12.435 +            raise XendError("unknown device type: " + type)
  12.436 +        return dctype.createDevController(vm, recreate=recreate)
  12.437  
  12.438 -        @param dom: backend domain
  12.439 -        @return: backend controller
  12.440 -        """
  12.441 -        return self.backendControllers.get(dom)
  12.442 -
  12.443 -    def getBackendController(self, dom):
  12.444 -        """Get the backend controller for a domain, creating
  12.445 -        if necessary.
  12.446 +def getDevControllerTable():
  12.447 +    global devControllerTable
  12.448 +    try:
  12.449 +        devControllerTable
  12.450 +    except:
  12.451 +        devControllerTable = DevControllerTable()
  12.452 +    return devControllerTable
  12.453  
  12.454 -        @param dom: backend domain
  12.455 -        @return: backend controller
  12.456 -        """
  12.457 -        b = self.getBackendControllerByDomain(dom)
  12.458 -        if b is None:
  12.459 -            b = self.createBackendController(dom)
  12.460 -            self.backendControllers[b.dom] = b
  12.461 -        return b
  12.462 +def addDevControllerType(dctype):
  12.463 +    return getDevControllerTable().addDevControllerType(dctype)
  12.464 +    
  12.465 +def addDevControllerClass(name, klass):
  12.466 +    ty = SimpleDevControllerType(name, klass)
  12.467 +    return addDevControllerType(ty)
  12.468 +
  12.469 +def createDevController(name, vm, recreate=False):
  12.470 +    return getDevControllerTable().createDevController(name, vm, recreate=recreate)
  12.471 +
  12.472 +class DevController:
  12.473 +    """Abstract class for a device controller attached to a domain.
  12.474 +    A device controller manages all the devices of a given type for a domain.
  12.475 +    There is exactly one device controller for each device type for
  12.476 +    a domain.
  12.477  
  12.478 -    def createBackendController(self, dom):
  12.479 -        """Create a backend controller. Define in a subclass.
  12.480 +    """
  12.481 +
  12.482 +    def __init__(self, dctype, vm, recreate=False):
  12.483 +        self.dctype = dctype
  12.484 +        self.destroyed = False
  12.485 +        self.vm = vm
  12.486 +        self.deviceId = 0
  12.487 +        self.devices = {}
  12.488 +        self.device_order = []
  12.489  
  12.490 -        @param dom: backend domain
  12.491 -        @return: backend controller
  12.492 -        """
  12.493 -        raise NotImplementedError()
  12.494 +    def getType(self):
  12.495 +        return self.dctype.getType()
  12.496 +
  12.497 +    def getDevControllerType(self):
  12.498 +        return self.dctype
  12.499  
  12.500 -    def delBackendController(self, ctrlr):
  12.501 -        """Remove a backend controller.
  12.502 +    def getDomain(self):
  12.503 +        return self.vm.getDomain()
  12.504 +
  12.505 +    def getDomainName(self):
  12.506 +        return self.vm.getName()
  12.507  
  12.508 -        @param ctrlr: backend controller
  12.509 -        """
  12.510 -        if ctrlr.dom in self.backendControllers:
  12.511 -            del self.backendControllers[ctrlr.dom]
  12.512 +    def getChannel(self):
  12.513 +        chan = self.vm.getChannel()
  12.514 +        return chan
  12.515 +    
  12.516 +    def getDomainInfo(self):
  12.517 +        return self.vm
  12.518  
  12.519 -    def backendControllerClosed(self, ctrlr):
  12.520 -        """Callback called when a backend is closed.
  12.521 -        """
  12.522 -        self.delBackendController(ctrlr)
  12.523 -        
  12.524 -    def createBackendInterface(self, ctrl, dom, handle):
  12.525 -        """Create a backend interface. Define in a subclass.
  12.526 +    #----------------------------------------------------------------------------
  12.527 +    # Subclass interface.
  12.528 +    # Subclasses should define the unimplemented methods..
  12.529 +    # Redefinitions must have the same arguments.
  12.530  
  12.531 -        @param ctrl: frontend controller
  12.532 -        @param dom: backend domain
  12.533 -        @return: backend interface
  12.534 +    def initController(self, recreate=False, reboot=False):
  12.535 +        self.destroyed = False
  12.536 +        if reboot:
  12.537 +            self.rebootDevices()
  12.538 +
  12.539 +    def newDevice(self, id, config, recreate=False):
  12.540 +        """Create a device with the given config.
  12.541 +        Must be defined in subclass.
  12.542 +
  12.543 +        @return device
  12.544          """
  12.545          raise NotImplementedError()
  12.546  
  12.547 -class BackendController(Controller):
  12.548 -    """Abstract class for a backend device controller attached to a domain.
  12.549 +    def createDevice(self, config, recreate=False, change=False):
  12.550 +        print 'DevController>createDevice>', 'config=', config, 'recreate=', recreate, 'change=', change
  12.551 +        dev = self.newDevice(self.nextDeviceId(), config, recreate=recreate)
  12.552 +        dev.init(recreate=recreate)
  12.553 +        self.addDevice(dev)
  12.554 +        idx = self.getDeviceIndex(dev)
  12.555 +        recreate = self.vm.get_device_recreate(self.getType(), idx)
  12.556 +        dev.attach(recreate=recreate, change=change)
  12.557 +        print 'DevController>createDevice<'
  12.558 +
  12.559 +    def configureDevice(self, id, config, change=False):
  12.560 +        """Reconfigure an existing device.
  12.561 +        May be defined in subclass."""
  12.562 +        dev = self.getDevice(id)
  12.563 +        if not dev:
  12.564 +            raise XendError("invalid device id: " + id)
  12.565 +        dev.configure(config, change=change)
  12.566  
  12.567 -    @ivar factory: backend controller factory
  12.568 -    @type factory: BackendControllerFactory
  12.569 -    @ivar dom:     backend domain
  12.570 -    @type dom:     int
  12.571 -    @ivar channel: channel to the domain
  12.572 -    @type channel: Channel
  12.573 -    """
  12.574 +    def destroyDevice(self, id, change=False, reboot=False):
  12.575 +        """Destroy a device.
  12.576 +        May be defined in subclass."""
  12.577 +        dev = self.getDevice(id)
  12.578 +        if not dev:
  12.579 +            raise XendError("invalid device id: " + id)
  12.580 +        dev.destroy(change=change, reboot=reboot)
  12.581 +        return dev
  12.582 +
  12.583 +    def deleteDevice(self, id, change=True):
  12.584 +        dev = self.destroyDevice(id, change=change)
  12.585 +        self.removeDevice(dev)
  12.586 +
  12.587 +    def destroyController(self, reboot=False):
  12.588 +        """Destroy all devices and clean up.
  12.589 +        May be defined in subclass."""
  12.590 +        self.destroyed = True
  12.591 +        self.destroyDevices(reboot=reboot)
  12.592 +
  12.593 +    #----------------------------------------------------------------------------
  12.594 +    
  12.595 +    def isDestroyed(self):
  12.596 +        return self.destroyed
  12.597 +
  12.598 +    def getDevice(self, id):
  12.599 +        return self.devices.get(id)
  12.600  
  12.601 -    
  12.602 -    def __init__(self, factory, dom):
  12.603 -        CtrlMsgRcvr.__init__(self)
  12.604 -        self.factory = factory
  12.605 -        self.dom = int(dom)
  12.606 -        self.channel = None
  12.607 -        self.backendInterfaces = {}
  12.608 -        
  12.609 -    def close(self):
  12.610 -        self.lostChannel()
  12.611 +    def getDeviceByIndex(self, idx):
  12.612 +        if 0 <= idx < len(self.device_order):
  12.613 +            return self.device_order[idx]
  12.614 +        else:
  12.615 +            return None
  12.616 +
  12.617 +    def getDeviceIndex(self, dev):
  12.618 +        return self.device_order.index(dev)
  12.619 +
  12.620 +    def getDeviceIds(self):
  12.621 +        return [ dev.getId() for dev in self.device_order ]
  12.622 +
  12.623 +    def getDevices(self):
  12.624 +        return self.device_order
  12.625 +
  12.626 +    def getDeviceConfig(self, id):
  12.627 +        return self.getDevice(id).getConfig()
  12.628 +
  12.629 +    def getDeviceConfigs(self):
  12.630 +        return [ dev.getConfig() for dev in self.device_order ]
  12.631 +
  12.632 +    def getDeviceSxprs(self):
  12.633 +        return [ dev.sxpr() for dev in self.device_order ]
  12.634 +
  12.635 +    def addDevice(self, dev):
  12.636 +        self.devices[dev.getId()] = dev
  12.637 +        self.device_order.append(dev)
  12.638 +        return dev
  12.639 +
  12.640 +    def removeDevice(self, dev):
  12.641 +        if dev.getId() in self.devices:
  12.642 +            del self.devices[dev.getId()]
  12.643 +        if dev in self.device_order:
  12.644 +            self.device_order.remove(dev)
  12.645 +
  12.646 +    def rebootDevices(self):
  12.647 +        print 'DevController>rebootDevices>', self
  12.648 +        for dev in self.getDevices():
  12.649 +            dev.reboot()
  12.650 +
  12.651 +    def destroyDevices(self, reboot=False):
  12.652 +        """Destroy all devices.
  12.653 +        """
  12.654 +        for dev in self.getDevices():
  12.655 +            dev.destroy(reboot=reboot)
  12.656  
  12.657 -    def lostChannel(self):
  12.658 -        self.deregisterChannel()
  12.659 -        self.backend.backendClosed(self)
  12.660 +    def getMaxDeviceId(self):
  12.661 +        maxid = 0
  12.662 +        for id in self.devices:
  12.663 +            if id > maxid:
  12.664 +                maxid = id
  12.665 +        return maxid
  12.666 +
  12.667 +    def nextDeviceId(self):
  12.668 +        id = self.deviceId
  12.669 +        self.deviceId += 1
  12.670 +        return id
  12.671 +
  12.672 +    def getDeviceCount(self):
  12.673 +        return len(self.devices)
  12.674 +
  12.675 +class Dev:
  12.676 +    """Abstract class for a device attached to a device controller.
  12.677  
  12.678 -    def registerInterface(self, intf):
  12.679 -        key = intf.getInterfaceKey()
  12.680 -        self.backendInterfaces[key] = intf
  12.681 +    @ivar id:        identifier
  12.682 +    @type id:        int
  12.683 +    @ivar controller: device controller
  12.684 +    @type controller: DevController
  12.685 +    """
  12.686 +    
  12.687 +    def __init__(self, controller, id, config, recreate=False):
  12.688 +        self.controller = controller
  12.689 +        self.id = id
  12.690 +        self.config = config
  12.691 +        self.destroyed = False
  12.692 +
  12.693 +    def getDomain(self):
  12.694 +        return self.controller.getDomain()
  12.695 +
  12.696 +    def getDomainName(self):
  12.697 +        return self.controller.getDomainName()
  12.698 +
  12.699 +    def getChannel(self):
  12.700 +        return self.controller.getChannel()
  12.701 +    
  12.702 +    def getDomainInfo(self):
  12.703 +        return self.controller.getDomainInfo()
  12.704 +    
  12.705 +    def getController(self):
  12.706 +        return self.controller
  12.707 +
  12.708 +    def getType(self):
  12.709 +        return self.controller.getType()
  12.710  
  12.711 -    def deregisterInterface(self, intf):
  12.712 -        key = intf.getInterfaceKey()
  12.713 -        if key in self.backendInterfaces:
  12.714 -            del self.backendInterfaces[key]
  12.715 +    def getId(self):
  12.716 +        return self.id
  12.717 +
  12.718 +    def getIndex(self):
  12.719 +        return self.controller.getDeviceIndex(self)
  12.720 +
  12.721 +    def getConfig(self):
  12.722 +        return self.config
  12.723 +
  12.724 +    def isDestroyed(self):
  12.725 +        return self.destroyed
  12.726 +
  12.727 +    #----------------------------------------------------------------------------
  12.728 +    # Subclass interface.
  12.729 +    # Define methods in subclass as needed.
  12.730 +    # Redefinitions must have the same arguments.
  12.731 +
  12.732 +    def init(self, recreate=False, reboot=False):
  12.733 +        """Initialization. Called on initial create (when reboot is False)
  12.734 +        and on reboot (when reboot is True). When xend is restarting is
  12.735 +        called with recreate True. Define in subclass if needed.
  12.736 +        """
  12.737 +        self.destroyed = False
  12.738  
  12.739 -    def getInterface(self, dom, handle):
  12.740 -        key = (dom, handle)
  12.741 -        return self.backendInterfaces.get(key)
  12.742 +    def attach(self, recreate=False, change=False):
  12.743 +        """Attach the device to its front and back ends.
  12.744 +        Define in subclass if needed.
  12.745 +        """
  12.746 +        pass
  12.747 +
  12.748 +    def reboot(self):
  12.749 +        """Reconnect device when the domain is rebooted.
  12.750 +        """
  12.751 +        print 'Dev>reboot>', self
  12.752 +        self.init(reboot=True)
  12.753 +        self.attach()
  12.754  
  12.755 -        
  12.756 -    def createBackendInterface(self, ctrl, dom, handle):
  12.757 -        """Create a backend interface. Define in a subclass.
  12.758 +    def sxpr(self):
  12.759 +        """Get the s-expression for the deivice.
  12.760 +        Implement in a subclass if needed.
  12.761  
  12.762 -        @param ctrl: controller
  12.763 -        @param dom: backend domain
  12.764 -        @param handle: backend handle
  12.765 +        @return: sxpr
  12.766 +        """
  12.767 +        return self.getConfig()
  12.768 +
  12.769 +    def configure(self, config, change=False):
  12.770 +        """Reconfigure the device.
  12.771 +
  12.772 +        Implement in subclass.
  12.773          """
  12.774          raise NotImplementedError()
  12.775  
  12.776 -    
  12.777 -class BackendInterface:
  12.778 -    """Abstract class for a domain's interface onto a backend controller.
  12.779 -    """
  12.780 -
  12.781 -    def __init__(self, controller, dom, handle):
  12.782 -        """
  12.783 -
  12.784 -        @param controller: front-end controller
  12.785 -        @param dom:        back-end domain
  12.786 -        @param handle:     back-end interface handle
  12.787 -        """
  12.788 -        self.factory = controller.factory
  12.789 -        self.controller = controller
  12.790 -        self.dom = int(dom)
  12.791 -        self.handle = handle
  12.792 -        self.backend = self.getBackendController()
  12.793 -
  12.794 -    def registerInterface(self):
  12.795 -        self.backend.registerInterface(self)
  12.796 -
  12.797 -    def getInterfaceKey(self):
  12.798 -        return (self.controller.dom, self.handle)
  12.799 -
  12.800 -    def getBackendController(self):
  12.801 -        return self.factory.getBackendController(self.dom)
  12.802 -
  12.803 -    def writeRequest(self, msg, response=None):
  12.804 -        return self.backend.writeRequest(msg, response=response)
  12.805 -
  12.806 -    def writeResponse(self, msg):
  12.807 -        return self.backend.writeResponse(msg)
  12.808 -    
  12.809 -    def close(self):
  12.810 -        self.backend.deregisterInterface(self)
  12.811 -        self.controller.backendInterfaceClosed(self)
  12.812 -        
  12.813 -class SplitController(Controller):
  12.814 -    """Abstract class for a device controller attached to a domain.
  12.815 -    A SplitController manages a BackendInterface for each backend domain
  12.816 -    it has at least one device for.
  12.817 -    """
  12.818 -
  12.819 -    def __init__(self, factory, dom):
  12.820 -        Controller.__init__(self, factory, dom)
  12.821 -        self.backendInterfaces = {}
  12.822 -        self.backendHandle = 0
  12.823 -        self.devices = {}
  12.824 -
  12.825 -    def getDevices(self):
  12.826 -        """Get a list of the devices..
  12.827 -        """
  12.828 -        return self.devices.values()
  12.829 -
  12.830 -    def delDevice(self, idx):
  12.831 -        """Remove the device with the given index from the device table.
  12.832 -
  12.833 -        @param idx device index
  12.834 -        """
  12.835 -        if idx in self.devices:
  12.836 -            del self.devices[idx]
  12.837 -
  12.838 -    def getDevice(self, idx):
  12.839 -        """Get the device with a given index.
  12.840 -
  12.841 -        @param idx device index
  12.842 -        @return device (or None)
  12.843 -        """
  12.844 -        return self.devices.get(idx)
  12.845 -
  12.846 -    def findDevice(self, idx):
  12.847 -        """Find a device. If idx is non-negative,
  12.848 -        get the device with the given index. If idx is negative,
  12.849 -        look for the device with least index greater than -idx - 2.
  12.850 -        For example, if idx is -2, look for devices with index
  12.851 -        greater than 0, i.e. 1 or above.
  12.852 -
  12.853 -        @param idx device index
  12.854 -        @return device (or None)
  12.855 -        """
  12.856 -        if idx < 0:
  12.857 -            idx = -idx - 2
  12.858 -            val = None
  12.859 -            for dev in self.devices.values():
  12.860 -                if dev.idx <= idx: continue
  12.861 -                if (val is None) or (dev.idx < val.idx):
  12.862 -                    val = dev
  12.863 -        else:
  12.864 -            val = getDevice(idx)
  12.865 -        return val
  12.866 -
  12.867 -    def getMaxDeviceIdx(self):
  12.868 -        """Get the maximum id used by devices.
  12.869 -
  12.870 -        @return maximum idx
  12.871 +    def refresh(self):
  12.872 +        """Refresh the device..
  12.873 +        Default no-op. Define in subclass if needed.
  12.874          """
  12.875 -        maxIdx = 0
  12.876 -        for dev in self.devices:
  12.877 -            if dev.idx > maxIdx:
  12.878 -                maxIdx = dev.idx
  12.879 -        return maxIdx
  12.880 -        
  12.881 -    def getBackendInterfaces(self):
  12.882 -        return self.backendInterfaces.values()
  12.883 -
  12.884 -    def getBackendInterfaceByHandle(self, handle):
  12.885 -        for b in self.getBackendInterfaces():
  12.886 -            if b.handle == handle:
  12.887 -                return b
  12.888 -        return None
  12.889 -
  12.890 -    def getBackendInterfaceByDomain(self, dom):
  12.891 -        return self.backendInterfaces.get(dom)
  12.892 -
  12.893 -    def getBackendInterface(self, dom):
  12.894 -        """Get the backend interface for a domain.
  12.895 -
  12.896 -        @param dom: domain
  12.897 -        @return: backend controller
  12.898 -        """
  12.899 -        b = self.getBackendInterfaceByDomain(dom)
  12.900 -        if b is None:
  12.901 -            handle = self.backendHandle
  12.902 -            self.backendHandle += 1
  12.903 -            b = self.factory.createBackendInterface(self, dom, handle)
  12.904 -            b.registerInterface()
  12.905 -            self.backendInterfaces[b.dom] = b
  12.906 -        return b
  12.907 -
  12.908 -    def delBackendInterface(self, ctrlr):
  12.909 -        """Remove a backend controller.
  12.910 -
  12.911 -        @param ctrlr: backend controller
  12.912 -        """
  12.913 -        if ctrlr.dom in self.backendInterfaces:
  12.914 -            del self.backendInterfaces[ctrlr.dom]
  12.915 -
  12.916 -    def backendInterfaceClosed(self, ctrlr):
  12.917 -        """Callback called when a backend is closed.
  12.918 -        """
  12.919 -        self.delBackendInterface(ctrlr)
  12.920 -        
  12.921 -class Dev:
  12.922 -    """Abstract class for a device attached to a device controller.
  12.923 +        pass
  12.924  
  12.925 -    @ivar idx:        identifier
  12.926 -    @type idx:        String
  12.927 -    @ivar controller: device controller
  12.928 -    @type controller: DeviceController
  12.929 -    @ivar props:      property table
  12.930 -    @type props:      { String: value }
  12.931 -    """
  12.932 +    def destroy(self, change=False, reboot=False):
  12.933 +        """Destroy the device.
  12.934 +        If change is True notify destruction (runtime change).
  12.935 +        If reboot is True the device is being destroyed for a reboot.
  12.936 +        Redefine in subclass if needed.
  12.937 +        """
  12.938 +        self.destroyed = True
  12.939 +        pass
  12.940      
  12.941 -    def __init__(self, idx, controller):
  12.942 -        self.idx = str(idx)
  12.943 -        self.controller = controller
  12.944 -        self.props = {}
  12.945 -
  12.946 -    def getidx(self):
  12.947 -        return self.idx
  12.948 -
  12.949 -    def setprop(self, k, v):
  12.950 -        self.props[k] = v
  12.951 -
  12.952 -    def getprop(self, k, v=None):
  12.953 -        return self.props.get(k, v)
  12.954 -
  12.955 -    def hasprop(self, k):
  12.956 -        return k in self.props
  12.957 -
  12.958 -    def delprop(self, k):
  12.959 -        if k in self.props:
  12.960 -            del self.props[k]
  12.961 -
  12.962 -    def sxpr(self):
  12.963 -        """Get the s-expression for the deivice.
  12.964 -        Implement in a subclass.
  12.965 -
  12.966 -        @return: sxpr
  12.967 -        """
  12.968 -        raise NotImplementedError()
  12.969 -
  12.970 -    def configure(self, config, change=0):
  12.971 -        raise NotImplementedError()
  12.972 -
  12.973 -class SplitDev(Dev):
  12.974 -
  12.975 -    def __init__(self, idx, controller):
  12.976 -        Dev.__init__(self, idx, controller)
  12.977 -        self.backendDomain = 0
  12.978 -        self.index = None
  12.979 -
  12.980 -    def getBackendInterface(self):
  12.981 -        return self.controller.getBackendInterface(self.backendDomain)
  12.982 -
  12.983 -    def getIndex(self):
  12.984 -        return self.index
  12.985 -
  12.986 -    def setIndex(self, index):
  12.987 -        self.index = index
  12.988 -
  12.989 -
  12.990 -
  12.991 -    
  12.992 +    #----------------------------------------------------------------------------
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/tools/python/xen/xend/server/event.py	Wed Apr 20 08:45:19 2005 +0000
    13.3 @@ -0,0 +1,198 @@
    13.4 +from twisted.internet import reactor, protocol, defer
    13.5 +
    13.6 +from xen.lowlevel import xu
    13.7 +
    13.8 +from xen.xend import sxp
    13.9 +from xen.xend import PrettyPrint
   13.10 +from xen.xend import EventServer
   13.11 +eserver = EventServer.instance()
   13.12 +from xen.xend.XendError import XendError
   13.13 +
   13.14 +from xen.xend import XendRoot
   13.15 +
   13.16 +DEBUG = 1
   13.17 +
   13.18 +class EventProtocol(protocol.Protocol):
   13.19 +    """Asynchronous handler for a connected event socket.
   13.20 +    """
   13.21 +
   13.22 +    def __init__(self, daemon):
   13.23 +        #protocol.Protocol.__init__(self)
   13.24 +        self.daemon = daemon
   13.25 +        # Event queue.
   13.26 +        self.queue = []
   13.27 +        # Subscribed events.
   13.28 +        self.events = []
   13.29 +        self.parser = sxp.Parser()
   13.30 +        self.pretty = 0
   13.31 +
   13.32 +        # For debugging subscribe to everything and make output pretty.
   13.33 +        self.subscribe(['*'])
   13.34 +        self.pretty = 1
   13.35 +
   13.36 +    def dataReceived(self, data):
   13.37 +        try:
   13.38 +            self.parser.input(data)
   13.39 +            if self.parser.ready():
   13.40 +                val = self.parser.get_val()
   13.41 +                res = self.dispatch(val)
   13.42 +                self.send_result(res)
   13.43 +            if self.parser.at_eof():
   13.44 +                self.loseConnection()
   13.45 +        except SystemExit:
   13.46 +            raise
   13.47 +        except:
   13.48 +            if DEBUG:
   13.49 +                raise
   13.50 +            else:
   13.51 +                self.send_error()
   13.52 +
   13.53 +    def loseConnection(self):
   13.54 +        if self.transport:
   13.55 +            self.transport.loseConnection()
   13.56 +        if self.connected:
   13.57 +            reactor.callLater(0, self.connectionLost)
   13.58 +
   13.59 +    def connectionLost(self, reason=None):
   13.60 +        self.unsubscribe()
   13.61 +
   13.62 +    def send_reply(self, sxpr):
   13.63 +        io = StringIO.StringIO()
   13.64 +        if self.pretty:
   13.65 +            PrettyPrint.prettyprint(sxpr, out=io)
   13.66 +        else:
   13.67 +            sxp.show(sxpr, out=io)
   13.68 +        print >> io
   13.69 +        io.seek(0)
   13.70 +        return self.transport.write(io.getvalue())
   13.71 +
   13.72 +    def send_result(self, res):
   13.73 +        return self.send_reply(['ok', res])
   13.74 +
   13.75 +    def send_error(self):
   13.76 +        (extype, exval) = sys.exc_info()[:2]
   13.77 +        return self.send_reply(['err',
   13.78 +                                ['type', str(extype)],
   13.79 +                                ['value', str(exval)]])
   13.80 +
   13.81 +    def send_event(self, val):
   13.82 +        return self.send_reply(['event', val[0], val[1]])
   13.83 +
   13.84 +    def unsubscribe(self):
   13.85 +        for event in self.events:
   13.86 +            eserver.unsubscribe(event, self.queue_event)
   13.87 +
   13.88 +    def subscribe(self, events):
   13.89 +        self.unsubscribe()
   13.90 +        for event in events:
   13.91 +            eserver.subscribe(event, self.queue_event)
   13.92 +        self.events = events
   13.93 +
   13.94 +    def queue_event(self, name, v):
   13.95 +        # Despite the name we don't queue the event here.
   13.96 +        # We send it because the transport will queue it.
   13.97 +        self.send_event([name, v])
   13.98 +        
   13.99 +    def opname(self, name):
  13.100 +         return 'op_' + name.replace('.', '_')
  13.101 +
  13.102 +    def operror(self, name, req):
  13.103 +        raise XendError('Invalid operation: ' +name)
  13.104 +
  13.105 +    def dispatch(self, req):
  13.106 +        op_name = sxp.name(req)
  13.107 +        op_method_name = self.opname(op_name)
  13.108 +        op_method = getattr(self, op_method_name, self.operror)
  13.109 +        return op_method(op_name, req)
  13.110 +
  13.111 +    def op_help(self, name, req):
  13.112 +        def nameop(x):
  13.113 +            if x.startswith('op_'):
  13.114 +                return x[3:].replace('_', '.')
  13.115 +            else:
  13.116 +                return x
  13.117 +        
  13.118 +        l = [ nameop(k) for k in dir(self) if k.startswith('op_') ]
  13.119 +        return l
  13.120 +
  13.121 +    def op_quit(self, name, req):
  13.122 +        self.loseConnection()
  13.123 +
  13.124 +    def op_exit(self, name, req):
  13.125 +        sys.exit(0)
  13.126 +
  13.127 +    def op_pretty(self, name, req):
  13.128 +        self.pretty = 1
  13.129 +        return ['ok']
  13.130 +
  13.131 +    def op_console_disconnect(self, name, req):
  13.132 +        id = sxp.child_value(req, 'id')
  13.133 +        if not id:
  13.134 +            raise XendError('Missing console id')
  13.135 +        id = int(id)
  13.136 +        self.daemon.console_disconnect(id)
  13.137 +        return ['ok']
  13.138 +
  13.139 +    def op_info(self, name, req):
  13.140 +        val = ['info']
  13.141 +        val += self.daemon.consoles()
  13.142 +        val += self.daemon.blkifs()
  13.143 +        val += self.daemon.netifs()
  13.144 +        val += self.daemon.usbifs()
  13.145 +        return val
  13.146 +
  13.147 +    def op_sys_subscribe(self, name, v):
  13.148 +        # (sys.subscribe event*)
  13.149 +        # Subscribe to the events:
  13.150 +        self.subscribe(v[1:])
  13.151 +        return ['ok']
  13.152 +
  13.153 +    def op_sys_inject(self, name, v):
  13.154 +        # (sys.inject event)
  13.155 +        event = v[1]
  13.156 +        eserver.inject(sxp.name(event), event)
  13.157 +        return ['ok']
  13.158 +
  13.159 +    def op_trace(self, name, v):
  13.160 +        mode = (v[1] == 'on')
  13.161 +        self.daemon.tracing(mode)
  13.162 +
  13.163 +    def op_log_stderr(self, name, v):
  13.164 +        mode = v[1]
  13.165 +        logging = XendRoot.instance().get_logging()
  13.166 +        if mode == 'on':
  13.167 +            logging.addLogStderr()
  13.168 +        else:
  13.169 +            logging.removeLogStderr()
  13.170 +
  13.171 +    def op_debug_msg(self, name, v):
  13.172 +        mode = v[1]
  13.173 +        import messages
  13.174 +        messages.DEBUG = (mode == 'on')
  13.175 +
  13.176 +    def op_debug_controller(self, name, v):
  13.177 +        mode = v[1]
  13.178 +        import controller
  13.179 +        controller.DEBUG = (mode == 'on')
  13.180 +
  13.181 +
  13.182 +class EventFactory(protocol.Factory):
  13.183 +    """Asynchronous handler for the event server socket.
  13.184 +    """
  13.185 +    protocol = EventProtocol
  13.186 +    service = None
  13.187 +
  13.188 +    def __init__(self, daemon):
  13.189 +        #protocol.Factory.__init__(self)
  13.190 +        self.daemon = daemon
  13.191 +
  13.192 +    def buildProtocol(self, addr):
  13.193 +        proto = self.protocol(self.daemon)
  13.194 +        proto.factory = self
  13.195 +        return proto
  13.196 +
  13.197 +
  13.198 +def listenEvent(daemon, port, interface):
  13.199 +    protocol = EventFactory(daemon)
  13.200 +    return reactor.listenTCP(port, protocol, interface=interface)
  13.201 +    
    14.1 --- a/tools/python/xen/xend/server/messages.py	Tue Apr 19 13:48:05 2005 +0000
    14.2 +++ b/tools/python/xen/xend/server/messages.py	Wed Apr 20 08:45:19 2005 +0000
    14.3 @@ -4,7 +4,12 @@ import types
    14.4  
    14.5  from xen.lowlevel import xu
    14.6  
    14.7 -DEBUG = 0
    14.8 +DEBUG = False
    14.9 +
   14.10 +#PORT_WILDCARD = 0xefffffff
   14.11 +
   14.12 +"""Wildcard for the control message types."""
   14.13 +TYPE_WILDCARD = 0xffff
   14.14  
   14.15  """ All message formats.
   14.16  Added to incrementally for the various message types.
   14.17 @@ -94,7 +99,6 @@ blkif_formats = {
   14.18      (CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS),
   14.19      # Notify device status to fe.
   14.20      # Also used to notify 'any' device change with status BLKIF_INTERFACE_STATUS_CHANGED.
   14.21 -    # Rename to blkif_fe_interface_status.
   14.22  
   14.23      'blkif_fe_driver_status_t':
   14.24      (CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS),
   14.25 @@ -102,7 +106,6 @@ blkif_formats = {
   14.26      # Xend sets be(s) to BLKIF_INTERFACE_STATUS_DISCONNECTED,
   14.27      # sends blkif_fe_interface_status_t to fe (from each be).
   14.28      #
   14.29 -    # Rename to blkif_fe_driver_status.
   14.30      # Reply with i/f count.
   14.31      # The i/f sends probes (using -ve trick), we reply with the info.
   14.32  
   14.33 @@ -227,24 +230,34 @@ USBIF_BE_STATUS_MAPPING_ERROR = 9
   14.34  usbif_formats = {
   14.35      'usbif_be_create_t':
   14.36      (CMSG_USBIF_BE, CMSG_USBIF_BE_CREATE),
   14.37 +
   14.38      'usbif_be_destroy_t':
   14.39      (CMSG_USBIF_BE, CMSG_USBIF_BE_DESTROY),
   14.40 +
   14.41      'usbif_be_connect_t':
   14.42      (CMSG_USBIF_BE, CMSG_USBIF_BE_CONNECT),
   14.43 +
   14.44      'usbif_be_disconnect_t':
   14.45      (CMSG_USBIF_BE, CMSG_USBIF_BE_DISCONNECT),
   14.46 +
   14.47      'usbif_be_claim_port_t':
   14.48      (CMSG_USBIF_BE, CMSG_USBIF_BE_CLAIM_PORT),
   14.49 +
   14.50      'usbif_be_release_port_t':
   14.51      (CMSG_USBIF_BE, CMSG_USBIF_BE_RELEASE_PORT),
   14.52 +
   14.53      'usbif_fe_interface_status_changed_t':
   14.54      (CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED),
   14.55 +
   14.56      'usbif_fe_driver_status_changed_t':
   14.57      (CMSG_USBIF_FE, CMSG_USBIF_FE_DRIVER_STATUS_CHANGED),
   14.58 +
   14.59      'usbif_fe_interface_connect_t':
   14.60      (CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_CONNECT),
   14.61 +
   14.62      'usbif_fe_interface_disconnect_t':
   14.63 -    (CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_DISCONNECT)
   14.64 +    (CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_DISCONNECT),
   14.65 +   
   14.66      }
   14.67      
   14.68  msg_formats.update(usbif_formats)
   14.69 @@ -364,8 +377,8 @@ def unpackMsg(ty, msg):
   14.70                  pass
   14.71          if macs:
   14.72              args['mac'] = mac
   14.73 -            print 'macs=', macs
   14.74 -            print 'args=', args
   14.75 +            #print 'macs=', macs
   14.76 +            #print 'args=', args
   14.77              for k in macs:
   14.78                  del args[k]
   14.79      if DEBUG:
   14.80 @@ -388,7 +401,7 @@ def msgTypeName(ty, subty):
   14.81              return name
   14.82      return None
   14.83  
   14.84 -def printMsg(msg, out=sys.stdout, all=0):
   14.85 +def printMsg(msg, out=sys.stdout, all=False):
   14.86      """Print a message.
   14.87  
   14.88      @param msg: message
   14.89 @@ -407,3 +420,18 @@ def printMsg(msg, out=sys.stdout, all=0)
   14.90      if all:
   14.91          print >>out, 'payload=', msg.get_payload()
   14.92  
   14.93 +
   14.94 +def getMessageType(msg):
   14.95 +    """Get a 2-tuple of the message type and subtype.
   14.96 +
   14.97 +    @param msg: message
   14.98 +    @type  msg: xu message
   14.99 +    @return: type info
  14.100 +    @rtype:  (int, int)
  14.101 +    """
  14.102 +    hdr = msg.get_header()
  14.103 +    return (hdr['type'], hdr.get('subtype'))
  14.104 +
  14.105 +def getMessageId(msg):
  14.106 +    hdr = msg.get_header()
  14.107 +    return hdr['id']
    15.1 --- a/tools/python/xen/xend/server/netif.py	Tue Apr 19 13:48:05 2005 +0000
    15.2 +++ b/tools/python/xen/xend/server/netif.py	Wed Apr 20 08:45:19 2005 +0000
    15.3 @@ -8,102 +8,44 @@ from twisted.internet import defer
    15.4  
    15.5  from xen.xend import sxp
    15.6  from xen.xend import Vifctl
    15.7 -from xen.xend.XendError import XendError
    15.8 +from xen.xend.XendError import XendError, VmError
    15.9  from xen.xend.XendLogging import log
   15.10  from xen.xend import XendVnet
   15.11  from xen.xend.XendRoot import get_component
   15.12  
   15.13  import channel
   15.14 -import controller
   15.15 +from controller import CtrlMsgRcvr, Dev, DevController
   15.16  from messages import *
   15.17  
   15.18 -class NetifBackendController(controller.BackendController):
   15.19 -    """Handler for the 'back-end' channel to a network device driver domain.
   15.20 -    """
   15.21 -    
   15.22 -    def __init__(self, ctrl, dom):
   15.23 -        controller.BackendController.__init__(self, ctrl, dom)
   15.24 -        self.addMethod(CMSG_NETIF_BE,
   15.25 -                       CMSG_NETIF_BE_DRIVER_STATUS,
   15.26 -                       self.recv_be_driver_status)
   15.27 -        self.registerChannel()
   15.28 -
   15.29 -    def recv_be_driver_status(self, msg, req):
   15.30 -        val = unpackMsg('netif_be_driver_status_t', msg)
   15.31 -        status = val['status']
   15.32 -
   15.33 -class NetifBackendInterface(controller.BackendInterface):
   15.34 -    """Handler for the 'back-end' channel to a network device driver domain
   15.35 -    on behalf of a front-end domain.
   15.36 -
   15.37 -    Each network device is handled separately, so we add no functionality
   15.38 -    here.
   15.39 -    """
   15.40 -
   15.41 -    pass
   15.42 -
   15.43 -class NetifControllerFactory(controller.SplitControllerFactory):
   15.44 -    """Factory for creating network interface controllers.
   15.45 +class NetDev(Dev):
   15.46 +    """A network device.
   15.47      """
   15.48  
   15.49 -    def __init__(self):
   15.50 -        controller.SplitControllerFactory.__init__(self)
   15.51 -
   15.52 -    def createController(self, dom):
   15.53 -        """Create a network interface controller for a domain.
   15.54 -
   15.55 -        @param dom:      domain
   15.56 -        @return: netif controller
   15.57 -        """
   15.58 -        return NetifController(self, dom)
   15.59 -
   15.60 -    def createBackendController(self, dom):
   15.61 -        """Create a network device backend controller.
   15.62 -
   15.63 -        @param dom: backend domain
   15.64 -        @return: backend controller
   15.65 -        """
   15.66 -        return NetifBackendController(self, dom)
   15.67 -    
   15.68 -    def createBackendInterface(self, ctrl, dom, handle):
   15.69 -        """Create a network device backend interface.
   15.70 -
   15.71 -        @param ctrl: controller
   15.72 -        @param dom: backend domain
   15.73 -        @param handle: interface handle
   15.74 -        @return: backend interface
   15.75 -        """
   15.76 -        return NetifBackendInterface(ctrl, dom, handle)
   15.77 +    def __init__(self, controller, id, config, recreate=False):
   15.78 +        Dev.__init__(self, controller, id, config, recreate=recreate)
   15.79 +        self.vif = int(self.id)
   15.80 +        self.evtchn = None
   15.81 +        self.status = NETIF_INTERFACE_STATUS_DISCONNECTED
   15.82 +        self.frontendDomain = self.getDomain()
   15.83 +        self.frontendChannel = None
   15.84 +        self.backendDomain = None
   15.85 +        self.backendChannel = None
   15.86 +        self.credit = None
   15.87 +        self.period = None
   15.88 +        self.mac = None
   15.89 +        self.be_mac = None
   15.90 +        self.bridge = None
   15.91 +        self.script = None
   15.92 +        self.ipaddr = None
   15.93 +        self.vifname = None
   15.94 +        self.configure(self.config, recreate=recreate)
   15.95  
   15.96 -    def getDomainDevices(self, dom):
   15.97 -        """Get the network devices for a domain.
   15.98 -
   15.99 -        @param dom:  domain
  15.100 -        @return: netif controller list
  15.101 -        """
  15.102 -        netif = self.getControllerByDom(dom)
  15.103 -        return (netif and netif.getDevices()) or []
  15.104 -
  15.105 -    def getDomainDevice(self, dom, vif):
  15.106 -        """Get a virtual network interface device for a domain.
  15.107 -
  15.108 -        @param dom: domain
  15.109 -        @param vif: virtual interface index
  15.110 -        @return: NetDev
  15.111 -        """
  15.112 -        netif = self.getControllerByDom(dom)
  15.113 -        return (netif and netif.getDevice(vif)) or None
  15.114 -        
  15.115 -class NetDev(controller.SplitDev):
  15.116 -    """Info record for a network device.
  15.117 -    """
  15.118 -
  15.119 -    def __init__(self, vif, ctrl, config):
  15.120 -        controller.SplitDev.__init__(self, vif, ctrl)
  15.121 -        self.vif = vif
  15.122 -        self.evtchn = None
  15.123 -        self.configure(config)
  15.124 -        self.status = NETIF_INTERFACE_STATUS_DISCONNECTED
  15.125 +    def init(self, recreate=False, reboot=False):
  15.126 +        self.destroyed = False
  15.127 +        self.frontendDomain = self.getDomain()
  15.128 +        self.frontendChannel = self.getChannel()
  15.129 +        cf = channel.channelFactory()
  15.130 +        self.backendChannel = cf.openChannel(self.backendDomain)
  15.131  
  15.132      def _get_config_mac(self, config):
  15.133          vmac = sxp.child_value(config, 'mac')
  15.134 @@ -129,7 +71,7 @@ class NetDev(controller.SplitDev):
  15.135              val = None
  15.136          return val
  15.137  
  15.138 -    def configure(self, config, change=0):
  15.139 +    def configure(self, config, change=False, recreate=False):
  15.140          if change:
  15.141              return self.reconfigure(config)
  15.142          self.config = config
  15.143 @@ -153,12 +95,18 @@ class NetDev(controller.SplitDev):
  15.144          self.bridge = sxp.child_value(config, 'bridge')
  15.145          self.script = sxp.child_value(config, 'script')
  15.146          self.ipaddr = self._get_config_ipaddr(config) or []
  15.147 +        self._config_credit_limit(config)
  15.148          
  15.149          try:
  15.150 -            xd = get_component('xen.xend.XendDomain')
  15.151 -            self.backendDomain = int(xd.domain_lookup(sxp.child_value(config, 'backend', '0')).id)
  15.152 +            if recreate:
  15.153 +                self.backendDomain = int(sxp.child_value(config, 'backend', '0'))
  15.154 +            else:
  15.155 +                #todo: Code below will fail on xend restart when backend is not domain 0.
  15.156 +                xd = get_component('xen.xend.XendDomain')
  15.157 +                self.backendDomain = int(xd.domain_lookup(sxp.child_value(config, 'backend', '0')).id)
  15.158          except:
  15.159              raise XendError('invalid backend domain')
  15.160 +        return self.config
  15.161  
  15.162      def reconfigure(self, config):
  15.163          """Reconfigure the interface with new values.
  15.164 @@ -178,8 +126,10 @@ class NetDev(controller.SplitDev):
  15.165          bridge = sxp.child_value(config, 'bridge')
  15.166          script = sxp.child_value(config, 'script')
  15.167          ipaddr = self._get_config_ipaddr(config)
  15.168 +        
  15.169          xd = get_component('xen.xend.XendDomain')
  15.170          backendDomain = str(xd.domain_lookup(sxp.child_value(config, 'backend', '0')).id)
  15.171 +
  15.172          if (mac is not None) and (mac != self.mac):
  15.173              raise XendError("cannot change mac")
  15.174          if (be_mac is not None) and (be_mac != self.be_mac):
  15.175 @@ -199,13 +149,36 @@ class NetDev(controller.SplitDev):
  15.176                  setattr(self, k, v)
  15.177              self.config = sxp.merge(config, self.config)
  15.178              self.vifctl("up")
  15.179 +
  15.180 +        self._config_credit_limit(config, change=True)
  15.181          return self.config
  15.182  
  15.183 +    def _config_credit_limit(self, config, change=False):
  15.184 +        period = sxp.child_value(config, 'period')
  15.185 +        credit = sxp.child_value(config, 'credit')
  15.186 +        if period and credit:
  15.187 +            try:
  15.188 +                period = int(period)
  15.189 +                credit = int(credit)
  15.190 +            except ex:
  15.191 +                raise XendError('vif: invalid credit limit')
  15.192 +            if change:
  15.193 +                self.setCreditLimit(credit, period)
  15.194 +                self.config = sxp.merge([sxp.name(self.config),
  15.195 +                                         ['credit', credit],
  15.196 +                                         ['period', period]],
  15.197 +                                        self.config)
  15.198 +            else:
  15.199 +                self.period = period
  15.200 +                self.credit = credit
  15.201 +        elif period or credit:
  15.202 +            raise XendError('vif: invalid credit limit')
  15.203 +
  15.204      def sxpr(self):
  15.205          vif = str(self.vif)
  15.206          mac = self.get_mac()
  15.207          val = ['vif',
  15.208 -               ['idx', self.idx],
  15.209 +               ['id', self.id],
  15.210                 ['vif', vif],
  15.211                 ['mac', mac],
  15.212                 ['vifname', self.vifname],
  15.213 @@ -219,12 +192,15 @@ class NetDev(controller.SplitDev):
  15.214              val.append(['script', self.script])
  15.215          for ip in self.ipaddr:
  15.216              val.append(['ip', ip])
  15.217 +        if self.credit:
  15.218 +            val.append(['credit', self.credit])
  15.219 +        if self.period:
  15.220 +            val.append(['period', self.period])
  15.221          if self.evtchn:
  15.222              val.append(['evtchn',
  15.223                          self.evtchn['port1'],
  15.224                          self.evtchn['port2']])
  15.225 -        if self.index is not None:
  15.226 -            val.append(['index', self.index])
  15.227 +        val.append(['index', self.getIndex()])
  15.228          return val
  15.229  
  15.230      def get_vifname(self):
  15.231 @@ -233,7 +209,7 @@ class NetDev(controller.SplitDev):
  15.232          return self.vifname
  15.233  
  15.234      def default_vifname(self):
  15.235 -        return "vif%d.%d" % (self.controller.dom, self.vif)
  15.236 +        return "vif%d.%d" % (self.frontendDomain, self.vif)
  15.237      
  15.238      def get_mac(self):
  15.239          """Get the MAC address as a string.
  15.240 @@ -248,7 +224,7 @@ class NetDev(controller.SplitDev):
  15.241      def vifctl_params(self, vmname=None):
  15.242          """Get the parameters to pass to vifctl.
  15.243          """
  15.244 -        dom = self.controller.dom
  15.245 +        dom = self.frontendDomain
  15.246          if vmname is None:
  15.247              xd = get_component('xen.xend.XendDomain')
  15.248              try:
  15.249 @@ -278,11 +254,23 @@ class NetDev(controller.SplitDev):
  15.250          if vnet:
  15.251              vnet.vifctl(op, self.get_vifname(), self.get_mac())
  15.252  
  15.253 -    def attach(self):
  15.254 -        d = self.send_be_create()
  15.255 -        d.addCallback(self.respond_be_create)
  15.256 -        return d
  15.257 +    def attach(self, recreate=False, change=False):
  15.258 +        if recreate:
  15.259 +            pass
  15.260 +        else:
  15.261 +            self.send_be_create()
  15.262 +            if self.credit and self.period:
  15.263 +                self.send_be_creditlimit(self.credit, self.period)
  15.264 +            self.vifctl('up', vmname=self.getDomainName())
  15.265 +        
  15.266 +    def closeEvtchn(self):
  15.267 +        if self.evtchn:
  15.268 +            channel.eventChannelClose(self.evtchn)
  15.269 +            self.evtchn = None
  15.270  
  15.271 +    def openEvtchn(self):
  15.272 +        self.evtchn = channel.eventChannel(self.backendDomain, self.frontendDomain)
  15.273 +        
  15.274      def getEventChannelBackend(self):
  15.275          val = 0
  15.276          if self.evtchn:
  15.277 @@ -296,90 +284,79 @@ class NetDev(controller.SplitDev):
  15.278          return val
  15.279  
  15.280      def send_be_create(self):
  15.281 -        d = defer.Deferred()
  15.282          msg = packMsg('netif_be_create_t',
  15.283 -                      { 'domid'        : self.controller.dom,
  15.284 +                      { 'domid'        : self.frontendDomain,
  15.285                          'netif_handle' : self.vif,
  15.286                          'be_mac'       : self.be_mac or [0, 0, 0, 0, 0, 0],
  15.287                          'mac'          : self.mac,
  15.288                          #'vifname'      : self.vifname
  15.289                          })
  15.290 -        self.getBackendInterface().writeRequest(msg, response=d)
  15.291 -        return d
  15.292 +        msg = self.backendChannel.requestResponse(msg)
  15.293 +        # todo: check return status
  15.294  
  15.295 -    def respond_be_create(self, msg):
  15.296 -        val = unpackMsg('netif_be_create_t', msg)
  15.297 -        return self
  15.298 -
  15.299 -    def destroy(self, change=0):
  15.300 +    def destroy(self, change=False, reboot=False):
  15.301          """Destroy the device's resources and disconnect from the back-end
  15.302          device controller. If 'change' is true notify the front-end interface.
  15.303  
  15.304          @param change: change flag
  15.305          """
  15.306 +        self.destroyed = True
  15.307          self.status = NETIF_INTERFACE_STATUS_CLOSED
  15.308 -        def cb_destroy(val):
  15.309 -            self.send_be_destroy()
  15.310 -            self.getBackendInterface().close()
  15.311 -            if change:
  15.312 -                self.reportStatus()
  15.313 -        log.debug("Destroying vif domain=%d vif=%d", self.controller.dom, self.vif)
  15.314 -        if self.evtchn:
  15.315 -            channel.eventChannelClose(self.evtchn)
  15.316 +        log.debug("Destroying vif domain=%d vif=%d", self.frontendDomain, self.vif)
  15.317 +        self.closeEvtchn()
  15.318          self.vifctl('down')
  15.319 -        d = self.send_be_disconnect()
  15.320 -        d.addCallback(cb_destroy)
  15.321 +        self.send_be_disconnect()
  15.322 +        self.send_be_destroy()
  15.323 +        if change:
  15.324 +            self.reportStatus()
  15.325  
  15.326      def send_be_disconnect(self):
  15.327 -        d = defer.Deferred()
  15.328          msg = packMsg('netif_be_disconnect_t',
  15.329 -                      { 'domid'        : self.controller.dom,
  15.330 +                      { 'domid'        : self.frontendDomain,
  15.331                          'netif_handle' : self.vif })
  15.332 -        self.getBackendInterface().writeRequest(msg, response=d)
  15.333 -        return d
  15.334 +        return self.backendChannel.writeRequest(msg)
  15.335  
  15.336      def send_be_destroy(self, response=None):
  15.337          msg = packMsg('netif_be_destroy_t',
  15.338 -                      { 'domid'        : self.controller.dom,
  15.339 +                      { 'domid'        : self.frontendDomain,
  15.340                          'netif_handle' : self.vif })
  15.341 -        self.controller.delDevice(self.vif)
  15.342 -        self.getBackendInterface().writeRequest(msg, response=response)
  15.343 +        return self.backendChannel.writeRequest(msg)
  15.344      
  15.345 -    def recv_fe_interface_connect(self, val, req):
  15.346 -        if not req: return
  15.347 -        self.evtchn = channel.eventChannel(self.backendDomain, self.controller.dom)
  15.348 +    def recv_fe_interface_connect(self, val):
  15.349 +        self.openEvtchn()
  15.350          msg = packMsg('netif_be_connect_t',
  15.351 -                      { 'domid'          : self.controller.dom,
  15.352 +                      { 'domid'          : self.frontendDomain,
  15.353                          'netif_handle'   : self.vif,
  15.354                          'evtchn'         : self.getEventChannelBackend(),
  15.355                          'tx_shmem_frame' : val['tx_shmem_frame'],
  15.356                          'rx_shmem_frame' : val['rx_shmem_frame'] })
  15.357 -        d = defer.Deferred()
  15.358 -        d.addCallback(self.respond_be_connect)
  15.359 -        self.getBackendInterface().writeRequest(msg, response=d)
  15.360 -        
  15.361 -    def respond_be_connect(self, msg):
  15.362 -        val = unpackMsg('netif_be_connect_t', msg)
  15.363 -        dom = val['domid']
  15.364 -        vif = val['netif_handle']
  15.365 +        msg = self.backendChannel.requestResponse(msg)
  15.366 +        #todo: check return status
  15.367          self.status = NETIF_INTERFACE_STATUS_CONNECTED
  15.368          self.reportStatus()
  15.369 +
  15.370 +    def setCreditLimit(self, credit, period):
  15.371 +        #todo: these params should be in sxpr and vif config.
  15.372 +        self.credit = credit
  15.373 +        self.period = period
  15.374 +        self.send_be_creditlimit(credit, period)
  15.375 +
  15.376 +    def getCredit(self):
  15.377 +        return self.credit
  15.378 +
  15.379 +    def getPeriod(self):
  15.380 +        return self.period
  15.381          
  15.382      def send_be_creditlimit(self, credit, period):
  15.383          msg = packMsg('netif_be_creditlimit_t',
  15.384 -                      { 'domid'          : self.controller.dom,
  15.385 +                      { 'domid'          : self.frontendDomain,
  15.386                          'netif_handle'   : self.vif,
  15.387                          'credit_bytes'   : credit,
  15.388                          'period_usec'    : period })
  15.389 -        d = defer.Deferred()
  15.390 -        d.addCallback(self.respond_be_creditlimit)
  15.391 -        self.getBackendInterface().writeRequest(msg, response=d)
  15.392 +        msg = self.backendChannel.requestResponse(msg)
  15.393 +        # todo: check return status
  15.394          
  15.395 -    def respond_be_creditlimit(self, msg):
  15.396 -        val = unpackMsg('netif_be_creditlimit_t', msg)
  15.397 -        return self
  15.398 -        
  15.399 -    def reportStatus(self, resp=0):
  15.400 +    def reportStatus(self, resp=False):
  15.401          msg = packMsg('netif_fe_interface_status_t',
  15.402                        { 'handle' : self.vif,
  15.403                          'status' : self.status,
  15.404 @@ -387,99 +364,80 @@ class NetDev(controller.SplitDev):
  15.405                          'domid'  : self.backendDomain,
  15.406                          'mac'    : self.mac })
  15.407          if resp:
  15.408 -            self.controller.writeResponse(msg)
  15.409 +            self.frontendChannel.writeResponse(msg)
  15.410          else:
  15.411 -            self.controller.writeRequest(msg)
  15.412 +            self.frontendChannel.writeRequest(msg)
  15.413  
  15.414      def interfaceChanged(self):
  15.415 -        """Notify the font-end that a device has been added or removed.
  15.416 +        """Notify the front-end that a device has been added or removed.
  15.417          """
  15.418          self.reportStatus()
  15.419          
  15.420 -class NetifController(controller.SplitController):
  15.421 +class NetifController(DevController):
  15.422      """Network interface controller. Handles all network devices for a domain.
  15.423      """
  15.424      
  15.425 -    def __init__(self, factory, dom):
  15.426 -        controller.SplitController.__init__(self, factory, dom)
  15.427 -        self.devices = {}
  15.428 -        self.addMethod(CMSG_NETIF_FE,
  15.429 -                       CMSG_NETIF_FE_DRIVER_STATUS,
  15.430 -                       self.recv_fe_driver_status)
  15.431 -        self.addMethod(CMSG_NETIF_FE,
  15.432 -                       CMSG_NETIF_FE_INTERFACE_STATUS,
  15.433 -                       self.recv_fe_interface_status)
  15.434 -        self.addMethod(CMSG_NETIF_FE,
  15.435 -                       CMSG_NETIF_FE_INTERFACE_CONNECT,
  15.436 -                       self.recv_fe_interface_connect)
  15.437 -        self.registerChannel()
  15.438 +    def __init__(self, dctype, vm, recreate=False):
  15.439 +        DevController.__init__(self, dctype, vm, recreate=recreate)
  15.440 +        self.channel = None
  15.441 +        self.rcvr = None
  15.442 +        self.channel = None
  15.443 +
  15.444 +    def initController(self, recreate=False, reboot=False):
  15.445 +        self.destroyed = False
  15.446 +        self.channel = self.getChannel()
  15.447 +        # Register our handlers for incoming requests.
  15.448 +        self.rcvr = CtrlMsgRcvr(self.channel)
  15.449 +        self.rcvr.addHandler(CMSG_NETIF_FE,
  15.450 +                             CMSG_NETIF_FE_DRIVER_STATUS,
  15.451 +                             self.recv_fe_driver_status)
  15.452 +        self.rcvr.addHandler(CMSG_NETIF_FE,
  15.453 +                             CMSG_NETIF_FE_INTERFACE_STATUS,
  15.454 +                             self.recv_fe_interface_status)
  15.455 +        self.rcvr.addHandler(CMSG_NETIF_FE,
  15.456 +                             CMSG_NETIF_FE_INTERFACE_CONNECT,
  15.457 +                             self.recv_fe_interface_connect)
  15.458 +        self.rcvr.registerChannel()
  15.459 +        if reboot:
  15.460 +            self.rebootDevices()
  15.461 +
  15.462 +    def destroyController(self, reboot=False):
  15.463 +        """Destroy the controller and all devices.
  15.464 +        """
  15.465 +        self.destroyed = True
  15.466 +        log.debug("Destroying netif domain=%d", self.getDomain())
  15.467 +        self.destroyDevices(reboot=reboot)
  15.468 +        if self.rcvr:
  15.469 +            self.rcvr.deregisterChannel()
  15.470  
  15.471      def sxpr(self):
  15.472 -        val = ['netif', ['dom', self.dom]]
  15.473 +        val = ['netif', ['dom', self.getDomain()]]
  15.474          return val
  15.475      
  15.476 -    def lostChannel(self):
  15.477 -        """Method called when the channel has been lost.
  15.478 -        """
  15.479 -        controller.Controller.lostChannel(self)
  15.480 -
  15.481 -    def addDevice(self, vif, config):
  15.482 -        """Add a network interface.
  15.483 +    def newDevice(self, id, config, recreate=False):
  15.484 +        """Create a network device.
  15.485  
  15.486 -        @param vif: device index
  15.487 -        @param config: device configuration 
  15.488 -        @return: device
  15.489 -        """
  15.490 -        if vif in self.devices:
  15.491 -            raise XendError('device exists:' + str(vif))
  15.492 -        dev = NetDev(vif, self, config)
  15.493 -        self.devices[vif] = dev
  15.494 -        return dev
  15.495 -
  15.496 -    def destroy(self):
  15.497 -        """Destroy the controller and all devices.
  15.498 -        """
  15.499 -        self.destroyDevices()
  15.500 -        
  15.501 -    def destroyDevices(self):
  15.502 -        """Destroy all devices.
  15.503 -        """
  15.504 -        for dev in self.getDevices():
  15.505 -            dev.destroy()
  15.506 -
  15.507 -    def attachDevice(self, vif, config, recreate=0):
  15.508 -        """Attach a network device.
  15.509 -
  15.510 -        @param vif: interface index
  15.511 +        @param id: interface id
  15.512          @param config: device configuration
  15.513          @param recreate: recreate flag (true after xend restart)
  15.514          @return: deferred
  15.515          """
  15.516 -        dev = self.addDevice(vif, config)
  15.517 -        if recreate:
  15.518 -            d = defer.succeed(dev)
  15.519 -        else:
  15.520 -            d = dev.attach()
  15.521 -        return d
  15.522 +        return NetDev(self, id, config, recreate=recreate)
  15.523  
  15.524      def limitDevice(self, vif, credit, period):        
  15.525          if vif not in self.devices:
  15.526              raise XendError('device does not exist for credit limit: vif'
  15.527 -                            + str(self.dom) + '.' + str(vif))
  15.528 +                            + str(self.getDomain()) + '.' + str(vif))
  15.529          
  15.530          dev = self.devices[vif]
  15.531 -        d = dev.send_be_creditlimit(credit, period)
  15.532 -        return d
  15.533 +        return dev.setCreditLimit(credit, period)
  15.534      
  15.535 -    def recv_fe_driver_status(self, msg, req):
  15.536 -        if not req: return
  15.537 -        print
  15.538 -        print 'recv_fe_driver_status>'
  15.539 +    def recv_fe_driver_status(self, msg):
  15.540          msg = packMsg('netif_fe_driver_status_t',
  15.541                        { 'status'     : NETIF_DRIVER_STATUS_UP,
  15.542                          ## FIXME: max_handle should be max active interface id
  15.543 -                        'max_handle' : len(self.devices)
  15.544 -                        #'max_handle' : self.getMaxDeviceIdx()
  15.545 +                        'max_handle' : self.getDeviceCount()
  15.546 +                        #'max_handle' : self.getMaxDeviceId()
  15.547                          })
  15.548          # Two ways of doing it:
  15.549          # 1) front-end requests driver status, we reply with the interface count,
  15.550 @@ -492,43 +450,37 @@ class NetifController(controller.SplitCo
  15.551          #
  15.552          # We really want to use 1), but at the moment the xenU kernel panics
  15.553          # in that mode, so we're sticking to 2) for now.
  15.554 -        resp = 0
  15.555 +        resp = False
  15.556          if resp:
  15.557 -            self.writeResponse(msg)
  15.558 +            self.channel.writeResponse(msg)
  15.559          else:
  15.560              for dev in self.devices.values():
  15.561                  dev.reportStatus()
  15.562 -            self.writeRequest(msg)
  15.563 +            self.channel.writeRequest(msg)
  15.564          return resp
  15.565  
  15.566 -    def recv_fe_interface_status(self, msg, req):
  15.567 -        if not req: return
  15.568 -        print
  15.569 -        val = unpackMsg('netif_fe_interface_status_t', msg)
  15.570 -        print "recv_fe_interface_status>", val
  15.571 +    def recv_fe_interface_status(self, msg):
  15.572          vif = val['handle']
  15.573          dev = self.findDevice(vif)
  15.574          if dev:
  15.575 -            print 'recv_fe_interface_status>', 'dev=', dev
  15.576 -            dev.reportStatus(resp=1)
  15.577 +            dev.reportStatus(resp=True)
  15.578          else:
  15.579 +            log.error('Received netif_fe_interface_status for unknown vif: dom=%d vif=%d',
  15.580 +                      self.dom, vif)
  15.581              msg = packMsg('netif_fe_interface_status_t',
  15.582                            { 'handle' : -1,
  15.583                              'status' : NETIF_INTERFACE_STATUS_CLOSED,
  15.584                              });
  15.585 -            print 'recv_fe_interface_status>', 'no dev, returning -1'
  15.586 -            self.writeResponse(msg)
  15.587 -        return 1
  15.588 +            self.channel.writeResponse(msg)
  15.589 +        return True
  15.590              
  15.591 -    
  15.592 -    def recv_fe_interface_connect(self, msg, req):
  15.593 +    def recv_fe_interface_connect(self, msg):
  15.594          val = unpackMsg('netif_fe_interface_connect_t', msg)
  15.595          vif = val['handle']
  15.596 -        print
  15.597 -        print "recv_fe_interface_connect", val
  15.598          dev = self.getDevice(vif)
  15.599          if dev:
  15.600 -            dev.recv_fe_interface_connect(val, req)
  15.601 +            dev.recv_fe_interface_connect(val)
  15.602          else:
  15.603              log.error('Received netif_fe_interface_connect for unknown vif: dom=%d vif=%d',
  15.604                        self.dom, vif)
  15.605 +
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/tools/python/xen/xend/server/pciif.py	Wed Apr 20 08:45:19 2005 +0000
    16.3 @@ -0,0 +1,59 @@
    16.4 +import types
    16.5 +
    16.6 +import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
    16.7 +
    16.8 +from xen.xend import sxp
    16.9 +from xen.xend.XendError import VmError
   16.10 +
   16.11 +from controller import Dev, DevController
   16.12 +
   16.13 +def parse_pci(val):
   16.14 +    """Parse a pci field.
   16.15 +    """
   16.16 +    if isinstance(val, types.StringType):
   16.17 +        radix = 10
   16.18 +        if val.startswith('0x') or val.startswith('0X'):
   16.19 +            radix = 16
   16.20 +        v = int(val, radix)
   16.21 +    else:
   16.22 +        v = val
   16.23 +    return v
   16.24 +
   16.25 +class PciDev(Dev):
   16.26 +
   16.27 +    def __init__(self, controller, id, config, recreate=False):
   16.28 +        Dev.__init__(self, controller, id, config, recreate=recreate)
   16.29 +        bus = sxp.child_value(self.config, 'bus')
   16.30 +        if not bus:
   16.31 +            raise VmError('pci: Missing bus')
   16.32 +        dev = sxp.child_value(self.config, 'dev')
   16.33 +        if not dev:
   16.34 +            raise VmError('pci: Missing dev')
   16.35 +        func = sxp.child_value(self.config, 'func')
   16.36 +        if not func:
   16.37 +            raise VmError('pci: Missing func')
   16.38 +        try:
   16.39 +            bus = parse_pci(bus)
   16.40 +            dev = parse_pci(dev)
   16.41 +            func = parse_pci(func)
   16.42 +        except:
   16.43 +            raise VmError('pci: invalid parameter')
   16.44 +
   16.45 +    def attach(self, recreate=False, change=False):
   16.46 +        rc = xc.physdev_pci_access_modify(dom    = self.getDomain(),
   16.47 +                                          bus    = bus,
   16.48 +                                          dev    = dev,
   16.49 +                                          func   = func,
   16.50 +                                          enable = True)
   16.51 +        if rc < 0:
   16.52 +            #todo non-fatal
   16.53 +            raise VmError('pci: Failed to configure device: bus=%s dev=%s func=%s' %
   16.54 +                          (bus, dev, func))
   16.55 +
   16.56 +    def destroy(self, change=False, reboot=False):
   16.57 +        pass
   16.58 +
   16.59 +class PciController(DevController):
   16.60 +
   16.61 +    def newDevice(self, id, config, recreate=False):
   16.62 +        return PciDev(self, id, config, recreate=recreate)
    17.1 --- a/tools/python/xen/xend/server/usbif.py	Tue Apr 19 13:48:05 2005 +0000
    17.2 +++ b/tools/python/xen/xend/server/usbif.py	Wed Apr 20 08:45:19 2005 +0000
    17.3 @@ -4,59 +4,61 @@
    17.4  """Support for virtual USB hubs.
    17.5  """
    17.6  
    17.7 -from twisted.internet import defer
    17.8 -#defer.Deferred.debug = 1
    17.9 -
   17.10  from xen.xend import sxp
   17.11  from xen.xend.XendLogging import log
   17.12  from xen.xend.XendError import XendError
   17.13  
   17.14  import channel
   17.15 -import controller
   17.16 +from controller import Dev, DevController
   17.17  from messages import *
   17.18  
   17.19 -class UsbifBackendController(controller.BackendController):
   17.20 -    """ Handler for the 'back-end' channel to a USB hub domain.
   17.21 -    Must be connected using connect() before it can be used.
   17.22 -    Do not create directly - use getBackend() on the UsbifController.
   17.23 +class UsbBackend:
   17.24 +    """Handler for the 'back-end' channel to a USB device driver domain
   17.25 +    on behalf of a front-end domain.
   17.26      """
   17.27 +    def __init__(self, controller, id, dom):
   17.28 +        self.controller = controller
   17.29 +        self.id = id
   17.30 +        self.destroyed = False
   17.31 +        self.connected = False
   17.32 +        self.connecting = False
   17.33 +        self.frontendDomain = self.controller.getDomain()
   17.34 +        self.backendDomain = dom
   17.35 +        self.frontendChannel = None
   17.36 +        self.backendChannel = None
   17.37  
   17.38 -    def __init__(self, ctrl, dom):
   17.39 -        controller.BackendController.__init__(self, ctrl, dom)
   17.40 -        self.connected = 0
   17.41 -        self.evtchn = None
   17.42 -        self.addMethod(CMSG_USBIF_BE,
   17.43 -                       CMSG_USBIF_BE_DRIVER_STATUS_CHANGED,
   17.44 -                       self.recv_be_driver_status_changed)
   17.45 -        self.registerChannel()
   17.46 +    def init(self, recreate=False, reboot=False):
   17.47 +        self.frontendChannel = self.controller.getChannel()
   17.48 +        cf = channel.channelFactory()
   17.49 +        self.backendChannel = cf.openChannel(self.backendDomain)
   17.50  
   17.51      def __str__(self):
   17.52 -        return '<UsbifBackendController %d>' % (self.dom)
   17.53 +        return ('<UsbifBackend frontend=%d backend=%d id=%d>'
   17.54 +                % (self.frontendDomain,
   17.55 +                   self.backendDomain,
   17.56 +                   self.id))
   17.57  
   17.58 -    def recv_be_driver_status_changed(self, msg, req):
   17.59 -        """Request handler for be_driver_status_changed messages.
   17.60 -        
   17.61 -        @param msg: message
   17.62 -        @type  msg: xu message
   17.63 -        @param req: request flag (true if the msg is a request)
   17.64 -        @type  req: bool
   17.65 -        """
   17.66 -        val = unpackMsg('usbif_be_driver_status_changed_t', msg)
   17.67 -        status = val['status']
   17.68 +    def closeEvtchn(self):
   17.69 +        if self.evtchn:
   17.70 +            channel.eventChannelClose(self.evtchn)
   17.71 +            self.evtchn = None
   17.72  
   17.73 -class UsbifBackendInterface(controller.BackendInterface):
   17.74 -    """Handler for the 'back-end' channel to a network device driver domain
   17.75 -    on behalf of a front-end domain.
   17.76 +    def openEvtchn(self):
   17.77 +        self.evtchn = channel.eventChannel(self.backendDomain, self.frontendDomain)
   17.78 +        
   17.79 +    def getEventChannelBackend(self):
   17.80 +        val = 0
   17.81 +        if self.evtchn:
   17.82 +            val = self.evtchn['port1']
   17.83 +        return val
   17.84  
   17.85 -    Each network device is handled separately, so we add no functionality
   17.86 -    here.
   17.87 -    """
   17.88 -    def __init__(self, ctrl, dom):
   17.89 -        controller.BackendInterface.__init__(self, ctrl, dom, 0)
   17.90 -        self.connected = 0
   17.91 -        self.connecting = False
   17.92 +    def getEventChannelFrontend(self):
   17.93 +        val = 0
   17.94 +        if self.evtchn:
   17.95 +            val = self.evtchn['port2']
   17.96 +        return val
   17.97  
   17.98 -    def connect(self, recreate=0):
   17.99 +    def connect(self, recreate=False):
  17.100          """Connect the controller to the usbif control interface.
  17.101  
  17.102          @param recreate: true if after xend restart
  17.103 @@ -64,86 +66,53 @@ class UsbifBackendInterface(controller.B
  17.104          """
  17.105          log.debug("Connecting usbif %s", str(self))
  17.106          if recreate or self.connected or self.connecting:
  17.107 -            d = defer.succeed(self)
  17.108 +            pass
  17.109          else:
  17.110 -            self.connecting = True
  17.111 -            d = self.send_be_create()
  17.112 -            d.addCallback(self.respond_be_create)
  17.113 -        return d
  17.114 +            self.send_be_create()
  17.115          
  17.116      def send_be_create(self):
  17.117 -        d = defer.Deferred()
  17.118          msg = packMsg('usbif_be_create_t',
  17.119 -                      { 'domid'        : self.controller.dom })
  17.120 -        self.writeRequest(msg, response=d)
  17.121 -        return d
  17.122 -
  17.123 -    def respond_be_create(self, msg):
  17.124 +                      { 'domid'        : self.frontendDomain })
  17.125 +        msg = self.backendChannel.requestResponse(msg)
  17.126          val = unpackMsg('usbif_be_create_t', msg)
  17.127          log.debug('>UsbifBackendController>respond_be_create> %s', str(val))
  17.128          self.connected = True
  17.129 -        return self
  17.130      
  17.131 -    def destroy(self):
  17.132 +    def destroy(self, reboot=False):
  17.133          """Disconnect from the usbif control interface and destroy it.
  17.134          """
  17.135 -        def cb_destroy(val):
  17.136 -            self.send_be_destroy()
  17.137 -        d = defer.Deferred()
  17.138 -        d.addCallback(cb_destroy)
  17.139 -        self.send_be_disconnect(response=d)
  17.140 +        self.destroyed = True
  17.141 +        self.send_be_disconnect()
  17.142 +        self.send_be_destroy()
  17.143 +        self.closeEvtchn()
  17.144          
  17.145 -    def send_be_disconnect(self, response=None):
  17.146 +    def send_be_disconnect(self):
  17.147          log.debug('>UsbifBackendController>send_be_disconnect> %s', str(self))
  17.148          msg = packMsg('usbif_be_disconnect_t',
  17.149 -                      { 'domid'        : self.controller.dom })
  17.150 -        self.writeRequest(msg, response=response)
  17.151 +                      { 'domid'        : self.frontendDomain })
  17.152 +        self.backendChannel.writeRequest(msg)
  17.153  
  17.154      def send_be_destroy(self, response=None):
  17.155          log.debug('>UsbifBackendController>send_be_destroy> %s', str(self))
  17.156          msg = packMsg('usbif_be_destroy_t',
  17.157 -                      { 'domid'        : self.controller.dom })
  17.158 -        self.writeRequest(msg, response=response)
  17.159 +                      { 'domid'        : self.frontendDomain })
  17.160 +        self.backendChannel.writeRequest(msg, response=response)
  17.161  
  17.162 -    def send_be_claim_port(self, path):
  17.163 -        d=defer.Deferred()
  17.164 -        log.debug(">UsbifBackendController>send_be_claim_port> about to claim port %s" % path)
  17.165 -        def cb(blah): log.debug(">UsbifBackendController> Claim port completed")
  17.166 -        d.addCallback(cb)
  17.167 -        msg = packMsg('usbif_be_claim_port_t',
  17.168 -                      { 'domid'        : self.controller.dom,
  17.169 -                        'path'         : path,
  17.170 -                        'usbif_port'   : self.controller.devices[path],
  17.171 -                        'status'       : 0})
  17.172 -        self.writeRequest(msg, response=d)
  17.173 -        # No need to add any callbacks, since the guest polls its virtual ports
  17.174 -        # anyhow, somewhat like a UHCI controller ;-)
  17.175 -        return d
  17.176 -
  17.177 -    def send_be_release_port(self, path):
  17.178 -        d=defer.Deferred()
  17.179 -        def cb(blah): log.debug(">UsbifBackendController> Release port completed")
  17.180 -        d.addCallback(cb)
  17.181 -        msg = packMsg('usbif_be_release_port_t',
  17.182 -                      { 'domid'        : self.controller.dom,
  17.183 -                        'path'         : path })
  17.184 -        self.writeRequest(msg, response)        
  17.185 -        # No need to add any callbacks, since the guest polls its virtual ports
  17.186 -        # anyhow, somewhat like a UHCI controller ;-)
  17.187      
  17.188      def connectInterface(self, val):
  17.189 -        self.evtchn = channel.eventChannel(0, self.controller.dom)
  17.190 +        self.openEvtchn()
  17.191          log.debug(">UsbifBackendController>connectInterface> connecting usbif to event channel %s ports=%d:%d",
  17.192 -                  str(self), self.evtchn['port1'], self.evtchn['port2'])
  17.193 +                  str(self),
  17.194 +                  self.getEventChannelBackend(),
  17.195 +                  self.getEventChannelFrontend())
  17.196          msg = packMsg('usbif_be_connect_t',
  17.197 -                      { 'domid'        : self.controller.dom,
  17.198 -                        'evtchn'       : self.evtchn['port1'],
  17.199 +                      { 'domid'        : self.frontendDomain,
  17.200 +                        'evtchn'       : self.getEventChannelBackend(),
  17.201                          'shmem_frame'  : val['shmem_frame'],
  17.202                          'bandwidth'    : 500 # XXX fix bandwidth!
  17.203                          })
  17.204 -        d = defer.Deferred()
  17.205 -        d.addCallback(self.respond_be_connect)
  17.206 -        self.writeRequest(msg, response=d)
  17.207 +        msg = self.backendChannel.requestResponse(msg)
  17.208 +        self.respond_be_connect(msg)
  17.209  
  17.210      def respond_be_connect(self, msg):
  17.211          """Response handler for a be_connect message.
  17.212 @@ -153,196 +122,201 @@ class UsbifBackendInterface(controller.B
  17.213          """
  17.214          val = unpackMsg('usbif_be_connect_t', msg)
  17.215          log.debug('>UsbifBackendController>respond_be_connect> %s, %s', str(self), str(val))
  17.216 -        d = defer.Deferred()
  17.217 -        def cb(blah):
  17.218 -            log.debug(">UsbifBackendController> Successfully connected USB interface for domain %d" % self.controller.dom)
  17.219 -            self.controller.claim_ports()
  17.220 -        d.addCallback(cb)
  17.221 -        self.send_fe_interface_status_changed(d)
  17.222 +        self.send_fe_interface_status_changed()
  17.223 +        log.debug(">UsbifBackendController> Successfully connected USB interface for domain %d" % self.frontendDomain)
  17.224 +        self.controller.claim_ports()
  17.225              
  17.226 -    def send_fe_interface_status_changed(self, response=None):
  17.227 +    def send_fe_interface_status_changed(self):
  17.228          msg = packMsg('usbif_fe_interface_status_changed_t',
  17.229 -                      { 'status' : USBIF_INTERFACE_STATUS_CONNECTED,
  17.230 -                        'domid'  : 0, ## FIXME: should be domid of backend
  17.231 -                        'evtchn' : self.evtchn['port2'],
  17.232 +                      { 'status'    : USBIF_INTERFACE_STATUS_CONNECTED,
  17.233 +                        'domid'     : self.backendDomain,
  17.234 +                        'evtchn'    : self.getEventChannelFrontend(),
  17.235                          'bandwidth' : 500,
  17.236 -                        'num_ports'    : len(self.controller.devices.keys())})
  17.237 -        self.controller.writeRequest(msg, response=response)
  17.238 +                        'num_ports' : len(self.controller.devices)
  17.239 +                        })
  17.240 +        self.frontendChannel.writeRequest(msg)
  17.241  
  17.242 -        
  17.243 -class UsbifControllerFactory(controller.SplitControllerFactory):
  17.244 -    """Factory for creating USB interface controllers.
  17.245 -    """
  17.246 +    def interfaceChanged(self):
  17.247 +        self.send_fe_interface_status_changed()
  17.248 +
  17.249  
  17.250 -    def __init__(self):
  17.251 -        controller.ControllerFactory.__init__(self)
  17.252 -        self.backendControllers = {}
  17.253 -
  17.254 -    def createController(self, dom, recreate=0):
  17.255 -        """Create a USB device controller for a domain.
  17.256 +class UsbDev(Dev):
  17.257 +    
  17.258 +    def __init__(self, controller, id, config, recreate=False):
  17.259 +        Dev.__init__(self, controller, id, config, recreate=recreate)
  17.260 +        self.port = id
  17.261 +        self.path = None
  17.262 +        self.frontendDomain = self.getDomain()
  17.263 +        self.frontendChannel = None
  17.264 +        self.backendDomain = 0
  17.265 +        self.backendChannel = None
  17.266 +        self.configure(self.config, recreate=recreate)
  17.267  
  17.268 -        @param dom: domain
  17.269 -        @type  dom: int
  17.270 -        @param recreate: if true it's a recreate (after xend restart)
  17.271 -        @type  recreate: bool
  17.272 -        @return: block device controller
  17.273 -        @rtype: UsbifController
  17.274 -        """
  17.275 -        usbif = self.getControllerByDom(dom)
  17.276 -        if usbif is None:
  17.277 -            usbif = UsbifController(self, dom)
  17.278 -            self.addController(usbif)
  17.279 -        return usbif
  17.280 -
  17.281 -    def getDomainDevices(self, dom):
  17.282 -        """Get the block devices for a domain.
  17.283 +    def init(self, recreate=False, reboot=False):
  17.284 +        self.destroyed = False
  17.285 +        self.frontendDomain = self.getDomain()
  17.286 +        self.frontendChannel = self.getChannel()
  17.287 +        backend = self.getBackend()
  17.288 +        self.backendChannel = backend.backendChannel
  17.289 +        
  17.290 +    def configure(self, config, change=False, recreate=False):
  17.291 +        if change:
  17.292 +            raise XendError("cannot reconfigure usb")
  17.293 +        #todo: FIXME: Use sxp access methods to get this value.
  17.294 +        # Must not use direct indexing.
  17.295 +        self.path = config[1][1]
  17.296 +        
  17.297 +        #todo: FIXME: Support configuring the backend domain.
  17.298 +##         try:
  17.299 +##             self.backendDomain = int(sxp.child_value(config, 'backend', '0'))
  17.300 +##         except:
  17.301 +##             raise XendError('invalid backend domain')
  17.302  
  17.303 -        @param dom: domain
  17.304 -        @type  dom: int
  17.305 -        @return: devices
  17.306 -        @rtype:  [device]
  17.307 -        """
  17.308 -        usbif = self.getControllerByDom(dom)
  17.309 -        return (usbif and usbif.getDevices()) or []
  17.310 -
  17.311 -    def getDomainDevice(self, dom, vdev):
  17.312 -        """Get a block device from a domain.
  17.313 +    def attach(self, recreate=False, change=False):
  17.314 +        if recreate:
  17.315 +            pass
  17.316 +        else:
  17.317 +            self.attachBackend()
  17.318 +        if change:
  17.319 +            self.interfaceChanged()
  17.320 +            
  17.321 +    def sxpr(self):
  17.322 +        val = ['usb',
  17.323 +               ['id', self.id],
  17.324 +               ['port', self.port],
  17.325 +               ['path', self.path],
  17.326 +               ]
  17.327 +        val.append(['index', self.getIndex()])
  17.328 +        return val
  17.329  
  17.330 -        @param dom: domain
  17.331 -        @type  dom: int
  17.332 -        @param vdev: device index
  17.333 -        @type  vdev: int
  17.334 -        @return: device
  17.335 -        @rtype:  device
  17.336 +    def getBackend(self):
  17.337 +        return self.controller.getBackend(self.backendDomain)
  17.338 +
  17.339 +    def destroy(self, change=False, reboot=False):
  17.340 +        """Destroy the device. If 'change' is true notify the front-end interface.
  17.341 +
  17.342 +        @param change: change flag
  17.343          """
  17.344 -        usbif = self.getControllerByDom(dom)
  17.345 -        return (usbif and usbif.getDevice(vdev)) or None
  17.346 -    
  17.347 -    def createBackendInterface(self, ctrl, dom, handle):
  17.348 -        """Create a network device backend interface.
  17.349 +        self.destroyed = True
  17.350 +        log.debug("Destroying usb domain=%d id=%s", self.frontendDomain, self.id)
  17.351 +        self.send_be_release_port()
  17.352 +        if change:
  17.353 +            self.interfaceChanged()
  17.354  
  17.355 -        @param ctrl: controller
  17.356 -        @param dom: backend domain
  17.357 -        @param handle: interface handle
  17.358 -        @return: backend interface
  17.359 +    def interfaceChanged(self):
  17.360 +        """Tell the back-end to notify the front-end that a device has been
  17.361 +        added or removed.
  17.362          """
  17.363 -        return UsbifBackendInterface(ctrl, dom)
  17.364 +        self.getBackend().interfaceChanged()
  17.365  
  17.366 -    def getBackendController(self, dom):
  17.367 -        """Get the backend controller for a domain, creating
  17.368 -        if necessary.
  17.369 +    def attachBackend(self):
  17.370 +        """Attach the device to its controller.
  17.371 +
  17.372 +        """
  17.373 +        self.getBackend().connect()
  17.374  
  17.375 -        @param dom: backend domain
  17.376 -        @return: backend controller
  17.377 -        """
  17.378 -        b = self.getBackendControllerByDomain(dom)
  17.379 -        if b is None:
  17.380 -            b = self.createBackendController(dom)
  17.381 -            self.backendControllers[b.dom] = b
  17.382 -        return b
  17.383 +    def send_be_claim_port(self):
  17.384 +        log.debug(">UsbifBackendController>send_be_claim_port> about to claim port %s" % self.path)
  17.385 +        msg = packMsg('usbif_be_claim_port_t',
  17.386 +                      { 'domid'        : self.frontendDomain,
  17.387 +                        'path'         : self.path,
  17.388 +                        'usbif_port'   : self.port,
  17.389 +                        'status'       : 0})
  17.390 +        self.backendChannel.writeRequest(msg)
  17.391 +        log.debug(">UsbifBackendController> Claim port completed")
  17.392 +        # No need to add any callbacks, since the guest polls its virtual ports
  17.393 +        # anyhow, somewhat like a UHCI controller ;-)
  17.394  
  17.395 -    def createBackendController(self, dom):
  17.396 -        return UsbifBackendController(self, dom)
  17.397 +    def send_be_release_port(self):
  17.398 +        msg = packMsg('usbif_be_release_port_t',
  17.399 +                      { 'domid'        : self.frontendDomain,
  17.400 +                        'path'         : self.path })
  17.401 +        self.backendChannel.writeRequest(msg)        
  17.402 +        log.debug(">UsbifBackendController> Release port completed")
  17.403 +        # No need to add any callbacks, since the guest polls its virtual ports
  17.404 +        # anyhow, somewhat like a UHCI controller ;-)
  17.405  
  17.406 -class UsbifController(controller.SplitController):
  17.407 +class UsbifController(DevController):
  17.408      """USB device interface controller. Handles all USB devices
  17.409      for a domain.
  17.410      """
  17.411      
  17.412 -    def __init__(self, factory, dom):
  17.413 +    def __init__(self, dctype, vm, recreate=False):
  17.414          """Create a USB device controller.
  17.415 -        Do not call directly - use createController() on the factory instead.
  17.416          """
  17.417 -        controller.SplitController.__init__(self, factory, dom)
  17.418 -        self.num_ports = 0
  17.419 -        self.devices = {}
  17.420 -        self.addMethod(CMSG_USBIF_FE,
  17.421 -                       CMSG_USBIF_FE_DRIVER_STATUS_CHANGED,
  17.422 -                       self.recv_fe_driver_status_changed)
  17.423 -        self.addMethod(CMSG_USBIF_FE,
  17.424 -                       CMSG_USBIF_FE_INTERFACE_CONNECT,
  17.425 -                       self.recv_fe_interface_connect)
  17.426 -        self.registerChannel()
  17.427 -        try:
  17.428 -            self.backendDomain = 0 #int(sxp.child_value(config, 'backend', '0')) TODO: configurable backends
  17.429 -        except:
  17.430 -            raise XendError('invalid backend domain')
  17.431 +        DevController.__init__(self, dctype, vm, recreate=recreate)
  17.432 +        self.backends = {}
  17.433 +        self.backendId = 0
  17.434 +        self.rcvr = None
  17.435  
  17.436 +    def init(self, recreate=False, reboot=False):
  17.437 +        self.destroyed = False
  17.438 +        self.rcvr = CtrlMsgRcvr(self.getChannel())
  17.439 +        self.rcvr.addHandler(CMSG_USBIF_FE,
  17.440 +                             CMSG_USBIF_FE_DRIVER_STATUS_CHANGED,
  17.441 +                             self.recv_fe_driver_status_changed)
  17.442 +        self.rcvr.addHandler(CMSG_USBIF_FE,
  17.443 +                             CMSG_USBIF_FE_INTERFACE_CONNECT,
  17.444 +                             self.recv_fe_interface_connect)
  17.445 +        self.rcvr.registerChannel()
  17.446 +        if reboot:
  17.447 +            self.rebootBackends()
  17.448 +            self.rebootDevices()
  17.449  
  17.450      def sxpr(self):
  17.451 -        val = ['usbif', ['dom', self.dom]]
  17.452 +        val = ['usbif',
  17.453 +               ['dom', self.getDomain()]]
  17.454          return val
  17.455  
  17.456 -    def createBackend(self, dom, handle):
  17.457 -        return UsbifBackendController(self, dom, handle)
  17.458 -
  17.459 -    def getDevices(self):
  17.460 -        return self.devices.values()
  17.461 -
  17.462 -    def attachDevice(self, path, recreate=0):
  17.463 -        """Add privileges for a particular device to the domain.
  17.464 -        @param path: the Linux-style path to the device port
  17.465 -        """
  17.466 -        self.devices[path[1][1]] = self.num_ports
  17.467 -        self.num_ports += 1
  17.468 -        log.debug(">UsbifController>attachDevice> device: %s, port: %d" %
  17.469 -                  (str(path), self.num_ports ) )
  17.470 -
  17.471 -        backend =self.getBackendInterface(self.backendDomain)
  17.472 +    def newDevice(self, id, config, recreate=False):
  17.473 +        return UsbDev(self, id, config, recreate=recreate)
  17.474  
  17.475 -        def cb(blah):
  17.476 -            log.debug(">UsbifController> Backend created")
  17.477 -            pass
  17.478 -        d = backend.connect()
  17.479 -        d.addCallback(cb) # Chaining the claim port operation
  17.480 -        return d
  17.481 -
  17.482 -
  17.483 -    def removeDevice(self, path):
  17.484 -        self.delDevice(path)
  17.485 -        backend = self.getBackendInterface(self.backendDomain)
  17.486 -        return backend.send_be_release_port(path)
  17.487 -
  17.488 -    def delDevice(self, path):
  17.489 -        if path in self.devices:
  17.490 -            del self.devices[path]
  17.491 -
  17.492 -    def attachPort(self, path, recreate=0):
  17.493 -        """Attach a device to the specified interface.
  17.494 -        On success the returned deferred will be called with the device.
  17.495 -
  17.496 -        @return: deferred
  17.497 -        @rtype:  Deferred
  17.498 -        """
  17.499 -        return self.attachDevice(path)
  17.500 -
  17.501 -    def destroy(self):
  17.502 +    def destroyController(self, reboot=False):
  17.503          """Destroy the controller and all devices.
  17.504          """
  17.505 -        log.debug("Destroying usbif domain=%d", self.dom)
  17.506 -        self.destroyBackends()
  17.507 +        self.destroyed = True
  17.508 +        log.debug("Destroying blkif domain=%d", self.getDomain())
  17.509 +        self.destroyDevices(reboot=reboot)
  17.510 +        self.destroyBackends(reboot=reboot)
  17.511 +        if self.rcvr:
  17.512 +            self.rcvr.deregisterChannel()
  17.513 +
  17.514 +    def rebootBackends(self):
  17.515 +        for backend in self.backends.values():
  17.516 +            backend.init(reboot=True)
  17.517 +
  17.518 +    def getBackendById(self, id):
  17.519 +        return self.backends.get(id)
  17.520  
  17.521 -    def destroyDevices(self):
  17.522 -        """Destroy all devices.
  17.523 -        """
  17.524 -        for path in self.getDevices():
  17.525 -            self.removeDevice(path)
  17.526 +    def getBackendByDomain(self, dom):
  17.527 +        for backend in self.backends.values():
  17.528 +            if backend.backendDomain == dom:
  17.529 +                return backend
  17.530 +        return None
  17.531  
  17.532 -    def destroyBackends(self):
  17.533 -        for backend in self.getBackendInterfaces():
  17.534 -            backend.destroy()
  17.535 +    def getBackend(self, dom):
  17.536 +        backend = self.getBackendByDomain(dom)
  17.537 +        if backend: return backend
  17.538 +        backend = UsbBackend(self, self.backendId, dom)
  17.539 +        self.backendId += 1
  17.540 +        self.backends[backend.getId()] = backend
  17.541 +        backend.init()
  17.542 +        return backend
  17.543 +    
  17.544 +    def destroyBackends(self, reboot=False):
  17.545 +        for backend in self.backends.values():
  17.546 +            backend.destroy(reboot=reboot)
  17.547  
  17.548 -    def recv_fe_driver_status_changed(self, msg, req):
  17.549 +    def recv_fe_driver_status_changed(self, msg):
  17.550          val = unpackMsg('usbif_fe_driver_status_changed_t', msg)
  17.551          log.debug('>UsbifController>recv_fe_driver_status_changed> %s', str(val))
  17.552 -        # For each backend?
  17.553 +        #todo: FIXME: For each backend?
  17.554          msg = packMsg('usbif_fe_interface_status_changed_t',
  17.555                        { 'status' : USBIF_INTERFACE_STATUS_DISCONNECTED,
  17.556 -                        'domid'  : 0, ## FIXME: should be domid of backend
  17.557 +                        'domid'  : 0, #todo: FIXME: should be domid of backend
  17.558                          'evtchn' : 0 })
  17.559 -        d = defer.Deferred()
  17.560 -        d.addCallback(self.disconnected_resp)
  17.561 -        self.writeRequest(msg)
  17.562 +        msg = self.getChannel().requestResponse(msg)
  17.563 +        self.disconnected_resp(msg)
  17.564  
  17.565      def disconnected_resp(self, msg):
  17.566          val = unpackMsg('usbif_fe_interface_status_changed_t', msg)
  17.567 @@ -351,18 +325,21 @@ class UsbifController(controller.SplitCo
  17.568          else:
  17.569              log.debug(">UsbifController>disconnected_resp> interface disconnected OK")
  17.570  
  17.571 -    def recv_fe_interface_connect(self, msg, req):
  17.572 +    def recv_fe_interface_connect(self, msg):
  17.573          val = unpackMsg('usbif_fe_interface_status_changed_t', msg)
  17.574          log.debug(">UsbifController>recv_fe_interface_connect> notifying backend")
  17.575 -        backend = self.getBackendInterfaceByHandle(0)
  17.576 +        #todo: FIXME: generalise to more than one backend.
  17.577 +        id = 0
  17.578 +        backend = self.getBackendById(id)
  17.579          if backend:
  17.580 -            d = backend.connectInterface(val)
  17.581 +            try:
  17.582 +                backend.connectInterface(val)
  17.583 +            except IOError, ex:
  17.584 +                log.error("Exception connecting backend: %s", ex)
  17.585          else:
  17.586 -            log.error('>UsbifController>recv_fe_interface_connect> unknown interface')
  17.587 +            log.error('interface connect on unknown interface: id=%d', id)
  17.588  
  17.589      def claim_ports(self):
  17.590 -        backend = self.getBackendInterfaceByHandle(0)
  17.591 -        for path in self.devices.keys():
  17.592 -            log.debug(">UsbifController>claim_ports> claiming port... %s" % path)
  17.593 -            backend.send_be_claim_port(path)
  17.594 +        for dev in self.devices.values():
  17.595 +            dev.send_be_claim_port()
  17.596