xend: pass-through: Parse command line for multi-function hot-plug and unplug

Hook things up to allow multi-function pass-through.

This includes making sure that request is valid.
In the case of pci-detach:

* All the functions requested must be attached to the same virtual
  slot * and;
* A request must include the functions attached to a virtual slot

Cc: Dexuan Cui <dexuan.cui@intel.com>
Cc: Masaki Kanno <kanno.masaki@jp.fujitsu.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
This commit is contained in:
Keir Fraser committed 2009-06-27 09:56:15 +01:00
1 parent 437cbbf3fb
commit 82334d45f3
2 files changed
+131 -35

No files matched your search

+46 -6
View File
@@ -42,7 +42,7 @@ from xen.util import xsconstants
from xen.util.pci import serialise_pci_opts, pci_opts_list_to_sxp, \
pci_dict_to_bdf_str, pci_dict_to_xc_str, \
pci_convert_sxp_to_dict, pci_convert_dict_to_sxp, \
pci_dict_cmp, PCI_FUNC
pci_dict_cmp, PCI_DEVFN, PCI_SLOT, PCI_FUNC
from xen.xend import balloon, sxp, uuid, image, arch
from xen.xend import XendOptions, XendNode, XendConfig
@@ -617,12 +617,52 @@ class XendDomainInfo:
dev_uuid = sxp.child_value(dev_info, 'uuid')
pci_conf = self.info['devices'][dev_uuid][1]
pci_devs = pci_conf['devs']
request = map(lambda x:
pci_convert_dict_to_sxp(x, 'Initialising', 'Booting'),
pci_devs)
for i in request:
self.pci_device_configure(i)
# Keep a set of keys that are done rather than
# just itterating through set(map(..., pci_devs))
# to preserve any order information present.
done = set()
for key in map(lambda x: x['key'], pci_devs):
if key in done:
continue
done |= set([key])
dev = filter(lambda x: x['key'] == key, pci_devs)
head_dev = dev.pop()
dev_sxp = pci_convert_dict_to_sxp(head_dev, 'Initialising',
'Booting')
self.pci_device_configure(dev_sxp)
# That is all for single-function virtual devices
if len(dev) == 0:
continue
if int(head_dev['vslot'], 16) & AUTO_PHP_SLOT:
new_dev_info = self._getDeviceInfo_pci(devid)
if new_dev_info is None:
continue
new_dev_uuid = sxp.child_value(new_dev_info, 'uuid')
new_pci_conf = self.info['devices'][new_dev_uuid][1]
new_pci_devs = new_pci_conf['devs']
new_head_dev = filter(lambda x: pci_dict_cmp(x, head_dev),
new_pci_devs)[0]
if int(new_head_dev['vslot'], 16) & AUTO_PHP_SLOT:
continue
vslot = PCI_SLOT(int(new_head_dev['vslot'], 16))
new_dev = []
for i in dev:
i['vslot'] = '0x%02x' % \
PCI_DEVFN(vslot, PCI_FUNC(int(i['vslot'], 16)))
new_dev.append(i)
dev = new_dev
for i in dev:
dev_sxp = pci_convert_dict_to_sxp(i, 'Initialising', 'Booting')
self.pci_device_configure(dev_sxp)
def hvm_pci_device_create(self, dev_config):
log.debug("XendDomainInfo.hvm_pci_device_create: %s"
+85 -29
View File
@@ -2226,8 +2226,9 @@ def xm_pci_list(args):
if len(devs) == 0:
return
devs.sort(None, lambda x: x['vslot'] << 32 | PCI_BDF(x['domain'], x['bus'],
x['slot'], x['func']))
devs.sort(None,
lambda x: (x['vslot'] - PCI_FUNC(x['vslot'])) << 32 |
PCI_BDF(x['domain'], x['bus'], x['slot'], x['func']))
has_vslot = False
for x in devs:
@@ -2505,7 +2506,7 @@ def xm_network_attach(args):
vif.append(vif_param)
server.xend.domain.device_create(dom, vif)
def parse_pci_configuration(args, state, opts = ''):
def parse_pci_configuration(args, opts = ''):
dom = args[0]
pci_dev_str = args[1]
if len(args) == 3:
@@ -2514,11 +2515,11 @@ def parse_pci_configuration(args, state, opts = ''):
pci_dev_str += ',' + serialise_pci_opts(opts)
try:
pci_dev = parse_pci_name_extended(pci_dev_str)[0]
pci_dev = parse_pci_name_extended(pci_dev_str)
except PciDeviceParseError, ex:
raise OptionError(str(ex))
return (dom, pci_convert_dict_to_sxp(pci_dev, state))
return (dom, pci_dev)
def xm_pci_attach(args):
config_pci_opts = []
@@ -2535,19 +2536,31 @@ def xm_pci_attach(args):
err("Invalid argument for 'xm pci-attach'")
usage('pci-attach')
(dom, pci) = parse_pci_configuration(params, 'Initialising',
config_pci_opts)
(dom, dev) = parse_pci_configuration(params, config_pci_opts)
head_dev = dev.pop(0)
xm_pci_attach_one(dom, head_dev)
# That is all for single-function virtual devices
if len(dev) == 0:
return
# If the slot wasn't spefified in the args then use the slot
# assigned to the head by qemu-xen for the rest of the functions
if int(head_dev['vslot'], 16) & AUTO_PHP_SLOT:
vdevfn = int(find_attached_devfn(attached_pci_dict(dom), head_dev), 16)
if not vdevfn & AUTO_PHP_SLOT:
vslot = PCI_SLOT(vdevfn)
for i in dev:
i['vslot'] = '0x%02x' % \
PCI_DEVFN(vslot, PCI_FUNC(int(i['vslot'], 16)))
for i in dev:
xm_pci_attach_one(dom, i)
def xm_pci_attach_one(dom, pci_dev):
if serverType == SERVER_XEN_API:
pci_dev = sxp.children(pci, 'dev')[0]
domain = int(sxp.child_value(pci_dev, 'domain'), 16)
bus = int(sxp.child_value(pci_dev, 'bus'), 16)
slot = int(sxp.child_value(pci_dev, 'slot'), 16)
func = int(sxp.child_value(pci_dev, 'func'), 16)
vslot = int(sxp.child_value(pci_dev, 'vslot'), 16)
key = sxp.child_value(pci_dev, 'key')
name = "%04x:%02x:%02x.%01x" % (domain, bus, slot, func)
name = pci_dict_to_bdf_str(pci_dev)
target_ref = None
for ppci_ref in server.xenapi.PPCI.get_all():
if name == server.xenapi.PPCI.get_name(ppci_ref):
@@ -2559,13 +2572,14 @@ def xm_pci_attach(args):
dpci_record = {
"VM": get_single_vm(dom),
"PPCI": target_ref,
"hotplug_slot": vslot,
"options": dict(config_pci_opts),
"key": key
"hotplug_slot": int(pci_dev['vslot'], 16),
"options": dict(pci_dev.get('opts', [])),
"key": pci_dev['key']
}
server.xenapi.DPCI.create(dpci_record)
else:
pci = pci_convert_dict_to_sxp(pci_dev, 'Initialising')
server.xend.domain.device_configure(dom, pci)
def parse_scsi_configuration(p_scsi, v_hctl, state):
@@ -2708,20 +2722,61 @@ def xm_network_detach(args):
arg_check(args, 'network-detach', 2, 3)
detach(args, 'vif')
def find_attached(attached, key):
l = filter(lambda dev: pci_dict_cmp(dev, key), attached)
if len(l) == 0:
raise OptionError("pci: device is not attached: " +
pci_dict_to_bdf_str(key))
# There shouldn't ever be more than one match,
# but perhaps an exception should be thrown if there is
return l[0]
def find_attached_devfn(attached, key):
pci_dev = find_attached(attached, key)
return pci_dev['vslot']
def xm_pci_detach(args):
arg_check(args, 'pci-detach', 2)
(dom, pci) = parse_pci_configuration(args, 'Closing')
(dom, dev) = parse_pci_configuration(args)
attached = attached_pci_dict(dom)
attached_dev = map(lambda x: find_attached(attached, x), dev)
def f(pci_dev):
vdevfn = int(pci_dev['vslot'], 16)
return PCI_SLOT(vdevfn) | (vdevfn & AUTO_PHP_SLOT)
vslots = map(f, attached_dev)
if len(set(vslots)) > 1:
err_str = map(lambda x: "\t%s is in slot 0x%02x\n" %
(pci_dict_to_bdf_str(x),
PCI_SLOT(int(x['vslot'], 16))), dev)
raise OptionError("More than one slot used by specified devices\n"
+ ''.join(err_str))
attached_to_slot = filter(lambda x:
f(x) == vslots[0] and
attached_dev[0]["key"] ==
x["key"], attached_dev)
if len(attached_to_slot) != len(dev):
err_str_ = map(lambda x: '\t%s\n' % pci_dict_to_bdf_str(x), dev)
err_str = "Requested:\n" + ''.join(err_str_)
err_str_ = map(lambda x: '\t%s (%s)\n' %
(pci_dict_to_bdf_str(x), x['key']),
attached_to_slot)
err_str += "Present:\n" + ''.join(err_str_)
raise OptionError(("Not all functions in slot 0x%02x have had "
"detachment requested.\n" % vslots[0]) + err_str)
for i in dev:
xm_pci_detach_one(dom, i)
def xm_pci_detach_one(dom, pci_dev):
if serverType == SERVER_XEN_API:
pci_dev = sxp.children(pci, 'dev')[0]
domain = int(sxp.child_value(pci_dev, 'domain'), 16)
bus = int(sxp.child_value(pci_dev, 'bus'), 16)
slot = int(sxp.child_value(pci_dev, 'slot'), 16)
func = int(sxp.child_value(pci_dev, 'func'), 16)
vslot = int(sxp.child_value(pci_dev, 'vslot'), 16)
name = "%04x:%02x:%02x.%01x" % (domain, bus, slot, func)
name = pci_dict_to_bdf_str(pci_dev)
target_ref = None
for dpci_ref in server.xenapi.VM.get_DPCIs(get_single_vm(dom)):
ppci_ref = server.xenapi.DPCI.get_PPCI(dpci_ref)
@@ -2733,6 +2788,7 @@ def xm_pci_detach(args):
raise OptionError("Device %s not assigned" % name)
else:
pci = pci_convert_dict_to_sxp(pci_dev, 'Closing')
server.xend.domain.device_configure(dom, pci)
def xm_scsi_detach(args):
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.