[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 <frode.nordahl@canonical.com> Change-Id: I34e2453ab206c13c3ca40c4181970c320bdd8e67
This commit is contained in:
parent
743bd1ccef
commit
cc1ff09b9e
@ -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 = [
|
||||
|
@ -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
|
||||
"""
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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):
|
||||
|
@ -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']},
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user