diff --git a/.rootkeys b/.rootkeys index e05072a017..ad520bef1b 100644 --- a/.rootkeys +++ b/.rootkeys @@ -465,6 +465,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 41dde8af6M2Pm1Rrv_f5jEFC_BIOIA tools/examples/xmexample.vmx 41090ec8Pj_bkgCBpg2W7WfmNkumEA tools/examples/xmexample1 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 6e084c4660..f509a1b8dd 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 @@ -119,7 +119,7 @@ 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); dev = alloc_netdev(sizeof(netif_t), name, ether_setup); 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 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. diff --git a/tools/python/xen/lowlevel/xu/xu.c b/tools/python/xen/lowlevel/xu/xu.c index 6b435032a1..22dd2bcd19 100644 --- a/tools/python/xen/lowlevel/xu/xu.c +++ b/tools/python/xen/lowlevel/xu/xu.c @@ -477,6 +477,7 @@ static PyTypeObject xu_notifier_type = { */ #define TYPE(_x,_y) (((_x)<<8)|(_y)) + #define P2C(_struct, _field, _ctype) \ do { \ PyObject *obj; \ @@ -497,6 +498,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 \ 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/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 2469a62894..b99ccb8dfc 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'], diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py index 00cd9216d5..1a7438c5c1 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 6dfebe37be..4957a91b94 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 2518a155ba..0a3bdacdbd 100755 --- a/tools/python/xen/xend/server/netif.py +++ b/tools/python/xen/xend/server/netif.py @@ -138,7 +138,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 = self.default_vifname() + 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") @@ -201,7 +207,10 @@ class NetDev(controller.SplitDev): val = ['vif', ['idx', self.idx], ['vif', vif], - ['mac', mac]] + ['mac', mac], + ['vifname', self.vifname], + ] + if self.be_mac: val.append(['be_mac', self.get_be_mac()]) if self.bridge: @@ -221,8 +230,11 @@ 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 default_vifname(self): + return "vif%d.%d" % (self.controller.dom, self.vif) + def get_mac(self): """Get the MAC address as a string. """ @@ -259,6 +271,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: @@ -287,7 +301,9 @@ class NetDev(controller.SplitDev): { 'domid' : self.controller.dom, 'netif_handle' : self.vif, 'be_mac' : self.be_mac or [0, 0, 0, 0, 0, 0], - 'mac' : self.mac }) + 'mac' : self.mac, + #'vifname' : self.vifname + }) self.getBackendInterface().writeRequest(msg, response=d) return d @@ -308,6 +324,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) diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index e79e02383c..bd8f81ae3e 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,14 @@ gopts.opt('console_autoconnect', short='c', fn=set_true, default=0, use="Connect to the console after the domain is created.") +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', fn=set_value, default=None, use="Domain name. Must be unique.") @@ -160,7 +169,7 @@ gopts.var('ipaddr', val="IPADDR", fn=append_value, default=[], use="Add an IP address to the domain.") -gopts.var('vif', val="mac=MAC,be_mac=MAC,bridge=BRIDGE,script=SCRIPT,backend=DOM", +gopts.var('vif', val="mac=MAC,be_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. @@ -170,6 +179,8 @@ gopts.var('vif', val="mac=MAC,be_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.""") @@ -321,6 +332,7 @@ 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() be_mac = None @@ -328,8 +340,11 @@ def configure_vifs(config_devs, vals): script = None backend = None ip = None + vifname = None config_vif = ['vif'] config_vif.append(['mac', mac]) + if vifname: + config_vif.append(['vifname', vifname]) if be_mac: config_vif.append(['be_mac', be_mac]) if bridge: @@ -429,7 +444,7 @@ def preprocess_vifs(opts, vals): (k, v) = b.strip().split('=', 1) k = k.strip() v = v.strip() - if k not in ['mac', 'be_mac', 'bridge', 'script', 'backend', 'ip']: + if k not in ['mac', 'be_mac', 'bridge', 'script', 'backend', 'ip', 'vifname']: opts.err('Invalid vif specifier: ' + vif) d[k] = v vifs.append(d) @@ -455,6 +470,58 @@ 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 + +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 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 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 def preprocess(opts, vals): if not vals.kernel: @@ -464,6 +531,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.