Add managed='no' flag to libvirt XML definition for VIF type TAP
libvirt 9.5.0 and later by default doesn't allow using a pre-created TAP device; instead it expects to create and manage the TAP device itself, which is incompatible with how Nova works. To restore compatibility with Nova we need to add the managed="no" flag to the target device section in the XML domain file. The libvirt change is here[1]. In particular it breaks Calico for OpenStack, because the Calico plugin (out of tree[2]) uses VIF type TAP. 1. https://github.com/libvirt/libvirt/commit/a2ae3d299cf 2. https://github.com/projectcalico/calico/blob/master/networking-calico/networking_calico/plugins/ml2/drivers/calico/mech_calico.py#L217 Many thanks to Masahito Muroi <masahito.muroi@linecorp.com> for proposing an earlier version of this fix. Closes-Bug: #2033681 Change-Id: I4a7b4ecf69cfe04c5291e5ca2a76db8829d6e592 Signed-off-by: Nell Jerram <nell@tigera.io>
This commit is contained in:
@@ -2103,6 +2103,7 @@ class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest):
|
||||
def test_config_ethernet(self):
|
||||
obj = config.LibvirtConfigGuestInterface()
|
||||
obj.net_type = "ethernet"
|
||||
obj.managed = "no"
|
||||
obj.mac_addr = "DE:AD:BE:EF:CA:FE"
|
||||
obj.model = "virtio"
|
||||
obj.target_dev = "vnet0"
|
||||
@@ -2120,7 +2121,7 @@ class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest):
|
||||
<mac address="DE:AD:BE:EF:CA:FE"/>
|
||||
<model type="virtio"/>
|
||||
<driver name="vhost"/>
|
||||
<target dev="vnet0"/>
|
||||
<target dev="vnet0" managed="no"/>
|
||||
<bandwidth>
|
||||
<inbound average="16384" peak="32768" burst="3276"/>
|
||||
<outbound average="32768" peak="65536" burst="6553"/>
|
||||
@@ -2136,6 +2137,7 @@ class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest):
|
||||
def test_config_ethernet_with_mtu(self):
|
||||
obj = config.LibvirtConfigGuestInterface()
|
||||
obj.net_type = "ethernet"
|
||||
obj.managed = "no"
|
||||
obj.mac_addr = "DE:AD:BE:EF:CA:FE"
|
||||
obj.model = "virtio"
|
||||
obj.target_dev = "vnet0"
|
||||
@@ -2155,7 +2157,7 @@ class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest):
|
||||
<model type="virtio"/>
|
||||
<driver name="vhost"/>
|
||||
<mtu size="9000"/>
|
||||
<target dev="vnet0"/>
|
||||
<target dev="vnet0" managed="no"/>
|
||||
<bandwidth>
|
||||
<inbound average="16384" peak="32768" burst="3276"/>
|
||||
<outbound average="32768" peak="65536" burst="6553"/>
|
||||
|
||||
@@ -540,14 +540,18 @@ class LibvirtVifTestCase(test.NoDBTestCase):
|
||||
mac = node.find("mac").get("address")
|
||||
self.assertEqual(mac, vif['address'])
|
||||
|
||||
def _assertTypeEquals(self, node, type, attr, source, br_want):
|
||||
def _assertTypeEquals(self, node, type, attr, source, br_want,
|
||||
managed_want=None):
|
||||
self.assertEqual(node.get("type"), type)
|
||||
br_name = node.find(attr).get(source)
|
||||
self.assertEqual(br_name, br_want)
|
||||
if managed_want is not None:
|
||||
managed = node.find(attr).get("managed")
|
||||
self.assertEqual(managed, managed_want)
|
||||
|
||||
def _assertTypeAndMacEquals(self, node, type, attr, source, vif,
|
||||
br_want=None):
|
||||
self._assertTypeEquals(node, type, attr, source, br_want)
|
||||
br_want=None, managed_want=None):
|
||||
self._assertTypeEquals(node, type, attr, source, br_want, managed_want)
|
||||
self._assertMacEquals(node, vif)
|
||||
|
||||
def _assertModel(self, xml, model_want=None, driver_want=None):
|
||||
@@ -1113,7 +1117,7 @@ class LibvirtVifTestCase(test.NoDBTestCase):
|
||||
xml = self._get_instance_xml(d, self.vif_tap)
|
||||
node = self._get_node(xml)
|
||||
self._assertTypeAndMacEquals(node, "ethernet", "target", "dev",
|
||||
self.vif_tap, br_want)
|
||||
self.vif_tap, br_want, "no")
|
||||
|
||||
@mock.patch('nova.privsep.linux_net.device_exists', return_value=True)
|
||||
@mock.patch('nova.privsep.linux_net.set_device_mtu')
|
||||
|
||||
@@ -1913,6 +1913,7 @@ class LibvirtConfigGuestInterface(LibvirtConfigGuestDevice):
|
||||
self.device_addr = None
|
||||
self.mtu = None
|
||||
self.alias = None
|
||||
self.managed = None
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, LibvirtConfigGuestInterface):
|
||||
@@ -2019,7 +2020,11 @@ class LibvirtConfigGuestInterface(LibvirtConfigGuestDevice):
|
||||
dev.append(vlan_elem)
|
||||
|
||||
if self.target_dev is not None:
|
||||
dev.append(etree.Element("target", dev=self.target_dev))
|
||||
if self.managed is not None:
|
||||
dev.append(etree.Element("target", dev=self.target_dev,
|
||||
managed=self.managed))
|
||||
else:
|
||||
dev.append(etree.Element("target", dev=self.target_dev))
|
||||
|
||||
if self.vporttype is not None:
|
||||
vport = etree.Element("virtualport", type=self.vporttype)
|
||||
@@ -2105,6 +2110,7 @@ class LibvirtConfigGuestInterface(LibvirtConfigGuestDevice):
|
||||
self.source_dev = c.get('bridge')
|
||||
elif c.tag == 'target':
|
||||
self.target_dev = c.get('dev')
|
||||
self.managed = c.get('managed')
|
||||
elif c.tag == 'script':
|
||||
self.script = c.get('path')
|
||||
elif c.tag == 'vlan':
|
||||
|
||||
@@ -435,6 +435,7 @@ class LibvirtGenericVIFDriver(object):
|
||||
|
||||
dev = self.get_vif_devname(vif)
|
||||
designer.set_vif_host_backend_ethernet_config(conf, dev)
|
||||
conf.managed = "no"
|
||||
|
||||
network = vif.get('network')
|
||||
if network and network.get_meta('mtu'):
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Nova operation with VIF type TAP was broken by a libvirt change (in 9.5.0)
|
||||
to treat TAP interface specifications as "managed" by default. This means
|
||||
that libvirt expects to create the TAP interface itself, which is
|
||||
incompatible with how Nova works, because Nova creates the TAP interface
|
||||
before telling libvirt about it. In particular this broke OpenStack with
|
||||
Calico as the network plugin, because Calico uses VIF type TAP.
|
||||
|
||||
This is now fixed, by Nova adding the `managed="no"` attribute to TAP
|
||||
interface XML specifications.
|
||||
|
||||
See `bug 2033681`_ for more details.
|
||||
|
||||
.. _bug 2033681: https://bugs.launchpad.net/nova/+bug/2033681
|
||||
Reference in New Issue
Block a user