Skip to content

Commit 3d036d5

Browse files
committed
[ovn] Specify port type if it's a router port when updating
In order to avoid multiple LogicalSwitchPortUpdateUpEvent and LogicalSwitchPortUpdateDownEvent is mandatory to specify the router port type when udpating the port. If the port is not specified when updating the port, the transactions will trigger a modification on the ovnnb db that will set the port status to down[0]. Triggering an unnecessary DownEvent followed by another UpEvent. Those unnecessary event most likely will trigger a revision conflict. [0] - https://github.com/ovn-org/ovn/blob/ 4f93381d7d38aa21f56fb3ff4ec00490fca12614/northd/northd.c#L15604 Conflicts: neutron/common/ovn/constants.py Closes-Bug: #1955578 Change-Id: I296003a936db16dd3a7d184ec44908fb3f261876 (cherry picked from commit 8c482b8)
1 parent 3b3b8eb commit 3d036d5

File tree

3 files changed

+77
-0
lines changed

3 files changed

+77
-0
lines changed

neutron/common/ovn/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@
354354
LSP_TYPE_VIRTUAL = 'virtual'
355355
LSP_TYPE_EXTERNAL = 'external'
356356
LSP_TYPE_LOCALPORT = 'localport'
357+
LSP_TYPE_ROUTER = 'router'
357358
LSP_OPTIONS_VIRTUAL_PARENTS_KEY = 'virtual-parents'
358359
LSP_OPTIONS_VIRTUAL_IP_KEY = 'virtual-ip'
359360
LSP_OPTIONS_VIF_PLUG_TYPE_KEY = 'vif-plug-type'

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,13 @@ def update_port(self, context, port, port_object=None):
630630
txn.add(check_rev_cmd)
631631
columns_dict = {}
632632
if utils.is_lsp_router_port(port):
633+
# It is needed to specify the port type, if not specified
634+
# the AddLSwitchPortCommand will trigger a change
635+
# on the northd status column from UP to DOWN, triggering a
636+
# LogicalSwitchPortUpdateDownEvent, that will most likely
637+
# cause a revision conflict.
638+
# https://bugs.launchpad.net/neutron/+bug/1955578
639+
columns_dict['type'] = ovn_const.LSP_TYPE_ROUTER
633640
port_info.options.update(
634641
self._nb_idl.get_router_port_options(port['id']))
635642
else:

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

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
from neutron.plugins.ml2.drivers.ovn.mech_driver import mech_driver
3939
from neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb import impl_idl_ovn
4040
from neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb import ovn_client
41+
from neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb import ovsdb_monitor
4142
from neutron.tests import base as tests_base
4243
from neutron.tests.functional import base
4344

@@ -602,6 +603,74 @@ def _test_external_port_create(self, vnic_type):
602603
self.assertEqual(utils.ovn_name(net_id),
603604
str(ovn_port.ha_chassis_group[0].name))
604605

606+
def _create_router_port(self, vnic_type):
607+
net_id = self.n1['network']['id']
608+
port_data = {
609+
'port': {'network_id': net_id,
610+
'tenant_id': self._tenant_id,
611+
portbindings.VNIC_TYPE: 'normal'}}
612+
613+
# Create port
614+
port_req = self.new_create_request('ports', port_data, self.fmt)
615+
port_res = port_req.get_response(self.api)
616+
port = self.deserialize(self.fmt, port_res)['port']
617+
618+
# Update it as lsp port
619+
port_upt_data = {
620+
'port': {'device_owner': "network:router_gateway"}
621+
}
622+
port_req = self.new_update_request(
623+
'ports', port_upt_data, port['id'], self.fmt)
624+
port_res = port_req.get_response(self.api)
625+
626+
def test_add_external_port_avoid_flapping(self):
627+
class LogicalSwitchPortUpdateUpEventTest(event.RowEvent):
628+
def __init__(self):
629+
self.count = 0
630+
table = 'Logical_Switch_Port'
631+
events = (self.ROW_UPDATE,)
632+
super(LogicalSwitchPortUpdateUpEventTest, self).__init__(
633+
events, table, (('up', '=', True),),
634+
old_conditions=(('up', '=', False),))
635+
636+
def run(self, event, row, old):
637+
self.count += 1
638+
639+
def get_count(self):
640+
return self.count
641+
642+
class LogicalSwitchPortUpdateDownEventTest(event.RowEvent):
643+
def __init__(self):
644+
self.count = 0
645+
table = 'Logical_Switch_Port'
646+
events = (self.ROW_UPDATE,)
647+
super(LogicalSwitchPortUpdateDownEventTest, self).__init__(
648+
events, table, (('up', '=', False),),
649+
old_conditions=(('up', '=', True),))
650+
651+
def run(self, event, row, old):
652+
self.count += 1
653+
654+
def get_count(self):
655+
return self.count
656+
657+
og_up_event = ovsdb_monitor.LogicalSwitchPortUpdateUpEvent(None)
658+
og_down_event = ovsdb_monitor.LogicalSwitchPortUpdateDownEvent(None)
659+
test_down_event = LogicalSwitchPortUpdateDownEventTest()
660+
test_up_event = LogicalSwitchPortUpdateUpEventTest()
661+
self.nb_api.idl.notify_handler.unwatch_events(
662+
[og_up_event, og_down_event])
663+
self.nb_api.idl.notify_handler.watch_events(
664+
[test_down_event, test_up_event])
665+
# Creating a port the same way as the osp cli cmd
666+
# openstack router add port ROUTER PORT
667+
# shouldn't trigger an status flapping (up -> down -> up)
668+
# it should be created with status false and then change the
669+
# status as up, triggering only a LogicalSwitchPortUpdateUpEvent.
670+
self._create_router_port(portbindings.VNIC_DIRECT)
671+
self.assertEqual(test_down_event.get_count(), 0)
672+
self.assertEqual(test_up_event.get_count(), 1)
673+
605674
def test_external_port_create_vnic_direct(self):
606675
self._test_external_port_create(portbindings.VNIC_DIRECT)
607676

0 commit comments

Comments
 (0)