Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -332,11 +332,17 @@ def get_all_logical_routers_with_rports(self):
if ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY not in (
lrouter.external_ids):
continue
lrports = {lrport.name.replace('lrp-', ''): lrport.networks
for lrport in getattr(lrouter, 'ports', [])}
sroutes = [{'destination': sroute.ip_prefix,
'nexthop': sroute.nexthop}
for sroute in getattr(lrouter, 'static_routes', [])]
lrports = {
lrport.name.replace('lrp-', ''): lrport.networks
for lrport in getattr(lrouter, 'ports', [])
if ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY in lrport.external_ids
}
sroutes = [
{'destination': route.ip_prefix, 'nexthop': route.nexthop}
for route in getattr(lrouter, 'static_routes', [])
if any(eid.startswith(constants.DEVICE_OWNER_NEUTRON_PREFIX)
for eid in route.external_ids)
]

dnat_and_snats = []
snat = []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,8 @@ def check_for_igmp_snoop_support(self):

cmds = []
for ls in self._nb_idl.ls_list().execute(check_error=True):
if ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY not in ls.external_ids:
continue
snooping = ls.other_config.get(ovn_const.MCAST_SNOOP)
flood = ls.other_config.get(ovn_const.MCAST_FLOOD_UNREGISTERED)

Expand Down Expand Up @@ -572,9 +574,11 @@ def check_for_ha_chassis_group(self):
context = n_context.get_admin_context()
with self._nb_idl.transaction(check_error=True) as txn:
for port in external_ports:
network_id = port.external_ids[
ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY].replace(
network_id = port.external_ids.get(
ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY, '').replace(
ovn_const.OVN_NAME_PREFIX, '')
if not network_id:
continue
ha_ch_grp, high_prio_ch = utils.sync_ha_chassis_group_network(
context, self._nb_idl, self._sb_idl, port.name,
network_id, txn)
Expand Down Expand Up @@ -1005,6 +1009,9 @@ def set_network_type(self):
for seg in net_segments}
cmds = []
for ls in self._nb_idl.ls_list().execute(check_error=True):
if ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY not in ls.external_ids:
continue

if ovn_const.OVN_NETTYPE_EXT_ID_KEY not in ls.external_ids:
net_id = utils.get_neutron_name(ls.name)
external_ids = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,11 @@ def sync_port_groups(self, ctx):
ovn_pgs = set()
port_groups = self.ovn_api.db_list_rows('Port_Group').execute() or []
for pg in port_groups:
ovn_pgs.add(pg.name)
# Default neutron "drop pg" does NOT have any external IDs, but
# we still want to manage it, so we match it on its name.
if (ovn_const.OVN_SG_EXT_ID_KEY in pg.external_ids or
pg.name == ovn_const.OVN_DROP_PORT_GROUP_NAME):
ovn_pgs.add(pg.name)

add_pgs = neutron_pgs.difference(ovn_pgs)
remove_pgs = ovn_pgs.difference(neutron_pgs)
Expand Down Expand Up @@ -260,6 +264,11 @@ def _get_acls_from_port_groups(self):
acl_string['port_group'] = pg.name
if id_key in acl.external_ids:
acl_string[id_key] = acl.external_ids[id_key]
elif pg.name != ovn_const.OVN_DROP_PORT_GROUP_NAME:
# If ACL is not associated with a security group rule,
# nor it belongs to the default neutron_pg_drop port group,
# it don't need to be synced.
continue
# This properties are present as lists of one item,
# converting them to string.
if acl_string['name']:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ def setUp(self, *args):
self.expected_dns_records = []
self.expected_ports_with_unknown_addr = []
self.expected_qos_records = []
# Set of externally managed resources that should not
# be cleaned up by the sync_db
self.create_ext_port_groups = []
self.create_ext_lrouter_ports = []
self.create_ext_lrouter_routes = []

