From b7df222032d7012801264b5c55035587dcb8ee9f Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Fri, 11 Mar 2005 17:01:00 +0000 Subject: [PATCH 1/9] bitkeeper revision 1.1159.269.2 (4231ceccPlcoLKWWixfu3trU9tb-_A) Improve error reporting for save/restore/migrate. Signed-off-by: Mike Wray --- tools/python/xen/xend/XendMigrate.py | 158 +++++++++++++--------- tools/python/xen/xend/server/SrvDomain.py | 17 --- 2 files changed, 91 insertions(+), 84 deletions(-) diff --git a/tools/python/xen/xend/XendMigrate.py b/tools/python/xen/xend/XendMigrate.py index a1c261deb5..f2570ae02b 100644 --- a/tools/python/xen/xend/XendMigrate.py +++ b/tools/python/xen/xend/XendMigrate.py @@ -6,12 +6,14 @@ import errno import sys import socket import time +import types from twisted.internet import reactor from twisted.internet import defer #defer.Deferred.debug = 1 from twisted.internet.protocol import Protocol from twisted.internet.protocol import ClientFactory +from twisted.python.failure import Failure import sxp import XendDB @@ -45,11 +47,9 @@ class Xfrd(Protocol): sxp.show(req, out=self.transport) def loseConnection(self): - print 'Xfrd>loseConnection>' self.transport.loseConnection() def connectionLost(self, reason): - print 'Xfrd>connectionLost>', reason self.xinfo.connectionLost(reason) def dataReceived(self, data): @@ -70,17 +70,15 @@ class XfrdClientFactory(ClientFactory): self.xinfo = xinfo def startedConnecting(self, connector): - print 'Started to connect', 'self=', self, 'connector=', connector + pass def buildProtocol(self, addr): - print 'buildProtocol>', addr return Xfrd(self.xinfo) def clientConnectionLost(self, connector, reason): - print 'clientConnectionLost>', 'connector=', connector, 'reason=', reason + pass def clientConnectionFailed(self, connector, reason): - print 'clientConnectionFailed>', 'connector=', connector, 'reason=', reason self.xinfo.error(reason) class XfrdInfo: @@ -90,7 +88,7 @@ class XfrdInfo: """Suspend timeout (seconds). We set a timeout because suspending a domain can hang.""" - timeout = 30 + timeout = 10 def __init__(self): from xen.xend import XendDomain @@ -98,6 +96,9 @@ class XfrdInfo: self.deferred = defer.Deferred() self.suspended = {} self.paused = {} + self.state = 'init' + # List of errors encountered. + self.errors = [] def vmconfig(self): dominfo = self.xd.domain_get(self.src_dom) @@ -107,12 +108,38 @@ class XfrdInfo: val = None return val + def add_error(self, err): + """Add an error to the error list. + Returns the error added (which may have been unwrapped if it + was a Twisted Failure). + """ + while isinstance(err, Failure): + err = err.value + if err not in self.errors: + self.errors.append(err) + return err + + def error_summary(self, msg=None): + """Get a XendError summarising the errors (if any). + """ + if msg is None: + msg = "errors" + if self.errors: + errmsg = msg + ': ' + ', '.join(map(str, self.errors)) + else: + errmsg = msg + return XendError(errmsg) + + def get_errors(self): + """Get the list of errors. + """ + return self.errors + def error(self, err): - print 'Error>', err self.state = 'error' + self.add_error(err) if not self.deferred.called: - print 'Error> calling errback' - self.deferred.errback(err) + self.deferred.errback(self.error_summary()) def dispatch(self, xfrd, val): @@ -139,28 +166,23 @@ class XfrdInfo: cbok(val) def unknown(self, xfrd, val): - print 'unknown>', val xfrd.loseConnection() return None def xfr_err(self, xfrd, val): # If we get an error with non-zero code the operation failed. # An error with code zero indicates hello success. - print 'xfr_err>', val v = sxp.child0(val) - print 'xfr_err>', type(v), v err = int(sxp.child0(val)) if not err: return - self.error(err); + self.error("transfer daemon (xfrd) error: " + str(err)) xfrd.loseConnection() return None def xfr_progress(self, xfrd, val): - print 'xfr_progress>', val return None def xfr_vm_destroy(self, xfrd, val): - print 'xfr_vm_destroy>', val try: vmid = sxp.child0(val) val = self.xd.domain_destroy(vmid) @@ -168,28 +190,32 @@ class XfrdInfo: del self.paused[vmid] if vmid in self.suspended: del self.suspended[vmid] - except: + except StandardError, err: + self.add_error("vm_destroy failed") + self.add_error(err) val = errno.EINVAL return ['xfr.err', val] def xfr_vm_pause(self, xfrd, val): - print 'xfr_vm_pause>', val try: vmid = sxp.child0(val) val = self.xd.domain_pause(vmid) self.paused[vmid] = 1 - except: + except StandardError, err: + self.add_error("vm_pause failed") + self.add_error(err) val = errno.EINVAL return ['xfr.err', val] def xfr_vm_unpause(self, xfrd, val): - print 'xfr_vm_unpause>', val try: vmid = sxp.child0(val) val = self.xd.domain_unpause(vmid) if vmid in self.paused: del self.paused[vmid] - except: + except StandardError, err: + self.add_error("vm_unpause failed") + self.add_error(err) val = errno.EINVAL return ['xfr.err', val] @@ -199,7 +225,6 @@ class XfrdInfo: Suspending can hang, so we set a timeout and fail if it takes too long. """ - print 'xfr_vm_suspend>', val try: vmid = sxp.child0(val) d = defer.Deferred() @@ -208,15 +233,15 @@ class XfrdInfo: # the domain died. Set a timeout and error handler so the subscriptions # will be cleaned up if suspending hangs or there is an error. def onSuspended(e, v): - print 'xfr_vm_suspend>onSuspended>', e, v if v[1] != vmid: return subscribe(on=0) - d.callback(v) + if not d.called: + d.callback(v) def onDied(e, v): - print 'xfr_vm_suspend>onDied>', e, v if v[1] != vmid: return - d.errback(XendError('Domain died')) + if not d.called: + d.errback(XendError('Domain %s died while suspending' % vmid)) def subscribe(on=1): if on: @@ -227,24 +252,25 @@ class XfrdInfo: action('xend.domain.died', onDied) def cberr(err): - print 'xfr_vm_suspend>cberr>', err subscribe(on=0) + self.add_error("suspend failed") + self.add_error(err) return err + d.addErrback(cberr) + d.setTimeout(self.timeout) subscribe() val = self.xd.domain_shutdown(vmid, reason='suspend') self.suspended[vmid] = 1 - d.addErrback(cberr) - d.setTimeout(self.timeout) return d except Exception, err: - print 'xfr_vm_suspend> Exception', err + self.add_error("suspend failed") + self.add_error(err) traceback.print_exc() val = errno.EINVAL return ['xfr.err', val] def connectionLost(self, reason=None): - print 'XfrdInfo>connectionLost>', reason for vmid in self.suspended: try: self.xd.domain_destroy(vmid) @@ -279,7 +305,7 @@ class XendMigrateInfo(XfrdInfo): ['id', self.xid ], ['state', self.state ], ['live', self.live ], - ['resource', self.resource] ] + ['resource', self.resource ] ] sxpr_src = ['src', ['host', self.src_host], ['domain', self.src_dom] ] sxpr.append(sxpr_src) sxpr_dst = ['dst', ['host', self.dst_host] ] @@ -291,12 +317,12 @@ class XendMigrateInfo(XfrdInfo): def request(self, xfrd): vmconfig = self.vmconfig() if not vmconfig: + self.error(XendError("vm config not found")) xfrd.loseConnection() return - log.info('Migrate BEGIN: ' + str(self.sxpr())) + log.info('Migrate BEGIN: %s' % str(self.sxpr())) eserver.inject('xend.domain.migrate', - [ self.dominfo.name, self.dominfo.id, - "begin", self.sxpr() ]) + [ self.dominfo.name, self.dominfo.id, "begin", self.sxpr() ]) xfrd.request(['xfr.migrate', self.src_dom, vmconfig, @@ -305,19 +331,6 @@ class XendMigrateInfo(XfrdInfo): self.live, self.resource ]) -## def xfr_vm_suspend(self, xfrd, val): -## def cbok(val): -## # Special case for localhost: destroy devices early. -## if self.dst_host in ["localhost", "127.0.0.1"]: -## self.dominfo.restart_cancel() -## self.dominfo.cleanup() -## self.dominfo.destroy_console() -## return val - -## d = XfrdInfo.xfr_vm_suspend(self, xfrd, val) -## d.addCallback(cbok) -## return d - def xfr_migrate_ok(self, xfrd, val): dom = int(sxp.child0(val)) self.state = 'ok' @@ -327,17 +340,15 @@ class XendMigrateInfo(XfrdInfo): self.deferred.callback(self) def connectionLost(self, reason=None): - print 'XfrdMigrateInfo>connectionLost>', reason XfrdInfo.connectionLost(self, reason) if self.state =='ok': log.info('Migrate OK: ' + str(self.sxpr())) else: self.state = 'error' - self.error(XendError("migrate failed")) + self.error("migrate failed") log.info('Migrate ERROR: ' + str(self.sxpr())) eserver.inject('xend.domain.migrate', - [ self.dominfo.name, self.dominfo.id, - self.state, self.sxpr() ]) + [ self.dominfo.name, self.dominfo.id, self.state, self.sxpr() ]) class XendSaveInfo(XfrdInfo): """Representation of a save in-progress and its interaction with xfrd. @@ -361,16 +372,15 @@ class XendSaveInfo(XfrdInfo): return sxpr def request(self, xfrd): - print '***request>', self.vmconfig() vmconfig = self.vmconfig() if not vmconfig: + self.error(XendError("vm config not found")) xfrd.loseConnection() return - print '***request> begin' log.info('Save BEGIN: ' + str(self.sxpr())) eserver.inject('xend.domain.save', - [self.dominfo.name, self.dominfo.id, - "begin", self.sxpr()]) + [ self.dominfo.name, self.dominfo.id, + "begin", self.sxpr() ]) xfrd.request(['xfr.save', self.src_dom, vmconfig, self.file ]) def xfr_save_ok(self, xfrd, val): @@ -380,13 +390,12 @@ class XendSaveInfo(XfrdInfo): self.deferred.callback(self) def connectionLost(self, reason=None): - print 'XfrdSaveInfo>connectionLost>', reason XfrdInfo.connectionLost(self, reason) if self.state =='ok': log.info('Save OK: ' + str(self.sxpr())) else: self.state = 'error' - self.error(XendError("save failed")) + self.error("save failed") log.info('Save ERROR: ' + str(self.sxpr())) eserver.inject('xend.domain.save', [ self.dominfo.name, self.dominfo.id, @@ -409,8 +418,9 @@ class XendRestoreInfo(XfrdInfo): return sxpr def request(self, xfrd): - print '***request>', self.file log.info('restore BEGIN: ' + str(self.sxpr())) + eserver.inject('xend.restore', [ 'begin', self.sxpr()]) + xfrd.request(['xfr.restore', self.file ]) def xfr_restore_ok(self, xfrd, val): @@ -419,8 +429,17 @@ class XendRestoreInfo(XfrdInfo): self.state = 'ok' if not self.deferred.called: self.deferred.callback(dominfo) - + def connectionLost(self, reason=None): + XfrdInfo.connectionLost(self, reason) + if self.state =='ok': + log.info('Restore OK: ' + self.file) + else: + self.state = 'error' + self.error("restore failed") + log.info('Restore ERROR: ' + str(self.sxpr())) + eserver.inject('xend.restore', [ self.state, self.sxpr()]) + class XendMigrate: """External api for interaction with xfrd for migrate and save. Singleton. @@ -445,7 +464,6 @@ class XendMigrate: self.db.saveall("", self.session_db) def sync_session(self, xid): - print 'sync_session>', type(xid), xid, self.session_db[xid] self.db.save(xid, self.session_db[xid]) def close(self): @@ -458,7 +476,6 @@ class XendMigrate: self.sync_session(xid) def _delete_session(self, xid): - print '***_delete_session>', xid if xid in self.session: del self.session[xid] if xid in self.session_db: @@ -482,16 +499,23 @@ class XendMigrate: @param info: session @return: deferred """ - def cbremove(val): - print '***cbremove>', val + dfr = defer.Deferred() + def cbok(val): self._delete_session(info.xid) + if not dfr.called: + dfr.callback(val) return val + def cberr(err): + self._delete_session(info.xid) + if not dfr.called: + dfr.errback(err) + return err self._add_session(info) - info.deferred.addCallback(cbremove) - info.deferred.addErrback(cbremove) + info.deferred.addCallback(cbok) + info.deferred.addErrback(cberr) xcf = XfrdClientFactory(info) reactor.connectTCP('localhost', XFRD_PORT, xcf) - return info.deferred + return dfr def migrate_begin(self, dominfo, host, port=XFRD_PORT, live=0, resource=0): """Begin to migrate a domain to another host. diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py index d73a39bff5..a4c06f6c8d 100644 --- a/tools/python/xen/xend/server/SrvDomain.py +++ b/tools/python/xen/xend/server/SrvDomain.py @@ -29,13 +29,8 @@ class SrvDomain(SrvDir): [['dom', 'int'], ['config', 'sxpr']]) deferred = fn(req.args, {'dom': self.dom.dom}) - deferred.addErrback(self._op_configure_err, req) return deferred - def _op_configure_err(self, err, req): - req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err)) - return str(err) - def op_unpause(self, op, req): val = self.xd.domain_unpause(self.dom.name) return val @@ -68,16 +63,11 @@ class SrvDomain(SrvDir): ['file', 'str']]) deferred = fn(req.args, {'dom': self.dom.id}) deferred.addCallback(self._op_save_cb, req) - deferred.addErrback(self._op_save_err, req) return deferred def _op_save_cb(self, val, req): return 0 - def _op_save_err(self, err, req): - req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err)) - return str(err) - def op_migrate(self, op, req): fn = FormFn(self.xd.domain_migrate, [['dom', 'str'], @@ -85,9 +75,7 @@ class SrvDomain(SrvDir): ['live', 'int'], ['resource', 'int']]) deferred = fn(req.args, {'dom': self.dom.id}) - print 'op_migrate>', deferred deferred.addCallback(self._op_migrate_cb, req) - deferred.addErrback(self._op_migrate_err, req) return deferred def _op_migrate_cb(self, info, req): @@ -101,11 +89,6 @@ class SrvDomain(SrvDir): print '_op_migrate_cb> url=', url return url - def _op_migrate_err(self, err, req): - print '_op_migrate_err>', err, req - req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err)) - return str(err) - def op_pincpu(self, op, req): fn = FormFn(self.xd.domain_pincpu, [['dom', 'str'], From 8d909771419ace2b3119e8620badaba6aa3b3380 Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Tue, 15 Mar 2005 11:52:56 +0000 Subject: [PATCH 2/9] bitkeeper revision 1.1159.269.3 (4236cc98Jkx2LDbrsWrj59Z-UTR_jA) Change default config to bind to localhost only. Signed-off-by: Mike Wray --- tools/examples/xend-config.sxp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/examples/xend-config.sxp b/tools/examples/xend-config.sxp index 8aa6ccaa7e..8d670c3d16 100644 --- a/tools/examples/xend-config.sxp +++ b/tools/examples/xend-config.sxp @@ -9,7 +9,7 @@ # Address xend should listen on for HTTP connections. # Specifying 'localhost' prevents remote connections. # Specifying the empty string '' allows all connections. -(xend-address '') +(xend-address 'localhost') # The port xend should start from when allocating a port # for a domain console. @@ -18,7 +18,7 @@ # Address xend should listen on for console connections. # Specifying 'localhost' prevents remote connections. # Specifying the empty string '' allows all connections. -(console-address '') +(console-address 'localhost') ## Use the following if VIF traffic is routed. # The script used to start/stop networking for xend. From 421b18073ab17499d4ec5eb4a34f6862739a0740 Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Tue, 15 Mar 2005 11:58:01 +0000 Subject: [PATCH 3/9] bitkeeper revision 1.1159.269.4 (4236cdc9eib4ejH25MkiyfkGp022dQ) Add channel function to close an event channel and call when devices are destroyed. Signed-off-by: Mike Wray --- tools/python/xen/xend/server/blkif.py | 2 ++ tools/python/xen/xend/server/channel.py | 26 ++++++++++++++++++++++++- tools/python/xen/xend/server/netif.py | 2 ++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py index 8a1de09bfc..e90b45f74c 100755 --- a/tools/python/xen/xend/server/blkif.py +++ b/tools/python/xen/xend/server/blkif.py @@ -181,6 +181,8 @@ class BlkifBackendInterface(controller.BackendInterface): self.close() d = defer.Deferred() d.addCallback(cb_destroy) + if self.evtchn: + channel.eventChannelClose(self.evtchn) self.send_be_disconnect(response=d) def send_be_disconnect(self, response=None): diff --git a/tools/python/xen/xend/server/channel.py b/tools/python/xen/xend/server/channel.py index 127f38f2c0..bdf7efd588 100755 --- a/tools/python/xen/xend/server/channel.py +++ b/tools/python/xen/xend/server/channel.py @@ -11,7 +11,31 @@ VIRQ_CONSOLE = 3 # (DOM0) bytes received on emergency console. VIRQ_DOM_EXC = 4 # (DOM0) Exceptional event for some domain. def eventChannel(dom1, dom2): - return xc.evtchn_bind_interdomain(dom1=dom1, dom2=dom2) + """Create an event channel between domains. + The returned dict contains dom1, dom2, port1 and port2 on success. + + @return dict (empty on error) + """ + evtchn = xc.evtchn_bind_interdomain(dom1=dom1, dom2=dom2) + if evtchn: + evtchn['dom1'] = dom1 + evtchn['dom2'] = dom2 + return evtchn + +def eventChannelClose(evtchn): + """Close an event channel that was opened by eventChannel(). + """ + def evtchn_close(dom, port): + if (dom is None) or (port is None): return + try: + xc.evtchn_close(dom=dom, port=port) + except Exception, ex: + pass + + if not evtchn: return + evtchn_close(evtchn.get('dom1'), evtchn.get('port1')) + evtchn_close(evtchn.get('dom2'), evtchn.get('port2')) + class ChannelFactory: """Factory for creating channels. diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py index d63c342435..753ae29972 100755 --- a/tools/python/xen/xend/server/netif.py +++ b/tools/python/xen/xend/server/netif.py @@ -288,6 +288,8 @@ class NetDev(controller.SplitDev): if change: self.reportStatus() log.debug("Destroying vif domain=%d vif=%d", self.controller.dom, self.vif) + if self.evtchn: + channel.eventChannelClose(self.evtchn) self.vifctl('down') d = self.send_be_disconnect() d.addCallback(cb_destroy) From afedb1e48fe477fb8ae2e13387f5a467fd912884 Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Wed, 16 Mar 2005 16:48:49 +0000 Subject: [PATCH 4/9] bitkeeper revision 1.1159.269.5 (42386371nvHctvk3SHgDUG4w3o9URw) Add support for specifying the interface name to be used by a netif backend driver instead of the default vifD.N. Signed-off-by: Mike Wray --- .../drivers/xen/netback/interface.c | 8 ++++-- tools/python/xen/lowlevel/xu/xu.c | 26 +++++++++++++++++++ tools/python/xen/xend/server/netif.py | 16 +++++++++--- tools/python/xen/xm/create.py | 10 +++++-- xen/include/public/io/domain_controller.h | 5 ++-- 5 files changed, 56 insertions(+), 9 deletions(-) diff --git a/linux-2.6.10-xen-sparse/drivers/xen/netback/interface.c b/linux-2.6.10-xen-sparse/drivers/xen/netback/interface.c index 9a3eea5932..f54dd0ad9c 100644 --- a/linux-2.6.10-xen-sparse/drivers/xen/netback/interface.c +++ b/linux-2.6.10-xen-sparse/drivers/xen/netback/interface.c @@ -119,9 +119,13 @@ void netif_create(netif_be_create_t *create) unsigned int handle = create->netif_handle; struct net_device *dev; netif_t **pnetif, *netif; - char name[IFNAMSIZ]; + char name[IFNAMSIZ] = {}; - snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle); + if(create->vifname[0] == '\0'){ + snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle); + } else { + snprintf(name, IFNAMSIZ - 1, "%s", create->vifname); + } dev = alloc_netdev(sizeof(netif_t), name, ether_setup); if ( dev == NULL ) { diff --git a/tools/python/xen/lowlevel/xu/xu.c b/tools/python/xen/lowlevel/xu/xu.c index 9a67693683..3f32cadc34 100644 --- a/tools/python/xen/lowlevel/xu/xu.c +++ b/tools/python/xen/lowlevel/xu/xu.c @@ -259,6 +259,7 @@ static PyTypeObject xu_notifier_type = { */ #define TYPE(_x,_y) (((_x)<<8)|(_y)) + #define P2C(_struct, _field, _ctype) \ do { \ PyObject *obj; \ @@ -279,6 +280,29 @@ static PyTypeObject xu_notifier_type = { } \ xum->msg.length = sizeof(_struct); \ } while ( 0 ) + +/** Set a char[] field in a struct from a Python string. + * Can't do this in P2C because of the typing. + */ +#define P2CSTRING(_struct, _field) \ + do { \ + PyObject *obj; \ + if ( (obj = PyDict_GetItemString(payload, #_field)) != NULL ) \ + { \ + if ( PyString_Check(obj) ) \ + { \ + _struct * _cobj = (_struct *)&xum->msg.msg[0]; \ + int _field_n = sizeof(_cobj->_field); \ + memset(_cobj->_field, 0, _field_n); \ + strncpy(_cobj->_field, \ + PyString_AsString(obj), \ + _field_n - 1); \ + dict_items_parsed++; \ + } \ + } \ + xum->msg.length = sizeof(_struct); \ + } while ( 0 ) + #define C2P(_struct, _field, _pytype, _ctype) \ do { \ PyObject *obj = Py ## _pytype ## _From ## _ctype \ @@ -456,6 +480,7 @@ static PyObject *xu_message_get_payload(PyObject *self, PyObject *args) C2P(netif_be_create_t, domid, Int, Long); C2P(netif_be_create_t, netif_handle, Int, Long); C2P(netif_be_create_t, status, Int, Long); + C2P(netif_be_create_t, vifname, String, String); return dict; case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY): C2P(netif_be_destroy_t, domid, Int, Long); @@ -623,6 +648,7 @@ static PyObject *xu_message_new(PyObject *self, PyObject *args) P2C(netif_be_create_t, mac[3], u8); P2C(netif_be_create_t, mac[4], u8); P2C(netif_be_create_t, mac[5], u8); + P2CSTRING(netif_be_create_t, vifname); break; case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY): P2C(netif_be_destroy_t, domid, u32); diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py index 753ae29972..5afb3df388 100755 --- a/tools/python/xen/xend/server/netif.py +++ b/tools/python/xen/xend/server/netif.py @@ -130,7 +130,13 @@ class NetDev(controller.SplitDev): self.bridge = None self.script = None self.ipaddr = [] + self.vifname = None + self.vifname = sxp.child_value(config, 'vifname') + if self.vifname is None: + self.vifname = "vif%d.%d" % (self.controller.dom, self.vif) + if len(self.vifname) > 15: + raise XendError('invalid vifname: too long: ' + self.vifname) mac = self._get_config_mac(config) if mac is None: raise XendError("invalid mac") @@ -189,7 +195,9 @@ class NetDev(controller.SplitDev): val = ['vif', ['idx', self.idx], ['vif', vif], - ['mac', mac]] + ['mac', mac], + ['vifname', self.vifname], + ] if self.bridge: val.append(['bridge', self.bridge]) if self.script: @@ -207,7 +215,7 @@ class NetDev(controller.SplitDev): def get_vifname(self): """Get the virtual interface device name. """ - return "vif%d.%d" % (self.controller.dom, self.vif) + return self.vifname def get_mac(self): """Get the MAC address as a string. @@ -267,7 +275,9 @@ class NetDev(controller.SplitDev): msg = packMsg('netif_be_create_t', { 'domid' : self.controller.dom, 'netif_handle' : self.vif, - 'mac' : self.mac }) + 'mac' : self.mac, + 'vifname' : self.vifname + }) self.getBackendInterface().writeRequest(msg, response=d) return d diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index 03f815eddb..ae023e49f5 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -151,7 +151,7 @@ gopts.var('ipaddr', val="IPADDR", fn=append_value, default=[], use="Add an IP address to the domain.") -gopts.var('vif', val="mac=MAC,bridge=BRIDGE,script=SCRIPT,backend=DOM", +gopts.var('vif', val="mac=MAC,bridge=BRIDGE,script=SCRIPT,backend=DOM,vifname=NAME", fn=append_value, default=[], use="""Add a network interface with the given MAC address and bridge. The vif is configured by calling the given configuration script. @@ -159,6 +159,8 @@ gopts.var('vif', val="mac=MAC,bridge=BRIDGE,script=SCRIPT,backend=DOM", If bridge is not specified the default bridge is used. If script is not specified the default script is used. If backend is not specified the default backend driver domain is used. + If vifname is not specified the backend virtual interface will have name vifD.N + where D is the domain id and N is the interface id. This option may be repeated to add more than one vif. Specifying vifs will increase the number of interfaces as needed.""") @@ -289,14 +291,18 @@ def configure_vifs(config_devs, vals): script = d.get('script') backend = d.get('backend') ip = d.get('ip') + vifname = d.get('vifname') else: mac = randomMAC() bridge = None script = None backend = None ip = None + vifname = None config_vif = ['vif'] config_vif.append(['mac', mac]) + if vifname: + config_vif.append(['vifname', vifname]) if bridge: config_vif.append(['bridge', bridge]) if script: @@ -383,7 +389,7 @@ def preprocess_vifs(opts, vals): (k, v) = b.strip().split('=', 1) k = k.strip() v = v.strip() - if k not in ['mac', 'bridge', 'script', 'backend', 'ip']: + if k not in ['mac', 'bridge', 'script', 'backend', 'ip', 'vifname']: opts.err('Invalid vif specifier: ' + vif) d[k] = v vifs.append(d) diff --git a/xen/include/public/io/domain_controller.h b/xen/include/public/io/domain_controller.h index 61ba2d3776..c706ab016e 100644 --- a/xen/include/public/io/domain_controller.h +++ b/xen/include/public/io/domain_controller.h @@ -477,9 +477,10 @@ typedef struct { u32 netif_handle; /* 4: Domain-specific interface handle. */ u8 mac[6]; /* 8 */ u16 __pad1; /* 14 */ + char vifname[16]; /* 16 */ /* OUT */ - u32 status; /* 16 */ -} PACKED netif_be_create_t; /* 20 bytes */ + u32 status; /* 32 */ +} PACKED netif_be_create_t; /* 36 bytes */ /* * CMSG_NETIF_BE_DESTROY: From 717339dbb2aafc7ac83ec7664019673930145528 Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Thu, 17 Mar 2005 16:28:34 +0000 Subject: [PATCH 5/9] bitkeeper revision 1.1159.269.6 (4239b032OtoMBkr4L88BtgvDYgxbLg) Add support in 'xm create' for spawning a vncviewer. Signed-off-by: Mike Wray --- tools/python/xen/xm/create.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index ae023e49f5..5d45732dff 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -5,6 +5,7 @@ import random import string import sys +import socket from xen.xend import sxp from xen.xend import PrettyPrint @@ -81,6 +82,13 @@ gopts.opt('console_autoconnect', short='c', fn=set_true, default=0, use="Connect to the console after the domain is created.") +gopts.opt('vnc', val='DISPLAY', + fn=set_int, default=None, + use="""Spawn a vncviewer listening for a vnc server in the domain. + The address of the vncviewer is passed to the domain on the kernel command + line using 'VNC_SERVER=:'. The port used by vnc is 5500 + DISPLAY. + """) + gopts.var('name', val='NAME', fn=set_value, default=None, use="Domain name. Must be unique.") @@ -415,6 +423,27 @@ def preprocess_nfs(opts, vals): opts.err('Must set nfs root and nfs server') nfs = 'nfsroot=' + vals.nfs_server + ':' + vals.nfs_root vals.extra = nfs + ' ' + vals.extra + + +def get_host_addr(): + host = socket.gethostname() + addr = socket.gethostbyname(host) + return addr + +def spawn_vnc(display): + os.system("vncviewer -listen %d &" % display) + return 5500 + display + +def preprocess_vnc(opts, vals): + """If vnc was specified, spawn a vncviewer in listen mode + and pass its address to the domain on the kernel command line. + """ + if vals.vnc is None: return + vnc_host = get_host_addr() + vnc_port = spawn_vnc(vals.vnc) + if vnc_port > 0: + vnc = 'VNC_VIEWER=%s:%d' % (vnc_host, vnc_port) + vals.extra = vnc + ' ' + vals.extra def preprocess(opts, vals): if not vals.kernel: @@ -424,6 +453,7 @@ def preprocess(opts, vals): preprocess_vifs(opts, vals) preprocess_ip(opts, vals) preprocess_nfs(opts, vals) + preprocess_vnc(opts, vals) def make_domain(opts, config): """Create, build and start a domain. From 4e8d6c72d0e111405a3b865b76c9b334fb78576f Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Thu, 17 Mar 2005 16:29:49 +0000 Subject: [PATCH 6/9] bitkeeper revision 1.1159.269.7 (4239b07dqrgbq5nyeaRv54s7lw6AsA) Add sxpr function for installing a new type. Signed-off-by: Mike Wray --- tools/libxutil/sxpr.c | 24 ++++++++++++++++++++++++ tools/libxutil/sxpr.h | 1 + 2 files changed, 25 insertions(+) diff --git a/tools/libxutil/sxpr.c b/tools/libxutil/sxpr.c index 5a9364a317..02a5040b52 100644 --- a/tools/libxutil/sxpr.c +++ b/tools/libxutil/sxpr.c @@ -82,6 +82,30 @@ static SxprType types[1024] = { /** Number of entries in the types array. */ static int type_sup = sizeof(types)/sizeof(types[0]); +/** Define a type. + * The tydef must have a non-zero type code. + * It is an error if the type code is out of range or already defined. + * + * @param tydef type definition + * @return 0 on success, error code otherwise + */ +int def_sxpr_type(SxprType *tydef){ + int err = 0; + int ty = tydef->type; + if(ty < 0 || ty >= type_sup){ + err = -EINVAL; + goto exit; + } + if(types[ty].type){ + err = -EEXIST; + goto exit; + } + types[ty] = *tydef; + exit: + return err; + +} + /** Get the type definition for a given type code. * * @param ty type code diff --git a/tools/libxutil/sxpr.h b/tools/libxutil/sxpr.h index 8b01e84736..761b8b2da7 100644 --- a/tools/libxutil/sxpr.h +++ b/tools/libxutil/sxpr.h @@ -307,6 +307,7 @@ typedef struct SxprType { } SxprType; +extern int def_sxpr_type(SxprType *tydef); extern SxprType *get_sxpr_type(int ty); /** Free the pointer in an sxpr. From 7b14405f61f000ad5d331a3dd480ee9d074762a9 Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Fri, 18 Mar 2005 10:52:26 +0000 Subject: [PATCH 7/9] bitkeeper revision 1.1159.269.8 (423ab2eapL4QIhT8q2gPBPlVaSKmZw) Script and xdm config to connect vnc in a domain back to a viewer running in domain-0. Signed-off-by: Mike Wray --- .rootkeys | 2 ++ tools/examples/vnc/Xservers | 5 ++++ tools/examples/vnc/Xvnc-xen | 53 +++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 tools/examples/vnc/Xservers create mode 100755 tools/examples/vnc/Xvnc-xen diff --git a/.rootkeys b/.rootkeys index f5baebe00f..e685054407 100644 --- a/.rootkeys +++ b/.rootkeys @@ -323,6 +323,8 @@ 40ee75a967sxgcRY4Q7zXoVUaJ4flA tools/examples/vif-bridge 41fc0c18AFAVXA1uGm1JFWHMeeznVw tools/examples/vif-nat 41e661e1ooiRKlOfwumG6wwzc0PdhQ tools/examples/vif-route +423ab2eaNCzxk3c-9yU1BwzxWvsDCQ tools/examples/vnc/Xservers +423ab2ea7ajZLdZOI-8Z-bpNdNhhAQ tools/examples/vnc/Xvnc-xen 40ee75a93cqxHp6MiYXxxwR5j2_8QQ tools/examples/xend-config.sxp 41090ec8Pj_bkgCBpg2W7WfmNkumEA tools/examples/xmexample1 40cf2937oKlROYOJTN8GWwWM5AmjBg tools/examples/xmexample2 diff --git a/tools/examples/vnc/Xservers b/tools/examples/vnc/Xservers new file mode 100644 index 0000000000..adc5748be6 --- /dev/null +++ b/tools/examples/vnc/Xservers @@ -0,0 +1,5 @@ +# Configuration lines to go in /etc/X11/xdm/Xservers to +# start Xvnc and connect back to a vncviewer in domain-0. +# See 'man xdm' under 'LOCAL SERVER SPECIFICATION' for format details. + +:1 Xvnc local /usr/X11R6/bin/Xvnc-xen :1 \ No newline at end of file diff --git a/tools/examples/vnc/Xvnc-xen b/tools/examples/vnc/Xvnc-xen new file mode 100755 index 0000000000..15058e622d --- /dev/null +++ b/tools/examples/vnc/Xvnc-xen @@ -0,0 +1,53 @@ +#!/bin/bash +#============================================================================ +# This script should be installed in /usr/X11R6/bin/Xvnc-xen. +#============================================================================ +# +# Start Xvnc and use vncconnect to connect back to a vncviewer listening in +# domain 0. The host and port to connect to are given by +# +# VNC_VIEWER=: +# +# in the kernel command line (/proc/cmdline). +# +# The '--vnc' option to 'xm create' will start a vncviewer and +# pass its address in VNC_VIEWER for this script to find. +# +# Usage: +# Xvnc-xen [args] +# +# Any arguments are passed to Xvnc. +# +#============================================================================ + +# Prefix for messages. +M="[$(basename $0)]" + +# Usage: vnc_addr +# Print : for the vncviewer given in +# the kernel command line. +vnc_addr () { + sed -n -e "s/.*VNC_VIEWER=\([^ ]*\).*/\1/p" /proc/cmdline +} + +# Usage: vnc_connect +# If a vncviewer address was given on the kernel command line, +# run vncconnect for it. +vnc_connect () { + local addr=$(vnc_addr) + + if [ -n "${addr}" ] ; then + echo "$M Connecting to ${addr}." + vncconnect ${addr} + else + echo "$M No VNC_VIEWER in kernel command line." + echo "$M Create the domain with 'xm create --vnc '." + return 1 + fi +} + +# Start the vnc server. +Xvnc "$@" >/dev/null 2>&1 & + +# Connect back to the viewer in domain-0. +vnc_connect From b9aefb2dd74e17762f3ead534f40669b91c36fb2 Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Mon, 21 Mar 2005 16:33:03 +0000 Subject: [PATCH 8/9] bitkeeper revision 1.1159.258.63 (423ef73fgHxWB39GjIH7wq4Q4o6-3Q) Change to choose a free vnc display based on netstat. Signed-off-by: Mike Wray --- tools/python/xen/xm/create.py | 44 ++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index 5d45732dff..d36c89af7b 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -82,11 +82,12 @@ gopts.opt('console_autoconnect', short='c', fn=set_true, default=0, use="Connect to the console after the domain is created.") -gopts.opt('vnc', val='DISPLAY', - fn=set_int, default=None, +gopts.var('vnc', val='no|yes', + fn=set_bool, default=None, use="""Spawn a vncviewer listening for a vnc server in the domain. The address of the vncviewer is passed to the domain on the kernel command line using 'VNC_SERVER=:'. The port used by vnc is 5500 + DISPLAY. + A display value with a free port is chosen if possible. """) gopts.var('name', val='NAME', @@ -430,18 +431,49 @@ def get_host_addr(): addr = socket.gethostbyname(host) return addr +VNC_BASE_PORT = 5500 + +def choose_vnc_display(): + """Try to choose a free vnc display. + """ + def netstat_local_ports(): + """Run netstat to get a list of the local ports in use. + """ + l = os.popen("netstat -nat").readlines() + r = [] + # Skip 2 lines of header. + for x in l[2:]: + # Local port is field 3. + y = x.split()[3] + # Field is addr:port, split off the port. + y = y.split(':')[1] + r.append(int(y)) + return r + + ports = netstat_local_ports() + for d in range(1, 100): + port = VNC_BASE_PORT + d + if port in ports: continue + return d + return None + def spawn_vnc(display): os.system("vncviewer -listen %d &" % display) - return 5500 + display + return VNC_BASE_PORT + display def preprocess_vnc(opts, vals): """If vnc was specified, spawn a vncviewer in listen mode and pass its address to the domain on the kernel command line. """ - if vals.vnc is None: return - vnc_host = get_host_addr() - vnc_port = spawn_vnc(vals.vnc) + if not vals.vnc: return + vnc_display = choose_vnc_display() + if not vnc_display: + opts.warn("No free vnc display") + return + print 'VNC=', vnc_display + vnc_port = spawn_vnc(vnc_display) if vnc_port > 0: + vnc_host = get_host_addr() vnc = 'VNC_VIEWER=%s:%d' % (vnc_host, vnc_port) vals.extra = vnc + ' ' + vals.extra From 3aca223127966196f412ddeba3736c2f2beeecf1 Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Thu, 24 Mar 2005 21:24:38 +0000 Subject: [PATCH 9/9] bitkeeper revision 1.1159.258.64 (42433016pzi5kr8wggkPTZcHlxXCpg) Back out changes to netif backend messaging to set vifname. Try using 'ip link' instead. Signed-off-by: Mike Wray --- .../drivers/xen/netback/interface.c | 6 +----- tools/python/xen/lowlevel/xu/xu.c | 2 -- tools/python/xen/xend/Vifctl.py | 13 +++++++++++++ tools/python/xen/xend/server/netif.py | 9 +++++++-- xen/include/public/io/domain_controller.h | 5 ++--- 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/linux-2.6.11-xen-sparse/drivers/xen/netback/interface.c b/linux-2.6.11-xen-sparse/drivers/xen/netback/interface.c index f54dd0ad9c..1d1a5923c4 100644 --- a/linux-2.6.11-xen-sparse/drivers/xen/netback/interface.c +++ b/linux-2.6.11-xen-sparse/drivers/xen/netback/interface.c @@ -121,11 +121,7 @@ void netif_create(netif_be_create_t *create) netif_t **pnetif, *netif; char name[IFNAMSIZ] = {}; - if(create->vifname[0] == '\0'){ - snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle); - } else { - snprintf(name, IFNAMSIZ - 1, "%s", create->vifname); - } + snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle); dev = alloc_netdev(sizeof(netif_t), name, ether_setup); if ( dev == NULL ) { diff --git a/tools/python/xen/lowlevel/xu/xu.c b/tools/python/xen/lowlevel/xu/xu.c index 3f32cadc34..2c3ee6b33f 100644 --- a/tools/python/xen/lowlevel/xu/xu.c +++ b/tools/python/xen/lowlevel/xu/xu.c @@ -480,7 +480,6 @@ static PyObject *xu_message_get_payload(PyObject *self, PyObject *args) C2P(netif_be_create_t, domid, Int, Long); C2P(netif_be_create_t, netif_handle, Int, Long); C2P(netif_be_create_t, status, Int, Long); - C2P(netif_be_create_t, vifname, String, String); return dict; case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY): C2P(netif_be_destroy_t, domid, Int, Long); @@ -648,7 +647,6 @@ static PyObject *xu_message_new(PyObject *self, PyObject *args) P2C(netif_be_create_t, mac[3], u8); P2C(netif_be_create_t, mac[4], u8); P2C(netif_be_create_t, mac[5], u8); - P2CSTRING(netif_be_create_t, vifname); break; case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY): P2C(netif_be_destroy_t, domid, u32); diff --git a/tools/python/xen/xend/Vifctl.py b/tools/python/xen/xend/Vifctl.py index 86f68db0b4..bfc750315a 100644 --- a/tools/python/xen/xend/Vifctl.py +++ b/tools/python/xen/xend/Vifctl.py @@ -37,6 +37,19 @@ def network(op, script=None, bridge=None, antispoof=None): args = ' '.join(args) os.system(script + ' ' + args) +def set_vif_name(vif_old, vif_new): + if vif_old == vif_new: + vif = view_new + if os.system("ip link show %s" % vif_old) == 0: + os.system("ip link set %s down" % vif_old) + os.system("ip link set %s name %s" % (vif_old, vif_new)) + os.system("ip link set %s up" % vif_new) + if os.system("ip link show %s" % vif_new) == 0: + vif = vif_new + else: + vif = vif_old + return vif + def vifctl(op, vif=None, script=None, domain=None, mac=None, bridge=None, ipaddr=[]): """Call a vif control script. Xend calls this when bringing vifs up or down. diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py index 5afb3df388..5d3ef5a18d 100755 --- a/tools/python/xen/xend/server/netif.py +++ b/tools/python/xen/xend/server/netif.py @@ -134,7 +134,7 @@ class NetDev(controller.SplitDev): self.vifname = sxp.child_value(config, 'vifname') if self.vifname is None: - self.vifname = "vif%d.%d" % (self.controller.dom, self.vif) + self.vifname = self.default_vifname() if len(self.vifname) > 15: raise XendError('invalid vifname: too long: ' + self.vifname) mac = self._get_config_mac(config) @@ -217,6 +217,9 @@ class NetDev(controller.SplitDev): """ return self.vifname + def default_vifname(self): + return "vif%d.%d" % (self.controller.dom, self.vif) + def get_mac(self): """Get the MAC address as a string. """ @@ -248,6 +251,8 @@ class NetDev(controller.SplitDev): @param op: operation name (up, down) @param vmname: vmname """ + if op == 'up': + Vifctl.set_vif_name(self.default_vifname(), self.vifname) Vifctl.vifctl(op, **self.vifctl_params(vmname=vmname)) vnet = XendVnet.instance().vnet_of_bridge(self.bridge) if vnet: @@ -276,7 +281,7 @@ class NetDev(controller.SplitDev): { 'domid' : self.controller.dom, 'netif_handle' : self.vif, 'mac' : self.mac, - 'vifname' : self.vifname + #'vifname' : self.vifname }) self.getBackendInterface().writeRequest(msg, response=d) return d diff --git a/xen/include/public/io/domain_controller.h b/xen/include/public/io/domain_controller.h index b42510d688..c3494e34ca 100644 --- a/xen/include/public/io/domain_controller.h +++ b/xen/include/public/io/domain_controller.h @@ -466,10 +466,9 @@ typedef struct { u32 netif_handle; /* 4: Domain-specific interface handle. */ u8 mac[6]; /* 8 */ u16 __pad1; /* 14 */ - char vifname[16]; /* 16 */ /* OUT */ - u32 status; /* 32 */ -} PACKED netif_be_create_t; /* 36 bytes */ + u32 status; /* 16 */ +} PACKED netif_be_create_t; /* 20 bytes */ /* * CMSG_NETIF_BE_DESTROY: