From cc1ff09b9e2e64eb6abd519a0d4ca3dda7439eb1 Mon Sep 17 00:00:00 2001 From: Frode Nordahl Date: Fri, 24 Mar 2023 17:07:36 +0100 Subject: [PATCH] [ovn] Add support for enable_default_route_bfd attribute When ``enable_default_route_bfd`` is set, maintain BFD records along with default route records. Default route records will also be fitted with the `output_port` key, which is a requirement for the OVN BFD support. Partial-Bug: #2002687 Signed-off-by: Frode Nordahl Change-Id: I34e2453ab206c13c3ca40c4181970c320bdd8e67 --- neutron/common/ovn/extensions.py | 2 + .../ml2/drivers/ovn/mech_driver/ovsdb/api.py | 8 +- .../drivers/ovn/mech_driver/ovsdb/commands.py | 38 +++- .../ovn/mech_driver/ovsdb/impl_idl_ovn.py | 11 +- .../ovn/mech_driver/ovsdb/ovn_client.py | 30 ++- .../ovn/mech_driver/ovsdb/test_impl_idl.py | 173 ++++++++++++++++++ .../functional/services/ovn_l3/test_plugin.py | 99 +++++++++- neutron/tests/unit/fake_resources.py | 3 +- .../ovn/mech_driver/ovsdb/test_ovn_client.py | 3 + .../tests/unit/services/ovn_l3/test_plugin.py | 9 +- requirements.txt | 2 +- 11 files changed, 364 insertions(+), 14 deletions(-) diff --git a/neutron/common/ovn/extensions.py b/neutron/common/ovn/extensions.py index f2d41f9bac7..7ca4b98f576 100644 --- a/neutron/common/ovn/extensions.py +++ b/neutron/common/ovn/extensions.py @@ -40,6 +40,7 @@ from neutron_lib.api.definitions import flavors from neutron_lib.api.definitions import floating_ip_port_forwarding from neutron_lib.api.definitions import floatingip_pools from neutron_lib.api.definitions import l3 +from neutron_lib.api.definitions import l3_enable_default_route_bfd from neutron_lib.api.definitions import l3_enable_default_route_ecmp from neutron_lib.api.definitions import l3_ext_gw_mode from neutron_lib.api.definitions import l3_ext_gw_multihoming @@ -122,6 +123,7 @@ ML2_SUPPORTED_API_EXTENSIONS_OVN_L3 = [ flavors.ALIAS, l3_flavors.ALIAS, l3_ext_gw_multihoming.ALIAS, + l3_enable_default_route_bfd.ALIAS, l3_enable_default_route_ecmp.ALIAS, ] ML2_SUPPORTED_API_EXTENSIONS = [ diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/api.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/api.py index bd378b80dd3..ee97ac05f2d 100644 --- a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/api.py +++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/api.py @@ -261,11 +261,13 @@ class API(api.API, metaclass=abc.ABCMeta): """ @abc.abstractmethod - def add_static_route(self, lrouter, **columns): + def add_static_route(self, lrouter, maintain_bfd=False, **columns): """Add static route to logical router. :param lrouter: The unique name of the lrouter :type lrouter: string + :param maintain_bfd: Ensure a BFD record exists for the static route. + :type maintain_bfd: bool :param columns: Dictionary of static columns Supported columns: prefix, nexthop, valid :type columns: dictionary @@ -533,11 +535,13 @@ class API(api.API, metaclass=abc.ABCMeta): """ @abc.abstractmethod - def delete_lrouter_ext_gw(self, lrouter_name): + def delete_lrouter_ext_gw(self, lrouter_name, maintain_bfd=True): """Delete Logical Router external gateway. :param lrouter_name: The name of the logical router :type lrouter_name: string + :param maintain_bfd: Ensure any existing BFD record is removed. + :type maintain_bfd: bool :returns: :class:`Command` with no result """ diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/commands.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/commands.py index 5687ea9d498..6aefa565a6d 100644 --- a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/commands.py +++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/commands.py @@ -15,6 +15,7 @@ from oslo_utils import timeutils from ovsdbapp.backend.ovs_idl import command from ovsdbapp.backend.ovs_idl import idlutils +from ovsdbapp.schema.ovn_northbound import commands as ovn_nb_commands from ovsdbapp import utils as ovsdbapp_utils from neutron._i18n import _ @@ -624,9 +625,10 @@ class DelACLCommand(command.BaseCommand): class AddStaticRouteCommand(command.BaseCommand): - def __init__(self, api, lrouter, **columns): + def __init__(self, api, lrouter, maintain_bfd=False, **columns): super(AddStaticRouteCommand, self).__init__(api) self.lrouter = lrouter + self.maintain_bfd = maintain_bfd self.columns = columns def run_idl(self, txn): @@ -637,9 +639,29 @@ class AddStaticRouteCommand(command.BaseCommand): msg = _("Logical Router %s does not exist") % self.lrouter raise RuntimeError(msg) + bfd_uuid = None + if (self.maintain_bfd and + 'nexthop' in self.columns and + 'output_port' in self.columns): + cmd = ovn_nb_commands.BFDAddCommand(self.api, + self.columns['output_port'], + self.columns['nexthop'], + may_exist=True) + cmd.run_idl(txn) + try: + bfd_uuid = cmd.result.uuid + except AttributeError: + # When the BFD record is created in the same transaction the + # post commit code that would resolve the real UUID and look up + # the bfd record has not run yet, and consequently the object + # returned by BFDAddCommand() is an UUID object. + bfd_uuid = cmd.result + row = txn.insert(self.api._tables['Logical_Router_Static_Route']) for col, val in self.columns.items(): setattr(row, col, val) + if bfd_uuid: + setattr(row, 'bfd', bfd_uuid) _addvalue_to_list(lrouter, 'static_routes', row.uuid) @@ -915,10 +937,11 @@ class CheckRevisionNumberCommand(command.BaseCommand): class DeleteLRouterExtGwCommand(command.BaseCommand): - def __init__(self, api, lrouter, if_exists): + def __init__(self, api, lrouter, if_exists, maintain_bfd=True): super(DeleteLRouterExtGwCommand, self).__init__(api) self.lrouter = lrouter self.if_exists = if_exists + self.maintain_bfd = maintain_bfd def run_idl(self, txn): try: @@ -930,9 +953,20 @@ class DeleteLRouterExtGwCommand(command.BaseCommand): msg = _("Logical Router %s does not exist") % self.lrouter raise RuntimeError(msg) + if self.maintain_bfd: + lrp_names = set() + for lrp in getattr(lrouter, 'ports', []): + lrp_names.add(lrp.name) for route in lrouter.static_routes: external_ids = getattr(route, 'external_ids', {}) if ovn_const.OVN_ROUTER_IS_EXT_GW in external_ids: + bfd = getattr(route, 'bfd', []) + if bfd and self.maintain_bfd: + for bfd_rec in bfd: + bfd_logical_port = getattr(bfd_rec, 'logical_port', '') + if bfd_logical_port in lrp_names: + route.delvalue('bfd', bfd_rec) + bfd_rec.delete() lrouter.delvalue('static_routes', route) route.delete() diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/impl_idl_ovn.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/impl_idl_ovn.py index c87214dad04..9ae4270c0e7 100644 --- a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/impl_idl_ovn.py +++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/impl_idl_ovn.py @@ -464,8 +464,9 @@ class OvsdbNbOvnIdl(nb_impl_idl.OvnNbApiIdlImpl, Backend): def delete_acl(self, lswitch, lport, if_exists=True): return cmd.DelACLCommand(self, lswitch, lport, if_exists) - def add_static_route(self, lrouter, **columns): - return cmd.AddStaticRouteCommand(self, lrouter, **columns) + def add_static_route(self, lrouter, maintain_bfd=False, **columns): + return cmd.AddStaticRouteCommand(self, lrouter, maintain_bfd, + **columns) def delete_static_route(self, lrouter, ip_prefix, nexthop, if_exists=True): return cmd.DelStaticRouteCommand(self, lrouter, ip_prefix, nexthop, @@ -815,8 +816,10 @@ class OvsdbNbOvnIdl(nb_impl_idl.OvnNbApiIdlImpl, Backend): return lr return None - def delete_lrouter_ext_gw(self, lrouter_name, if_exists=True): - return cmd.DeleteLRouterExtGwCommand(self, lrouter_name, if_exists) + def delete_lrouter_ext_gw(self, lrouter_name, if_exists=True, + maintain_bfd=True): + return cmd.DeleteLRouterExtGwCommand(self, lrouter_name, if_exists, + maintain_bfd) def get_port_group(self, pg_name): if uuidutils.is_uuid_like(pg_name): diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py index a80d5e7353b..ec8ff73bd3e 100644 --- a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py +++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py @@ -1264,6 +1264,8 @@ class OVNClient(object): lrouter_name = utils.ovn_name(router['id']) router_default_route_ecmp_enabled = router.get( 'enable_default_route_ecmp', False) + router_default_route_bfd_enabled = router.get( + 'enable_default_route_bfd', False) # 1. Add the external gateway router port. admin_context = context.elevated() @@ -1285,9 +1287,16 @@ class OVNClient(object): columns = {'external_ids': { ovn_const.OVN_ROUTER_IS_EXT_GW: 'true', ovn_const.OVN_SUBNET_EXT_ID_KEY: gw_info.subnet_id}} + if router_default_route_bfd_enabled: + columns.update({ + 'output_port': utils.ovn_lrouter_port_name( + gw_port['id']), + }) txn.add(self._nb_idl.add_static_route( lrouter_name, ip_prefix=gw_info.ip_prefix, - nexthop=gw_info.gateway_ip, **columns)) + nexthop=gw_info.gateway_ip, + maintain_bfd=router_default_route_bfd_enabled, + **columns)) # 3. Add snat rules for tenant networks in lrouter if snat is enabled if utils.is_snat_enabled(router) and networks: @@ -1328,6 +1337,22 @@ class OVNClient(object): if snat.external_ip != gw_info.router_ip: return True + router_default_route_bfd = router.get( + 'enable_default_route_bfd', + False + ) + + for route in ovn_static_routes: + # If gateway in OVN DB has static routes, the ovn_static_route + # parameter contains data from + # `utils.get_lrouter_ext_gw_static_route`, otherwise it will + # contain a Dict ref `update_router` method. + route_bfd = getattr(route, 'bfd', []) + if router_default_route_bfd and not route_bfd: + return True + elif route_bfd and not router_default_route_bfd: + return True + return False def update_router_routes(self, context, router_id, add, remove, @@ -1528,6 +1553,9 @@ class OVNClient(object): """Delete a logical router.""" lrouter_name = utils.ovn_name(router_id) with self._nb_idl.transaction(check_error=True) as txn: + # This will ensure any BFD records are removed + txn.add(self._nb_idl.delete_lrouter_ext_gw(lrouter_name, + if_exists=True)) txn.add(self._nb_idl.lr_del(lrouter_name, if_exists=True)) db_rev.delete_revision(context, router_id, ovn_const.TYPE_ROUTERS) diff --git a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_impl_idl.py b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_impl_idl.py index d0b0e37b506..1b5a61aec29 100644 --- a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_impl_idl.py +++ b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_impl_idl.py @@ -21,6 +21,7 @@ from neutron_lib import constants from oslo_utils import netutils from oslo_utils import uuidutils from ovsdbapp.backend.ovs_idl import connection +from ovsdbapp.backend.ovs_idl import idlutils from ovsdbapp import constants as const from ovsdbapp import event as ovsdb_event from ovsdbapp.tests.functional import base @@ -417,6 +418,178 @@ class TestNbApi(BaseOvnIdlTest): self.assertEqual(r.options[ovn_const.LR_OPTIONS_MAC_AGE_LIMIT], ovn_conf.get_ovn_mac_binding_age_threshold()) + def _add_static_route(self, txn, lr_name, lrp_name, **columns): + r = txn.add(self.nbapi.lr_add(lr_name)) + if lrp_name: + txn.add(self.nbapi.add_lrouter_port(lrp_name, lr_name)) + columns.update({'output_port': lrp_name}) + txn.add(self.nbapi.add_static_route(lr_name, **columns)) + + return r + + def test_add_static_route(self): + name = 'router_with_static_routes' + columns = { + 'bfd': [], + 'external_ids': {'fake_eid_key': 'fake_eid_value'}, + 'ip_prefix': '0.0.0.0/0', + 'nexthop': '192.0.2.1', + 'options': {'fake_option_key': 'fake_option_value'}, + 'output_port': [], + 'policy': ['dst-ip'], + 'route_table': '', + } + with self.nbapi.transaction(check_error=True) as txn: + r = self._add_static_route(txn, name, '', **columns) + for route in r.result.static_routes: + for k, v in columns.items(): + self.assertEqual( + getattr(route, k), + v) + + def _add_static_route_bfd_assert(self, r, lr_name, lrp_name, ip_prefix, + nexthop): + for route in r.result.static_routes: + self.assertEqual( + route.ip_prefix, + ip_prefix) + self.assertEqual( + route.nexthop, + nexthop) + self.assertEqual( + route.output_port[0], + lrp_name) + + self.assertEqual( + route.bfd[0].logical_port, + lrp_name) + self.assertEqual( + route.bfd[0].dst_ip, + nexthop) + + def test_add_static_route_bfd(self): + lr_name = 'router_with_static_routes_and_bfd' + lrp_name = 'lrp-' + lr_name + ip_prefix = '0.0.0.0/0' + nexthop = '192.0.2.1' + with self.nbapi.transaction(check_error=True) as txn: + r = self._add_static_route(txn, lr_name, lrp_name, + ip_prefix=ip_prefix, + nexthop=nexthop, + maintain_bfd=True) + + self._add_static_route_bfd_assert(r, lr_name, lrp_name, ip_prefix, + nexthop) + + def test_add_static_route_bfd_record_exists(self): + lr_name = 'router_with_static_routes_and_preexisting_bfd_record' + lrp_name = 'lrp-' + lr_name + ip_prefix = '0.0.0.0/0' + nexthop = '192.0.2.1' + with self.nbapi.transaction(check_error=True) as txn: + bfd = txn.add(self.nbapi.bfd_add(lrp_name, nexthop)) + r = self._add_static_route(txn, lr_name, lrp_name, + ip_prefix=ip_prefix, + nexthop=nexthop, + maintain_bfd=True) + + for route in r.result.static_routes: + self.assertEqual( + bfd.result, + route.bfd[0], + ) + self._add_static_route_bfd_assert(r, lr_name, lrp_name, ip_prefix, + nexthop) + + def test_add_static_route_bfd_record_exists_multiple_txn(self): + lr_name = 'router_with_static_routes_and_preexisting_bfd_record_txn' + lrp_name = 'lrp-' + lr_name + ip_prefix = '0.0.0.0/0' + nexthop = '192.0.2.1' + with self.nbapi.transaction(check_error=True) as txn: + bfd = txn.add(self.nbapi.bfd_add(lrp_name, nexthop)) + with self.nbapi.transaction(check_error=True) as txn: + r = self._add_static_route(txn, lr_name, lrp_name, + ip_prefix=ip_prefix, + nexthop=nexthop, + maintain_bfd=True) + + for route in r.result.static_routes: + self.assertEqual( + bfd.result, + route.bfd[0], + ) + self._add_static_route_bfd_assert(r, lr_name, lrp_name, ip_prefix, + nexthop) + + def test_delete_lrouter_ext_gw(self): + lr_name = 'router_with_ext_gw' + ip_prefix = '0.0.0.0/0' + nexthop = '192.0.2.1' + external_ids = {ovn_const.OVN_ROUTER_IS_EXT_GW: 'True'} + with self.nbapi.transaction(check_error=True) as txn: + r = self._add_static_route(txn, lr_name, '', + ip_prefix=ip_prefix, + nexthop=nexthop, + external_ids=external_ids) + + uuids = [] + for route in r.result.static_routes: + lkp = self.nbapi.lookup("Logical_Router_Static_Route", route.uuid) + uuids.append(lkp.uuid) + self.assertTrue(len(uuids)) + + with self.nbapi.transaction(check_error=True) as txn: + txn.add(self.nbapi.delete_lrouter_ext_gw(lr_name)) + + for route_uuid in uuids: + self.assertRaises( + idlutils.RowNotFound, + self.nbapi.lookup, + "Logical_Router_Static_Route", + route_uuid) + + def test_delete_lrouter_ext_gw_bfd(self): + lr_name = 'router_with_ext_gw_bfd' + lrp_name = 'lrp-' + lr_name + ip_prefix = '0.0.0.0/0' + nexthop = '192.0.2.1' + external_ids = {ovn_const.OVN_ROUTER_IS_EXT_GW: 'True'} + with self.nbapi.transaction(check_error=True) as txn: + r = self._add_static_route(txn, lr_name, lrp_name, + ip_prefix=ip_prefix, + nexthop=nexthop, + external_ids=external_ids, + maintain_bfd=True) + + uuids = [] + bfd_uuids = [] + for route in r.result.static_routes: + lkp = self.nbapi.lookup("Logical_Router_Static_Route", route.uuid) + uuids.append(lkp.uuid) + self.assertTrue(len(lkp.bfd)) + for bfd_rec in lkp.bfd: + bfd_uuids.append(bfd_rec.uuid) + self.assertTrue(len(uuids)) + self.assertTrue(len(bfd_uuids)) + + with self.nbapi.transaction(check_error=True) as txn: + txn.add(self.nbapi.delete_lrouter_ext_gw(lr_name)) + + for route_uuid in uuids: + self.assertRaises( + idlutils.RowNotFound, + self.nbapi.lookup, + "Logical_Router_Static_Route", + route_uuid) + + for bfd_uuid in bfd_uuids: + self.assertRaises( + idlutils.RowNotFound, + self.nbapi.lookup, + "BFD", + bfd_uuid) + class TestIgnoreConnectionTimeout(BaseOvnIdlTest): @classmethod diff --git a/neutron/tests/functional/services/ovn_l3/test_plugin.py b/neutron/tests/functional/services/ovn_l3/test_plugin.py index 84b85b0eb3e..c0036433e6a 100644 --- a/neutron/tests/functional/services/ovn_l3/test_plugin.py +++ b/neutron/tests/functional/services/ovn_l3/test_plugin.py @@ -45,7 +45,7 @@ class TestRouter(base.TestOVNFunctionalBase): self.sb_api.idl.notify_handler.watch_event(self.cr_lrp_pb_event) def _create_router(self, name, gw_info=None, az_hints=None, - enable_ecmp=None): + enable_ecmp=None, enable_bfd=None): router = {'router': {'name': name, 'admin_state_up': True, @@ -54,6 +54,8 @@ class TestRouter(base.TestOVNFunctionalBase): router['router']['availability_zone_hints'] = az_hints if gw_info: router['router']['external_gateway_info'] = gw_info + if enable_bfd: + router['router']['enable_default_route_bfd'] = enable_bfd if enable_ecmp: router['router']['enable_default_route_ecmp'] = enable_ecmp return self.l3_plugin.create_router(self.context, router) @@ -658,6 +660,101 @@ class TestRouter(base.TestOVNFunctionalBase): len(lr.static_routes), len(gws['router']['external_gateways'])) + def test_create_delete_router_multiple_gw_ports_ecmp_and_bfd(self): + default_gw = "10.0.60.1" + ext6 = self._create_ext_network( + 'ext6', 'flat', 'physnet6', None, default_gw, "10.0.60.0/24") + router = self._create_router('router6', gw_info=None, + enable_bfd=True, enable_ecmp=True) + gws = self._add_external_gateways( + router['id'], + [ + {'network_id': ext6['network']['id']}, + {'network_id': ext6['network']['id']}, + ]) + lr = self.nb_api.lookup('Logical_Router', + ovn_utils.ovn_name(router['id'])) + + # Check that the expected number of ports are created + self.assertEqual( + len(lr.ports), + len(gws['router']['external_gateways'])) + # Check that the expected number of static routes are created + self.assertEqual( + len(lr.static_routes), + len(gws['router']['external_gateways'])) + # Check that static_route bfd and output_port attributes is set to the + # expected values + for static_route in lr.static_routes: + self.assertNotEqual( + [], + static_route.bfd) + self.assertNotEqual( + [], + static_route.output_port) + self.assertIn(static_route.output_port[0], + [lrp.name + for lrp in lr.ports]) + self.assertIn(static_route.bfd[0].logical_port, + [lrp.name + for lrp in lr.ports]) + self.assertEqual(static_route.bfd[0].logical_port, + static_route.output_port[0]) + + router_ips = set() + for ext_gws in gws['router']['external_gateways']: + for ext_fip in ext_gws['external_fixed_ips']: + router_ips.add(ext_fip['ip_address']) + + lrps = set() + for lrp in lr.ports: + for network in lrp.networks: + self.assertIn( + network.split('/')[0], + router_ips) + lrps.add(lrp.name) + bfd_rows = self.nb_api.bfd_find( + lrp.name, default_gw).execute(check_error=True) + if not bfd_rows: + raise AssertionError('None of the expected BFD rows found.') + for bfd_row in bfd_rows: + self.assertEqual( + bfd_row.logical_port, + lrp.name) + self.assertEqual( + bfd_row.dst_ip, + default_gw) + + self.l3_plugin.delete_router(self.context, id=router['id']) + self.assertRaises(idlutils.RowNotFound, self.nb_api.lookup, + 'Logical_Router', ovn_utils.ovn_name(router['id'])) + for lrp_name in lrps: + if self.nb_api.bfd_find( + lrp.name, default_gw).execute(check_error=True): + raise AssertionError('Unexpectedly found BFD rows.') + + def test_update_router_single_gw_bfd(self): + ext1 = self._create_ext_network( + 'ext7', 'flat', 'physnet1', None, "10.0.70.1", "10.0.70.0/24") + gw_info = {'network_id': ext1['network']['id']} + router = self._create_router('router7', gw_info=gw_info) + self.assertFalse(router['enable_default_route_bfd']) + lr = self.nb_api.lr_get(ovn_utils.ovn_name(router['id'])).execute() + for route in ovn_utils.get_lrouter_ext_gw_static_route(lr): + self.assertEqual( + [], + route.bfd) + + router = self.l3_plugin.update_router( + self.context, router['id'], + {'router': {'enable_default_route_bfd': True}}) + self.assertTrue(router['enable_default_route_bfd']) + lr = self.nb_api.lr_get(ovn_utils.ovn_name(router['id'])).execute() + for route in ovn_utils.get_lrouter_ext_gw_static_route(lr): + self.assertNotEqual( + [], + route.bfd) + def test_gateway_chassis_rebalance(self): ovn_client = self.l3_plugin._ovn_client chassis4 = self.add_fake_chassis( diff --git a/neutron/tests/unit/fake_resources.py b/neutron/tests/unit/fake_resources.py index 14ebb9d93c0..57cebdd2eca 100644 --- a/neutron/tests/unit/fake_resources.py +++ b/neutron/tests/unit/fake_resources.py @@ -797,7 +797,8 @@ class FakeOVNPort(object): FakeStaticRoute = collections.namedtuple( - 'Static_Routes', ['ip_prefix', 'nexthop', 'external_ids']) + 'Static_Routes', ['ip_prefix', 'nexthop', 'external_ids', 'bfd'], + defaults=([],)) class FakeOVNRouterPort(object): diff --git a/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovn_client.py b/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovn_client.py index 2abc8f887fa..58ab1ef5258 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovn_client.py +++ b/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovn_client.py @@ -85,6 +85,7 @@ class TestOVNClient(TestOVNClientBase): 'neutron-' + router['id'], ip_prefix='0.0.0.0/0', nexthop='10.42.0.1', + maintain_bfd=False, external_ids={ 'neutron:is_ext_gw': 'true', 'neutron:subnet_id': subnet['id']}) @@ -136,6 +137,7 @@ class TestOVNClient(TestOVNClientBase): mock.call('neutron-' + router['id'], ip_prefix='0.0.0.0/0', nexthop=subnet1['gateway_ip'], + maintain_bfd=False, external_ids={ 'neutron:is_ext_gw': 'true', 'neutron:subnet_id': subnet1['id']}, @@ -143,6 +145,7 @@ class TestOVNClient(TestOVNClientBase): mock.call('neutron-' + router['id'], ip_prefix='0.0.0.0/0', nexthop=subnet2['gateway_ip'], + maintain_bfd=False, external_ids={ 'neutron:is_ext_gw': 'true', 'neutron:subnet_id': subnet2['id']}, diff --git a/neutron/tests/unit/services/ovn_l3/test_plugin.py b/neutron/tests/unit/services/ovn_l3/test_plugin.py index a748c331603..c561c49089e 100644 --- a/neutron/tests/unit/services/ovn_l3/test_plugin.py +++ b/neutron/tests/unit/services/ovn_l3/test_plugin.py @@ -627,6 +627,7 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase): expected_calls = [ mock.call('neutron-router-id', ip_prefix='0.0.0.0/0', nexthop='192.168.1.254', + maintain_bfd=False, external_ids={ ovn_const.OVN_ROUTER_IS_EXT_GW: 'true', ovn_const.OVN_SUBNET_EXT_ID_KEY: 'ext-subnet-id'})] @@ -798,6 +799,7 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase): lsp_address=ovn_const.DEFAULT_ADDR_FOR_LSP_WITH_PEER) self.l3_inst._nb_ovn.add_static_route.assert_called_once_with( 'neutron-router-id', ip_prefix='0.0.0.0/0', + maintain_bfd=False, external_ids={ovn_const.OVN_ROUTER_IS_EXT_GW: 'true', ovn_const.OVN_SUBNET_EXT_ID_KEY: 'ext-subnet-id'}, nexthop='192.168.1.254') @@ -868,6 +870,7 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase): self.l3_inst._nb_ovn.add_static_route.assert_called_once_with( 'neutron-router-id', ip_prefix='0.0.0.0/0', nexthop='192.168.1.254', + maintain_bfd=False, external_ids={ovn_const.OVN_ROUTER_IS_EXT_GW: 'true', ovn_const.OVN_SUBNET_EXT_ID_KEY: 'ext-subnet-id'}) self.l3_inst._nb_ovn.add_nat_rule_in_lrouter.assert_called_once_with( @@ -920,6 +923,7 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase): self.l3_inst._nb_ovn.add_static_route.assert_called_once_with( 'neutron-router-id', ip_prefix='0.0.0.0/0', nexthop='192.168.1.254', + maintain_bfd=False, external_ids={ovn_const.OVN_ROUTER_IS_EXT_GW: 'true', ovn_const.OVN_SUBNET_EXT_ID_KEY: 'ext-subnet-id'}) self.l3_inst._nb_ovn.add_nat_rule_in_lrouter.assert_called_once_with( @@ -971,6 +975,7 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase): # Need not check lsp and lrp here, it has been tested in other cases self.l3_inst._nb_ovn.add_static_route.assert_called_once_with( 'neutron-router-id', ip_prefix='0.0.0.0/0', + maintain_bfd=False, external_ids={ovn_const.OVN_ROUTER_IS_EXT_GW: 'true', ovn_const.OVN_SUBNET_EXT_ID_KEY: 'ext-subnet-id'}, nexthop='192.168.1.254') @@ -2131,8 +2136,8 @@ class OVNL3ExtrarouteTests(test_l3_gw.ExtGwModeIntTestCase, ovn_const.OVN_SUBNET_EXT_ID_KEY: mock.ANY} add_static_route_calls = [ mock.call(mock.ANY, ip_prefix='0.0.0.0/0', nexthop='10.0.0.1', - external_ids=expected_ext_ids), + maintain_bfd=False, external_ids=expected_ext_ids), mock.call(mock.ANY, ip_prefix='::/0', nexthop='2001:db8::', - external_ids=expected_ext_ids)] + maintain_bfd=False, external_ids=expected_ext_ids)] self.l3_inst._nb_ovn.add_static_route.assert_has_calls( add_static_route_calls, any_order=True) diff --git a/requirements.txt b/requirements.txt index 7fa16745ca0..101d4f3d578 100644 --- a/requirements.txt +++ b/requirements.txt @@ -46,7 +46,7 @@ osprofiler>=2.3.0 # Apache-2.0 os-ken>=2.2.0 # Apache-2.0 os-resource-classes>=1.1.0 # Apache-2.0 ovs>=2.10.0 # Apache-2.0 -ovsdbapp>=2.2.1 # Apache-2.0 +ovsdbapp>=2.3.0 # Apache-2.0 psutil>=5.3.0 # BSD pyroute2>=0.7.3;sys_platform!='win32' # Apache-2.0 (+ dual licensed GPL2) pyOpenSSL>=17.1.0 # Apache-2.0