aboutsummaryrefslogtreecommitdiffstats
path: root/tools/python/xen/xend/XendDomainInfo.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/python/xen/xend/XendDomainInfo.py')
-rw-r--r--tools/python/xen/xend/XendDomainInfo.py908
1 files changed, 908 insertions, 0 deletions
diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py
new file mode 100644
index 0000000000..a7e5aa3b2f
--- /dev/null
+++ b/tools/python/xen/xend/XendDomainInfo.py
@@ -0,0 +1,908 @@
+#!/usr/bin/python
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+"""Representation of a single domain.
+Includes support for domain construction, using
+open-ended configurations.
+
+Author: Mike Wray <mike.wray@hpl.hp.com>
+
+"""
+
+import string
+import re
+import sys
+import os
+
+from twisted.internet import defer
+
+import xen.ext.xc; xc = xen.ext.xc.new()
+import xen.util.ip
+
+import sxp
+
+import XendConsole
+xendConsole = XendConsole.instance()
+
+import server.SrvDaemon
+xend = server.SrvDaemon.instance()
+
+SIF_BLK_BE_DOMAIN = (1<<4)
+SIF_NET_BE_DOMAIN = (1<<5)
+
+def readlines(fd):
+ """Version of readlines safe against EINTR.
+ """
+ import errno
+
+ lines = []
+ while 1:
+ try:
+ line = fd.readline()
+ except IOError, ex:
+ if ex.errno == errno.EINTR:
+ continue
+ else:
+ raise
+ if line == '': break
+ lines.append(line)
+ return lines
+
+class VmError(ValueError):
+ """Vm construction error."""
+
+ def __init__(self, value):
+ self.value = value
+
+ def __str__(self):
+ return self.value
+
+
+def blkdev_name_to_number(name):
+ """Take the given textual block-device name (e.g., '/dev/sda1',
+ 'hda') and return the device number used by the OS. """
+
+ if not re.match( '/dev/', name ):
+ name = '/dev/' + name
+
+ return os.stat(name).st_rdev
+
+def lookup_raw_partn(partition):
+ """Take the given block-device name (e.g., '/dev/sda1', 'hda')
+ and return a dictionary { device, start_sector,
+ nr_sectors, type }
+ device: Device number of the given partition
+ start_sector: Index of first sector of the partition
+ nr_sectors: Number of sectors comprising this partition
+ type: 'Disk' or identifying name for partition type
+ """
+
+ if not re.match( '/dev/', partition ):
+ partition = '/dev/' + partition
+
+ drive = re.split( '[0-9]', partition )[0]
+
+ if drive == partition:
+ fd = os.popen( '/sbin/sfdisk -s ' + drive + ' 2>/dev/null' )
+ line = readline(fd)
+ if line:
+ return [ { 'device' : blkdev_name_to_number(drive),
+ 'start_sector' : long(0),
+ 'nr_sectors' : long(line) * 2,
+ 'type' : 'Disk' } ]
+ return None
+
+ # determine position on disk
+ fd = os.popen( '/sbin/sfdisk -d ' + drive + ' 2>/dev/null' )
+
+ #['/dev/sda3 : start= 16948575, size=16836120, Id=83, bootable\012']
+ lines = readlines(fd)
+ for line in lines:
+ m = re.search( '^' + partition + '\s*: start=\s*([0-9]+), ' +
+ 'size=\s*([0-9]+), Id=\s*(\S+).*$', line)
+ if m:
+ return [ { 'device' : blkdev_name_to_number(drive),
+ 'start_sector' : long(m.group(1)),
+ 'nr_sectors' : long(m.group(2)),
+ 'type' : m.group(3) } ]
+
+ return None
+
+def lookup_disk_uname(uname):
+ """Lookup a list of segments for a physical device.
+ uname [string]: name of the device in the format \'phy:dev\' for a physical device
+ returns [list of dicts]: list of extents that make up the named device
+ """
+ ( type, d_name ) = string.split( uname, ':' )
+
+ if type == "phy":
+ segments = lookup_raw_partn( d_name )
+ else:
+ segments = None
+ return segments
+
+def make_disk(dom, uname, dev, mode, recreate=0):
+ """Create a virtual disk device for a domain.
+
+ @returns Deferred
+ """
+ segments = lookup_disk_uname(uname)
+ if not segments:
+ raise VmError("vbd: Segments not found: uname=%s" % uname)
+ if len(segments) > 1:
+ raise VmError("vbd: Multi-segment vdisk: uname=%s" % uname)
+ segment = segments[0]
+ vdev = blkdev_name_to_number(dev)
+ ctrl = xend.blkif_create(dom, recreate=recreate)
+
+ def fn(ctrl):
+ return xend.blkif_dev_create(dom, vdev, mode, segment, recreate=recreate)
+ ctrl.addCallback(fn)
+ return ctrl
+
+def make_vif(dom, vif, vmac, recreate=0):
+ """Create a virtual network device for a domain.
+
+
+ @returns Deferred
+ """
+ xend.netif_create(dom, recreate=recreate)
+ d = xend.netif_dev_create(dom, vif, vmac, recreate=recreate)
+ return d
+
+def vif_up(iplist):
+ """send an unsolicited ARP reply for all non link-local IP addresses.
+
+ iplist IP addresses
+ """
+
+ IP_NONLOCAL_BIND = '/proc/sys/net/ipv4/ip_nonlocal_bind'
+
+ def get_ip_nonlocal_bind():
+ return int(open(IP_NONLOCAL_BIND, 'r').read()[0])
+
+ def set_ip_nonlocal_bind(v):
+ print >> open(IP_NONLOCAL_BIND, 'w'), str(v)
+
+ def link_local(ip):
+ return xen.util.ip.check_subnet(ip, '169.254.0.0', '255.255.0.0')
+
+ def arping(ip, gw):
+ cmd = '/usr/sbin/arping -A -b -I eth0 -c 1 -s %s %s' % (ip, gw)
+ print cmd
+ os.system(cmd)
+
+ gateway = xen.util.ip.get_current_ipgw() or '255.255.255.255'
+ nlb = get_ip_nonlocal_bind()
+ if not nlb: set_ip_nonlocal_bind(1)
+ try:
+ for ip in iplist:
+ if not link_local(ip):
+ arping(ip, gateway)
+ finally:
+ if not nlb: set_ip_nonlocal_bind(0)
+
+config_handlers = {}
+
+def add_config_handler(name, h):
+ """Add a handler for a config field.
+
+ name field name
+ h handler: fn(vm, config, field, index)
+ """
+ config_handlers[name] = h
+
+def get_config_handler(name):
+ """Get a handler for a config field.
+
+ returns handler or None
+ """
+ return config_handlers.get(name)
+
+"""Table of handlers for virtual machine images.
+Indexed by image type.
+"""
+image_handlers = {}
+
+def add_image_handler(name, h):
+ """Add a handler for an image type
+ name image type
+ h handler: fn(config, name, memory, image)
+ """
+ image_handlers[name] = h
+
+def get_image_handler(name):
+ """Get the handler for an image type.
+ name image type
+
+ returns handler or None
+ """
+ return image_handlers.get(name)
+
+"""Table of handlers for devices.
+Indexed by device type.
+"""
+device_handlers = {}
+
+def add_device_handler(name, h):
+ """Add a handler for a device type.
+
+ name device type
+ h handler: fn(vm, dev)
+ """
+ device_handlers[name] = h
+
+def get_device_handler(name):
+ """Get the handler for a device type.
+
+ name device type
+
+ returns handler or None
+ """
+ return device_handlers.get(name)
+
+def vm_create(config):
+ """Create a VM from a configuration.
+ If a vm has been partially created and there is an error it
+ is destroyed.
+
+ config configuration
+
+ returns Deferred
+ raises VmError for invalid configuration
+ """
+ print 'vm_create>'
+ vm = XendDomainInfo()
+ return vm.construct(config)
+
+def vm_recreate(config, info):
+ """Create the VM object for an existing domain.
+ """
+ vm = XendDomainInfo()
+ vm.recreate = 1
+ vm.setdom(info['dom'])
+ vm.name = info['name']
+ vm.memory = info['mem_kb']/1024
+ if config:
+ d = vm.construct(config)
+ else:
+ d = defer.Deferred()
+ d.callback(vm)
+ return d
+
+def vm_restore(src, progress=0):
+ """Restore a VM from a disk image.
+
+ src saved state to restore
+ progress progress reporting flag
+ returns deferred
+ raises VmError for invalid configuration
+ """
+ vm = XendDomainInfo()
+ ostype = "linux" #todo Set from somewhere (store in the src?).
+ restorefn = getattr(xc, "%s_restore" % ostype)
+ d = restorefn(state_file=src, progress=progress)
+ dom = int(d['dom'])
+ if dom < 0:
+ raise VMError('restore failed')
+ vmconfig = sxp.from_string(d['vmconfig'])
+ vm.config = sxp.child_value(vmconfig, 'config')
+ deferred = vm.dom_configure(dom)
+ def vifs_cb(val, vm):
+ vif_up(vm.ipaddrs)
+ deferred.addCallback(vifs_cb, vm)
+ return deferred
+
+def dom_get(dom):
+ domlist = xc.domain_getinfo(dom=dom)
+ if domlist and dom == domlist[0]['dom']:
+ return domlist[0]
+ return None
+
+
+def append_deferred(dlist, v):
+ if isinstance(v, defer.Deferred):
+ dlist.append(v)
+
+def _vm_configure1(val, vm):
+ d = vm.create_devices()
+ print '_vm_configure1> made devices...'
+ def cbok(x):
+ print '_vm_configure1> cbok', x
+ return x
+ d.addCallback(cbok)
+ d.addCallback(_vm_configure2, vm)
+ print '_vm_configure1<'
+ return d
+
+def _vm_configure2(val, vm):
+ print '>callback _vm_configure2...'
+ d = vm.configure_fields()
+ def cbok(results):
+ print '_vm_configure2> cbok', results
+ return vm
+ def cberr(err):
+ print '_vm_configure2> cberr', err
+ vm.destroy()
+ return err
+ d.addCallback(cbok)
+ d.addErrback(cberr)
+ print '<_vm_configure2'
+ return d
+
+class XendDomainInfo:
+ """Virtual machine object."""
+
+ def __init__(self):
+ self.recreate = 0
+ self.config = None
+ self.id = None
+ self.dom = None
+ self.name = None
+ self.memory = None
+ self.image = None
+ self.ramdisk = None
+ self.cmdline = None
+ self.console = None
+ self.devices = {}
+ self.configs = []
+ self.info = None
+ self.ipaddrs = []
+ self.blkif_backend = 0
+ self.netif_backend = 0
+ #todo: state: running, suspended
+ self.state = 'running'
+ #todo: set to migrate info if migrating
+ self.migrate = None
+
+ def setdom(self, dom):
+ self.dom = int(dom)
+ self.id = str(dom)
+
+ def update(self, info):
+ """Update with info from xc.domain_getinfo().
+ """
+ self.info = info
+ self.memory = self.info['mem_kb'] / 1024
+
+ def __str__(self):
+ s = "domain"
+ s += " id=" + self.id
+ s += " name=" + self.name
+ s += " memory=" + str(self.memory)
+ if self.console:
+ s += " console=" + self.console.id
+ if self.image:
+ s += " image=" + self.image
+ s += ""
+ return s
+
+ __repr__ = __str__
+
+ def sxpr(self):
+ sxpr = ['domain',
+ ['id', self.id],
+ ['name', self.name],
+ ['memory', self.memory] ]
+ if self.info:
+ run = (self.info['running'] and 'r') or '-'
+ block = (self.info['blocked'] and 'b') or '-'
+ stop = (self.info['paused'] and 'p') or '-'
+ susp = (self.info['shutdown'] and 's') or '-'
+ crash = (self.info['crashed'] and 'c') or '-'
+ state = run + block + stop + susp + crash
+ sxpr.append(['state', state])
+ if self.info['shutdown']:
+ reasons = ["poweroff", "reboot", "suspend"]
+ reason = reasons[self.info['shutdown_reason']]
+ sxpr.append(['shutdown_reason', reason])
+ sxpr.append(['cpu', self.info['cpu']])
+ sxpr.append(['cpu_time', self.info['cpu_time']/1e9])
+ if self.console:
+ sxpr.append(self.console.sxpr())
+ if self.config:
+ sxpr.append(['config', self.config])
+ return sxpr
+
+ def construct(self, config):
+ # todo - add support for scheduling params?
+ self.config = config
+ try:
+ self.name = sxp.child_value(config, 'name')
+ self.memory = int(sxp.child_value(config, 'memory', '128'))
+ self.configure_backends()
+ image = sxp.child_value(config, 'image')
+ image_name = sxp.name(image)
+ image_handler = get_image_handler(image_name)
+ if image_handler is None:
+ raise VmError('unknown image type: ' + image_name)
+ image_handler(self, image)
+ deferred = self.configure()
+ except StandardError, ex:
+ # Catch errors, cleanup and re-raise.
+ self.destroy()
+ raise
+ def cbok(x):
+ print 'vm_create> cbok', x
+ return x
+ deferred.addCallback(cbok)
+ print 'vm_create<'
+ return deferred
+
+ def config_devices(self, name):
+ """Get a list of the 'device' nodes of a given type from the config.
+
+ name device type
+ return list of device configs
+ """
+ devices = []
+ for d in sxp.children(self.config, 'device'):
+ dev = sxp.child0(d)
+ if dev is None: continue
+ if name == sxp.name(dev):
+ devices.append(dev)
+ return devices
+
+ def add_device(self, type, dev):
+ """Add a device to a virtual machine.
+
+ dev device to add
+ """
+ dl = self.devices.get(type, [])
+ dl.append(dev)
+ self.devices[type] = dl
+
+ def get_devices(self, type):
+ val = self.devices.get(type, [])
+ return val
+
+ def get_device_by_id(self, type, id):
+ """Get the device with the given id.
+
+ id device id
+
+ returns device or None
+ """
+ dl = self.get_devices(type)
+ for d in dl:
+ if d.getprop('id') == id:
+ return d
+ return None
+
+ def get_device_by_index(self, type, idx):
+ """Get the device with the given index.
+
+ idx device index
+
+ returns device or None
+ """
+ dl = self.get_devices(type)
+ if 0 <= idx < len(dl):
+ return dl[idx]
+ else:
+ return None
+
+ def add_config(self, val):
+ """Add configuration data to a virtual machine.
+
+ val data to add
+ """
+ self.configs.append(val)
+
+ def destroy(self):
+ if self.dom <= 0:
+ return 0
+ return xc.domain_destroy(dom=self.dom)
+
+ def died(self):
+ print 'died>', self.dom
+ self.release_devices()
+
+ def release_devices(self):
+ print 'release_devices>', self.dom
+ self.release_vifs()
+ self.release_vbds()
+ self.devices = {}
+
+ def release_vifs(self):
+ print 'release_vifs>', self.dom
+ if self.dom is None: return
+ ctrl = xend.netif_get(self.dom)
+ if ctrl:
+ ctrl.destroy()
+
+ def release_vbds(self):
+ print 'release_vbds>', self.dom
+ if self.dom is None: return
+ ctrl = xend.blkif_get(self.dom)
+ if ctrl:
+ ctrl.destroy()
+
+ def show(self):
+ """Print virtual machine info.
+ """
+ print "[VM dom=%d name=%s memory=%d" % (self.dom, self.name, self.memory)
+ print "image:"
+ sxp.show(self.image)
+ print
+ for dl in self.devices:
+ for dev in dl:
+ print "device:"
+ sxp.show(dev)
+ print
+ for val in self.configs:
+ print "config:"
+ sxp.show(val)
+ print
+ print "]"
+
+ def init_domain(self):
+ """Initialize the domain memory.
+ """
+ if self.recreate: return
+ memory = self.memory
+ name = self.name
+ cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
+ print 'init_domain>', memory, name, cpu
+ dom = xc.domain_create(mem_kb= memory * 1024, name= name, cpu= cpu)
+ if dom <= 0:
+ raise VmError('Creating domain failed: name=%s memory=%d'
+ % (name, memory))
+ self.setdom(dom)
+
+ def build_domain(self, ostype, kernel, ramdisk, cmdline, vifs_n):
+ """Build the domain boot image.
+ """
+ if self.recreate: return
+ if len(cmdline) >= 256:
+ print 'Warning: kernel cmdline too long'
+ dom = self.dom
+ buildfn = getattr(xc, '%s_build' % ostype)
+ print 'build_domain>', ostype, dom, kernel, cmdline, ramdisk
+ flags = 0
+ if self.netif_backend: flags |= SIF_NET_BE_DOMAIN
+ if self.blkif_backend: flags |= SIF_BLK_BE_DOMAIN
+ err = buildfn(dom = dom,
+ image = kernel,
+ control_evtchn = self.console.port2,
+ cmdline = cmdline,
+ ramdisk = ramdisk,
+ flags = flags)
+ if err != 0:
+ raise VmError('Building domain failed: type=%s dom=%d err=%d'
+ % (ostype, dom, err))
+
+ def create_domain(self, ostype, kernel, ramdisk, cmdline, vifs_n):
+ """Create a domain. Builds the image but does not configure it.
+
+ ostype OS type
+ kernel kernel image
+ ramdisk kernel ramdisk
+ cmdline kernel commandline
+ vifs_n number of network interfaces
+ """
+ print 'create_domain>', ostype, kernel
+ if not self.recreate:
+ if not os.path.isfile(kernel):
+ raise VmError('Kernel image does not exist: %s' % kernel)
+ if ramdisk and not os.path.isfile(ramdisk):
+ raise VMError('Kernel ramdisk does not exist: %s' % ramdisk)
+ print 'create-domain> init_domain...'
+ self.init_domain()
+ print 'create_domain>', 'dom=', self.dom
+ self.console = xendConsole.console_create(self.dom)
+ self.build_domain(ostype, kernel, ramdisk, cmdline, vifs_n)
+ self.image = kernel
+ self.ramdisk = ramdisk
+ self.cmdline = cmdline
+
+ def create_devices(self):
+ """Create the devices for a vm.
+
+ returns Deferred
+ raises VmError for invalid devices
+ """
+ print '>create_devices'
+ dlist = []
+ devices = sxp.children(self.config, 'device')
+ index = {}
+ for d in devices:
+ dev = sxp.child0(d)
+ if dev is None:
+ raise VmError('invalid device')
+ dev_name = sxp.name(dev)
+ dev_index = index.get(dev_name, 0)
+ dev_handler = get_device_handler(dev_name)
+ if dev_handler is None:
+ raise VmError('unknown device type: ' + dev_name)
+ v = dev_handler(self, dev, dev_index)
+ append_deferred(dlist, v)
+ index[dev_name] = dev_index + 1
+ deferred = defer.DeferredList(dlist, fireOnOneErrback=1)
+ print '<create_devices'
+ return deferred
+
+ def configure_backends(self):
+ """Set configuration flags if the vm is a backend for netif of blkif.
+ """
+ for c in sxp.children(self.config, 'backend'):
+ name = sxp.name(sxp.child0(c))
+ if name == 'blkif':
+ self.blkif_backend = 1
+ elif name == 'netif':
+ self.netif_backend = 1
+ else:
+ raise VmError('invalid backend type:' + str(name))
+
+ def create_backends(self):
+ """Setup the netif and blkif backends.
+ """
+ if self.blkif_backend:
+ xend.blkif_set_control_domain(self.dom, recreate=self.recreate)
+ if self.netif_backend:
+ xend.netif_set_control_domain(self.dom, recreate=self.recreate)
+
+ def configure(self):
+ """Configure a vm.
+
+ vm virtual machine
+ config configuration
+
+ returns Deferred - calls callback with vm
+ """
+ if self.blkif_backend:
+ d = defer.Deferred()
+ d.callback(1)
+ else:
+ d = xend.blkif_create(self.dom, recreate=self.recreate)
+ d.addCallback(_vm_configure1, self)
+ return d
+
+ def dom_configure(self, dom):
+ """Configure a domain.
+
+ dom domain id
+ returns deferred
+ """
+ d = dom_get(dom)
+ if not d:
+ raise VMError("Domain not found: %d" % dom)
+ try:
+ self.setdom(dom)
+ self.name = d['name']
+ self.memory = d['memory']/1024
+ deferred = self.configure()
+ except StandardError, ex:
+ self.destroy()
+ raise
+ return deferred
+
+ def configure_fields(self):
+ dlist = []
+ index = {}
+ for field in sxp.children(self.config):
+ field_name = sxp.name(field)
+ field_index = index.get(field_name, 0)
+ field_handler = get_config_handler(field_name)
+ # Ignore unknown fields. Warn?
+ if field_handler:
+ v = field_handler(self, self.config, field, field_index)
+ append_deferred(dlist, v)
+ index[field_name] = field_index + 1
+ d = defer.DeferredList(dlist, fireOnOneErrback=1)
+ return d
+
+
+def vm_image_linux(vm, image):
+ """Create a VM for a linux image.
+
+ name vm name
+ memory vm memory
+ image image config
+
+ returns vm
+ """
+ kernel = sxp.child_value(image, "kernel")
+ cmdline = ""
+ ip = sxp.child_value(image, "ip", "dhcp")
+ if ip:
+ cmdline += " ip=" + ip
+ root = sxp.child_value(image, "root")
+ if root:
+ cmdline += " root=" + root
+ args = sxp.child_value(image, "args")
+ if args:
+ cmdline += " " + args
+ ramdisk = sxp.child_value(image, "ramdisk", '')
+ vifs = vm.config_devices("vif")
+ vm.create_domain("linux", kernel, ramdisk, cmdline, len(vifs))
+ return vm
+
+def vm_image_netbsd(vm, image):
+ """Create a VM for a bsd image.
+
+ name vm name
+ memory vm memory
+ image image config
+
+ returns vm
+ """
+ #todo: Same as for linux. Is that right? If so can unify them.
+ kernel = sxp.child_value(image, "kernel")
+ cmdline = ""
+ ip = sxp.child_value(image, "ip", "dhcp")
+ if ip:
+ cmdline += "ip=" + ip
+ root = sxp.child_value(image, "root")
+ if root:
+ cmdline += "root=" + root
+ args = sxp.child_value(image, "args")
+ if args:
+ cmdline += " " + args
+ ramdisk = sxp.child_value(image, "ramdisk")
+ vifs = vm.config_devices("vif")
+ vm.create_domain("netbsd", kernel, ramdisk, cmdline, len(vifs))
+ return vm
+
+
+def vm_dev_vif(vm, val, index):
+ """Create a virtual network interface (vif).
+
+ vm virtual machine
+ val vif config
+ index vif index
+ """
+ if vm.netif_backend:
+ raise VmError('vif: vif in netif backend domain')
+ vif = index #todo
+ vmac = sxp.child_value(val, "mac")
+ defer = make_vif(vm.dom, vif, vmac, vm.recreate)
+ def fn(id):
+ dev = xend.netif_dev(vm.dom, vif)
+ devid = sxp.attribute(val, 'id')
+ if devid:
+ dev.setprop('id', devid)
+ bridge = sxp.child_value(val, "bridge")
+ dev.up(bridge)
+ vm.add_device('vif', dev)
+ print 'vm_dev_vif> created', dev
+ return id
+ defer.addCallback(fn)
+ return defer
+
+def vm_dev_vbd(vm, val, index):
+ """Create a virtual block device (vbd).
+
+ vm virtual machine
+ val vbd config
+ index vbd index
+ """
+ if vm.blkif_backend:
+ raise VmError('vbd: vbd in blkif backend domain')
+ vdev = index
+ uname = sxp.child_value(val, 'uname')
+ if not uname:
+ raise VMError('vbd: Missing uname')
+ dev = sxp.child_value(val, 'dev')
+ if not dev:
+ raise VMError('vbd: Missing dev')
+ mode = sxp.child_value(val, 'mode', 'r')
+ defer = make_disk(vm.dom, uname, dev, mode, vm.recreate)
+ def fn(vbd):
+ dev = xend.blkif_dev(vm.dom, vdev)
+ vm.add_device('vbd', dev)
+ return vbd
+ defer.addCallback(fn)
+ return defer
+
+def parse_pci(val):
+ if isinstance(val, StringType):
+ radix = 10
+ if val.startswith('0x') or val.startswith('0X'):
+ radix = 16
+ v = int(val, radix)
+ else:
+ v = val
+ return v
+
+def vm_dev_pci(vm, val, index):
+ bus = sxp.child_value(val, 'bus')
+ if not bus:
+ raise VMError('pci: Missing bus')
+ dev = sxp.child_value(val, 'dev')
+ if not dev:
+ raise VMError('pci: Missing dev')
+ func = sxp.child_value(val, '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')
+ rc = xc.physdev_pci_access_modify(dom=vm.dom, bus=bus, dev=dev,
+ func=func, enable=1)
+ if rc < 0:
+ #todo non-fatal
+ raise VMError('pci: Failed to configure device: bus=%s dev=%s func=%s' %
+ (bus, dev, func))
+ return rc
+
+
+def vm_field_vfr(vm, config, val, index):
+ """Handle a vfr field in a config.
+
+ vm virtual machine
+ config vm config
+ val vfr field
+ """
+ # Get the rules and add them.
+ # (vfr (vif (id foo) (ip x.x.x.x)) ... )
+ list = sxp.children(val, 'vif')
+ ipaddrs = []
+ for v in list:
+ id = sxp.child_value(v, 'id')
+ if id is None:
+ raise VmError('vfr: missing vif id')
+ id = int(id)
+ dev = vm.get_device_by_index('vif', id)
+ if not dev:
+ raise VmError('vfr: invalid vif id %d' % id)
+ vif = sxp.child_value(dev, 'vif')
+ ip = sxp.child_value(v, 'ip')
+ if not ip:
+ raise VmError('vfr: missing ip address')
+ ipaddrs.append(ip);
+ # todo: Configure the ipaddrs.
+ vm.ipaddrs = ipaddrs
+
+def vnet_bridge(vnet, vmac, dom, idx):
+ """Add the device for the vif to the bridge for its vnet.
+ """
+ vif = "vif%d.%d" % (dom, idx)
+ try:
+ cmd = "(vif.conn (vif %s) (vnet %s) (vmac %s))" % (vif, vnet, vmac)
+ print "*** vnet_bridge>", cmd
+ out = file("/proc/vnet/policy", "wb")
+ out.write(cmd)
+ err = out.close()
+ print "vnet_bridge>", "err=", err
+ except IOError, ex:
+ print "vnet_bridge>", ex
+
+def vm_field_vnet(vm, config, val, index):
+ """Handle a vnet field in a config.
+
+ vm virtual machine
+ config vm config
+ val vnet field
+ index index
+ """
+ # Get the vif children. For each vif look up the vif device
+ # with the given id and configure its vnet.
+ # (vnet (vif (id foo) (vnet 2) (mac x:x:x:x:x:x)) ... )
+ vif_vnets = sxp.children(val, 'vif')
+ for v in vif_vnets:
+ id = sxp.child_value(v, 'id')
+ if id is None:
+ raise VmError('vnet: missing vif id')
+ dev = vm.get_device_by_id('vif', id)
+ #vnet = sxp.child_value(v, 'vnet', 1)
+ #mac = sxp.child_value(dev, 'mac')
+ #vif = sxp.child_value(dev, 'vif')
+ #vnet_bridge(vnet, mac, vm.dom, 0)
+ #vm.add_config([ 'vif.vnet', ['id', id], ['vnet', vnet], ['mac', mac]])
+
+# Register image handlers for linux and bsd.
+add_image_handler('linux', vm_image_linux)
+add_image_handler('netbsd', vm_image_netbsd)
+
+# Register device handlers for vifs and vbds.
+add_device_handler('vif', vm_dev_vif)
+add_device_handler('vbd', vm_dev_vbd)
+add_device_handler('pci', vm_dev_pci)
+
+# Register config handlers for vfr and vnet.
+add_config_handler('vfr', vm_field_vfr)
+add_config_handler('vnet', vm_field_vnet)