self.ctx = context.get_admin_context()
ovn_config.cfg.CONF.set_override('ovn_metadata_enabled', True,
group='ovn')
Expand Down Expand Up @@ -515,6 +521,9 @@ def _create_resources(self, restart_ovsdb_processes=False):
self.create_lrouter_routes.append(('neutron-' + r1['id'],
'10.13.0.0/24',
'20.0.0.13'))
self.create_ext_lrouter_routes.append(('neutron-' + r1['id'],
'10.14.0.0/24',
'20.0.0.14'))
self.delete_lrouter_routes.append(('neutron-' + r1['id'],
'10.10.0.0/24',
'20.0.0.10'))
Expand Down Expand Up @@ -662,10 +671,18 @@ def _create_resources(self, restart_ovsdb_processes=False):
'neutron-' + r1['id']))
self.create_lrouter_ports.append(('lrp-' + uuidutils.generate_uuid(),
'neutron-' + r1['id']))
self.create_ext_lrouter_ports.append(
('ext-lrp-' + uuidutils.generate_uuid(), 'neutron-' + r1['id'])
)
self.create_ext_lrouter_ports.append(
('ext-lrp-' + uuidutils.generate_uuid(), 'neutron-' + r1['id'])
)
self.delete_lrouters.append('neutron-' + r2['id'])

self.create_port_groups.extend([{'name': 'pg1', 'acls': []},
{'name': 'pg2', 'acls': []}])
self.create_ext_port_groups.extend([{'name': 'ext-pg1', 'acls': []},
{'name': 'ext-pg2', 'acls': []}])
self.delete_port_groups.append(
utils.ovn_port_group_name(n1_prtr['port']['security_groups'][0]))
# Create a network and subnet with orphaned OVN resources.
Expand Down Expand Up @@ -790,7 +807,14 @@ def _modify_resources_in_nb_db(self):
txn.add(self.nb_api.lr_del(lrouter_name, if_exists=True))

for lrport, lrouter_name in self.create_lrouter_ports:
txn.add(self.nb_api.add_lrouter_port(lrport, lrouter_name))
external_ids = {ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY:
lrouter_name}
txn.add(self.nb_api.add_lrouter_port(
lrport, lrouter_name, True, external_ids=external_ids))

for lrport, lrouter_name in self.create_ext_lrouter_ports:
txn.add(self.nb_api.add_lrouter_port(
lrport, lrouter_name, True))

for lrport, lrouter_name, networks in self.update_lrouter_ports:
txn.add(self.nb_api.update_lrouter_port(
Expand All @@ -807,6 +831,10 @@ def _modify_resources_in_nb_db(self):
ip_prefix=ip_prefix,
nexthop=nexthop,
**columns))
for lr_name, ip_prefix, nexthop in self.create_ext_lrouter_routes:
txn.add(self.nb_api.add_static_route(lr_name,
ip_prefix=ip_prefix,
nexthop=nexthop))
routers = defaultdict(list)
for lrouter_name, ip_prefix, nexthop in self.delete_lrouter_routes:
routers[lrouter_name].append((ip_prefix, nexthop))
Expand Down Expand Up @@ -839,7 +867,12 @@ def _modify_resources_in_nb_db(self):
txn.add(self.nb_api.delete_acl(lswitch_name,
lport_name, True))

columns = {
'external_ids': {ovn_const.OVN_SG_EXT_ID_KEY: 'sg_uuid'},
}
for pg in self.create_port_groups:
txn.add(self.nb_api.pg_add(**pg, **columns))
for pg in self.create_ext_port_groups:
txn.add(self.nb_api.pg_add(**pg))
for pg in self.delete_port_groups:
txn.add(self.nb_api.pg_del(pg))
Expand Down Expand Up @@ -1310,6 +1343,7 @@ def _get_ipv6_ra_configs_for_router_port(port):
self.ctx, port))
return ipv6_ra_configs

