[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] Replaced the device handling mechanism used by XendDomainInfo. Superficially,
# HG changeset patch # User emellor@ewan # Node ID 7e8eac6e96c6099d34fc1251c771f075096e471c # Parent e703abaf6e3de653089d10f660c6fee49df0c434 Replaced the device handling mechanism used by XendDomainInfo. Superficially, this looks like the resurrection of DevController from controller.py, but the mechanism is actually very different. Device handling is now stateless inside xend, relying on the store for state management, reducing DevController instances to one-shot lifetimes. Dev and its subclasses have gone completely. The device creation code itself has moved from XendDomainInfo.createDevice into DevController subclasses, and the previous contents of the subclasses has been discarded (these subclasses were no longer being called, so all this code was dead). XendDomainInfo.getDeviceIds has gone, as it was unused. XendDomainInfo.delete_device has been subsumed by XendDomainInfo.destroyDevice; since device handling is now stateless inside xend, the distinction between device 'deletion' and device 'destruction' is meaningless. The s-expression describing devices has gone, as this information is no longer available to xend in the same way, and seems to be unused. If it is required, it can be reinstated by loading device information from Xen or the store. Signed-off-by: Ewan Mellor <ewan@xxxxxxxxxxxxx> diff -r e703abaf6e3d -r 7e8eac6e96c6 tools/python/xen/xend/XendDomain.py --- a/tools/python/xen/xend/XendDomain.py Sun Sep 18 13:42:13 2005 +++ b/tools/python/xen/xend/XendDomain.py Sun Sep 18 14:41:28 2005 @@ -660,9 +660,8 @@ @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 -r e703abaf6e3d -r 7e8eac6e96c6 tools/python/xen/xend/XendDomainInfo.py --- a/tools/python/xen/xend/XendDomainInfo.py Sun Sep 18 13:42:13 2005 +++ b/tools/python/xen/xend/XendDomainInfo.py Sun Sep 18 14:41:28 2005 @@ -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 @@ """ -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.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 @@ 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 @@ -333,6 +326,12 @@ 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 @@ __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 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; - - backdom = domain_exists(sxp.child_value(devconfig, 'backend', '0')) - - devnum = blkdev_name_to_number(sxp.child_value(devconfig, 'dev')) - - 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) - - (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 - - 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 getDeviceController(self, name): + if name not in controllerClasses: + raise XendError("unknown device type: " + str(name)) + + return controllerClasses[name](self) + + + def createDevice(self, deviceClass, devconfig): + return self.getDeviceController(deviceClass).createDevice(devconfig) + + + def configureDevice(self, deviceClass, devid, devconfig): + return self.getDeviceController(deviceClass).configureDevice( + devid, devconfig) + + + def destroyDevice(self, deviceClass, devid): + return self.getDeviceController(deviceClass).destroyDevice(devid) + def sxpr(self): sxpr = ['domain', @@ -607,23 +482,8 @@ 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): @@ -798,18 +658,20 @@ 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 @@ 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 @@ @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 @@ @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() - - def device_configure(self, dev_config, id): + 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, devid): """Configure an existing device. - @param dev_config: device configuration - @param id: 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 - - 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()) + @param devid: device id + """ + deviceClass = sxp.name(dev_config) + self.configureDevice(deviceClass, devid, dev_config) + def configure_restart(self): """Configure the vm restart mode. @@ -1060,11 +888,6 @@ """ 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 @@ #============================================================================ # 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 -r e703abaf6e3d -r 7e8eac6e96c6 tools/python/xen/xend/server/blkif.py --- a/tools/python/xen/xend/server/blkif.py Sun Sep 18 13:42:13 2005 +++ b/tools/python/xen/xend/server/blkif.py Sun Sep 18 14:41:28 2005 @@ -13,322 +13,47 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #============================================================================ # Copyright (C) 2004, 2005 Mike Wray <mike.wray@xxxxxx> +# 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 ('<BlkifBackend frontend=%d backend=%d id=%d>' - % (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@xxxxxxxxxxxx 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 getDeviceDetails(self, config): + """@see DevController.getDeviceDetails""" + + typedev = sxp.child_value(config, 'dev') + if re.match('^ioemu:', typedev): + return - def rebootBackends(self): - for backend in self.backends.values(): - backend.init(reboot=True) + devid = blkif.blkdev_name_to_number(sxp.child_value(config, 'dev')) - def getBackendById(self, id): - return self.backends.get(id) + (typ, params) = string.split(sxp.child_value(config, 'uname'), ':', 1) + back = { 'type' : typ, + 'params' : params + } - def getBackendByDomain(self, dom): - for backend in self.backends.values(): - if backend.backendDomain == dom: - return backend - return None + if 'r' == sxp.child_value(config, 'mode', 'r'): + back['read-only'] = "" # existence indicates read-only - 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 + front = { 'virtual-device' : "%i" % devid } - 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 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) - - def destroyBackends(self, reboot=False): - for backend in self.backends.values(): - backend.destroy(reboot=reboot) + return (devid, back, front) diff -r e703abaf6e3d -r 7e8eac6e96c6 tools/python/xen/xend/server/netif.py --- a/tools/python/xen/xend/server/netif.py Sun Sep 18 13:42:13 2005 +++ b/tools/python/xen/xend/server/netif.py Sun Sep 18 14:41:28 2005 @@ -13,396 +13,64 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #============================================================================ # Copyright (C) 2004, 2005 Mike Wray <mike.wray@xxxxxx> +# 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 -r e703abaf6e3d -r 7e8eac6e96c6 tools/python/xen/xend/server/pciif.py --- a/tools/python/xen/xend/server/pciif.py Sun Sep 18 13:42:13 2005 +++ b/tools/python/xen/xend/server/pciif.py Sun Sep 18 14:41:28 2005 @@ -13,16 +13,22 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #============================================================================ # Copyright (C) 2004, 2005 Mike Wray <mike.wray@xxxxxx> +# 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 @@ 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 attach(self, recreate=False, change=False): + 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') + rc = xc.physdev_pci_access_modify(dom = self.getDomain(), bus = bus, dev = dev, @@ -64,13 +75,8 @@ 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 -r e703abaf6e3d -r 7e8eac6e96c6 tools/python/xen/xend/server/tpmif.py --- a/tools/python/xen/xend/server/tpmif.py Sun Sep 18 13:42:13 2005 +++ b/tools/python/xen/xend/server/tpmif.py Sun Sep 18 14:41:28 2005 @@ -1,45 +1,47 @@ +#============================================================================ +# 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 <mike.wray@xxxxxx> # Copyright (C) 2005 IBM Corporation -# Authort: Stefan Berger, stefanb@xxxxxxxxxx -# Derived from netif.py: -# Copyright (C) 2004 Mike Wray <mike.wray@xxxxxx> +# Author: Stefan Berger, stefanb@xxxxxxxxxx +# Copyright (C) 2005 XenSource Ltd +#============================================================================ + """Support for virtual TPM interfaces. """ -import random +from xen.xend import sxp +from xen.xend.XendLogging import log -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.DevController import DevController -from xen.xend.server.controller import Dev, 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 -r e703abaf6e3d -r 7e8eac6e96c6 tools/python/xen/xend/server/usbif.py --- a/tools/python/xen/xend/server/usbif.py Sun Sep 18 13:42:13 2005 +++ b/tools/python/xen/xend/server/usbif.py Sun Sep 18 14:41:28 2005 @@ -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 <mike.wray@xxxxxx> # Copyright (C) 2004 Intel Research Cambridge # Copyright (C) 2004 Mark Williamson <mark.williamson@xxxxxxxxxxxx> +# 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 ('<UsbifBackend frontend=%d backend=%d id=%d>' - % (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, {}, {}) diff -r e703abaf6e3d -r 7e8eac6e96c6 tools/python/xen/xend/server/DevController.py --- /dev/null Sun Sep 18 13:42:13 2005 +++ b/tools/python/xen/xend/server/DevController.py Sun Sep 18 14:41:28 2005 @@ -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 <mike.wray@xxxxxx> +# 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 -r e703abaf6e3d -r 7e8eac6e96c6 tools/python/xen/xend/server/controller.py --- a/tools/python/xen/xend/server/controller.py Sun Sep 18 13:42:13 2005 +++ /dev/null Sun Sep 18 14:41:28 2005 @@ -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 <mike.wray@xxxxxx> -#============================================================================ - -"""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/<type> : for controller - # device/<type>/<id> : 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 - - #---------------------------------------------------------------------------- _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |