diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 3f5f7e4247..e835ea9063 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -660,9 +660,8 @@ class XendDomain: @param type: device type """ dominfo = self.domain_lookup(id) - val = dominfo.device_delete(type, devid) - dominfo.exportToDB() - return val + return dominfo.destroyDevice(type, devid) + def domain_devtype_ls(self, id, type): """Get list of device sxprs for a domain. diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 30f88790cd..6979e35f31 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -1,4 +1,4 @@ -#============================================================================ +#=========================================================================== # This library is free software; you can redistribute it and/or # modify it under the terms of version 2.1 of the GNU Lesser General Public # License as published by the Free Software Foundation. @@ -23,23 +23,18 @@ Author: Mike Wray """ -import string, re -import os +import string import time import threading import errno import xen.lowlevel.xc; xc = xen.lowlevel.xc.new() -from xen.util.ip import check_subnet, get_current_ipgw from xen.util.blkif import blkdev_uname_to_file -from xen.xend.server import controller from xen.xend.server import SrvDaemon; xend = SrvDaemon.instance() from xen.xend.server.channel import EventChannel -from xen.util.blkif import blkdev_name_to_number, expand_dev_name from xen.xend import sxp -from xen.xend import Blkctl from xen.xend.PrettyPrint import prettyprintstring from xen.xend.XendBootloader import bootloader from xen.xend.XendLogging import log @@ -47,7 +42,7 @@ from xen.xend.XendError import XendError, VmError from xen.xend.XendRoot import get_component from xen.xend.uuid import getUuid -from xen.xend.xenstore import DBVar, XenNode, DBMap +from xen.xend.xenstore import DBVar from xen.xend.xenstore.xstransact import xstransact from xen.xend.xenstore.xsutil import IntroduceDomain @@ -248,11 +243,9 @@ class XendDomainInfo: self.store_mfn = None self.console_channel = None self.console_mfn = None - self.controllers = {} self.info = None self.backend_flags = 0 - self.netif_idx = 0 #todo: state: running, suspended self.state = STATE_VM_OK @@ -334,6 +327,12 @@ class XendDomainInfo: def getName(self): return self.name + def getPath(self): + return self.path + + def getUuid(self): + return self.uuid + def getVCpuCount(self): return self.vcpus @@ -408,150 +407,26 @@ class XendDomainInfo: __repr__ = __str__ - def getDeviceController(self, type, error=True): - ctrl = self.controllers.get(type) - if not ctrl and error: - raise XendError("invalid device type:" + type) - return ctrl - - def findDeviceController(self, type): - return (self.getDeviceController(type, error=False) - or self.createDeviceController(type)) - def createDeviceController(self, type): - ctrl = controller.createDevController(type, self, recreate=self.recreate) - self.controllers[type] = ctrl - return ctrl + def getDeviceController(self, name): + if name not in controllerClasses: + raise XendError("unknown device type: " + str(name)) - def createDevice(self, type, devconfig, change=False): - if self.recreate: - return - if type == 'vbd': - typedev = sxp.child_value(devconfig, 'dev') - if re.match('^ioemu:', typedev): - return; + return controllerClasses[name](self) - backdom = domain_exists(sxp.child_value(devconfig, 'backend', '0')) - devnum = blkdev_name_to_number(sxp.child_value(devconfig, 'dev')) + def createDevice(self, deviceClass, devconfig): + return self.getDeviceController(deviceClass).createDevice(devconfig) - backpath = "%s/backend/%s/%s/%d" % (backdom.path, type, - self.uuid, devnum) - frontpath = "%s/device/%s/%d" % (self.path, type, devnum) - front = { 'backend' : backpath, - 'backend-id' : "%i" % backdom.domid, - 'virtual-device' : "%i" % devnum } - xstransact.Write(frontpath, front) + def configureDevice(self, deviceClass, devid, devconfig): + return self.getDeviceController(deviceClass).configureDevice( + devid, devconfig) - (type, params) = string.split(sxp.child_value(devconfig, - 'uname'), ':', 1) - readonly = sxp.child_value(devconfig, 'mode', 'r') - back = { 'type' : type, - 'params' : params, - 'frontend' : frontpath, - 'frontend-id' : "%i" % self.domid } - if readonly == 'r': - back['read-only'] = "" # existence indicates read-only - xstransact.Write(backpath, back) - return + def destroyDevice(self, deviceClass, devid): + return self.getDeviceController(deviceClass).destroyDevice(devid) - if type == 'vif': - from xen.xend import XendRoot - xroot = XendRoot.instance() - - def _get_config_ipaddr(config): - val = [] - for ipaddr in sxp.children(config, elt='ip'): - val.append(sxp.child0(ipaddr)) - return val - - backdom = domain_exists(sxp.child_value(devconfig, 'backend', '0')) - - devnum = self.netif_idx - self.netif_idx += 1 - - script = sxp.child_value(devconfig, 'script', - xroot.get_vif_script()) - script = os.path.join(xroot.network_script_dir, script) - bridge = sxp.child_value(devconfig, 'bridge', - xroot.get_vif_bridge()) - mac = sxp.child_value(devconfig, 'mac') - ipaddr = _get_config_ipaddr(devconfig) - - backpath = "%s/backend/%s/%s/%d" % (backdom.path, type, - self.uuid, devnum) - frontpath = "%s/device/%s/%d" % (self.path, type, devnum) - - front = { 'backend' : backpath, - 'backend-id' : "%i" % backdom.domid, - 'handle' : "%i" % devnum, - 'mac' : mac } - xstransact.Write(frontpath, front) - - back = { 'script' : script, - 'domain' : self.name, - 'mac' : mac, - 'bridge' : bridge, - 'frontend' : frontpath, - 'frontend-id' : "%i" % self.domid, - 'handle' : "%i" % devnum } - if ipaddr: - back['ip'] = ' '.join(ipaddr) - xstransact.Write(backpath, back) - - return - - if type == 'vtpm': - backdom = domain_exists(sxp.child_value(devconfig, 'backend', '0')) - - devnum = int(sxp.child_value(devconfig, 'instance', '0')) - log.error("The domain has a TPM with instance %d." % devnum) - - backpath = "%s/backend/%s/%s/%d" % (backdom.path, type, - self.uuid, devnum) - frontpath = "%s/device/%s/%d" % (self.path, type, devnum) - - front = { 'backend' : backpath, - 'backend-id' : "%i" % backdom.domid, - 'handle' : "%i" % devnum } - xstransact.Write(frontpath, front) - - back = { 'instance' : "%i" % devnum, - 'frontend' : frontpath, - 'frontend-id' : "%i" % self.domid } - xstransact.Write(backpath, back) - - return - - ctrl = self.findDeviceController(type) - return ctrl.createDevice(devconfig, recreate=self.recreate, - change=change) - - def configureDevice(self, type, id, devconfig): - ctrl = self.getDeviceController(type) - return ctrl.configureDevice(id, devconfig) - - def destroyDevice(self, type, id, change=False, reboot=False): - ctrl = self.getDeviceController(type) - return ctrl.destroyDevice(id, change=change, reboot=reboot) - - def deleteDevice(self, type, id): - ctrl = self.getDeviceController(type) - return ctrl.deleteDevice(id) - - def getDevice(self, type, id, error=True): - ctrl = self.getDeviceController(type) - return ctrl.getDevice(id, error=error) - - def getDeviceIds(self, type): - ctrl = self.getDeviceController(type) - return ctrl.getDeviceIds() - - def getDeviceSxprs(self, type): - ctrl = self.getDeviceController(type) - return ctrl.getDeviceSxprs() def sxpr(self): sxpr = ['domain', @@ -607,25 +482,10 @@ class XendDomainInfo: sxpr.append(['restart_state', self.restart_state]) if self.restart_time: sxpr.append(['restart_time', str(self.restart_time)]) - - devs = self.sxpr_devices() - if devs: - sxpr.append(devs) if self.config: sxpr.append(['config', self.config]) return sxpr - def sxpr_devices(self): - sxpr = [] - for ty in self.controllers.keys(): - devs = self.getDeviceSxprs(ty) - sxpr += devs - if sxpr: - sxpr.insert(0, 'devices') - else: - sxpr = None - return sxpr - def check_name(self, name): """Check if a vm name is valid. Valid names contain alphabetic characters, digits, or characters in '_-.:/+'. @@ -798,19 +658,21 @@ class XendDomainInfo: def release_devices(self): """Release all vm devices. """ - reboot = self.restart_pending() - for ctrl in self.controllers.values(): - if ctrl.isDestroyed(): continue - ctrl.destroyController(reboot=reboot) + t = xstransact("%s/device" % self.path) - for d in t.list("vbd"): - t.remove(d) - for d in t.list("vif"): - t.remove(d) - for d in t.list("vtpm"): - t.remove(d) + for n in controllerClasses.keys(): + for d in t.list(n): + try: + t.remove(d) + except ex: + # Log and swallow any exceptions in removal -- there's + # nothing more we can do. + log.exception( + "Device release failed: %s; %s; %s; %s" % + (self.info['name'], n, d, str(ex))) t.commit() + def show(self): """Print virtual machine info. """ @@ -866,9 +728,6 @@ class XendDomainInfo: raise VmError('invalid device') dev_type = sxp.name(dev_config) - if not controller.isDevControllerClass(dev_type): - raise VmError('unknown device type: ' + dev_type) - self.createDevice(dev_type, dev_config) @@ -877,10 +736,7 @@ class XendDomainInfo: @raise: VmError for invalid devices """ - if self.rebooting(): - for ctrl in self.controllers.values(): - ctrl.initController(reboot=True) - else: + if not self.rebooting(): self.create_configured_devices() self.image.createDeviceModel() @@ -890,47 +746,19 @@ class XendDomainInfo: @param dev_config: device configuration """ dev_type = sxp.name(dev_config) - dev = self.createDevice(dev_type, dev_config, change=True) - self.config.append(['device', dev.getConfig()]) - return dev.sxpr() + devid = self.createDevice(dev_type, dev_config) +# self.config.append(['device', dev.getConfig()]) + return self.getDeviceController(dev_type).sxpr(devid) - def device_configure(self, dev_config, id): + + def device_configure(self, dev_config, devid): """Configure an existing device. - @param dev_config: device configuration - @param id: device id + @param devid: device id """ - type = sxp.name(dev_config) - dev = self.getDevice(type, id) - old_config = dev.getConfig() - new_config = dev.configure(dev_config, change=True) - # Patch new config into vm config. - new_full_config = ['device', new_config] - old_full_config = ['device', old_config] - old_index = self.config.index(old_full_config) - self.config[old_index] = new_full_config - return new_config + deviceClass = sxp.name(dev_config) + self.configureDevice(deviceClass, devid, dev_config) - def device_refresh(self, type, id): - """Refresh a device. - - @param type: device type - @param id: device id - """ - dev = self.getDevice(type, id) - dev.refresh() - - def device_delete(self, type, id): - """Destroy and remove a device. - - @param type: device type - @param id: device id - """ - dev = self.getDevice(type, id) - dev_config = dev.getConfig() - if dev_config: - self.config.remove(['device', dev_config]) - self.deleteDevice(type, dev.getId()) def configure_restart(self): """Configure the vm restart mode. @@ -1060,11 +888,6 @@ class XendDomainInfo: """ return - blkif = self.getDeviceController("vbd", error=False) - if not blkif: - blkif = self.createDeviceController("vbd") - backend = blkif.getBackend(0) - backend.connect(recreate=self.recreate) def configure_fields(self): """Process the vm configuration fields using the registered handlers. @@ -1213,9 +1036,21 @@ config_handlers = { #============================================================================ # Register device controllers and their device config types. +"""A map from device-class names to the subclass of DevController that +implements the device control specific to that device-class.""" +controllerClasses = {} + + +def addControllerClass(device_class, cls): + """Register a subclass of DevController to handle the named device-class. + """ + cls.deviceClass = device_class + controllerClasses[device_class] = cls + + from xen.xend.server import blkif, netif, tpmif, pciif, usbif -controller.addDevControllerClass("vbd", blkif.BlkifController) -controller.addDevControllerClass("vif", netif.NetifController) -controller.addDevControllerClass("vtpm", tpmif.TPMifController) -controller.addDevControllerClass("pci", pciif.PciController) -controller.addDevControllerClass("usb", usbif.UsbifController) +addControllerClass('vbd', blkif.BlkifController) +addControllerClass('vif', netif.NetifController) +addControllerClass('vtpm', tpmif.TPMifController) +addControllerClass('pci', pciif.PciController) +addControllerClass('usb', usbif.UsbifController) diff --git a/tools/python/xen/xend/server/DevController.py b/tools/python/xen/xend/server/DevController.py new file mode 100644 index 0000000000..f315f0470b --- /dev/null +++ b/tools/python/xen/xend/server/DevController.py @@ -0,0 +1,175 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (C) 2004, 2005 Mike Wray +# Copyright (C) 2005 XenSource Ltd +#============================================================================ + + +from xen.xend import sxp +from xen.xend.XendError import VmError +from xen.xend.XendLogging import log +from xen.xend.xenstore.xstransact import xstransact + + +class DevController: + """Abstract base class for a device controller. Device controllers create + appropriate entries in the store to trigger the creation, reconfiguration, + and destruction of devices in guest domains. Each subclass of + DevController is responsible for a particular device-class, and + understands the details of configuration specific to that device-class. + + DevController itself provides the functionality common to all device + creation tasks, as well as providing an interface to XendDomainInfo for + triggering those events themselves. + """ + + # Set when registered. + deviceClass = None + + + ## public: + + def __init__(self, vm): + self.vm = vm + + + def createDevice(self, config): + """Trigger the creation of a device with the given configuration. + + @return The ID for the newly created device. + """ + (devid, back, front) = self.getDeviceDetails(config) + + self.writeDetails(config, devid, back, front) + + return devid + + + def reconfigureDevice(self, devid, config): + """Reconfigure the specified device. + + The implementation here just raises VmError. This may be overridden + by those subclasses that can reconfigure their devices. + """ + raise VmError('%s devices may not be reconfigured' % self.deviceClass) + + + def destroyDevice(self, devid): + """Destroy the specified device. + + The implementation here simply deletes the appropriate paths from + the store. This may be overridden by subclasses who need to perform + other tasks on destruction. + """ + + frontpath = self.frontendPath(devid) + backpath = xstransact.Read("%s/backend" % frontpath) + + xstransact.Remove(frontpath) + xstransact.Remove(backpath) + + + def sxpr(self, devid): + """@return an s-expression describing the specified device. + """ + return [self.deviceClass, ['dom', self.vm.getDomain(), + 'id', devid]] + + + ## protected: + + def getDeviceDetails(self, config): + """Compute the details for creation of a device corresponding to the + given configuration. These details consist of a tuple of (devID, + backDetails, frontDetails), where devID is the ID for the new device, + and backDetails and frontDetails are the device configuration + specifics for the backend and frontend respectively. + + backDetails and frontDetails should be dictionaries, the keys and + values of which will be used as paths in the store. There is no need + for these dictionaries to include the references from frontend to + backend, nor vice versa, as these will be handled by DevController. + + Abstract; must be implemented by every subclass. + + @return (devID, backDetails, frontDetails), as specified above. + """ + + raise NotImplementedError() + + + def getDomain(self): + """Stub to {@link XendDomainInfo.getDomain}, for use by our + subclasses. + """ + return self.vm.getDomain() + + + ## private: + + def writeDetails(self, config, devid, backDetails, frontDetails): + """Write the details in the store to trigger creation of a device. + The backend domain ID is taken from the given config, paths for + frontend and backend are computed, and these are written to the store + appropriately, including references from frontend to backend and vice + versa. + + @param config The configuration of the device, as given to + {@link #createDevice}. + @param devid As returned by {@link #getDeviceDetails}. + @param backDetails As returned by {@link #getDeviceDetails}. + @param frontDetails As returned by {@link #getDeviceDetails}. + """ + + import xen.xend.XendDomain + backdom = xen.xend.XendDomain.instance().domain_lookup_by_name( + sxp.child_value(config, 'backend', '0')) + + frontpath = self.frontendPath(devid) + backpath = self.backendPath(backdom, devid) + + frontDetails.update({ + 'backend' : backpath, + 'backend-id' : "%i" % backdom.getDomain() + }) + + + backDetails.update({ + 'domain' : self.vm.getName(), + 'frontend' : frontpath, + 'frontend-id' : "%i" % self.vm.getDomain() + }) + + log.debug('DevController: writing %s to %s.', str(frontDetails), + frontpath) + log.debug('DevController: writing %s to %s.', str(backDetails), + backpath) + + xstransact.Write(frontpath, frontDetails) + xstransact.Write(backpath, backDetails) + + + def backendPath(self, backdom, devid): + """@param backdom [XendDomainInfo] The backend domain info.""" + + return "%s/backend/%s/%s/%d" % (backdom.getPath(), + self.deviceClass, + self.vm.getUuid(), devid) + + + def frontendPath(self, devid): + return "%s/device/%s/%d" % (self.vm.getPath(), + self.deviceClass, + devid) diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py index d142c9afb4..cb93e64005 100755 --- a/tools/python/xen/xend/server/blkif.py +++ b/tools/python/xen/xend/server/blkif.py @@ -13,322 +13,47 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #============================================================================ # Copyright (C) 2004, 2005 Mike Wray +# Copyright (C) 2005 XenSource Ltd #============================================================================ -"""Support for virtual block devices. -""" + +import re import string from xen.util import blkif -from xen.xend.XendError import XendError, VmError -from xen.xend.XendRoot import get_component -from xen.xend.XendLogging import log from xen.xend import sxp -from xen.xend import Blkctl -from xen.xend.xenstore import DBVar -from xen.xend.server.controller import Dev, DevController +from xen.xend.server.DevController import DevController -class BlkifBackend: - """ Handler for the 'back-end' channel to a block device driver domain - on behalf of a front-end domain. - Must be connected using connect() before it can be used. - """ - def __init__(self, controller, id, dom, recreate=False): - self.controller = controller - self.id = id - self.frontendDomain = self.controller.getDomain() - self.backendDomain = dom - self.destroyed = False - self.connected = False - self.status = None - - def init(self, recreate=False, reboot=False): - self.destroyed = False - self.status = BLKIF_INTERFACE_STATUS_DISCONNECTED - self.frontendDomain = self.controller.getDomain() - - def __str__(self): - return ('' - % (self.frontendDomain, - self.backendDomain, - self.id)) - - def getId(self): - return self.id - - def connect(self, recreate=False): - """Connect to the blkif control interface. - - @param recreate: true if after xend restart - """ - log.debug("Connecting blkif %s", str(self)) - if recreate or self.connected: - self.connected = True - pass - - def destroy(self, change=False, reboot=False): - """Disconnect from the blkif control interface and destroy it. - """ - self.destroyed = True - # For change true need to notify front-end, or back-end will do it? - - def connectInterface(self, val): - self.status = BLKIF_INTERFACE_STATUS_CONNECTED - - def interfaceDisconnected(self): - self.status = BLKIF_INTERFACE_STATUS_DISCONNECTED - -class BlkDev(Dev): - """Info record for a block device. - """ - - __exports__ = Dev.__exports__ + [ - DBVar('dev', ty='str'), - DBVar('vdev', ty='int'), - DBVar('mode', ty='str'), - DBVar('viftype', ty='str'), - DBVar('params', ty='str'), - DBVar('node', ty='str'), - DBVar('device', ty='long'), - DBVar('dev_handle', ty='long'), - DBVar('start_sector', ty='long'), - DBVar('nr_sectors', ty='long'), - ] - - def __init__(self, controller, id, config, recreate=False): - Dev.__init__(self, controller, id, config, recreate=recreate) - self.dev = None - self.uname = None - self.vdev = None - self.mode = None - self.type = None - self.params = None - self.node = None - self.device = None - self.dev_handle = 0 - self.start_sector = None - self.nr_sectors = None - - self.frontendDomain = self.getDomain() - self.backendDomain = None - self.backendId = 0 - self.configure(self.config, recreate=recreate) - - def exportToDB(self, save=False): - Dev.exportToDB(self, save=save) - backend = self.getBackend() - - def init(self, recreate=False, reboot=False): - self.frontendDomain = self.getDomain() - backend = self.getBackend() - self.backendId = backend.domid - - def configure(self, config, change=False, recreate=False): - if change: - raise XendError("cannot reconfigure vbd") - self.config = config - self.uname = sxp.child_value(config, 'uname') - if not self.uname: - raise VmError('vbd: Missing uname') - # Split into type and type-specific params (which are passed to the - # type-specific control script). - (self.type, self.params) = string.split(self.uname, ':', 1) - self.dev = sxp.child_value(config, 'dev') - if not self.dev: - raise VmError('vbd: Missing dev') - self.mode = sxp.child_value(config, 'mode', 'r') - - self.vdev = blkif.blkdev_name_to_number(self.dev) - if not self.vdev: - raise VmError('vbd: Device not found: %s' % self.dev) - - try: - xd = get_component('xen.xend.XendDomain') - self.backendDomain = xd.domain_lookup_by_name(sxp.child_value(config, 'backend', '0')).domid - except: - raise XendError('invalid backend domain') - - return self.config - - def attach(self, recreate=False, change=False): - if recreate: - pass - else: - node = Blkctl.block('bind', self.type, self.params) - self.setNode(node) - self.attachBackend() - if change: - self.interfaceChanged() - - def unbind(self): - if self.node is None: return - log.debug("Unbinding vbd (type %s) from %s" - % (self.type, self.node)) - Blkctl.block('unbind', self.type, self.node) - - def setNode(self, node): - - # NOTE: - # This clause is testing code for storage system experiments. - # Add a new disk type that will just pass an opaque id in the - # dev_handle and use an experimental device type. - # Please contact andrew.warfield@cl.cam.ac.uk with any concerns. - if self.type == 'parallax': - self.node = node - self.device = 61440 # (240,0) - self.dev_handle = long(self.params) - self.nr_sectors = long(0) - return - # done. - - mounted_mode = self.check_mounted(node) - if not '!' in self.mode and mounted_mode: - if mounted_mode == "w": - raise VmError("vbd: Segment %s is in writable use" % - self.uname) - elif 'w' in self.mode: - raise VmError("vbd: Segment %s is in read-only use" % - self.uname) - - segment = blkif.blkdev_segment(node) - if not segment: - raise VmError("vbd: Segment not found: uname=%s" % self.uname) - self.node = node - self.device = segment['device'] - self.start_sector = segment['start_sector'] - self.nr_sectors = segment['nr_sectors'] - - def check_mounted(self, name): - mode = blkif.mount_mode(name) - xd = get_component('xen.xend.XendDomain') - for vm in xd.list(): - ctrl = vm.getDeviceController(self.getType(), error=False) - if (not ctrl): continue - for dev in ctrl.getDevices(): - if dev is self: continue - if dev.type == 'phy' and name == blkif.expand_dev_name(dev.params): - mode = dev.mode - if 'w' in mode: - return 'w' - if mode and 'r' in mode: - return 'r' - return None - - def readonly(self): - return 'w' not in self.mode - - def sxpr(self): - val = ['vbd', - ['id', self.id], - ['vdev', self.vdev], - ['device', self.device], - ['mode', self.mode]] - if self.dev: - val.append(['dev', self.dev]) - if self.uname: - val.append(['uname', self.uname]) - if self.node: - val.append(['node', self.node]) - return val - - def getBackend(self): - return self.controller.getBackend(self.backendDomain) - - def refresh(self): - log.debug("Refreshing vbd domain=%d id=%s", self.frontendDomain, - self.id) - self.interfaceChanged() - - def destroy(self, change=False, reboot=False): - """Destroy the device. If 'change' is true notify the front-end interface. - - @param change: change flag - """ - self.destroyed = True - log.debug("Destroying vbd domain=%d id=%s", self.frontendDomain, - self.id) - if change: - self.interfaceChanged() - self.unbind() - - def interfaceChanged(self): - """Tell the back-end to notify the front-end that a device has been - added or removed. - """ - self.getBackend().interfaceChanged() - - def attachBackend(self): - """Attach the device to its controller. - - """ - self.getBackend().connect() - class BlkifController(DevController): """Block device interface controller. Handles all block devices for a domain. """ - def __init__(self, vm, recreate=False): + def __init__(self, vm): """Create a block device controller. """ - DevController.__init__(self, vm, recreate=recreate) - self.backends = {} - self.backendId = 0 + DevController.__init__(self, vm) - def initController(self, recreate=False, reboot=False): - self.destroyed = False - if reboot: - self.rebootBackends() - self.rebootDevices() - def sxpr(self): - val = ['blkif', ['dom', self.getDomain()]] - return val - - def rebootBackends(self): - for backend in self.backends.values(): - backend.init(reboot=True) - - def getBackendById(self, id): - return self.backends.get(id) - - def getBackendByDomain(self, dom): - for backend in self.backends.values(): - if backend.backendDomain == dom: - return backend - return None - - def getBackend(self, dom): - backend = self.getBackendByDomain(dom) - if backend: return backend - backend = BlkifBackend(self, self.backendId, dom) - self.backendId += 1 - self.backends[backend.getId()] = backend - backend.init() - return backend - - def newDevice(self, id, config, recreate=False): - """Create a device.. - - @param id: device id - @param config: device configuration - @param recreate: if true it's being recreated (after xend restart) - @type recreate: bool - @return: device - @rtype: BlkDev - """ - return BlkDev(self, id, config, recreate=recreate) + def getDeviceDetails(self, config): + """@see DevController.getDeviceDetails""" - def destroyController(self, reboot=False): - """Destroy the controller and all devices. - """ - self.destroyed = True - log.debug("Destroying blkif domain=%d", self.getDomain()) - self.destroyDevices(reboot=reboot) - self.destroyBackends(reboot=reboot) + typedev = sxp.child_value(config, 'dev') + if re.match('^ioemu:', typedev): + return - def destroyBackends(self, reboot=False): - for backend in self.backends.values(): - backend.destroy(reboot=reboot) + devid = blkif.blkdev_name_to_number(sxp.child_value(config, 'dev')) + + (typ, params) = string.split(sxp.child_value(config, 'uname'), ':', 1) + back = { 'type' : typ, + 'params' : params + } + + if 'r' == sxp.child_value(config, 'mode', 'r'): + back['read-only'] = "" # existence indicates read-only + + front = { 'virtual-device' : "%i" % devid } + + return (devid, back, front) diff --git a/tools/python/xen/xend/server/controller.py b/tools/python/xen/xend/server/controller.py deleted file mode 100755 index 5a4f67cd5a..0000000000 --- a/tools/python/xen/xend/server/controller.py +++ /dev/null @@ -1,423 +0,0 @@ -#============================================================================ -# This library is free software; you can redistribute it and/or -# modify it under the terms of version 2.1 of the GNU Lesser General Public -# License as published by the Free Software Foundation. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -#============================================================================ -# Copyright (C) 2004, 2005 Mike Wray -#============================================================================ - -"""General support for controllers, which handle devices -for a domain. -""" - -from xen.xend.XendError import XendError -from xen.xend.xenstore import DBVar - -DEBUG = 0 - -class DevControllerTable: - """Table of device controller classes, indexed by type name. - """ - - def __init__(self): - self.controllerClasses = {} - - def getDevControllerClass(self, type): - return self.controllerClasses.get(type) - - def addDevControllerClass(self, cls): - self.controllerClasses[cls.getType()] = cls - - def delDevControllerClass(self, type): - if type in self.controllerClasses: - del self.controllerClasses[type] - - def createDevController(self, type, vm, recreate=False): - cls = self.getDevControllerClass(type) - if not cls: - raise XendError("unknown device type: " + str(type)) - return cls.createDevController(vm, recreate=recreate) - -def getDevControllerTable(): - """Singleton constructor for the controller table. - """ - global devControllerTable - try: - devControllerTable - except: - devControllerTable = DevControllerTable() - return devControllerTable - -def addDevControllerClass(name, cls): - """Add a device controller class to the controller table. - """ - cls.type = name - getDevControllerTable().addDevControllerClass(cls) - - -def isDevControllerClass(name): - """@return True if a device controller class has been registered with - the controller table under the given name.""" - return name in getDevControllerTable().controllerClasses - - -def createDevController(name, vm, recreate=False): - return getDevControllerTable().createDevController(name, vm, recreate=recreate) - -class DevController: - """Abstract class for a device controller attached to a domain. - A device controller manages all the devices of a given type for a domain. - There is exactly one device controller for each device type for - a domain. - - """ - - # State: - # controller/ : for controller - # device// : for each device - - def createDevController(cls, vm, recreate=False): - """Class method to create a dev controller. - """ - ctrl = cls(vm, recreate=recreate) - ctrl.initController(recreate=recreate) - ctrl.exportToDB() - return ctrl - - createDevController = classmethod(createDevController) - - def getType(cls): - return cls.type - - getType = classmethod(getType) - - __exports__ = [ - DBVar('type', 'str'), - DBVar('destroyed', 'bool'), - ] - - # Set when registered. - type = None - - def __init__(self, vm, recreate=False): - self.destroyed = False - self.vm = vm - self.db = self.getDB() - self.deviceId = 0 - self.devices = {} - self.device_order = [] - - def getDB(self): - """Get the db node to use for a controller. - """ - return self.vm.db.addChild("/controller/%s" % self.getType()) - - def getDevDB(self, id): - """Get the db node to use for a device. - """ - return self.vm.db.addChild("/device/%s/%s" % (self.getType(), id)) - - def exportToDB(self, save=False): - self.db.exportToDB(self, fields=self.__exports__, save=save) - - def importFromDB(self): - self.db.importFromDB(self, fields=self.__exports__) - - def getDevControllerType(self): - return self.dctype - - def getDomain(self): - return self.vm.getDomain() - - def getDomainName(self): - return self.vm.getName() - - def getDomainInfo(self): - return self.vm - - #---------------------------------------------------------------------------- - # Subclass interface. - # Subclasses should define the unimplemented methods.. - # Redefinitions must have the same arguments. - - def initController(self, recreate=False, reboot=False): - """Initialise the controller. Called when the controller is - first created, and again after the domain is rebooted (with reboot True). - If called with recreate True (and reboot False) the controller is being - recreated after a xend restart. - - As this can be a re-init (after reboot) any controller state should - be reset. For example the destroyed flag. - """ - self.destroyed = False - if reboot: - self.rebootDevices() - - def newDevice(self, id, config, recreate=False): - """Create a device with the given config. - Must be defined in subclass. - Called with recreate True when the device is being recreated after a - xend restart. - - @return device - """ - raise NotImplementedError() - - def createDevice(self, config, recreate=False, change=False): - """Create a device and attach to its front- and back-ends. - If recreate is true the device is being recreated after a xend restart. - If change is true the device is a change to an existing domain, - i.e. it is being added at runtime rather than when the domain is created. - """ - dev = self.newDevice(self.nextDeviceId(), config, recreate=recreate) - if self.vm.recreate: - dev.importFromDB() - dev.init(recreate=recreate) - self.addDevice(dev) - if not recreate: - dev.exportToDB() - dev.attach(recreate=recreate, change=change) - dev.exportToDB() - - return dev - - def configureDevice(self, id, config, change=False): - """Reconfigure an existing device. - May be defined in subclass.""" - dev = self.getDevice(id, error=True) - dev.configure(config, change=change) - - def destroyDevice(self, id, change=False, reboot=False): - """Destroy a device. - May be defined in subclass. - - If reboot is true the device is being destroyed for a domain reboot. - - The device is not deleted, since it may be recreated later. - """ - dev = self.getDevice(id, error=True) - dev.destroy(change=change, reboot=reboot) - return dev - - def deleteDevice(self, id, change=True): - """Destroy a device and delete it. - Normally called to remove a device from a domain at runtime. - """ - dev = self.destroyDevice(id, change=change) - self.removeDevice(dev) - - def destroyController(self, reboot=False): - """Destroy all devices and clean up. - May be defined in subclass. - If reboot is true the controller is being destroyed for a domain reboot. - Called at domain shutdown. - """ - self.destroyed = True - self.destroyDevices(reboot=reboot) - - #---------------------------------------------------------------------------- - - def isDestroyed(self): - return self.destroyed - - def getDevice(self, id, error=False): - dev = self.devices.get(int(id)) - if error and not dev: - raise XendError("invalid device id: " + str(id)) - return dev - - def getDeviceIds(self): - return [ dev.getId() for dev in self.device_order ] - - def getDevices(self): - return self.device_order - - def getDeviceConfig(self, id): - return self.getDevice(id).getConfig() - - def getDeviceConfigs(self): - return [ dev.getConfig() for dev in self.device_order ] - - def getDeviceSxprs(self): - return [ dev.sxpr() for dev in self.device_order ] - - def addDevice(self, dev): - self.devices[dev.getId()] = dev - self.device_order.append(dev) - return dev - - def removeDevice(self, dev): - if dev.getId() in self.devices: - del self.devices[dev.getId()] - if dev in self.device_order: - self.device_order.remove(dev) - - def rebootDevices(self): - for dev in self.getDevices(): - dev.reboot() - - def destroyDevices(self, reboot=False): - """Destroy all devices. - """ - for dev in self.getDevices(): - dev.destroy(reboot=reboot) - - def getMaxDeviceId(self): - maxid = 0 - for id in self.devices: - if id > maxid: - maxid = id - return maxid - - def nextDeviceId(self): - id = self.deviceId - self.deviceId += 1 - return id - - def getDeviceCount(self): - return len(self.devices) - -class Dev: - """Abstract class for a device attached to a device controller. - - @ivar id: identifier - @type id: int - @ivar controller: device controller - @type controller: DevController - """ - - # ./status : need 2: actual and requested? - # down-down: initial. - # up-up: fully up. - # down-up: down requested, still up. Watch front and back, when both - # down go to down-down. But what if one (or both) is not connected? - # Still have front/back trees with status? Watch front/status, back/status? - # up-down: up requested, still down. - # Back-end watches ./status, front/status - # Front-end watches ./status, back/status - # i.e. each watches the other 2. - # Each is status/request status/actual? - # - # backend? - # frontend? - - __exports__ = [ - DBVar('id', ty='int'), - DBVar('type', ty='str'), - DBVar('config', ty='sxpr'), - DBVar('destroyed', ty='bool'), - ] - - def __init__(self, controller, id, config, recreate=False): - self.controller = controller - self.id = id - self.config = config - self.destroyed = False - self.type = self.getType() - - self.db = controller.getDevDB(id) - - def exportToDB(self, save=False): - self.db.exportToDB(self, fields=self.__exports__, save=save) - - def importFromDB(self): - self.db.importFromDB(self, fields=self.__exports__) - - def getDomain(self): - return self.controller.getDomain() - - def getDomainName(self): - return self.controller.getDomainName() - - def getDomainInfo(self): - return self.controller.getDomainInfo() - - def getController(self): - return self.controller - - def getType(self): - return self.controller.getType() - - def getId(self): - return self.id - - def getConfig(self): - return self.config - - def isDestroyed(self): - return self.destroyed - - #---------------------------------------------------------------------------- - # Subclass interface. - # Define methods in subclass as needed. - # Redefinitions must have the same arguments. - - def init(self, recreate=False, reboot=False): - """Initialization. Called on initial create (when reboot is False) - and on reboot (when reboot is True). When xend is restarting is - called with recreate True. Define in subclass if needed. - - Device instance variables must be defined in the class constructor, - but given null or default values. The real values should be initialised - in this method. This allows devices to be re-initialised. - - Since this can be called to re-initialise a device any state flags - should be reset. - """ - self.destroyed = False - - def attach(self, recreate=False, change=False): - """Attach the device to its front and back ends. - Define in subclass if needed. - """ - pass - - def reboot(self): - """Reconnect the device when the domain is rebooted. - """ - self.init(reboot=True) - self.attach() - - def sxpr(self): - """Get the s-expression for the deivice. - Implement in a subclass if needed. - - @return: sxpr - """ - return self.getConfig() - - def configure(self, config, change=False): - """Reconfigure the device. - - Implement in subclass. - """ - raise NotImplementedError() - - def refresh(self): - """Refresh the device.. - Default no-op. Define in subclass if needed. - """ - pass - - def destroy(self, change=False, reboot=False): - """Destroy the device. - If change is True notify destruction (runtime change). - If reboot is True the device is being destroyed for a reboot. - Redefine in subclass if needed. - - Called at domain shutdown and when a device is deleted from - a running domain (with change True). - """ - self.destroyed = True - pass - - #---------------------------------------------------------------------------- diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py index acb7967c53..2e5addb9b9 100755 --- a/tools/python/xen/xend/server/netif.py +++ b/tools/python/xen/xend/server/netif.py @@ -13,396 +13,64 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #============================================================================ # Copyright (C) 2004, 2005 Mike Wray +# Copyright (C) 2005 XenSource Ltd #============================================================================ + """Support for virtual network interfaces. """ -import random - -from xen.util.mac import macFromString, macToString +import os from xen.xend import sxp -from xen.xend import Vifctl -from xen.xend.XendError import XendError, VmError -from xen.xend.XendLogging import log -from xen.xend import XendVnet -from xen.xend.XendRoot import get_component -from xen.xend.xenstore import DBVar -from xen.xend.server.controller import Dev, DevController +from xen.xend.server.DevController import DevController -class NetDev(Dev): - """A network device. - """ - # State: - # inherited + - # ./config - # ./mac - # ./be_mac - # ./bridge - # ./script - # ./ipaddr ? - # - # ./credit - # ./period - # - # ./vifctl: up/down? - # ./vifname - # - # - # Poss should have no backend state here - except for ref to backend's own tree - # for the device? And a status - the one we want. - # ./back/dom - # ./back/devid - id for back-end (netif_handle) - same as front/devid - # ./back/id - backend id (if more than one b/e per domain) - # ./back/status - # ./back/tx_shmem_frame - actually these belong in back-end state - # ./back/rx_shmem_frame - # - # ./front/dom - # ./front/devid - # ./front/status - need 2: one for requested, one for actual? Or drive from dev status - # and this is front status only. - # ./front/tx_shmem_frame - # ./front/rx_shmem_frame - # - # ./evtchn/front - here or in front/back? - # ./evtchn/back - # ./evtchn/status ? - # At present created by dev: but should be created unbound by front/back - # separately and then bound (by back)? +next_devid = 1 - __exports__ = Dev.__exports__ + [ - DBVar('config', ty='sxpr'), - DBVar('mac', ty='mac'), - DBVar('be_mac', ty='mac'), - DBVar('bridge', ty='str'), - DBVar('script', ty='str'), - DBVar('credit', ty='int'), - DBVar('period', ty='int'), - DBVar('vifname', ty='str'), - ] - def __init__(self, controller, id, config, recreate=False): - Dev.__init__(self, controller, id, config, recreate=recreate) - self.vif = int(self.id) - self.status = None - self.frontendDomain = self.getDomain() - self.backendDomain = None - self.credit = None - self.period = None - self.mac = None - self.be_mac = None - self.bridge = None - self.script = None - self.ipaddr = None - self.mtu = None - self.vifname = None - self.configure(self.config, recreate=recreate) - - def exportToDB(self, save=False): - Dev.exportToDB(self, save=save) - - def init(self, recreate=False, reboot=False): - self.destroyed = False - self.status = NETIF_INTERFACE_STATUS_DISCONNECTED - self.frontendDomain = self.getDomain() - - def _get_config_mac(self, config): - vmac = sxp.child_value(config, 'mac') - if not vmac: return None - try: - mac = macFromString(vmac) - except: - raise XendError("invalid mac: %s" % vmac) - return mac - - def _get_config_be_mac(self, config): - vmac = sxp.child_value(config, 'be_mac') - if not vmac: return None - try: - mac = macFromString(vmac) - except: - raise XendError("invalid backend mac: %s" % vmac) - return mac - - def _get_config_ipaddr(self, config): - ips = sxp.children(config, elt='ip') - if ips: - val = [] - for ipaddr in ips: - val.append(sxp.child0(ipaddr)) - else: - val = None - return val - - def _get_config_mtu(self, config): - mtu = sxp.child_value(config, 'mtu') - if not mtu: return None - try: - mtu = int(mtu) - except: - raise XendError("invalid mtu: %s" & mtu) - return mtu - - def configure(self, config, change=False, recreate=False): - if change: - return self.reconfigure(config) - self.config = config - self.mac = None - self.be_mac = None - 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") - self.mac = mac - self.be_mac = self._get_config_be_mac(config) - self.bridge = sxp.child_value(config, 'bridge') - self.script = sxp.child_value(config, 'script') - self.ipaddr = self._get_config_ipaddr(config) or [] - self.mtu = self._get_config_mtu(config) - self._config_credit_limit(config) - - try: - if recreate: - self.backendDomain = int(sxp.child_value(config, 'backend', '0')) - else: - #todo: Code below will fail on xend restart when backend is not domain 0. - xd = get_component('xen.xend.XendDomain') - self.backendDomain = xd.domain_lookup_by_name(sxp.child_value(config, 'backend', '0')).domid - except: - raise XendError('invalid backend domain') - return self.config - - def reconfigure(self, config): - """Reconfigure the interface with new values. - Not all configuration parameters can be changed: - bridge, script and ip addresses can, - backend and mac cannot. - - To leave a parameter unchanged, omit it from the changes. - - @param config configuration changes - @return updated interface configuration - @raise XendError on errors - """ - changes = {} - mac = self._get_config_mac(config) - be_mac = self._get_config_be_mac(config) - bridge = sxp.child_value(config, 'bridge') - script = sxp.child_value(config, 'script') - ipaddr = self._get_config_ipaddr(config) - mtu = self._get_config_mtu(config) - - xd = get_component('xen.xend.XendDomain') - backendDomain = xd.domain_lookup_by_name(sxp.child_value(config, 'backend', '0')).domid - - if (mac is not None) and (mac != self.mac): - raise XendError("cannot change mac") - if (be_mac is not None) and (be_mac != self.be_mac): - raise XendError("cannot change backend mac") - if (backendDomain is not None) and (backendDomain != self.backendDomain): - raise XendError("cannot change backend") - if (bridge is not None) and (bridge != self.bridge): - changes['bridge'] = bridge - if (script is not None) and (script != self.script): - changes['script'] = script - if (ipaddr is not None) and (ipaddr != self.ipaddr): - changes['ipaddr'] = ipaddr - if (mtu is not None) and (mtu != self.mtu): - changes['mtu'] = mtu - - if changes: - self.vifctl("down") - for (k, v) in changes.items(): - setattr(self, k, v) - self.config = sxp.merge(config, self.config) - self.vifctl("up") - - self._config_credit_limit(config, change=True) - return self.config - - def _config_credit_limit(self, config, change=False): - period = sxp.child_value(config, 'period') - credit = sxp.child_value(config, 'credit') - if period and credit: - try: - period = int(period) - credit = int(credit) - except ex: - raise XendError('vif: invalid credit limit') - if change: - self.setCreditLimit(credit, period) - self.config = sxp.merge([sxp.name(self.config), - ['credit', credit], - ['period', period]], - self.config) - else: - self.period = period - self.credit = credit - elif period or credit: - raise XendError('vif: invalid credit limit') - - def sxpr(self): - vif = str(self.vif) - mac = self.get_mac() - val = ['vif', - ['id', self.id], - ['vif', vif], - ['mac', mac], - ['vifname', self.vifname], - ] - - if self.be_mac: - val.append(['be_mac', self.get_be_mac()]) - if self.bridge: - val.append(['bridge', self.bridge]) - if self.script: - val.append(['script', self.script]) - for ip in self.ipaddr: - val.append(['ip', ip]) - if self.credit: - val.append(['credit', self.credit]) - if self.period: - val.append(['period', self.period]) - return val - - def get_vifname(self): - """Get the virtual interface device name. - """ - return self.vifname - - def default_vifname(self): - return "vif%d.%d" % (self.frontendDomain, self.vif) - - def get_mac(self): - """Get the MAC address as a string. - """ - return macToString(self.mac) - - def get_be_mac(self): - """Get the backend MAC address as a string. - """ - return macToString(self.be_mac) - - def vifctl_params(self, vmname=None): - """Get the parameters to pass to vifctl. - """ - dom = self.frontendDomain - if vmname is None: - xd = get_component('xen.xend.XendDomain') - try: - vm = xd.domain_lookup(dom) - vmname = vm.name - except: - vmname = 'Domain-%d' % dom - return { 'domain': vmname, - 'vif' : self.get_vifname(), - 'mac' : self.get_mac(), - 'bridge': self.bridge, - 'script': self.script, - 'ipaddr': self.ipaddr, } - - def vifctl(self, op, vmname=None): - """Bring the device up or down. - The vmname is needed when bringing a device up for a new domain because - the domain is not yet in the table so we can't look its name up. - - @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: - vnet.vifctl(op, self.get_vifname(), self.get_mac()) - - def attach(self, recreate=False, change=False): - if recreate: - pass - else: - if self.credit and self.period: - #self.send_be_creditlimit(self.credit, self.period) - pass - self.vifctl('up', vmname=self.getDomainName()) - - def destroy(self, change=False, reboot=False): - """Destroy the device's resources and disconnect from the back-end - device controller. If 'change' is true notify the front-end interface. - - @param change: change flag - """ - self.destroyed = True - self.status = NETIF_INTERFACE_STATUS_CLOSED - log.debug("Destroying vif domain=%d vif=%d", self.frontendDomain, self.vif) - self.vifctl('down') - if change: - self.reportStatus() - - def setCreditLimit(self, credit, period): - #todo: these params should be in sxpr and vif config. - self.credit = credit - self.period = period - - def getCredit(self): - return self.credit - - def getPeriod(self): - return self.period - - def interfaceChanged(self): - """Notify the front-end that a device has been added or removed. - """ - pass - class NetifController(DevController): """Network interface controller. Handles all network devices for a domain. """ - def __init__(self, vm, recreate=False): - DevController.__init__(self, vm, recreate=recreate) + def __init__(self, vm): + DevController.__init__(self, vm) - def initController(self, recreate=False, reboot=False): - self.destroyed = False - if reboot: - self.rebootDevices() - def destroyController(self, reboot=False): - """Destroy the controller and all devices. - """ - self.destroyed = True - log.debug("Destroying netif domain=%d", self.getDomain()) - self.destroyDevices(reboot=reboot) + def getDeviceDetails(self, config): + """@see DevController.getDeviceDetails""" - def sxpr(self): - val = ['netif', ['dom', self.getDomain()]] - return val - - def newDevice(self, id, config, recreate=False): - """Create a network device. + global next_devid - @param id: interface id - @param config: device configuration - @param recreate: recreate flag (true after xend restart) - """ - return NetDev(self, id, config, recreate=recreate) + from xen.xend import XendRoot + xroot = XendRoot.instance() - def limitDevice(self, vif, credit, period): - if vif not in self.devices: - raise XendError('device does not exist for credit limit: vif' - + str(self.getDomain()) + '.' + str(vif)) - - dev = self.devices[vif] - return dev.setCreditLimit(credit, period) + def _get_config_ipaddr(config): + val = [] + for ipaddr in sxp.children(config, elt='ip'): + val.append(sxp.child0(ipaddr)) + return val + + devid = next_devid + next_devid += 1 + + script = os.path.join(xroot.network_script_dir, + sxp.child_value(config, 'script', + xroot.get_vif_script())) + bridge = sxp.child_value(config, 'bridge', + xroot.get_vif_bridge()) + mac = sxp.child_value(config, 'mac') + ipaddr = _get_config_ipaddr(config) + + back = { 'script' : script, + 'mac' : mac, + 'bridge' : bridge, + 'handle' : "%i" % devid } + if ipaddr: + back['ip'] = ' '.join(ipaddr) + + front = { 'handle' : "%i" % devid, + 'mac' : mac } + + return (devid, back, front) diff --git a/tools/python/xen/xend/server/pciif.py b/tools/python/xen/xend/server/pciif.py index 681285d404..480d11ddc5 100644 --- a/tools/python/xen/xend/server/pciif.py +++ b/tools/python/xen/xend/server/pciif.py @@ -13,16 +13,22 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #============================================================================ # Copyright (C) 2004, 2005 Mike Wray +# Copyright (C) 2005 XenSource Ltd #============================================================================ + import types -import xen.lowlevel.xc; xc = xen.lowlevel.xc.new() +import xen.lowlevel.xc; from xen.xend import sxp from xen.xend.XendError import VmError -from controller import Dev, DevController +from xen.xend.server.DevController import DevController + + +xc = xen.lowlevel.xc.new() + def parse_pci(val): """Parse a pci field. @@ -36,27 +42,32 @@ def parse_pci(val): v = val return v -class PciDev(Dev): - def __init__(self, controller, id, config, recreate=False): - Dev.__init__(self, controller, id, config, recreate=recreate) - bus = sxp.child_value(self.config, 'bus') - if not bus: - raise VmError('pci: Missing bus') - dev = sxp.child_value(self.config, 'dev') - if not dev: - raise VmError('pci: Missing dev') - func = sxp.child_value(self.config, 'func') - if not func: - raise VmError('pci: Missing func') - try: - bus = parse_pci(bus) - dev = parse_pci(dev) - func = parse_pci(func) - except: - raise VmError('pci: invalid parameter') +class PciController(DevController): + + def __init__(self, vm): + DevController.__init__(self, vm) + + + def getDeviceDetails(self, config): + """@see DevController.getDeviceDetails""" + + def get_param(field): + try: + val = sxp.child_value(config, field) + + if not val: + raise VmError('pci: Missing %s config setting' % field) + + return parse_pci(val) + except: + raise VmError('pci: Invalid config setting %s: %s' % + (field, val)) + + bus = get_param('bus') + dev = get_param('dev') + func = get_param('func') - def attach(self, recreate=False, change=False): rc = xc.physdev_pci_access_modify(dom = self.getDomain(), bus = bus, dev = dev, @@ -64,13 +75,8 @@ class PciDev(Dev): enable = True) if rc < 0: #todo non-fatal - raise VmError('pci: Failed to configure device: bus=%s dev=%s func=%s' % - (bus, dev, func)) + raise VmError( + 'pci: Failed to configure device: bus=%s dev=%s func=%s' % + (bus, dev, func)) - def destroy(self, change=False, reboot=False): - pass - -class PciController(DevController): - - def newDevice(self, id, config, recreate=False): - return PciDev(self, id, config, recreate=recreate) + return (dev, {}, {}) diff --git a/tools/python/xen/xend/server/tpmif.py b/tools/python/xen/xend/server/tpmif.py index 28d50f47a9..a2fc2c6335 100644 --- a/tools/python/xen/xend/server/tpmif.py +++ b/tools/python/xen/xend/server/tpmif.py @@ -1,45 +1,47 @@ -# Copyright (C) 2005 IBM Corporation -# Authort: Stefan Berger, stefanb@us.ibm.com -# Derived from netif.py: +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ # Copyright (C) 2004 Mike Wray +# Copyright (C) 2005 IBM Corporation +# Author: Stefan Berger, stefanb@us.ibm.com +# Copyright (C) 2005 XenSource Ltd +#============================================================================ + """Support for virtual TPM interfaces. """ -import random - from xen.xend import sxp -from xen.xend.XendError import XendError, VmError from xen.xend.XendLogging import log -from xen.xend.XendRoot import get_component -from xen.xend.xenstore import DBVar -from xen.xend.server.controller import Dev, DevController +from xen.xend.server.DevController import DevController + class TPMifController(DevController): """TPM interface controller. Handles all TPM devices for a domain. """ - def __init__(self, vm, recreate=False): - DevController.__init__(self, vm, recreate=recreate) + def __init__(self, vm): + DevController.__init__(self, vm) - def initController(self, recreate=False, reboot=False): - self.destroyed = False - def destroyController(self, reboot=False): - """Destroy the controller and all devices. - """ - self.destroyed = True - self.destroyDevices(reboot=reboot) + def getDeviceDetails(self, config): + """@see DevController.getDeviceDetails""" + + devid = int(sxp.child_value(config, 'instance', '0')) + log.error("The domain has a TPM with instance %d." % devid) - def sxpr(self): - val = ['tpmif', ['dom', self.getDomain()]] - return val + back = { 'instance' : "%i" % devid } + front = { 'handle' : "%i" % devid } - def newDevice(self, id, config, recreate=False): - """Create a TPM device. - - @param id: interface id - @param config: device configuration - @param recreate: recreate flag (true after xend restart) - """ - return None + return (devid, back, front) diff --git a/tools/python/xen/xend/server/usbif.py b/tools/python/xen/xend/server/usbif.py index 63b25c4b66..84cf87e3af 100644 --- a/tools/python/xen/xend/server/usbif.py +++ b/tools/python/xen/xend/server/usbif.py @@ -1,185 +1,50 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ # Copyright (C) 2004 Mike Wray # Copyright (C) 2004 Intel Research Cambridge # Copyright (C) 2004 Mark Williamson +# Copyright (C) 2005 XenSource Ltd +#============================================================================ + + """Support for virtual USB hubs. """ -from xen.xend import sxp -from xen.xend.XendLogging import log -from xen.xend.XendError import XendError -from xen.xend.xenstore import DBVar - -from xen.xend.server.controller import Dev, DevController - -class UsbBackend: - """Handler for the 'back-end' channel to a USB device driver domain - on behalf of a front-end domain. - """ - def __init__(self, controller, id, dom): - self.controller = controller - self.id = id - self.destroyed = False - self.connected = False - self.connecting = False - self.frontendDomain = self.controller.getDomain() - self.backendDomain = dom - - def init(self, recreate=False, reboot=False): - pass - - def __str__(self): - return ('' - % (self.frontendDomain, - self.backendDomain, - self.id)) - - def connect(self, recreate=False): - """Connect the controller to the usbif control interface. - - @param recreate: true if after xend restart - """ - log.debug("Connecting usbif %s", str(self)) - if recreate or self.connected or self.connecting: - pass - - def destroy(self, reboot=False): - """Disconnect from the usbif control interface and destroy it. - """ - self.destroyed = True - - def interfaceChanged(self): - pass +from xen.xend.server.DevController import DevController -class UsbDev(Dev): +next_devid = 1 - __exports__ = Dev.__exports__ + [ - DBVar('port', ty='int'), - DBVar('path', ty='str'), - ] - - def __init__(self, controller, id, config, recreate=False): - Dev.__init__(self, controller, id, config, recreate=recreate) - self.port = id - self.path = None - self.frontendDomain = self.getDomain() - self.backendDomain = 0 - self.configure(self.config, recreate=recreate) - - def init(self, recreate=False, reboot=False): - self.destroyed = False - self.frontendDomain = self.getDomain() - - def configure(self, config, change=False, recreate=False): - if change: - raise XendError("cannot reconfigure usb") - #todo: FIXME: Use sxp access methods to get this value. - # Must not use direct indexing. - self.path = config[1][1] - - #todo: FIXME: Support configuring the backend domain. -## try: -## self.backendDomain = int(sxp.child_value(config, 'backend', '0')) -## except: -## raise XendError('invalid backend domain') - - def attach(self, recreate=False, change=False): - if recreate: - pass - else: - self.attachBackend() - if change: - self.interfaceChanged() - - def sxpr(self): - val = ['usb', - ['id', self.id], - ['port', self.port], - ['path', self.path], - ] - return val - - def getBackend(self): - return self.controller.getBackend(self.backendDomain) - - def destroy(self, change=False, reboot=False): - """Destroy the device. If 'change' is true notify the front-end interface. - - @param change: change flag - """ - self.destroyed = True - log.debug("Destroying usb domain=%d id=%s", self.frontendDomain, self.id) - if change: - self.interfaceChanged() - - def interfaceChanged(self): - """Tell the back-end to notify the front-end that a device has been - added or removed. - """ - self.getBackend().interfaceChanged() - - def attachBackend(self): - """Attach the device to its controller. - - """ - self.getBackend().connect() class UsbifController(DevController): """USB device interface controller. Handles all USB devices for a domain. """ - def __init__(self, vm, recreate=False): + def __init__(self, vm): """Create a USB device controller. """ - DevController.__init__(self, vm, recreate=recreate) - self.backends = {} - self.backendId = 0 + DevController.__init__(self, vm) - def init(self, recreate=False, reboot=False): - self.destroyed = False - if reboot: - self.rebootBackends() - self.rebootDevices() - def sxpr(self): - val = ['usbif', - ['dom', self.getDomain()]] - return val + def getDeviceDetails(self, _): + """@see DevController.getDeviceDetails""" - def newDevice(self, id, config, recreate=False): - return UsbDev(self, id, config, recreate=recreate) + global next_devid - def destroyController(self, reboot=False): - """Destroy the controller and all devices. - """ - self.destroyed = True - log.debug("Destroying blkif domain=%d", self.getDomain()) - self.destroyDevices(reboot=reboot) - self.destroyBackends(reboot=reboot) + devid = next_devid + next_devid += 1 - def rebootBackends(self): - for backend in self.backends.values(): - backend.init(reboot=True) - - def getBackendById(self, id): - return self.backends.get(id) - - def getBackendByDomain(self, dom): - for backend in self.backends.values(): - if backend.backendDomain == dom: - return backend - return None - - def getBackend(self, dom): - backend = self.getBackendByDomain(dom) - if backend: return backend - backend = UsbBackend(self, self.backendId, dom) - self.backendId += 1 - self.backends[backend.getId()] = backend - backend.init() - return backend - - def destroyBackends(self, reboot=False): - for backend in self.backends.values(): - backend.destroy(reboot=reboot) + return (devid, {}, {})