Support os-vif TAP pre-creation for OVS/OVN ports
Add support for os-vif TAP device pre-creation when Neutron sets the 'ovs_create_tap' flag in vif_details. This reduces live migration downtime by ensuring the network is fully wired before the VM starts. Changes: - Add VIF_DETAILS_OVS_CREATE_TAP constant to model.py - Propagate create_tap from binding details to os-vif port profile in os_vif_util.py - Set managed='no' in libvirt XML when create_tap is enabled so libvirt uses the pre-created TAP device - Set multiqueue on port profile in _plug_os_vif based on instance flavor/image hw:vif_multiqueue_enabled property When checking oslo.versionedobjects fields for backward compat: - Use 'field in obj.fields' to check if field exists in schema - Use 'field in obj' to check if field value is set Depends-On: https://review.opendev.org/c/openstack/os-vif/+/971231 Generated-By: Cursor claude-opus-4.5 Closes-Bug: #2069718 Change-Id: I32343658b53e317696d1bd8b984793bfeeccd409 Signed-off-by: Sean Mooney <work@seanmooney.info>
This commit is contained in:
@@ -95,6 +95,11 @@ VIF_DETAILS_TAP_MAC_ADDRESS = 'mac_address'
|
|||||||
VIF_DETAILS_OVS_DATAPATH_SYSTEM = 'system'
|
VIF_DETAILS_OVS_DATAPATH_SYSTEM = 'system'
|
||||||
VIF_DETAILS_OVS_DATAPATH_NETDEV = 'netdev'
|
VIF_DETAILS_OVS_DATAPATH_NETDEV = 'netdev'
|
||||||
|
|
||||||
|
# Specifies whether os-vif should create the TAP device. When True, os-vif
|
||||||
|
# will pre-create the TAP device before adding it to OVS, reducing live
|
||||||
|
# migration downtime. See bug #2069718.
|
||||||
|
VIF_DETAILS_OVS_CREATE_TAP = 'ovs_create_tap'
|
||||||
|
|
||||||
# Define supported virtual NIC types. VNIC_TYPE_DIRECT and VNIC_TYPE_MACVTAP
|
# Define supported virtual NIC types. VNIC_TYPE_DIRECT and VNIC_TYPE_MACVTAP
|
||||||
# are used for SR-IOV ports
|
# are used for SR-IOV ports
|
||||||
VNIC_TYPE_NORMAL = 'normal'
|
VNIC_TYPE_NORMAL = 'normal'
|
||||||
|
|||||||
@@ -332,6 +332,18 @@ def _nova_to_osvif_vif_ovs(vif):
|
|||||||
interface_id=vif.get('ovs_interfaceid') or vif['id'],
|
interface_id=vif.get('ovs_interfaceid') or vif['id'],
|
||||||
datapath_type=vif['details'].get(
|
datapath_type=vif['details'].get(
|
||||||
model.VIF_DETAILS_OVS_DATAPATH_TYPE))
|
model.VIF_DETAILS_OVS_DATAPATH_TYPE))
|
||||||
|
|
||||||
|
# Set create_tap from Neutron binding details if supported by the
|
||||||
|
# os-vif version (check profile.fields for schema, not profile for set
|
||||||
|
# values)
|
||||||
|
create_tap = vif['details'].get(
|
||||||
|
model.VIF_DETAILS_OVS_CREATE_TAP, False)
|
||||||
|
if 'create_tap' in profile.fields:
|
||||||
|
profile.create_tap = create_tap
|
||||||
|
# NOTE: multiqueue is determined by Nova from hw:vif_multiqueue_enabled
|
||||||
|
# flavor extra spec or image property. It is set in _plug_os_vif() in
|
||||||
|
# nova/virt/libvirt/vif.py where the instance is available.
|
||||||
|
|
||||||
if vnic_type in (model.VNIC_TYPE_DIRECT, model.VNIC_TYPE_VDPA):
|
if vnic_type in (model.VNIC_TYPE_DIRECT, model.VNIC_TYPE_VDPA):
|
||||||
obj = _get_vnic_direct_vif_instance(
|
obj = _get_vnic_direct_vif_instance(
|
||||||
vif,
|
vif,
|
||||||
|
|||||||
@@ -473,7 +473,8 @@ class OSVIFUtilTestCase(test.NoDBTestCase):
|
|||||||
port_profile=osv_objects.vif.VIFPortProfileOpenVSwitch(
|
port_profile=osv_objects.vif.VIFPortProfileOpenVSwitch(
|
||||||
interface_id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
|
interface_id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
|
||||||
datapath_type=None,
|
datapath_type=None,
|
||||||
create_port=False),
|
create_port=False,
|
||||||
|
create_tap=False),
|
||||||
preserve_on_delete=False,
|
preserve_on_delete=False,
|
||||||
vif_name="nicdc065497-3c",
|
vif_name="nicdc065497-3c",
|
||||||
network=osv_objects.network.Network(
|
network=osv_objects.network.Network(
|
||||||
@@ -604,7 +605,8 @@ class OSVIFUtilTestCase(test.NoDBTestCase):
|
|||||||
port_profile=osv_objects.vif.VIFPortProfileOpenVSwitch(
|
port_profile=osv_objects.vif.VIFPortProfileOpenVSwitch(
|
||||||
interface_id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
|
interface_id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
|
||||||
datapath_type=model.VIF_DETAILS_OVS_DATAPATH_SYSTEM,
|
datapath_type=model.VIF_DETAILS_OVS_DATAPATH_SYSTEM,
|
||||||
create_port=True),
|
create_port=True,
|
||||||
|
create_tap=False),
|
||||||
preserve_on_delete=False,
|
preserve_on_delete=False,
|
||||||
vif_name="nicdc065497-3c",
|
vif_name="nicdc065497-3c",
|
||||||
network=osv_objects.network.Network(
|
network=osv_objects.network.Network(
|
||||||
@@ -644,7 +646,8 @@ class OSVIFUtilTestCase(test.NoDBTestCase):
|
|||||||
bridge_name="qbrdc065497-3c",
|
bridge_name="qbrdc065497-3c",
|
||||||
port_profile=osv_objects.vif.VIFPortProfileOpenVSwitch(
|
port_profile=osv_objects.vif.VIFPortProfileOpenVSwitch(
|
||||||
interface_id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
|
interface_id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
|
||||||
datapath_type="system"),
|
datapath_type="system",
|
||||||
|
create_tap=False),
|
||||||
preserve_on_delete=False,
|
preserve_on_delete=False,
|
||||||
vif_name="nicdc065497-3c",
|
vif_name="nicdc065497-3c",
|
||||||
network=osv_objects.network.Network(
|
network=osv_objects.network.Network(
|
||||||
@@ -1292,3 +1295,55 @@ class OSVIFUtilTestCase(test.NoDBTestCase):
|
|||||||
objects=[])))
|
objects=[])))
|
||||||
|
|
||||||
self.assertObjEqual(expect, actual)
|
self.assertObjEqual(expect, actual)
|
||||||
|
|
||||||
|
def test_nova_to_osvif_vif_ovs_with_tap_creation(self):
|
||||||
|
"""Test that ovs_create_tap is propagated to create_tap."""
|
||||||
|
vif = model.VIF(
|
||||||
|
id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
|
||||||
|
type=model.VIF_TYPE_OVS,
|
||||||
|
address="22:52:25:62:e2:aa",
|
||||||
|
network=model.Network(
|
||||||
|
id="b82c1929-051e-481d-8110-4669916c7915",
|
||||||
|
label="Demo Net",
|
||||||
|
subnets=[]),
|
||||||
|
details={
|
||||||
|
model.VIF_DETAILS_PORT_FILTER: True,
|
||||||
|
model.VIF_DETAILS_OVS_DATAPATH_TYPE:
|
||||||
|
model.VIF_DETAILS_OVS_DATAPATH_SYSTEM,
|
||||||
|
model.VIF_DETAILS_OVS_CREATE_TAP: True,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
actual = os_vif_util.nova_to_osvif_vif(vif)
|
||||||
|
|
||||||
|
# Verify the port profile has create_tap set
|
||||||
|
self.assertIsInstance(
|
||||||
|
actual.port_profile, osv_objects.vif.VIFPortProfileOpenVSwitch)
|
||||||
|
# Check if the field exists in the schema (for backward compat)
|
||||||
|
if 'create_tap' in actual.port_profile.fields:
|
||||||
|
self.assertTrue(actual.port_profile.create_tap)
|
||||||
|
|
||||||
|
def test_nova_to_osvif_vif_ovs_without_tap_creation(self):
|
||||||
|
"""Test that create_tap defaults to False when not in details."""
|
||||||
|
vif = model.VIF(
|
||||||
|
id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
|
||||||
|
type=model.VIF_TYPE_OVS,
|
||||||
|
address="22:52:25:62:e2:aa",
|
||||||
|
network=model.Network(
|
||||||
|
id="b82c1929-051e-481d-8110-4669916c7915",
|
||||||
|
label="Demo Net",
|
||||||
|
subnets=[]),
|
||||||
|
details={
|
||||||
|
model.VIF_DETAILS_PORT_FILTER: True,
|
||||||
|
model.VIF_DETAILS_OVS_DATAPATH_TYPE:
|
||||||
|
model.VIF_DETAILS_OVS_DATAPATH_SYSTEM,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
actual = os_vif_util.nova_to_osvif_vif(vif)
|
||||||
|
|
||||||
|
# Verify the port profile doesn't have create_tap set to True
|
||||||
|
self.assertIsInstance(
|
||||||
|
actual.port_profile, osv_objects.vif.VIFPortProfileOpenVSwitch)
|
||||||
|
if 'create_tap' in actual.port_profile.fields:
|
||||||
|
self.assertFalse(actual.port_profile.create_tap)
|
||||||
|
|||||||
@@ -1547,6 +1547,107 @@ class LibvirtVifTestCase(test.NoDBTestCase):
|
|||||||
def test_osvif_plug_fail(self):
|
def test_osvif_plug_fail(self):
|
||||||
self._test_osvif_plug(True)
|
self._test_osvif_plug(True)
|
||||||
|
|
||||||
|
@mock.patch("nova.network.os_vif_util.nova_to_osvif_instance")
|
||||||
|
@mock.patch("nova.network.os_vif_util.nova_to_osvif_vif")
|
||||||
|
@mock.patch.object(os_vif, "plug")
|
||||||
|
def test_osvif_plug_multiqueue_with_create_tap(self, mock_plug,
|
||||||
|
mock_convert_vif,
|
||||||
|
mock_convert_inst):
|
||||||
|
"""Test that multiqueue is set on port profile when create_tap=True."""
|
||||||
|
# Skip test if os-vif doesn't support create_tap/multiqueue fields
|
||||||
|
test_prof = osv_objects.vif.VIFPortProfileOpenVSwitch(
|
||||||
|
interface_id="07bd6cea-fb37-4594-b769-90fc51854ee9",
|
||||||
|
profile_id="fishfood")
|
||||||
|
if ('create_tap' not in test_prof.fields or
|
||||||
|
'multiqueue' not in test_prof.fields):
|
||||||
|
self.skipTest("os-vif does not support create_tap/multiqueue")
|
||||||
|
|
||||||
|
# Create a port profile with create_tap=True and multiqueue field
|
||||||
|
os_vif_ovs_tap_prof = osv_objects.vif.VIFPortProfileOpenVSwitch(
|
||||||
|
interface_id="07bd6cea-fb37-4594-b769-90fc51854ee9",
|
||||||
|
profile_id="fishfood",
|
||||||
|
create_tap=True,
|
||||||
|
multiqueue=False) # Will be set to True by _plug_os_vif
|
||||||
|
|
||||||
|
os_vif_ovs_tap = osv_objects.vif.VIFOpenVSwitch(
|
||||||
|
id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
|
||||||
|
address="22:52:25:62:e2:aa",
|
||||||
|
vif_name="nicdc065497-3c",
|
||||||
|
bridge_name="br0",
|
||||||
|
port_profile=os_vif_ovs_tap_prof,
|
||||||
|
network=self.os_vif_network)
|
||||||
|
|
||||||
|
mock_convert_vif.return_value = os_vif_ovs_tap
|
||||||
|
mock_convert_inst.return_value = self.os_vif_inst_info
|
||||||
|
|
||||||
|
# Create an instance with multiqueue enabled via image property
|
||||||
|
ins = objects.Instance(
|
||||||
|
id=1, uuid='f0000000-0000-0000-0000-000000000001',
|
||||||
|
image_ref=uuids.image_ref, flavor=self.flavor_2vcpu,
|
||||||
|
project_id=723,
|
||||||
|
system_metadata={
|
||||||
|
'image_hw_vif_multiqueue_enabled': 'True'
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
d = vif.LibvirtGenericVIFDriver()
|
||||||
|
d.plug(ins, self.vif_ovs)
|
||||||
|
|
||||||
|
# Verify multiqueue was set to True on the port profile
|
||||||
|
self.assertTrue(os_vif_ovs_tap_prof.multiqueue)
|
||||||
|
mock_plug.assert_called_once()
|
||||||
|
|
||||||
|
@mock.patch("nova.network.os_vif_util.nova_to_osvif_instance")
|
||||||
|
@mock.patch("nova.network.os_vif_util.nova_to_osvif_vif")
|
||||||
|
@mock.patch.object(os_vif, "plug")
|
||||||
|
def test_osvif_plug_multiqueue_without_create_tap(self, mock_plug,
|
||||||
|
mock_convert_vif,
|
||||||
|
mock_convert_inst):
|
||||||
|
"""Test multiqueue is NOT set when create_tap=False."""
|
||||||
|
# Skip test if os-vif doesn't support create_tap/multiqueue fields
|
||||||
|
test_prof = osv_objects.vif.VIFPortProfileOpenVSwitch(
|
||||||
|
interface_id="07bd6cea-fb37-4594-b769-90fc51854ee9",
|
||||||
|
profile_id="fishfood")
|
||||||
|
if ('create_tap' not in test_prof.fields or
|
||||||
|
'multiqueue' not in test_prof.fields):
|
||||||
|
self.skipTest("os-vif does not support create_tap/multiqueue")
|
||||||
|
|
||||||
|
# Create a profile with create_port=True but create_tap=False
|
||||||
|
os_vif_ovs_no_tap_prof = osv_objects.vif.VIFPortProfileOpenVSwitch(
|
||||||
|
interface_id="07bd6cea-fb37-4594-b769-90fc51854ee9",
|
||||||
|
profile_id="fishfood",
|
||||||
|
create_port=True,
|
||||||
|
create_tap=False,
|
||||||
|
multiqueue=False)
|
||||||
|
|
||||||
|
os_vif_ovs_no_tap = osv_objects.vif.VIFOpenVSwitch(
|
||||||
|
id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
|
||||||
|
address="22:52:25:62:e2:aa",
|
||||||
|
vif_name="nicdc065497-3c",
|
||||||
|
bridge_name="br0",
|
||||||
|
port_profile=os_vif_ovs_no_tap_prof,
|
||||||
|
network=self.os_vif_network)
|
||||||
|
|
||||||
|
mock_convert_vif.return_value = os_vif_ovs_no_tap
|
||||||
|
mock_convert_inst.return_value = self.os_vif_inst_info
|
||||||
|
|
||||||
|
# Instance with multiqueue enabled
|
||||||
|
ins = objects.Instance(
|
||||||
|
id=1, uuid='f0000000-0000-0000-0000-000000000001',
|
||||||
|
image_ref=uuids.image_ref, flavor=self.flavor_2vcpu,
|
||||||
|
project_id=723,
|
||||||
|
system_metadata={
|
||||||
|
'image_hw_vif_multiqueue_enabled': 'True'
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
d = vif.LibvirtGenericVIFDriver()
|
||||||
|
d.plug(ins, self.vif_ovs)
|
||||||
|
|
||||||
|
# Verify multiqueue was NOT set (remains False) since create_tap=False
|
||||||
|
self.assertFalse(os_vif_ovs_no_tap_prof.multiqueue)
|
||||||
|
mock_plug.assert_called_once()
|
||||||
|
|
||||||
@mock.patch("nova.network.os_vif_util.nova_to_osvif_instance")
|
@mock.patch("nova.network.os_vif_util.nova_to_osvif_instance")
|
||||||
@mock.patch("nova.network.os_vif_util.nova_to_osvif_vif")
|
@mock.patch("nova.network.os_vif_util.nova_to_osvif_vif")
|
||||||
@mock.patch.object(os_vif, "unplug")
|
@mock.patch.object(os_vif, "unplug")
|
||||||
@@ -1725,6 +1826,46 @@ class LibvirtVifTestCase(test.NoDBTestCase):
|
|||||||
|
|
||||||
self._test_config_os_vif(os_vif_type, vif_type, expected_xml)
|
self._test_config_os_vif(os_vif_type, vif_type, expected_xml)
|
||||||
|
|
||||||
|
def test_config_os_vif_ovs_with_create_tap(self):
|
||||||
|
"""Test that create_tap=True results in managed='no' in XML."""
|
||||||
|
# Skip test if os-vif doesn't support create_tap field
|
||||||
|
test_prof = osv_objects.vif.VIFPortProfileOpenVSwitch(
|
||||||
|
interface_id="07bd6cea-fb37-4594-b769-90fc51854ee9",
|
||||||
|
profile_id="fishfood")
|
||||||
|
if 'create_tap' not in test_prof.fields:
|
||||||
|
self.skipTest("os-vif does not support create_tap")
|
||||||
|
|
||||||
|
# Create a port profile with create_tap=True
|
||||||
|
os_vif_ovs_tap_prof = osv_objects.vif.VIFPortProfileOpenVSwitch(
|
||||||
|
interface_id="07bd6cea-fb37-4594-b769-90fc51854ee9",
|
||||||
|
profile_id="fishfood",
|
||||||
|
create_tap=True)
|
||||||
|
|
||||||
|
os_vif_type = osv_objects.vif.VIFOpenVSwitch(
|
||||||
|
id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
|
||||||
|
address="22:52:25:62:e2:aa",
|
||||||
|
vif_name="nicdc065497-3c",
|
||||||
|
bridge_name="br0",
|
||||||
|
port_profile=os_vif_ovs_tap_prof,
|
||||||
|
network=self.os_vif_network)
|
||||||
|
|
||||||
|
vif_type = self.vif_ovs
|
||||||
|
|
||||||
|
# Expected XML should have managed="no" on the target element
|
||||||
|
expected_xml = """
|
||||||
|
<interface type="ethernet">
|
||||||
|
<mac address="22:52:25:62:e2:aa"/>
|
||||||
|
<model type="virtio"/>
|
||||||
|
<mtu size="9000"/>
|
||||||
|
<target dev="nicdc065497-3c" managed="no"/>
|
||||||
|
<bandwidth>
|
||||||
|
<inbound average="100" peak="200" burst="300"/>
|
||||||
|
<outbound average="10" peak="20" burst="30"/>
|
||||||
|
</bandwidth>
|
||||||
|
</interface>"""
|
||||||
|
|
||||||
|
self._test_config_os_vif(os_vif_type, vif_type, expected_xml)
|
||||||
|
|
||||||
def test_config_os_vif_hostdevice_ethernet(self):
|
def test_config_os_vif_hostdevice_ethernet(self):
|
||||||
os_vif_type = self.os_vif_hostdevice_ethernet
|
os_vif_type = self.os_vif_hostdevice_ethernet
|
||||||
vif_type = self.vif_bridge
|
vif_type = self.vif_bridge
|
||||||
|
|||||||
@@ -457,9 +457,33 @@ class LibvirtGenericVIFDriver(object):
|
|||||||
conf.target_dev = vif.vif_name
|
conf.target_dev = vif.vif_name
|
||||||
|
|
||||||
def _set_config_VIFOpenVSwitch(self, instance, vif, conf):
|
def _set_config_VIFOpenVSwitch(self, instance, vif, conf):
|
||||||
# if delegating creation to os-vif, create an ethernet-type VIF and let
|
# Check if os-vif will create the TAP device (with backward compat
|
||||||
# os-vif do the actual wiring up
|
# check for older os-vif versions that don't have create_tap field)
|
||||||
if 'create_port' in vif.port_profile and vif.port_profile.create_port:
|
# NOTE: 'field in profile.fields' checks schema existence,
|
||||||
|
# 'field in profile' checks if the attribute is set
|
||||||
|
create_tap = (
|
||||||
|
'create_tap' in vif.port_profile.fields and
|
||||||
|
'create_tap' in vif.port_profile and
|
||||||
|
vif.port_profile.create_tap
|
||||||
|
)
|
||||||
|
# Check if delegating port creation to os-vif
|
||||||
|
create_port = (
|
||||||
|
'create_port' in vif.port_profile.fields and
|
||||||
|
'create_port' in vif.port_profile and
|
||||||
|
vif.port_profile.create_port
|
||||||
|
)
|
||||||
|
|
||||||
|
# TODO(sean-k-mooney): we should always delegate to os-vif and have
|
||||||
|
# os-vif create the tap once we are sure all compute nodes are
|
||||||
|
# upgraded. Simplify this logic in 2026.2+
|
||||||
|
if create_tap:
|
||||||
|
# os-vif will create the TAP device, so use ethernet-type VIF
|
||||||
|
# and set managed=no so libvirt uses the existing TAP device
|
||||||
|
self._set_config_VIFGeneric(instance, vif, conf)
|
||||||
|
conf.managed = "no"
|
||||||
|
elif create_port:
|
||||||
|
# Delegating creation to os-vif, create an ethernet-type VIF
|
||||||
|
# and let os-vif do the actual wiring up
|
||||||
self._set_config_VIFGeneric(instance, vif, conf)
|
self._set_config_VIFGeneric(instance, vif, conf)
|
||||||
else:
|
else:
|
||||||
conf.net_type = "bridge"
|
conf.net_type = "bridge"
|
||||||
@@ -706,6 +730,24 @@ class LibvirtGenericVIFDriver(object):
|
|||||||
def _plug_os_vif(self, instance, vif):
|
def _plug_os_vif(self, instance, vif):
|
||||||
instance_info = os_vif_util.nova_to_osvif_instance(instance)
|
instance_info = os_vif_util.nova_to_osvif_instance(instance)
|
||||||
|
|
||||||
|
# Set multiqueue on the port profile if create_tap is enabled and
|
||||||
|
# the instance has multiqueue enabled via flavor/image properties.
|
||||||
|
# This must be done here because nova_to_osvif_vif doesn't have
|
||||||
|
# access to the instance.
|
||||||
|
# NOTE: 'field in obj.fields' checks schema existence,
|
||||||
|
# 'field in obj' checks if the attribute is set on the instance
|
||||||
|
if ('port_profile' in vif.fields and
|
||||||
|
'port_profile' in vif):
|
||||||
|
profile = vif.port_profile
|
||||||
|
if (profile is not None and
|
||||||
|
'create_tap' in profile.fields and
|
||||||
|
'create_tap' in profile and
|
||||||
|
profile.create_tap and
|
||||||
|
'multiqueue' in profile.fields):
|
||||||
|
multiqueue = hardware.get_vif_multiqueue_constraint(
|
||||||
|
instance.flavor, instance.image_meta)
|
||||||
|
profile.multiqueue = multiqueue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os_vif.plug(vif, instance_info)
|
os_vif.plug(vif, instance_info)
|
||||||
except osv_exception.ExceptionBase as ex:
|
except osv_exception.ExceptionBase as ex:
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
Updated nova to support os-vif TAP device pre-creation for OVN ports.
|
||||||
|
When Neutron sets ``ovs_create_tap`` in vif_details (enabled via
|
||||||
|
the ``[ovn]/ovs_create_tap`` config option in the ML2 driver config),
|
||||||
|
Nova propagates this to os-vif which creates the TAP
|
||||||
|
device before libvirt starts the VM. Nova then configures libvirt with
|
||||||
|
``managed="no"`` so it uses the pre-created TAP device instead of creating
|
||||||
|
a new one. This allows nova via os-vif to pre create the tap device in
|
||||||
|
pre live migration allowing ovn to install openflow rules before nova
|
||||||
|
starts the live migration. This reduces network connectivity downtime
|
||||||
|
when ovn is overloaded.
|
||||||
|
|
||||||
|
See `bug 2069718 <https://bugs.launchpad.net/neutron/+bug/2069718>`_.
|
||||||
Reference in New Issue
Block a user