addhardware: differentiate duplicate usb devices by bus/addr

When there are multiple usb devices with same vendor/product
in the host device list, the bus/addr is going to be used when
attaching one of usb devices.

Currently is_dup flag is only useful to VirtualHostDeviceUSB.

I put get_nodedevs_number() in connection.py, so the startup
hooks can use it.
This commit is contained in:
Guannan Ren 2013-04-30 22:53:10 +08:00 committed by Cole Robinson
parent 4c1039252a
commit 32f0781531
5 changed files with 45 additions and 14 deletions

View File

@ -1,5 +1,7 @@
<hostdev mode='subsystem' type='usb' managed='yes'>
<source>
<vendor id='0x0781'/>
<product id='0x5151'/>
<address bus='1' device='4'/>
</source>
</hostdev>

View File

@ -53,12 +53,12 @@ class TestNodeDev(unittest.TestCase):
for attr in vals.keys():
self.assertEqual(vals[attr], getattr(dev, attr))
def _testNode2DeviceCompare(self, nodename, devfile, nodedev=None):
def _testNode2DeviceCompare(self, nodename, devfile, nodedev=None, is_dup=False):
devfile = os.path.join("tests/nodedev-xml/devxml", devfile)
if not nodedev:
nodedev = self._nodeDevFromName(nodename)
dev = VirtualHostDevice.device_from_node(conn, nodedev=nodedev)
dev = VirtualHostDevice.device_from_node(conn, nodedev=nodedev, is_dup=is_dup)
utils.diff_compare(dev.get_xml_config() + "\n", devfile)
def testSystemDevice(self):
@ -202,11 +202,7 @@ class TestNodeDev(unittest.TestCase):
devfile = "usbdev2.xml"
nodedev = self._nodeDevFromName(nodename)
# Force xml building to use bus, addr
nodedev.product_id = None
nodedev.vendor_id = None
self._testNode2DeviceCompare(nodename, devfile, nodedev=nodedev)
self._testNode2DeviceCompare(nodename, devfile, nodedev=nodedev, is_dup=True)
def testNodeDev2PCI(self):
nodename = "pci_1180_592"

View File

@ -281,7 +281,7 @@ class vmmAddHardware(vmmGObjectUI):
# Host device list
# model = [ Description, nodedev name ]
host_dev = self.widget("host-device")
host_dev_model = Gtk.ListStore(str, str)
host_dev_model = Gtk.ListStore(str, str, str, object)
host_dev.set_model(host_dev_model)
host_col = Gtk.TreeViewColumn()
@ -577,7 +577,7 @@ class vmmAddHardware(vmmGObjectUI):
if dev.name == subdev.parent:
prettyname = dev.pretty_name(subdev)
model.append([prettyname, dev.name])
model.append([prettyname, dev.name, devtype, dev])
if len(model) == 0:
model.append([_("No Devices Available"), None])
@ -1403,15 +1403,32 @@ class vmmAddHardware(vmmGObjectUI):
def validate_page_hostdev(self):
ret = self.get_config_host_device_info()
nodedev_name = ret and ret[1] or None
is_dup = False
if nodedev_name is None:
return self.err.val_err(_("Physical Device Required"),
_("A device must be selected."))
devtype = ret[2]
nodedev = ret[3]
if devtype == "usb_device":
vendor = nodedev.vendor_id
product = nodedev.product_id
count = self.conn.get_nodedevs_number(devtype, vendor, product)
if not count:
raise RuntimeError(_("Could not find USB device "
"(vendorId: %s, productId: %s) "
% (vendor, product)))
if count > 1:
is_dup = True
try:
self._dev = virtinst.VirtualHostDevice.device_from_node(
conn=self.conn.vmm,
name=nodedev_name)
name=nodedev_name,
nodedev=nodedev,
is_dup=is_dup)
except Exception, e:
return self.err.val_err(_("Host device parameter error"), e)

View File

@ -712,6 +712,21 @@ class vmmConnection(vmmGObject):
return retdevs
def get_nodedevs_number(self, devtype, vendor, product):
count = 0
devs = self.get_nodedevs(devtype)
for dev in devs:
if vendor == dev.vendor_id and \
product == dev.product_id:
count += 1
logging.debug("There are %d node devices with "
"vendorId: %s, productId: %s",
count, vendor, product)
return count
def get_net_by_name(self, name):
for net in self.nets.values():
if net.get_name() == name:

View File

@ -28,7 +28,7 @@ class VirtualHostDevice(VirtualDevice):
_virtual_device_type = VirtualDevice.VIRTUAL_DEV_HOSTDEV
def device_from_node(conn, name=None, nodedev=None):
def device_from_node(conn, name=None, nodedev=None, is_dup=False):
"""
Convert the passed device name to a VirtualHostDevice
instance, with proper error reporting. Name can be any of the
@ -56,7 +56,7 @@ class VirtualHostDevice(VirtualDevice):
if isinstance(nodeinst, NodeDeviceParser.PCIDevice):
return VirtualHostDevicePCI(conn, nodedev=nodeinst)
elif isinstance(nodeinst, NodeDeviceParser.USBDevice):
return VirtualHostDeviceUSB(conn, nodedev=nodeinst)
return VirtualHostDeviceUSB(conn, nodedev=nodeinst, is_dup=is_dup)
elif isinstance(nodeinst, NodeDeviceParser.NetDevice):
parentname = nodeinst.parent
try:
@ -198,11 +198,12 @@ class VirtualHostDevice(VirtualDevice):
class VirtualHostDeviceUSB(VirtualHostDevice):
def __init__(self, conn, nodedev=None):
def __init__(self, conn, nodedev=None, is_dup=False):
VirtualHostDevice.__init__(self, conn, nodedev)
self.mode = "subsystem"
self.type = "usb"
self.is_dup = is_dup
self._set_from_nodedev(self._nodedev)
@ -217,7 +218,7 @@ class VirtualHostDeviceUSB(VirtualHostDevice):
self.vendor = nodedev.vendor_id
self.product = nodedev.product_id
if not (self.vendor or self.product):
if self.is_dup:
self.bus = nodedev.bus
self.device = nodedev.device