debuggers.hg
changeset 4618: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>
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>
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