neutron_prefix = constants.DEVICE_OWNER_NEUTRON_PREFIX
for router_id in db_router_ids:
r_ports = self._list('ports',
query_params='device_id=%s' % (router_id))
Expand All @@ -1328,18 +1362,26 @@ def _get_ipv6_ra_configs_for_router_port(port):
lrouter = idlutils.row_by_value(
self.mech_driver.nb_ovn.idl, 'Logical_Router', 'name',
'neutron-' + str(router_id), None)
lports = getattr(lrouter, 'ports', [])
all_lports = getattr(lrouter, 'ports', [])
managed_lports = [
lport for lport in all_lports
if (ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY in
lport.external_ids)]

plugin_lrouter_port_ids = [lport.name.replace('lrp-', '')
for lport in lports]
for lport in managed_lports]
plugin_lport_networks = {
lport.name.replace('lrp-', ''): lport.networks
for lport in lports}
for lport in managed_lports}
plugin_lport_ra_configs = {
lport.name.replace('lrp-', ''): lport.ipv6_ra_configs
for lport in lports}
for lport in managed_lports}
sroutes = getattr(lrouter, 'static_routes', [])
plugin_routes = [sroute.ip_prefix + sroute.nexthop
for sroute in sroutes]
plugin_routes = []
for sroute in sroutes:
if any(e_id.startswith(neutron_prefix)
for e_id in sroute.external_ids):
plugin_routes.append(sroute.ip_prefix + sroute.nexthop)
nats = getattr(lrouter, 'nat', [])
plugin_nats = [
nat.external_ip + nat.logical_ip + nat.type +
Expand All @@ -1355,18 +1397,28 @@ def _get_ipv6_ra_configs_for_router_port(port):
lrouter = idlutils.row_by_value(
self.nb_api.idl, 'Logical_Router', 'name',
'neutron-' + router_id, None)
lports = getattr(lrouter, 'ports', [])
all_lports = getattr(lrouter, 'ports', [])
managed_lports = [
lport for lport in all_lports
if (ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY in
lport.external_ids)]
monitor_lrouter_port_ids = [lport.name.replace('lrp-', '')
for lport in lports]
for lport in managed_lports]
monitor_lport_networks = {
lport.name.replace('lrp-', ''): lport.networks
for lport in lports}
for lport in managed_lports}
monitor_lport_ra_configs = {
lport.name.replace('lrp-', ''): lport.ipv6_ra_configs
for lport in lports}
for lport in managed_lports}
sroutes = getattr(lrouter, 'static_routes', [])
monitor_routes = [sroute.ip_prefix + sroute.nexthop
for sroute in sroutes]
monitor_routes = []
for sroute in sroutes:
if any(e_id.startswith(neutron_prefix)
for e_id in sroute.external_ids):
monitor_routes.append(
sroute.ip_prefix + sroute.nexthop
)

