Skip to content

Commit 6bba3bd

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "[OVN] Prevent binding a virtual type port" into stable/2023.1
2 parents d8679f2 + 43cfe83 commit 6bba3bd

File tree

4 files changed

+56
-2
lines changed

4 files changed

+56
-2
lines changed

neutron/common/ovn/utils.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -976,3 +976,27 @@ def determine_bind_host(sb_idl, port, port_context=None):
976976
bp_info.bp_param[
977977
constants.VIF_DETAILS_CARD_SERIAL_NUMBER]).hostname
978978
return ''
979+
980+
981+
def validate_port_binding_and_virtual_port(
982+
port_context, nb_idl, sb_idl, ml2_plugin, port):
983+
"""If the port is type=virtual and it is bound, raise BadRequest"""
984+
if not determine_bind_host(sb_idl, port, port_context=port_context):
985+
# The port is not bound, exit.
986+
return
987+
988+
fixed_ips = port.get('fixed_ips', [])
989+
subnet_ids = set([fixed_ip['subnet_id'] for fixed_ip in fixed_ips
990+
if 'subnet_id' in fixed_ip])
991+
if not subnet_ids:
992+
# If the port has no fixed_ips/subnets, it cannot be virtual.
993+
return
994+
995+
subnets = ml2_plugin.get_subnets(port_context.plugin_context,
996+
filters={'id': list(subnet_ids)})
997+
port_type, _, _ = get_port_type_virtual_and_parents(
998+
subnets, fixed_ips, port['network_id'], port['id'], nb_idl)
999+
if port_type == constants.LSP_TYPE_VIRTUAL:
1000+
raise n_exc.BadRequest(
1001+
resource='port',
1002+
msg='A virtual logical switch port cannot be bound to a host')

neutron/plugins/ml2/drivers/ovn/mech_driver/mech_driver.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,8 @@ def update_port_precommit(self, context):
814814
self._validate_ignored_port(port, original_port)
815815
ovn_utils.validate_and_get_data_from_binding_profile(port)
816816
self._validate_port_extra_dhcp_opts(port)
817+
ovn_utils.validate_port_binding_and_virtual_port(
818+
context, self.nb_ovn, self.sb_ovn, self._plugin, port)
817819
if self._is_port_provisioning_required(port, context.host,
818820
context.original_host):
819821
self._insert_port_provisioning_block(context.plugin_context,

neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4342,7 +4342,7 @@ def setUp(self):
43424342
self.fmt, name='net1', admin_state_up=True)['network']
43434343
self.subnet = self._make_subnet(
43444344
self.fmt, {'network': self.net},
4345-
'10.0.0.1', '10.0.0.0/24')['subnet']
4345+
'10.0.0.1', '10.0.0.0/24')
43464346

43474347
@mock.patch.object(ovn_utils, 'determine_bind_host')
43484348
def test_create_port_with_virtual_type_and_options(self, *args):
@@ -4353,7 +4353,7 @@ def test_create_port_with_virtual_type_and_options(self, *args):
43534353
'mac_address': '00:00:00:00:00:00',
43544354
'device_owner': device_owner,
43554355
'network_id': self.net['id'],
4356-
'fixed_ips': [{'subnet_id': self.subnet['id'],
4356+
'fixed_ips': [{'subnet_id': self.subnet['subnet']['id'],
43574357
'ip_address': '10.0.0.55'}],
43584358
portbindings.PROFILE: {},
43594359
}
@@ -4416,6 +4416,25 @@ def test_delete_virtual_port_parent(self):
44164416
self.nb_idl.unset_lswitch_port_to_virtual_type.assert_called_once_with(
44174417
virt_port['id'], parent['id'], if_exists=True)
44184418

4419+
def test_update_port_bound(self):
4420+
with self.port(subnet=self.subnet, is_admin=True) as port:
4421+
port = port['port']
4422+
updated_port = copy.deepcopy(port)
4423+
updated_port[portbindings.HOST_ID] = 'host1'
4424+
context = mock.Mock(current=updated_port, original=port)
4425+
with mock.patch.object(self.mech_driver._plugin, 'get_subnets') \
4426+
as mock_get_subnets:
4427+
mock_get_subnets.return_value = [self.subnet['subnet']]
4428+
# 1) The port is not virtual, it has no parents.
4429+
self.mock_vp_parents.return_value = ''
4430+
self.mech_driver.update_port_precommit(context)
4431+
# 2) The port (LSP) has parents, that means it is a virtual
4432+
# port.
4433+
self.mock_vp_parents.return_value = ['parent-0', 'parent-1']
4434+
self.assertRaises(n_exc.BadRequest,
4435+
self.mech_driver.update_port_precommit,
4436+
context)
4437+
44194438

44204439
class TestOVNAvailabilityZone(OVNMechanismDriverTestCase):
44214440

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
other:
3+
- |
4+
A ML2/OVN virtual port cannot be bound to a virtual machine. If a port
5+
IP address is assigned as an allowed address pair into another port, the
6+
first one is considered a virtual port. If the second port (non-virtual)
7+
is bound to ML2/OVN, the virtual port cannot be bound to a virtual
8+
machine; a virtual port is created only to reserve a set of IP addresses
9+
to be used by other ports.

0 commit comments

Comments
 (0)