Syncing neutron db with ovn does not provide external_ids for static routes

This change adds external_ids to the static routes in case the route is of
type gateway_ip during ovn_db_sync.

Change-Id: I17795b9986aa8655f5467dca0fb4e3cd5cb82252
Closes-Bug: #1902888
This commit is contained in:
Benjamin Reichel
2020-11-04 15:42:54 +01:00
parent 4db2d39e9e
commit 43c60d6216
2 changed files with 267 additions and 14 deletions

View File

@@ -306,6 +306,27 @@ class OvnNbSynchronizer(OvnDbSynchronizer):
LOG.debug('ACL-SYNC: finished @ %s', str(datetime.now()))
def _calculate_routes_differences(self, ovn_routes, db_routes):
to_add = []
to_remove = []
for db_route in db_routes:
for ovn_route in ovn_routes:
if (ovn_route['destination'] == db_route['destination'] and
ovn_route['nexthop'] == db_route['nexthop']):
break
else:
to_add.append(db_route)
for ovn_route in ovn_routes:
for db_route in db_routes:
if (ovn_route['destination'] == db_route['destination'] and
ovn_route['nexthop'] == db_route['nexthop']):
break
else:
to_remove.append(ovn_route)
return to_add, to_remove
def _calculate_fips_differences(self, ovn_fips, ovn_rtr_lb_pfs, db_fips):
to_add = []
to_remove = []
@@ -431,7 +452,11 @@ class OvnNbSynchronizer(OvnDbSynchronizer):
if gw_info.gateway_ip:
db_extends[router['id']]['routes'].append(
{'destination': prefix,
'nexthop': gw_info.gateway_ip})
'nexthop': gw_info.gateway_ip,
'external_ids': {
ovn_const.OVN_ROUTER_IS_EXT_GW: 'true',
ovn_const.OVN_SUBNET_EXT_ID_KEY:
gw_info.subnet_id}})
if gw_info.ip_version == constants.IP_VERSION_6:
continue
if gw_info.router_ip and utils.is_snat_enabled(router):
@@ -495,7 +520,7 @@ class OvnNbSynchronizer(OvnDbSynchronizer):
db_routes.extend(db_extends[lrouter['name']]['routes'])
ovn_routes = lrouter['static_routes']
add_routes, del_routes = helpers.diff_list_of_dict(
add_routes, del_routes = self._calculate_routes_differences(
ovn_routes, db_routes)
update_sroutes_list.append({'id': lrouter['name'],
'add': add_routes,
@@ -623,10 +648,15 @@ class OvnNbSynchronizer(OvnDbSynchronizer):
LOG.warning("Add static routes %s to OVN NB DB",
sroute['add'])
for route in sroute['add']:
columns = {}
if 'external_ids' in route:
columns['external_ids'] = route['external_ids']
txn.add(self.ovn_api.add_static_route(
utils.ovn_name(sroute['id']),
ip_prefix=route['destination'],
nexthop=route['nexthop']))
nexthop=route['nexthop'],
**columns))
if sroute['del']:
LOG.warning("Router %(id)s static routes %(route)s "
"found in OVN but not in Neutron",

View File

@@ -234,7 +234,8 @@ class TestOvnNbSyncML2(test_mech_driver.OVNMechanismDriverTestCase):
self.routers = [{'id': 'r1', 'routes': [{'nexthop': '20.0.0.100',
'destination': '11.0.0.0/24'}, {
'nexthop': '20.0.0.101',
'destination': '12.0.0.0/24'}],
'destination': '12.0.0.0/24',
'external_ids': {}}],
'gw_port_id': 'gpr1',
'external_gateway_info': {
'network_id': "ext-net", 'enable_snat': True,
@@ -242,7 +243,8 @@ class TestOvnNbSyncML2(test_mech_driver.OVNMechanismDriverTestCase):
{'subnet_id': 'ext-subnet',
'ip_address': '90.0.0.2'}]}},
{'id': 'r2', 'routes': [{'nexthop': '40.0.0.100',
'destination': '30.0.0.0/24'}],
'destination': '30.0.0.0/24',
'external_ids': {}}],
'gw_port_id': 'gpr2',
'external_gateway_info': {
'network_id': "ext-net", 'enable_snat': True,
@@ -354,12 +356,12 @@ class TestOvnNbSyncML2(test_mech_driver.OVNMechanismDriverTestCase):
return {
'r1': [ovn_client.GW_INFO(router_ip='90.0.0.2',
gateway_ip='90.0.0.1',
network_id='', subnet_id='',
network_id='', subnet_id='ext-subnet',
ip_version=4,
ip_prefix=const.IPv4_ANY)],
'r2': [ovn_client.GW_INFO(router_ip='100.0.0.2',
gateway_ip='100.0.0.1',
network_id='', subnet_id='',
network_id='', subnet_id='ext-subnet',
ip_version=4,
ip_prefix=const.IPv4_ANY)]
}.get(router['id'], [])
@@ -614,7 +616,9 @@ class TestOvnNbSyncML2(test_mech_driver.OVNMechanismDriverTestCase):
delete_lswitch_port_calls, any_order=True)
add_route_calls = [mock.call(mock.ANY, ip_prefix=route['destination'],
nexthop=route['nexthop'])
nexthop=route['nexthop'],
external_ids=route.get('external_ids',
{}))
for route in add_static_route_list]
ovn_api.add_static_route.assert_has_calls(add_route_calls,
any_order=True)
@@ -740,7 +744,8 @@ class TestOvnNbSyncML2(test_mech_driver.OVNMechanismDriverTestCase):
'provider:segmentation_id': 1000}]
create_router_list = [{
'id': 'r2', 'routes': [
{'nexthop': '40.0.0.100', 'destination': '30.0.0.0/24'}],
{'nexthop': '40.0.0.100', 'destination': '30.0.0.0/24',
'external_ids': {}}],
'gw_port_id': 'gpr2',
'external_gateway_info': {
'network_id': "ext-net", 'enable_snat': True,
@@ -753,15 +758,26 @@ class TestOvnNbSyncML2(test_mech_driver.OVNMechanismDriverTestCase):
# Test adding behaviors for router r2 only existing in neutron DB.
# Static routes with destination 0.0.0.0/0 are default gateway routes
add_static_route_list = [{'nexthop': '20.0.0.101',
'destination': '12.0.0.0/24'},
'destination': '12.0.0.0/24',
'external_ids': {}},
{'nexthop': '90.0.0.1',
'destination': '0.0.0.0/0'},
'destination': '0.0.0.0/0',
'external_ids': {
ovn_const.OVN_ROUTER_IS_EXT_GW: 'true',
ovn_const.OVN_SUBNET_EXT_ID_KEY:
'ext-subnet'}},
{'nexthop': '40.0.0.100',
'destination': '30.0.0.0/24'},
'destination': '30.0.0.0/24',
'external_ids': {}},
{'nexthop': '100.0.0.1',
'destination': '0.0.0.0/0'}]
'destination': '0.0.0.0/0',
'external_ids': {
ovn_const.OVN_ROUTER_IS_EXT_GW: 'true',
ovn_const.OVN_SUBNET_EXT_ID_KEY:
'ext-subnet'}}]
del_static_route_list = [{'nexthop': '20.0.0.100',
'destination': '10.0.0.0/24'}]
'destination': '10.0.0.0/24',
'external_ids': {}}]
add_snat_list = [{'logical_ip': '172.16.2.0/24',
'external_ip': '90.0.0.2',
'type': 'snat'},
@@ -883,6 +899,213 @@ class TestOvnNbSyncML2(test_mech_driver.OVNMechanismDriverTestCase):
add_port_groups_list,
del_port_groups_list)
def _test_ovn_nb_sync_calculate_routes_helper(self,
ovn_routes,
db_routes,
expected_added,
expected_deleted):
ovn_nb_synchronizer = ovn_db_sync.OvnNbSynchronizer(
self.plugin, self.mech_driver._nb_ovn, self.mech_driver._sb_ovn,
'repair', self.mech_driver)
add_routes, del_routes = ovn_nb_synchronizer. \
_calculate_routes_differences(ovn_routes, db_routes)
self.assertEqual(add_routes, expected_added)
self.assertEqual(del_routes, expected_deleted)
def test_ovn_nb_sync_calculate_routes_add_two_routes(self):
# add 2 routes to ovn
ovn_routes = []
db_routes = [{'nexthop': '20.0.0.100',
'destination': '11.0.0.0/24',
'external_ids': {}},
{'nexthop': '90.0.0.1',
'destination': '0.0.0.0/0',
'external_ids': {
ovn_const.OVN_ROUTER_IS_EXT_GW: 'true',
ovn_const.OVN_SUBNET_EXT_ID_KEY:
'ext-subnet'}}]
expected_added = db_routes
expected_deleted = []
self._test_ovn_nb_sync_calculate_routes_helper(ovn_routes,
db_routes,
expected_added,
expected_deleted)
def test_ovn_nb_sync_calculate_routes_remove_two_routes(self):
# remove 2 routes from ovn
ovn_routes = [{'nexthop': '20.0.0.100',
'destination': '11.0.0.0/24',
'external_ids': {}},
{'nexthop': '90.0.0.1',
'destination': '0.0.0.0/0',
'external_ids': {
ovn_const.OVN_ROUTER_IS_EXT_GW: 'true',
ovn_const.OVN_SUBNET_EXT_ID_KEY:
'ext-subnet'}}]
db_routes = []
expected_added = []
expected_deleted = ovn_routes
self._test_ovn_nb_sync_calculate_routes_helper(ovn_routes,
db_routes,
expected_added,
expected_deleted)
def test_ovn_nb_sync_calculate_routes_remove_and_add_two_routes(self):
# remove 2 routes from ovn, add 2 routes to ovn
ovn_routes = [{'nexthop': '90.0.0.1',
'destination': '0.0.0.0/0',
'external_ids': {
ovn_const.OVN_ROUTER_IS_EXT_GW: 'true',
ovn_const.OVN_SUBNET_EXT_ID_KEY:
'ext-subnet'}},
{'nexthop': '20.0.0.100',
'destination': '13.0.0.0/24',
'external_ids': {}}]
db_routes = [{'nexthop': '20.0.0.100',
'destination': '11.0.0.0/24',
'external_ids': {}},
{'nexthop': '20.0.0.100',
'destination': '12.0.0.0/24',
'external_ids': {}}]
expected_added = db_routes
expected_deleted = ovn_routes
self._test_ovn_nb_sync_calculate_routes_helper(ovn_routes,
db_routes,
expected_added,
expected_deleted)
def test_ovn_nb_sync_calculate_routes_remove_and_keep_two_routes(self):
# remove 2 routes from ovn, keep 2 routes
ovn_routes = [{'nexthop': '20.0.0.100',
'destination': '11.0.0.0/24',
'external_ids': {}},
{'nexthop': '20.0.0.100',
'destination': '12.0.0.0/24',
'external_ids': {}},
{'nexthop': '90.0.0.1',
'destination': '0.0.0.0/0',
'external_ids': {
ovn_const.OVN_ROUTER_IS_EXT_GW: 'true',
ovn_const.OVN_SUBNET_EXT_ID_KEY:
'ext-subnet'}},
{'nexthop': '20.0.0.100',
'destination': '13.0.0.0/24',
'external_ids': {}}]
db_routes = [{'nexthop': '20.0.0.100',
'destination': '11.0.0.0/24',
'external_ids': {}},
{'nexthop': '20.0.0.100',
'destination': '12.0.0.0/24',
'external_ids': {}}]
expected_added = []
expected_deleted = [{'nexthop': '90.0.0.1',
'destination': '0.0.0.0/0',
'external_ids': {
ovn_const.OVN_ROUTER_IS_EXT_GW: 'true',
ovn_const.OVN_SUBNET_EXT_ID_KEY:
'ext-subnet'}},
{'nexthop': '20.0.0.100',
'destination': '13.0.0.0/24',
'external_ids': {}}]
self._test_ovn_nb_sync_calculate_routes_helper(ovn_routes,
db_routes,
expected_added,
expected_deleted)
def test_ovn_nb_sync_calculate_routes_add_and_keep_two_routes(self):
# add 2 routes to ovn, keep 2 routes
ovn_routes = [{'nexthop': '20.0.0.100',
'destination': '11.0.0.0/24',
'external_ids': {}},
{'nexthop': '20.0.0.100',
'destination': '12.0.0.0/24',
'external_ids': {}}]
db_routes = [{'nexthop': '20.0.0.100',
'destination': '11.0.0.0/24',
'external_ids': {}},
{'nexthop': '20.0.0.100',
'destination': '12.0.0.0/24',
'external_ids': {}},
{'nexthop': '90.0.0.1',
'destination': '0.0.0.0/0',
'external_ids': {
ovn_const.OVN_ROUTER_IS_EXT_GW: 'true',
ovn_const.OVN_SUBNET_EXT_ID_KEY:
'ext-subnet'}},
{'nexthop': '20.0.0.100',
'destination': '13.0.0.0/24',
'external_ids': {}}]
expected_added = [{'nexthop': '90.0.0.1',
'destination': '0.0.0.0/0',
'external_ids': {
ovn_const.OVN_ROUTER_IS_EXT_GW: 'true',
ovn_const.OVN_SUBNET_EXT_ID_KEY:
'ext-subnet'}},
{'nexthop': '20.0.0.100',
'destination': '13.0.0.0/24',
'external_ids': {}}]
expected_deleted = []
self._test_ovn_nb_sync_calculate_routes_helper(ovn_routes,
db_routes,
expected_added,
expected_deleted)
def test_ovn_nb_sync_calculate_routes_add_remove_keep_two_routes(self):
# add 2 routes to ovn, remove 2 routes from ovn, keep 2 routes
ovn_routes = [{'nexthop': '20.0.0.100',
'destination': '13.0.0.0/24',
'external_ids': {}},
{'nexthop': '90.0.0.1',
'destination': '0.0.0.0/0',
'external_ids': {
ovn_const.OVN_ROUTER_IS_EXT_GW: 'true',
ovn_const.OVN_SUBNET_EXT_ID_KEY:
'ext-subnet'}},
{'nexthop': '20.0.0.100',
'destination': '14.0.0.0/24',
'external_ids': {}},
{'nexthop': '20.0.0.100',
'destination': '15.0.0.0/24',
'external_ids': {}}]
db_routes = [{'nexthop': '20.0.0.100',
'destination': '11.0.0.0/24',
'external_ids': {}},
{'nexthop': '20.0.0.100',
'destination': '12.0.0.0/24',
'external_ids': {}},
{'nexthop': '20.0.0.100',
'destination': '13.0.0.0/24',
'external_ids': {}},
{'nexthop': '90.0.0.1',
'destination': '0.0.0.0/0',
'external_ids': {
ovn_const.OVN_ROUTER_IS_EXT_GW: 'true',
ovn_const.OVN_SUBNET_EXT_ID_KEY:
'ext-subnet'}}]
expected_added = [{'nexthop': '20.0.0.100',
'destination': '11.0.0.0/24',
'external_ids': {}},
{'nexthop': '20.0.0.100',
'destination': '12.0.0.0/24',
'external_ids': {}}]
expected_deleted = [{'nexthop': '20.0.0.100',
'destination': '14.0.0.0/24',
'external_ids': {}},
{'nexthop': '20.0.0.100',
'destination': '15.0.0.0/24',
'external_ids': {}}]
self._test_ovn_nb_sync_calculate_routes_helper(ovn_routes,
db_routes,
expected_added,
expected_deleted)
class TestOvnSbSyncML2(test_mech_driver.OVNMechanismDriverTestCase):