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@xensource.com>
This commit is contained in:
emellor@ewan committed 2005-09-18 15:41:28 +01:00
1 parent c353c7fdd0
commit 27b7ea09e0
9 files changed
+394 -1542

No files matched your search

+2 -3
View File
@@ -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.
+58 -223
View File
@@ -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 <mike.wray@hp.com>
"""
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)
@@ -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@hp.com>
# 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)
+24 -299
View File
@@ -13,322 +13,47 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
# 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@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)
-423
View File
@@ -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@hp.com>
#============================================================================
"""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
#----------------------------------------------------------------------------
+40 -372
View File
@@ -13,396 +13,64 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
# 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)
+36 -30
View File
@@ -13,16 +13,22 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
# 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, {}, {})
+31 -29
View File
@@ -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 <mike.wray@hp.com>
# 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)
+28 -163
View File
@@ -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@hp.com>
# Copyright (C) 2004 Intel Research Cambridge
# Copyright (C) 2004 Mark Williamson <mark.williamson@cl.cam.ac.uk>
# 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, {}, {})
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.