diff --git a/nova/pci/utils.py b/nova/pci/utils.py
index 80b8c35f8b99..e10a30315662 100644
--- a/nova/pci/utils.py
+++ b/nova/pci/utils.py
@@ -69,6 +69,10 @@ def get_pci_address_fields(pci_addr):
return (domain, bus, slot, func)
+def get_pci_address(domain, bus, slot, func):
+ return '%s:%s:%s.%s' % (domain, bus, slot, func)
+
+
def get_function_by_ifname(ifname):
"""Given the device name, returns the PCI address of a device
and returns True if the address in a physical function.
diff --git a/nova/tests/unit/virt/libvirt/test_config.py b/nova/tests/unit/virt/libvirt/test_config.py
index 08d570c0ad15..98a22df57f3a 100644
--- a/nova/tests/unit/virt/libvirt/test_config.py
+++ b/nova/tests/unit/virt/libvirt/test_config.py
@@ -1302,6 +1302,12 @@ class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest):
""")
+ # parse the xml from the first object into a new object and make sure
+ # they are the same
+ obj2 = config.LibvirtConfigGuestInterface()
+ obj2.parse_str(xml)
+ self.assertXmlEqual(xml, obj2.to_xml())
+
def test_config_driver_options(self):
obj = config.LibvirtConfigGuestInterface()
obj.net_type = "ethernet"
@@ -1320,6 +1326,12 @@ class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest):
""")
+ # parse the xml from the first object into a new object and make sure
+ # they are the same
+ obj2 = config.LibvirtConfigGuestInterface()
+ obj2.parse_str(xml)
+ self.assertXmlEqual(xml, obj2.to_xml())
+
def test_config_bridge(self):
obj = config.LibvirtConfigGuestInterface()
obj.net_type = "bridge"
@@ -1352,6 +1364,12 @@ class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest):
""")
+ # parse the xml from the first object into a new object and make sure
+ # they are the same
+ obj2 = config.LibvirtConfigGuestInterface()
+ obj2.parse_str(xml)
+ self.assertXmlEqual(xml, obj2.to_xml())
+
def test_config_bridge_ovs(self):
obj = config.LibvirtConfigGuestInterface()
obj.net_type = "bridge"
@@ -1374,6 +1392,12 @@ class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest):
""")
+ # parse the xml from the first object into a new object and make sure
+ # they are the same
+ obj2 = config.LibvirtConfigGuestInterface()
+ obj2.parse_str(xml)
+ self.assertXmlEqual(xml, obj2.to_xml())
+
def test_config_bridge_xen(self):
obj = config.LibvirtConfigGuestInterface()
obj.net_type = "bridge"
@@ -1389,6 +1413,12 @@ class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest):
""")
+ # parse the xml from the first object into a new object and make sure
+ # they are the same
+ obj2 = config.LibvirtConfigGuestInterface()
+ obj2.parse_str(xml)
+ self.assertXmlEqual(xml, obj2.to_xml())
+
def test_config_8021Qbh(self):
obj = config.LibvirtConfigGuestInterface()
obj.net_type = "direct"
@@ -1408,6 +1438,12 @@ class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest):
""")
+ # parse the xml from the first object into a new object and make sure
+ # they are the same
+ obj2 = config.LibvirtConfigGuestInterface()
+ obj2.parse_str(xml)
+ self.assertXmlEqual(xml, obj2.to_xml())
+
def test_config_direct(self):
obj = config.LibvirtConfigGuestInterface()
obj.net_type = "direct"
@@ -1424,6 +1460,12 @@ class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest):
""")
+ # parse the xml from the first object into a new object and make sure
+ # they are the same
+ obj2 = config.LibvirtConfigGuestInterface()
+ obj2.parse_str(xml)
+ self.assertXmlEqual(xml, obj2.to_xml())
+
def test_config_8021Qbh_hostdev(self):
obj = config.LibvirtConfigGuestInterface()
obj.net_type = "hostdev"
@@ -1445,6 +1487,12 @@ class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest):
""")
+ # parse the xml from the first object into a new object and make sure
+ # they are the same
+ obj2 = config.LibvirtConfigGuestInterface()
+ obj2.parse_str(xml)
+ self.assertXmlEqual(xml, obj2.to_xml())
+
def test_config_hw_veb_hostdev(self):
obj = config.LibvirtConfigGuestInterface()
obj.net_type = "hostdev"
@@ -1465,6 +1513,12 @@ class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest):
""")
+ # parse the xml from the first object into a new object and make sure
+ # they are the same
+ obj2 = config.LibvirtConfigGuestInterface()
+ obj2.parse_str(xml)
+ self.assertXmlEqual(xml, obj2.to_xml())
+
def test_config_vhostuser(self):
obj = config.LibvirtConfigGuestInterface()
obj.net_type = "vhostuser"
@@ -1481,6 +1535,12 @@ class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest):
""")
+ # parse the xml from the first object into a new object and make sure
+ # they are the same
+ obj2 = config.LibvirtConfigGuestInterface()
+ obj2.parse_str(xml)
+ self.assertXmlEqual(xml, obj2.to_xml())
+
class LibvirtConfigGuestFeatureTest(LibvirtConfigBaseTest):
diff --git a/nova/tests/unit/virt/libvirt/test_guest.py b/nova/tests/unit/virt/libvirt/test_guest.py
index 0be0d0922057..a2c818ae4b50 100644
--- a/nova/tests/unit/virt/libvirt/test_guest.py
+++ b/nova/tests/unit/virt/libvirt/test_guest.py
@@ -363,6 +363,13 @@ class GuestTestCase(test.NoDBTestCase):
+
+
+
+
+
+
+
@@ -373,14 +380,15 @@ class GuestTestCase(test.NoDBTestCase):
self.domain.XMLDesc.return_value = xml
devs = self.guest.get_all_devices()
- # Only currently parse and elements
+ # Only currently parse , and elements
# hence we're not counting the controller/memballoon
- self.assertEqual(5, len(devs))
+ self.assertEqual(6, len(devs))
self.assertIsInstance(devs[0], vconfig.LibvirtConfigGuestDisk)
self.assertIsInstance(devs[1], vconfig.LibvirtConfigGuestDisk)
self.assertIsInstance(devs[2], vconfig.LibvirtConfigGuestDisk)
self.assertIsInstance(devs[3], vconfig.LibvirtConfigGuestHostdev)
self.assertIsInstance(devs[4], vconfig.LibvirtConfigGuestHostdev)
+ self.assertIsInstance(devs[5], vconfig.LibvirtConfigGuestInterface)
devs = self.guest.get_all_devices(vconfig.LibvirtConfigGuestDisk)
self.assertEqual(3, len(devs))
@@ -399,6 +407,10 @@ class GuestTestCase(test.NoDBTestCase):
self.assertIsInstance(devs[0], vconfig.LibvirtConfigGuestHostdev)
self.assertIsInstance(devs[1], vconfig.LibvirtConfigGuestHostdev)
+ devs = self.guest.get_all_devices(vconfig.LibvirtConfigGuestInterface)
+ self.assertEqual(1, len(devs))
+ self.assertIsInstance(devs[0], vconfig.LibvirtConfigGuestInterface)
+
def test_get_info(self):
self.domain.info.return_value = (1, 2, 3, 4, 5)
self.domain.ID.return_value = 6
diff --git a/nova/virt/libvirt/config.py b/nova/virt/libvirt/config.py
index 7969e58836d0..1fe41eef52b2 100644
--- a/nova/virt/libvirt/config.py
+++ b/nova/virt/libvirt/config.py
@@ -1255,6 +1255,84 @@ class LibvirtConfigGuestInterface(LibvirtConfigGuestDevice):
return dev
+ def parse_dom(self, xmldoc):
+ super(LibvirtConfigGuestInterface, self).parse_dom(xmldoc)
+
+ self.net_type = xmldoc.get('type')
+
+ for c in xmldoc.getchildren():
+ if c.tag == 'mac':
+ self.mac_addr = c.get('address')
+ elif c.tag == 'model':
+ self.model = c.get('type')
+ elif c.tag == 'driver':
+ self.driver_name = c.get('name')
+ self.vhost_queues = c.get('queues')
+ elif c.tag == 'source':
+ if self.net_type == 'direct':
+ self.source_dev = c.get('dev')
+ self.source_mode = c.get('mode', 'private')
+ elif self.net_type == 'vhostuser':
+ self.vhostuser_type = c.get('type')
+ self.vhostuser_mode = c.get('mode')
+ self.vhostuser_path = c.get('path')
+ elif self.net_type == 'hostdev':
+ for sub in c.getchildren():
+ if sub.tag == 'address' and sub.get('type') == 'pci':
+ # strip the 0x prefix on each attribute since
+ # format_dom puts them back on - note that
+ # LibvirtConfigGuestHostdevPCI does not do this...
+ self.source_dev = (
+ pci_utils.get_pci_address(
+ sub.get('domain')[2:],
+ sub.get('bus')[2:],
+ sub.get('slot')[2:],
+ sub.get('function')[2:]
+ )
+ )
+ else:
+ self.source_dev = c.get('bridge')
+ elif c.tag == 'target':
+ self.target_dev = c.get('dev')
+ elif c.tag == 'script':
+ self.script = c.get('path')
+ elif c.tag == 'vlan':
+ # NOTE(mriedem): The vlan element can have multiple tag
+ # sub-elements but we're currently only storing a single tag
+ # id in the vlan attribute.
+ for sub in c.getchildren():
+ if sub.tag == 'tag' and sub.get('id'):
+ self.vlan = sub.get('id')
+ break
+ elif c.tag == 'virtualport':
+ self.vporttype = c.get('type')
+ for sub in c.getchildren():
+ if sub.tag == 'parameters':
+ for k, v in dict(sub.attrib).items():
+ self.add_vport_param(k, v)
+ elif c.tag == 'filterref':
+ self.filtername = c.get('filter')
+ for sub in c.getchildren():
+ if sub.tag == 'parameter':
+ self.add_filter_param(sub.get('name'),
+ sub.get('value'))
+ elif c.tag == 'bandwidth':
+ for sub in c.getchildren():
+ # Note that only average is mandatory, burst and peak are
+ # optional (and all are ints).
+ if sub.tag == 'inbound':
+ self.vif_inbound_average = int(sub.get('average'))
+ if sub.get('burst'):
+ self.vif_inbound_burst = int(sub.get('burst'))
+ if sub.get('peak'):
+ self.vif_inbound_peak = int(sub.get('peak'))
+ elif sub.tag == 'outbound':
+ self.vif_outbound_average = int(sub.get('average'))
+ if sub.get('burst'):
+ self.vif_outbound_burst = int(sub.get('burst'))
+ if sub.get('peak'):
+ self.vif_outbound_peak = int(sub.get('peak'))
+
def add_filter_param(self, key, value):
self.filterparams.append({'key': key, 'value': value})
@@ -1992,6 +2070,7 @@ class LibvirtConfigGuest(LibvirtConfigObject):
def parse_dom(self, xmldoc):
# Note: This cover only for: LibvirtConfigGuestDisks
# LibvirtConfigGuestHostdevPCI
+ # LibvirtConfigGuestInterface
# LibvirtConfigGuestUidMap
# LibvirtConfigGuestGidMap
# LibvirtConfigGuestCPU
@@ -2006,6 +2085,10 @@ class LibvirtConfigGuest(LibvirtConfigObject):
obj = LibvirtConfigGuestHostdevPCI()
obj.parse_dom(d)
self.devices.append(obj)
+ elif d.tag == 'interface':
+ obj = LibvirtConfigGuestInterface()
+ obj.parse_dom(d)
+ self.devices.append(obj)
if c.tag == 'idmap':
for map in c.getchildren():
obj = None