nats = getattr(lrouter, 'nat', [])
monitor_nats = [
nat.external_ip + nat.logical_ip + nat.type +
Expand Down Expand Up @@ -1524,7 +1576,9 @@ def _validate_port_groups(self, should_match=True):

mn_pgs = []
for row in self.nb_api.tables['Port_Group'].rows.values():
mn_pgs.append(getattr(row, 'name', ''))
if (ovn_const.OVN_SG_EXT_ID_KEY in row.external_ids or
row.name == ovn_const.OVN_DROP_PORT_GROUP_NAME):
mn_pgs.append(getattr(row, 'name', ''))

if should_match:
self.assertCountEqual(nb_pgs, db_pgs)
Expand Down Expand Up @@ -1630,6 +1684,46 @@ def _test_ovn_nb_sync_helper(self, mode, modify_resources=True,

self._sync_resources(mode)
self._validate_resources(should_match=should_match_after_sync)
if not restart_ovsdb_processes:
# Restarting ovsdb-server removes all its previous content.
# We can not expect to find external resources in the DB
# if it was wiped out.
self._validate_external_resources()

def _validate_external_resources(self):
"""Ensure that resources not owned by Neutron are in the OVN DB.

This function is useful to validate that external resources survived
ovn_db_sync.
"""
db_routers = self._list('routers')
db_router_ids = [router['id'] for router in db_routers['routers']]

pgs = []
for pg in self.nb_api.tables['Port_Group'].rows.values():
pgs.append(pg.name)

lrports = []
sroutes = []
for router_id in db_router_ids:
lrouter = idlutils.row_by_value(
self.mech_driver.nb_ovn.idl, 'Logical_Router', 'name',
'neutron-' + str(router_id), None)

for lrport in getattr(lrouter, 'ports', []):
lrports.append(lrport.name)

for route in getattr(lrouter, 'static_routes', []):
sroutes.append(route.ip_prefix + route.nexthop)

for port_name, _ in self.create_ext_lrouter_ports:
self.assertIn(port_name, lrports)

for _, prefix, next_hop in self.create_ext_lrouter_routes:
self.assertIn(prefix + next_hop, sroutes)

for ext_pg in self.create_ext_port_groups:
self.assertIn(ext_pg['name'], pgs)

def test_ovn_nb_sync_repair(self):
self._test_ovn_nb_sync_helper(ovn_const.OVN_DB_SYNC_MODE_REPAIR)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,25 +183,46 @@ class TestNBImplIdlOvn(TestDBImplIdlOvn):
'networks': ['10.0.3.0/24'],
'options': {ovn_const.OVN_GATEWAY_CHASSIS_KEY: None}},
{'name': 'xrp-id-b1',
'external_ids': {}, 'networks': ['20.0.1.0/24']},
'external_ids': {
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY:
utils.ovn_name('lr-id-b'),
}, 'networks': ['20.0.1.0/24']},
{'name': utils.ovn_lrouter_port_name('orp-id-b2'),
'external_ids': {}, 'networks': ['20.0.2.0/24'],
'external_ids': {
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY:
utils.ovn_name('lr-id-b')},
'networks': ['20.0.2.0/24'],
'options': {ovn_const.OVN_GATEWAY_CHASSIS_KEY: 'host-2'}},
{'name': utils.ovn_lrouter_port_name('orp-id-b3'),
'external_ids': {}, 'networks': ['20.0.3.0/24'],
'external_ids': {
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY:
utils.ovn_name('lr-id-b')},
'networks': ['20.0.3.0/24'],
'options': {}},
{'name': utils.ovn_lrouter_port_name('gwc'),
'external_ids': {ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'lr-id-f',
ovn_const.OVN_ROUTER_IS_EXT_GW: str(True)},
'networks': ['10.0.4.0/24'],
'options': {}},
{'name': utils.ovn_lrouter_port_name('not-managed'),
'external_ids': {
'owner': 'not-owned-by-neutron'},
'networks': ['10.0.5.0/24'],
'options': {}}],
'gateway_chassis': [
{'chassis_name': 'fake-chassis',
'name': utils.ovn_lrouter_port_name('gwc') + '_fake-chassis'}],
'static_routes': [{'ip_prefix': '20.0.0.0/16',
'nexthop': '10.0.3.253'},
'nexthop': '10.0.3.253',
'external_ids': {
ovn_const.OVN_SUBNET_EXT_ID_KEY: 'uuid_1'}},
{'ip_prefix': '10.0.0.0/16',
'nexthop': '20.0.2.253'}],
'nexthop': '20.0.2.253',
'external_ids': {
ovn_const.OVN_SUBNET_EXT_ID_KEY: 'uuid_2'}},
{'ip_prefix': '30.0.0.0/16',
'nexthop': '30.0.4.253',
'external_ids': {'owner': 'not-owned-by-neutron'}}],
'nats': [{'external_ip': '10.0.3.1', 'logical_ip': '20.0.0.0/16',
'type': 'snat'},
{'external_ip': '20.0.2.1', 'logical_ip': '10.0.0.0/24',
Expand Down Expand Up @@ -481,7 +502,7 @@ def test_get_all_logical_switches_with_ports(self):

def _test_get_all_logical_routers_with_rports(self, is_gw_port):
# Test empty
mapping = self.nb_ovn_idl.get_all_logical_switches_with_ports()
mapping = self.nb_ovn_idl.get_all_logical_routers_with_rports()
self.assertCountEqual(mapping, {})
# Test loaded values
self._load_nb_db()
Expand Down
Loading