Check the device ID and host ID during virtual port binding
If a port receives a device ID and a binding profile host ID fields update, at the same time, this is because Nova is trying to bind the port to a VM (device ID) in a host (host ID). In ML2/OVN, a virtual port cannot be bound to a VM. NOTE: * A virtual port can receive a host ID update. That happens when the fixed IP port that has the virtual port IP address as allowed address pair is bound. * A virtual port can receive a devide ID update. Octavia uses the devide ID to identify to what load balancer the virtual port belongs. This check was introduced in [1]. [1]https://review.opendev.org/c/openstack/neutron/+/882588 Closes-Bug: #2028651 Related-Bug: #2018529 Change-Id: I8784c6716f5a53b91d43323771e6f30fa8e8e506
This commit is contained in:
parent
bffb88f5f8
commit
a3b00768d6
@ -1059,10 +1059,13 @@ def determine_bind_host(sb_idl, port, port_context=None):
|
||||
|
||||
|
||||
def validate_port_binding_and_virtual_port(
|
||||
port_context, nb_idl, sb_idl, ml2_plugin, port):
|
||||
port_context, nb_idl, ml2_plugin, port, original_port):
|
||||
"""If the port is type=virtual and it is bound, raise BadRequest"""
|
||||
if not determine_bind_host(sb_idl, port, port_context=port_context):
|
||||
# The port is not bound, exit.
|
||||
# If the port receives an update of the device ID and the binding profile
|
||||
# host ID fields, at the same time, this is because Nova is trying to bind
|
||||
# the port to a VM (device ID) in a host (host ID).
|
||||
if not (port['device_id'] != original_port['device_id'] and
|
||||
port[portbindings.HOST_ID] != original_port[portbindings.HOST_ID]):
|
||||
return
|
||||
|
||||
fixed_ips = port.get('fixed_ips', [])
|
||||
|
@ -823,7 +823,7 @@ class OVNMechanismDriver(api.MechanismDriver):
|
||||
ovn_utils.validate_and_get_data_from_binding_profile(port)
|
||||
self._validate_port_extra_dhcp_opts(port)
|
||||
ovn_utils.validate_port_binding_and_virtual_port(
|
||||
context, self.nb_ovn, self.sb_ovn, self._plugin, port)
|
||||
context, self.nb_ovn, self._plugin, port, original_port)
|
||||
if self._is_port_provisioning_required(port, context.host,
|
||||
context.original_host):
|
||||
self._insert_port_provisioning_block(context.plugin_context,
|
||||
|
@ -4434,20 +4434,21 @@ class TestOVNVVirtualPort(OVNMechanismDriverTestCase):
|
||||
with self.port(subnet=self.subnet, is_admin=True) as port:
|
||||
port = port['port']
|
||||
updated_port = copy.deepcopy(port)
|
||||
updated_port[portbindings.HOST_ID] = 'host1'
|
||||
context = mock.Mock(current=updated_port, original=port)
|
||||
updated_port['device_id'] = 'device_id_new'
|
||||
updated_port[portbindings.HOST_ID] = 'host_id_new'
|
||||
_context = mock.Mock(current=updated_port, original=port)
|
||||
with mock.patch.object(self.mech_driver._plugin, 'get_subnets') \
|
||||
as mock_get_subnets:
|
||||
mock_get_subnets.return_value = [self.subnet['subnet']]
|
||||
# 1) The port is not virtual, it has no parents.
|
||||
self.mock_vp_parents.return_value = ''
|
||||
self.mech_driver.update_port_precommit(context)
|
||||
self.mech_driver.update_port_precommit(_context)
|
||||
# 2) The port (LSP) has parents, that means it is a virtual
|
||||
# port.
|
||||
self.mock_vp_parents.return_value = ['parent-0', 'parent-1']
|
||||
self.assertRaises(n_exc.BadRequest,
|
||||
self.mech_driver.update_port_precommit,
|
||||
context)
|
||||
_context)
|
||||
|
||||
|
||||
class TestOVNAvailabilityZone(OVNMechanismDriverTestCase):
|
||||
|
@ -6,4 +6,5 @@ other:
|
||||
first one is considered a virtual port. If the second port (non-virtual)
|
||||
is bound to ML2/OVN, the virtual port cannot be bound to a virtual
|
||||
machine; a virtual port is created only to reserve a set of IP addresses
|
||||
to be used by other ports.
|
||||
to be used by other ports. The OVN mechanism driver prevents that a virtual
|
||||
port has a device ID; a device ID is provided when the port is being bound.
|
||||
|
Loading…
Reference in New Issue
Block a user