mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
Update image handling code for xstransact.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
This commit is contained in:
1 parent
47ff2422db
commit
5d2ca06d84
4 files changed
+134
-142
No files matched your search
@@ -89,6 +89,4 @@ def bootloader(blexec, disk, quiet = 0, vcpus = None, entry = None):
|
||||
if vcpus and sxp.child_value(config_image, "vcpus") is None:
|
||||
config_image.append(['vcpus', vcpus])
|
||||
|
||||
config = ['image', config_image]
|
||||
return config
|
||||
|
||||
return config_image
|
||||
@@ -214,7 +214,6 @@ class XendDomainInfo:
|
||||
DBVar('restart_state', ty='str'),
|
||||
DBVar('restart_time', ty='float'),
|
||||
DBVar('restart_count', ty='int'),
|
||||
DBVar('device_model_pid', ty='int'),
|
||||
]
|
||||
|
||||
def __init__(self, uuid, path, db):
|
||||
@@ -264,7 +263,6 @@ class XendDomainInfo:
|
||||
|
||||
self.vcpus = 1
|
||||
self.bootloader = None
|
||||
self.device_model_pid = 0
|
||||
|
||||
self.writeVm("uuid", self.uuid)
|
||||
self.storeDom("vm", self.path)
|
||||
@@ -306,8 +304,6 @@ class XendDomainInfo:
|
||||
self.db.saveDB(save=save, sync=sync)
|
||||
|
||||
def exportToDB(self, save=False, sync=False):
|
||||
if self.image:
|
||||
self.image.exportToDB(save=save, sync=sync)
|
||||
self.db.exportToDB(self, fields=self.__exports__, save=save, sync=sync)
|
||||
|
||||
def importFromDB(self):
|
||||
@@ -589,8 +585,6 @@ class XendDomainInfo:
|
||||
sxpr.append(devs)
|
||||
if self.config:
|
||||
sxpr.append(['config', self.config])
|
||||
if self.device_model_pid:
|
||||
sxpr.append(['device_model_pid',self.device_model_pid])
|
||||
return sxpr
|
||||
|
||||
def sxpr_devices(self):
|
||||
@@ -759,7 +753,6 @@ class XendDomainInfo:
|
||||
pass
|
||||
if self.image:
|
||||
try:
|
||||
self.device_model_pid = 0
|
||||
self.image.destroy()
|
||||
self.image = None
|
||||
except:
|
||||
@@ -865,8 +858,7 @@ class XendDomainInfo:
|
||||
ctrl.initController(reboot=True)
|
||||
else:
|
||||
self.create_configured_devices()
|
||||
if not self.device_model_pid:
|
||||
self.device_model_pid = self.image.createDeviceModel()
|
||||
self.image.createDeviceModel()
|
||||
|
||||
def device_create(self, dev_config):
|
||||
"""Create a new device.
|
||||
|
||||
+115
-112
@@ -36,10 +36,13 @@ SIF_NET_BE_DOMAIN = (1<<5)
|
||||
"""Flag for a TPM device backend domain."""
|
||||
SIF_TPM_BE_DOMAIN = (1<<7)
|
||||
|
||||
MAX_GUEST_CMDLINE = 1024
|
||||
|
||||
class ImageHandler:
|
||||
"""Abstract base class for image handlers.
|
||||
|
||||
initDomain() is called to initialise the domain memory.
|
||||
initDomain() is called to initialise the domain memory and parse
|
||||
the configuration.
|
||||
|
||||
createImage() is called to configure and build the domain from its
|
||||
kernel image and ramdisk etc.
|
||||
@@ -103,34 +106,42 @@ class ImageHandler:
|
||||
#======================================================================
|
||||
# Instance vars and methods.
|
||||
|
||||
db = None
|
||||
ostype = None
|
||||
|
||||
config = None
|
||||
kernel = None
|
||||
ramdisk = None
|
||||
cmdline = None
|
||||
|
||||
flags = 0
|
||||
|
||||
__exports__ = [
|
||||
DBVar('ostype', ty='str'),
|
||||
DBVar('config', ty='sxpr'),
|
||||
DBVar('kernel', ty='str'),
|
||||
DBVar('ramdisk', ty='str'),
|
||||
DBVar('cmdline', ty='str'),
|
||||
DBVar('flags', ty='int'),
|
||||
]
|
||||
|
||||
def __init__(self, vm, config):
|
||||
def __init__(self, vm, config=None):
|
||||
self.vm = vm
|
||||
self.db = vm.db.addChild('/image')
|
||||
self.config = config
|
||||
self.configure(config)
|
||||
|
||||
def exportToDB(self, save=False, sync=False):
|
||||
self.db.exportToDB(self, fields=self.__exports__, save=save, sync=sync)
|
||||
|
||||
def importFromDB(self):
|
||||
self.db.importFromDB(self, fields=self.__exports__)
|
||||
def configure(self, config):
|
||||
"""Config actions common to all unix-like domains."""
|
||||
if not config:
|
||||
self.kernel, self.cmdline, self.ramdisk = self.vm.gatherVm(
|
||||
("image/kernel"), ("image/cmdline"), ("image/ramdisk"))
|
||||
return
|
||||
|
||||
self.kernel = sxp.child_value(config, "kernel")
|
||||
self.cmdline = ""
|
||||
ip = sxp.child_value(config, "ip", None)
|
||||
if ip:
|
||||
self.cmdline += " ip=" + ip
|
||||
root = sxp.child_value(config, "root")
|
||||
if root:
|
||||
self.cmdline += " root=" + root
|
||||
args = sxp.child_value(config, "args")
|
||||
if args:
|
||||
self.cmdline += " " + args
|
||||
self.ramdisk = sxp.child_value(config, "ramdisk", '')
|
||||
|
||||
self.vm.storeVm(("image/ostype", self.ostype),
|
||||
("image/kernel", self.kernel),
|
||||
("image/cmdline", self.cmdline),
|
||||
("image/ramdisk", self.ramdisk))
|
||||
|
||||
def unlink(self, f):
|
||||
if not f: return
|
||||
@@ -159,12 +170,7 @@ class ImageHandler:
|
||||
xc.domain_setmaxmem(dom, mem_kb)
|
||||
|
||||
try:
|
||||
# Give the domain some memory below 4GB
|
||||
lmem_kb = 0
|
||||
if lmem_kb > 0:
|
||||
xc.domain_memory_increase_reservation(dom, min(lmem_kb,mem_kb), 0, 32)
|
||||
if mem_kb > lmem_kb:
|
||||
xc.domain_memory_increase_reservation(dom, mem_kb-lmem_kb, 0, 0)
|
||||
xc.domain_memory_increase_reservation(dom, mem_kb, 0, 0)
|
||||
except:
|
||||
xc.domain_destroy(dom)
|
||||
raise
|
||||
@@ -177,48 +183,33 @@ class ImageHandler:
|
||||
"""Entry point to create domain memory image.
|
||||
Override in subclass if needed.
|
||||
"""
|
||||
self.configure()
|
||||
self.createDomain()
|
||||
|
||||
def configure(self):
|
||||
"""Config actions common to all unix-like domains."""
|
||||
self.kernel = sxp.child_value(self.config, "kernel")
|
||||
self.cmdline = ""
|
||||
ip = sxp.child_value(self.config, "ip", None)
|
||||
if ip:
|
||||
self.cmdline += " ip=" + ip
|
||||
root = sxp.child_value(self.config, "root")
|
||||
if root:
|
||||
self.cmdline += " root=" + root
|
||||
args = sxp.child_value(self.config, "args")
|
||||
if args:
|
||||
self.cmdline += " " + args
|
||||
self.ramdisk = sxp.child_value(self.config, "ramdisk", '')
|
||||
|
||||
def createDomain(self):
|
||||
"""Build the domain boot image.
|
||||
"""
|
||||
if self.vm.recreate or self.vm.restore:
|
||||
return
|
||||
|
||||
# Set params and call buildDomain().
|
||||
self.flags = 0
|
||||
if self.vm.netif_backend: self.flags |= SIF_NET_BE_DOMAIN
|
||||
if self.vm.blkif_backend: self.flags |= SIF_BLK_BE_DOMAIN
|
||||
if self.vm.tpmif_backend: self.flags |= SIF_TPM_BE_DOMAIN
|
||||
|
||||
if self.vm.recreate or self.vm.restore:
|
||||
return
|
||||
if not os.path.isfile(self.kernel):
|
||||
raise VmError('Kernel image does not exist: %s' % self.kernel)
|
||||
if self.ramdisk and not os.path.isfile(self.ramdisk):
|
||||
raise VmError('Kernel ramdisk does not exist: %s' % self.ramdisk)
|
||||
if len(self.cmdline) >= 256:
|
||||
log.warning('kernel cmdline too long, domain %d', self.vm.getDomain())
|
||||
if len(self.cmdline) >= MAX_GUEST_CMDLINE:
|
||||
log.warning('kernel cmdline too long, domain %d', self.vm.domid)
|
||||
|
||||
log.info("buildDomain os=%s dom=%d vcpus=%d", self.ostype,
|
||||
self.vm.getDomain(), self.vm.vcpus)
|
||||
self.vm.domid, self.vm.vcpus)
|
||||
err = self.buildDomain()
|
||||
if err != 0:
|
||||
raise VmError('Building domain failed: ostype=%s dom=%d err=%d'
|
||||
% (self.ostype, self.vm.getDomain(), err))
|
||||
% (self.ostype, self.vm.domid, err))
|
||||
|
||||
def getDomainMemory(self, mem_mb):
|
||||
"""Memory (in KB) the domain will need for mem_mb (in MB)."""
|
||||
@@ -258,7 +249,7 @@ class LinuxImageHandler(ImageHandler):
|
||||
else:
|
||||
console_evtchn = 0
|
||||
|
||||
log.debug("dom = %d", self.vm.getDomain())
|
||||
log.debug("dom = %d", self.vm.domid)
|
||||
log.debug("image = %s", self.kernel)
|
||||
log.debug("store_evtchn = %d", store_evtchn)
|
||||
log.debug("console_evtchn = %d", console_evtchn)
|
||||
@@ -267,7 +258,7 @@ class LinuxImageHandler(ImageHandler):
|
||||
log.debug("flags = %d", self.flags)
|
||||
log.debug("vcpus = %d", self.vm.vcpus)
|
||||
|
||||
ret = xc.linux_build(dom = self.vm.getDomain(),
|
||||
ret = xc.linux_build(dom = self.vm.domid,
|
||||
image = self.kernel,
|
||||
store_evtchn = store_evtchn,
|
||||
console_evtchn = console_evtchn,
|
||||
@@ -282,49 +273,63 @@ class LinuxImageHandler(ImageHandler):
|
||||
|
||||
class VmxImageHandler(ImageHandler):
|
||||
|
||||
__exports__ = ImageHandler.__exports__ + [
|
||||
DBVar('memmap', ty='str'),
|
||||
DBVar('memmap_value', ty='sxpr'),
|
||||
# device channel?
|
||||
]
|
||||
|
||||
ostype = "vmx"
|
||||
|
||||
memmap = None
|
||||
memmap_value = []
|
||||
device_channel = None
|
||||
pid = 0
|
||||
|
||||
def configure(self, config):
|
||||
ImageHandler.configure(self, config)
|
||||
if not config:
|
||||
self.memmap, self.dmargs, self.device_model, self.display = self.vm.gatherVm(
|
||||
("image/memmap"), ("image/dmargs"), ("image/device-model"),
|
||||
("image/display"))
|
||||
return
|
||||
|
||||
self.memmap = sxp.child_value(config, 'memmap')
|
||||
self.dmargs = self.parseDeviceModelArgs(config)
|
||||
self.device_model = sxp.child_value(config, 'device_model')
|
||||
if not self.device_model:
|
||||
raise VmError("vmx: missing device model")
|
||||
self.display = sxp.child_value(config, 'display')
|
||||
|
||||
self.storeVm(("image/memmap", self.memmap),
|
||||
("image/dmargs", self.dmargs),
|
||||
("image/device-model", self.device_model),
|
||||
("image/display", self.display))
|
||||
|
||||
def createImage(self):
|
||||
"""Create a VM for the VMX environment.
|
||||
"""
|
||||
self.configure()
|
||||
self.parseMemmap()
|
||||
self.createDomain()
|
||||
|
||||
def buildDomain(self):
|
||||
# Create an event channel
|
||||
self.device_channel = channel.eventChannel(0, self.vm.getDomain())
|
||||
self.device_channel = channel.eventChannel(0, self.vm.domid)
|
||||
log.info("VMX device model port: %d", self.device_channel.port2)
|
||||
if self.vm.store_channel:
|
||||
store_evtchn = self.vm.store_channel.port2
|
||||
else:
|
||||
store_evtchn = 0
|
||||
ret = xc.vmx_build(dom = self.vm.getDomain(),
|
||||
image = self.kernel,
|
||||
control_evtchn = self.device_channel.port2,
|
||||
store_evtchn = store_evtchn,
|
||||
memsize = self.vm.memory,
|
||||
memmap = self.memmap_value,
|
||||
cmdline = self.cmdline,
|
||||
ramdisk = self.ramdisk,
|
||||
flags = self.flags,
|
||||
vcpus = self.vm.vcpus)
|
||||
ret = xc.vmx_build(dom = self.vm.domid,
|
||||
image = self.kernel,
|
||||
control_evtchn = self.device_channel.port2,
|
||||
store_evtchn = store_evtchn,
|
||||
memsize = self.vm.memory,
|
||||
memmap = self.memmap_value,
|
||||
cmdline = self.cmdline,
|
||||
ramdisk = self.ramdisk,
|
||||
flags = self.flags,
|
||||
vcpus = self.vm.vcpus)
|
||||
if isinstance(ret, dict):
|
||||
self.set_vminfo(ret)
|
||||
return 0
|
||||
return ret
|
||||
|
||||
def parseMemmap(self):
|
||||
self.memmap = sxp.child_value(self.vm.config, "memmap")
|
||||
if self.memmap is None:
|
||||
return
|
||||
memmap = sxp.parse(open(self.memmap))[0]
|
||||
@@ -333,12 +338,12 @@ class VmxImageHandler(ImageHandler):
|
||||
|
||||
# Return a list of cmd line args to the device models based on the
|
||||
# xm config file
|
||||
def parseDeviceModelArgs(self):
|
||||
dmargs = [ 'cdrom', 'boot', 'fda', 'fdb',
|
||||
def parseDeviceModelArgs(self, config):
|
||||
dmargs = [ 'cdrom', 'boot', 'fda', 'fdb',
|
||||
'localtime', 'serial', 'stdvga', 'isa' ]
|
||||
ret = []
|
||||
for a in dmargs:
|
||||
v = sxp.child_value(self.vm.config, a)
|
||||
ret = []
|
||||
for a in dmargs:
|
||||
v = sxp.child_value(config, a)
|
||||
|
||||
# python doesn't allow '-' in variable names
|
||||
if a == 'stdvga': a = 'std-vga'
|
||||
@@ -347,13 +352,13 @@ class VmxImageHandler(ImageHandler):
|
||||
if a in ['localtime', 'std-vga', 'isa']:
|
||||
if v != None: v = int(v)
|
||||
|
||||
log.debug("args: %s, val: %s" % (a,v))
|
||||
if v:
|
||||
ret.append("-%s" % a)
|
||||
ret.append("%s" % v)
|
||||
log.debug("args: %s, val: %s" % (a,v))
|
||||
if v:
|
||||
ret.append("-%s" % a)
|
||||
ret.append("%s" % v)
|
||||
|
||||
# Handle disk/network related options
|
||||
devices = sxp.children(self.vm.config, 'device')
|
||||
devices = sxp.children(config, 'device')
|
||||
for device in devices:
|
||||
name = sxp.name(sxp.child0(device))
|
||||
if name == 'vbd':
|
||||
@@ -384,51 +389,48 @@ class VmxImageHandler(ImageHandler):
|
||||
ret.append("-instance")
|
||||
ret.append("%s" % instance)
|
||||
|
||||
# Handle graphics library related options
|
||||
vnc = sxp.child_value(self.vm.config, 'vnc')
|
||||
sdl = sxp.child_value(self.vm.config, 'sdl')
|
||||
nographic = sxp.child_value(self.vm.config, 'nographic')
|
||||
if nographic:
|
||||
ret.append('-nographic')
|
||||
return ret
|
||||
|
||||
if vnc and sdl:
|
||||
ret = ret + ['-vnc-and-sdl', '-k', 'en-us']
|
||||
elif vnc:
|
||||
ret = ret + ['-vnc', '-k', 'en-us']
|
||||
if vnc:
|
||||
vncport = int(self.vm.getDomain()) + 5900
|
||||
ret = ret + ['-vncport', '%d' % vncport]
|
||||
return ret
|
||||
|
||||
# Handle graphics library related options
|
||||
vnc = sxp.child_value(config, 'vnc')
|
||||
sdl = sxp.child_value(config, 'sdl')
|
||||
nographic = sxp.child_value(config, 'nographic')
|
||||
if nographic:
|
||||
ret.append('-nographic')
|
||||
return ret
|
||||
|
||||
if vnc and sdl:
|
||||
ret = ret + ['-vnc-and-sdl', '-k', 'en-us']
|
||||
elif vnc:
|
||||
ret = ret + ['-vnc', '-k', 'en-us']
|
||||
if vnc:
|
||||
vncport = int(self.vm.domid) + 5900
|
||||
ret = ret + ['-vncport', '%d' % vncport]
|
||||
return ret
|
||||
|
||||
def createDeviceModel(self):
|
||||
device_model = sxp.child_value(self.vm.config, 'device_model')
|
||||
if not device_model:
|
||||
raise VmError("vmx: missing device model")
|
||||
if self.pid:
|
||||
return
|
||||
# Execute device model.
|
||||
#todo: Error handling
|
||||
# XXX RN: note that the order of args matter!
|
||||
args = [device_model]
|
||||
args = [self.device_model]
|
||||
vnc = self.vncParams()
|
||||
if len(vnc):
|
||||
args = args + vnc
|
||||
args = args + ([ "-d", "%d" % self.vm.getDomain(),
|
||||
args = args + ([ "-d", "%d" % self.vm.domid,
|
||||
"-p", "%d" % self.device_channel.port1,
|
||||
"-m", "%s" % self.vm.memory ])
|
||||
args = args + self.parseDeviceModelArgs()
|
||||
args = args + self.dmargs
|
||||
env = dict(os.environ)
|
||||
env['DISPLAY'] = sxp.child_value(self.vm.config, 'display')
|
||||
log.info("spawning device models: %s %s", device_model, args)
|
||||
self.pid = os.spawnve(os.P_NOWAIT, device_model, args, env)
|
||||
env['DISPLAY'] = self.display
|
||||
log.info("spawning device models: %s %s", self.device_model, args)
|
||||
self.pid = os.spawnve(os.P_NOWAIT, self.device_model, args, env)
|
||||
log.info("device model pid: %d", self.pid)
|
||||
return self.pid
|
||||
|
||||
def vncParams(self):
|
||||
# see if a vncviewer was specified
|
||||
# XXX RN: bit of a hack. should unify this, maybe stick in config space
|
||||
vncconnect=[]
|
||||
image = self.config
|
||||
args = sxp.child_value(image, "args")
|
||||
args = self.cmdline
|
||||
if args:
|
||||
arg_list = string.split(args)
|
||||
for arg in arg_list:
|
||||
@@ -442,7 +444,7 @@ class VmxImageHandler(ImageHandler):
|
||||
channel.eventChannelClose(self.device_channel)
|
||||
import signal
|
||||
if not self.pid:
|
||||
self.pid = self.vm.device_model_pid
|
||||
return
|
||||
os.kill(self.pid, signal.SIGKILL)
|
||||
(pid, status) = os.waitpid(self.pid, 0)
|
||||
self.pid = 0
|
||||
@@ -462,8 +464,9 @@ class VmxImageHandler(ImageHandler):
|
||||
# 1 page for the PGD + 1 pte page for 4MB of memory (rounded)
|
||||
if os.uname()[4] == 'x86_64':
|
||||
return (5 + ((mem_mb + 1) >> 1)) * 4
|
||||
elif os.uname()[4] == 'ia64':
|
||||
# XEN/IA64 has p2m table allocated on demand, so only return guest firmware size here.
|
||||
return 16 * 1024
|
||||
elif os.uname()[4] == 'ia64':
|
||||
# XEN/IA64 has p2m table allocated on demand, so only return
|
||||
# guest firmware size here.
|
||||
return 16 * 1024
|
||||
else:
|
||||
return (1 + ((mem_mb + 3) >> 2)) * 4
|
||||
@@ -109,7 +109,7 @@ gopts.var('vncviewer', val='no|yes',
|
||||
The address of the vncviewer is passed to the domain on the kernel command
|
||||
line using 'VNC_SERVER=<host>:<port>'. The port used by vnc is 5500 + DISPLAY.
|
||||
A display value with a free port is chosen if possible.
|
||||
Only valid when vnc=1.
|
||||
Only valid when vnc=1.
|
||||
""")
|
||||
|
||||
gopts.var('name', val='NAME',
|
||||
@@ -342,7 +342,7 @@ def strip(pre, s):
|
||||
else:
|
||||
return s
|
||||
|
||||
def configure_image(opts, config, vals):
|
||||
def configure_image(opts, vals):
|
||||
"""Create the image config.
|
||||
"""
|
||||
config_image = [ vals.builder ]
|
||||
@@ -359,8 +359,7 @@ def configure_image(opts, config, vals):
|
||||
config_image.append(['args', vals.extra])
|
||||
if vals.vcpus:
|
||||
config_image.append(['vcpus', vals.vcpus])
|
||||
config.append(['image', config_image ])
|
||||
|
||||
return config_image
|
||||
|
||||
def configure_disks(opts, config_devs, vals):
|
||||
"""Create the config for disks (virtual block devices).
|
||||
@@ -494,17 +493,17 @@ def configure_vfr(opts, config, vals):
|
||||
config_vfr.append(['vif', ['id', idx], ['ip', ip]])
|
||||
config.append(config_vfr)
|
||||
|
||||
def configure_vmx(opts, config_devs, vals):
|
||||
def configure_vmx(opts, config_image, vals):
|
||||
"""Create the config for VMX devices.
|
||||
"""
|
||||
args = [ 'memmap', 'device_model', 'cdrom',
|
||||
'boot', 'fda', 'fdb', 'localtime', 'serial', 'macaddr', 'stdvga',
|
||||
'isa', 'nographic', 'vnc', 'vncviewer', 'sdl', 'display']
|
||||
'boot', 'fda', 'fdb', 'localtime', 'serial', 'macaddr', 'stdvga',
|
||||
'isa', 'nographic', 'vnc', 'vncviewer', 'sdl', 'display']
|
||||
for a in args:
|
||||
if (vals.__dict__[a]):
|
||||
config_devs.append([a, vals.__dict__[a]])
|
||||
if (vals.__dict__[a]):
|
||||
config_image.append([a, vals.__dict__[a]])
|
||||
|
||||
def run_bootloader(opts, config, vals):
|
||||
def run_bootloader(opts, vals):
|
||||
if not os.access(vals.bootloader, os.X_OK):
|
||||
opts.err("Bootloader isn't executable")
|
||||
if len(vals.disk) < 1:
|
||||
@@ -512,11 +511,8 @@ def run_bootloader(opts, config, vals):
|
||||
(uname, dev, mode, backend) = vals.disk[0]
|
||||
file = blkif.blkdev_uname_to_file(uname)
|
||||
|
||||
blcfg = bootloader(vals.bootloader, file, not vals.console_autoconnect,
|
||||
vals.vcpus, vals.blentry)
|
||||
|
||||
config.append(['bootloader', vals.bootloader])
|
||||
config.append(blcfg)
|
||||
return bootloader(vals.bootloader, file, not vals.console_autoconnect,
|
||||
vals.vcpus, vals.blentry)
|
||||
|
||||
def make_config(opts, vals):
|
||||
"""Create the domain configuration.
|
||||
@@ -542,16 +538,19 @@ def make_config(opts, vals):
|
||||
config.append(['restart', vals.restart])
|
||||
|
||||
if vals.bootloader:
|
||||
run_bootloader(opts, config, vals)
|
||||
config.append(['bootloader', vals.bootloader])
|
||||
config_image = run_bootloader(opts, vals)
|
||||
else:
|
||||
configure_image(opts, config, vals)
|
||||
config_image = configure_image(opts, vals)
|
||||
configure_vmx(opts, config_image, vals)
|
||||
config.append(['image', config_image ])
|
||||
|
||||
config_devs = []
|
||||
configure_disks(opts, config_devs, vals)
|
||||
configure_pci(opts, config_devs, vals)
|
||||
configure_vifs(opts, config_devs, vals)
|
||||
configure_usb(opts, config_devs, vals)
|
||||
configure_vtpm(opts, config_devs, vals)
|
||||
configure_vmx(opts, config_devs, vals)
|
||||
config += config_devs
|
||||
|
||||
return config
|
||||
|
||||