def test_diff_list_of_dict(self): old_list = [{"key1": "value1"}, {"key2": "value2"}, {"key3": "value3"}] new_list = [{"key1": "value1"}, {"key2": "value2"}, {"key4": "value4"}] added, removed = helpers.diff_list_of_dict(old_list, new_list) self.assertEqual(added, [dict(key4="value4")]) self.assertEqual(removed, [dict(key3="value3")])
def update_router(self, context, id, router): original_router = self.get_router(context, id) result = super(OVNL3RouterPlugin, self).update_router(context, id, router) update = {} added = [] removed = [] router_name = utils.ovn_name(id) if 'admin_state_up' in router['router']: enabled = router['router']['admin_state_up'] if enabled != original_router['admin_state_up']: update['enabled'] = enabled if 'name' in router['router']: if router['router']['name'] != original_router['name']: external_ids = { ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: router['router']['name'] } update['external_ids'] = external_ids """Update static routes""" if 'routes' in router['router']: routes = router['router']['routes'] added, removed = helpers.diff_list_of_dict( original_router['routes'], routes) if update or added or removed: try: with self._ovn.transaction(check_error=True) as txn: if update: txn.add(self._ovn.update_lrouter( router_name, **update)) for route in added: txn.add( self._ovn.add_static_route( router_name, ip_prefix=route['destination'], nexthop=route['nexthop'])) for route in removed: txn.add( self._ovn.delete_static_route( router_name, ip_prefix=route['destination'], nexthop=route['nexthop'])) except Exception: LOG.exception(_LE('Unable to update lrouter for %s'), id) super(OVNL3RouterPlugin, self).update_router(context, id, original_router) raise n_exc.ServiceUnavailable() return result
def routes_updated(self, old_routes, new_routes): adds, removes = helpers.diff_list_of_dict(old_routes, new_routes) for route in adds: LOG.debug("Added route entry is '%s'", route) # remove replaced route from deleted route for del_route in removes: if route['destination'] == del_route['destination']: removes.remove(del_route) #replace success even if there is no existing route self.update_routing_table('replace', route) for route in removes: LOG.debug("Removed route entry is '%s'", route) self.update_routing_table('delete', route)
def _update_extra_routes(self, context, router, routes): self._validate_routes(context, router['id'], routes) old_routes, routes_dict = self._get_extra_routes_dict_by_router_id( context, router['id']) added, removed = helpers.diff_list_of_dict(old_routes, routes) LOG.debug('Added routes are %s', added) for route in added: router_routes = l3_models.RouterRoute( router_id=router['id'], destination=route['destination'], nexthop=route['nexthop']) context.session.add(router_routes) LOG.debug('Removed routes are %s', removed) for route in removed: context.session.delete(routes_dict[(route['destination'], route['nexthop'])])
def _update_extra_routes(self, context, router, routes): self._validate_routes(context, router['id'], routes) old_routes = self._get_extra_routes_by_router_id(context, router['id']) added, removed = helpers.diff_list_of_dict(old_routes, routes) LOG.debug('Added routes are %s', added) for route in added: l3_obj.RouterRoute( context, router_id=router['id'], destination=utils.AuthenticIPNetwork(route['destination']), nexthop=netaddr.IPAddress(route['nexthop'])).create() LOG.debug('Removed routes are %s', removed) for route in removed: l3_obj.RouterRoute.get_object(context, router_id=router['id'], destination=route['destination'], nexthop=route['nexthop']).delete()
def _update_extra_routes(self, context, router, routes): self._validate_routes(context, router['id'], routes) old_routes, routes_dict = self._get_extra_routes_dict_by_router_id( context, router['id']) added, removed = helpers.diff_list_of_dict(old_routes, routes) LOG.debug('Added routes are %s', added) for route in added: router_routes = l3_models.RouterRoute( router_id=router['id'], destination=route['destination'], nexthop=route['nexthop']) context.session.add(router_routes) LOG.debug('Removed routes are %s', removed) for route in removed: context.session.delete( routes_dict[(route['destination'], route['nexthop'])])
def _update_extra_routes(self, context, router, routes): self._validate_routes(context, router['id'], routes) old_routes = self._get_extra_routes_by_router_id(context, router['id']) added, removed = helpers.diff_list_of_dict(old_routes, routes) LOG.debug('Added routes are %s', added) for route in added: l3_obj.RouterRoute( context, router_id=router['id'], destination=utils.AuthenticIPNetwork(route['destination']), nexthop=netaddr.IPAddress(route['nexthop'])).create() LOG.debug('Removed routes are %s', removed) for route in removed: l3_obj.RouterRoute.get_object( context, router_id=router['id'], destination=route['destination'], nexthop=route['nexthop']).delete()
def update_router(self, context, id, router): original_router = self.get_router(context, id) result = super(OVNL3RouterPlugin, self).update_router(context, id, router) gateway_new = result.get(l3.EXTERNAL_GW_INFO) gateway_old = original_router.get(l3.EXTERNAL_GW_INFO) revert_router = {'router': original_router} try: if gateway_new and not gateway_old: # Route gateway is set self._add_router_ext_gw(context, result) elif gateway_old and not gateway_new: # router gateway is removed self._delete_router_ext_gw(context, id, original_router) elif gateway_new and gateway_old: # Check if external gateway has changed, if yes, delete the old # gateway and add the new gateway if (gateway_old['network_id'] != gateway_new['network_id'] or set([ str(fixed_ip) for fixed_ip in gateway_old['external_fixed_ips'] ]) != set([ str(fixed_ip) for fixed_ip in gateway_new['external_fixed_ips'] ])): self._delete_router_ext_gw(context, id, original_router) self._add_router_ext_gw(context, result) else: # Check if snat has been enabled/disabled and update old_snat_state = gateway_old.get('enable_snat', True) new_snat_state = gateway_new.get('enable_snat', True) if old_snat_state != new_snat_state: networks = self._get_v4_network_of_all_router_ports( context, id) self._update_snat_for_networks( context, result, networks, enable_snat=new_snat_state) except Exception: with excutils.save_and_reraise_exception(): LOG.error(_LE('Unable to update lrouter for %s'), id) super(OVNL3RouterPlugin, self).update_router(context, id, revert_router) # Check for change in admin_state_up update = {} router_name = utils.ovn_name(id) if 'admin_state_up' in router['router']: enabled = router['router']['admin_state_up'] if enabled != original_router['admin_state_up']: update['enabled'] = enabled # Check for change in name if 'name' in router['router']: if router['router']['name'] != original_router['name']: external_ids = { ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: router['router']['name'] } update['external_ids'] = external_ids if update: try: self._ovn.update_lrouter(router_name, **update).execute(check_error=True) except Exception: with excutils.save_and_reraise_exception(): LOG.error(_LE('Unable to update lrouter for %s'), id) super(OVNL3RouterPlugin, self).update_router(context, id, revert_router) # Check for route updates added = [] removed = [] if 'routes' in router['router']: routes = router['router']['routes'] added, removed = helpers.diff_list_of_dict( original_router['routes'], routes) if added or removed: try: self._update_lrouter_routes(context, id, added, removed) except Exception: with excutils.save_and_reraise_exception(): LOG.error( _LE('Unable to update static routes in lrouter ' '%s'), id) super(OVNL3RouterPlugin, self).update_router(context, id, revert_router) return result
def sync_routers_and_rports(self, ctx): """Sync Routers between neutron and NB. @param ctx: neutron context @type ctx: object of type neutron.context.Context @var db_routers: List of Routers from neutron DB @var db_router_ports: List of Router ports from neutron DB @var lrouters: NB dictionary of logical routers and the corresponding logical router ports. vs list-of-acls @var del_lrouters_list: List of Routers that need to be deleted from NB @var del_lrouter_ports_list: List of Router ports that need to be deleted from NB @return: Nothing """ if not config.is_ovn_l3(): LOG.debug("OVN L3 mode is disabled, skipping " "sync routers and router ports") return # TODO(chandrav): Add sync support for NAT, bug #1629076. LOG.debug('OVN-NB Sync Routers and Router ports started') db_routers = {} db_router_ports = {} for router in self.l3_plugin.get_routers(ctx): db_routers[router['id']] = router interfaces = self.l3_plugin._get_sync_interfaces(ctx, db_routers.keys()) for interface in interfaces: db_router_ports[interface['id']] = interface db_router_ports[interface['id']]['networks'] = sorted( self.l3_plugin.get_networks_for_lrouter_port( ctx, interface['fixed_ips'])) lrouters = self.ovn_api.get_all_logical_routers_with_rports() del_lrouters_list = [] del_lrouter_ports_list = [] update_sroutes_list = [] update_lrport_list = [] for lrouter in lrouters: if lrouter['name'] in db_routers: for lrport, lrport_nets in lrouter['ports'].items(): if lrport in db_router_ports: db_lrport_nets = db_router_ports[lrport]['networks'] if db_lrport_nets != sorted(lrport_nets): update_lrport_list.append(( lrouter['name'], db_router_ports[lrport])) del db_router_ports[lrport] else: del_lrouter_ports_list.append( {'port': lrport, 'lrouter': lrouter['name']}) if 'routes' in db_routers[lrouter['name']]: db_routes = db_routers[lrouter['name']]['routes'] else: db_routes = [] ovn_routes = lrouter['static_routes'] add_routes, del_routes = helpers.diff_list_of_dict( ovn_routes, db_routes) update_sroutes_list.append({'id': lrouter['name'], 'add': add_routes, 'del': del_routes}) del db_routers[lrouter['name']] else: del_lrouters_list.append(lrouter) for r_id, router in db_routers.items(): LOG.warning(_LW("Router found in Neutron but not in " "OVN DB, router id=%s"), router['id']) if self.mode == SYNC_MODE_REPAIR: try: LOG.warning(_LW("Creating the router %s in OVN NB DB"), router['id']) self.l3_plugin.create_lrouter_in_ovn(router) if 'routes' in router: update_sroutes_list.append( {'id': router['id'], 'add': router['routes'], 'del': []}) except RuntimeError: LOG.warning(_LW("Create router in OVN NB failed for" " router %s"), router['id']) for rp_id, rrport in db_router_ports.items(): LOG.warning(_LW("Router Port found in Neutron but not in OVN " "DB, router port_id=%s"), rrport['id']) if self.mode == SYNC_MODE_REPAIR: try: LOG.warning(_LW("Creating the router port %s in " "OVN NB DB"), rrport['id']) self.l3_plugin.create_lrouter_port_in_ovn( ctx, rrport['device_id'], rrport) except RuntimeError: LOG.warning(_LW("Create router port in OVN " "NB failed for" " router port %s"), rrport['id']) for router_id, rport in update_lrport_list: LOG.warning(_LW("Router Port port_id=%s needs to be updated" " for networks changed"), rport['id']) if self.mode == SYNC_MODE_REPAIR: try: LOG.warning(_LW("Updating networks on router port %s in " "OVN NB DB"), rport['id']) self.l3_plugin.update_lrouter_port_in_ovn( ctx, router_id, rport, rport['networks']) except RuntimeError: LOG.warning(_LW("Update router port networks in OVN " "NB failed for" " router port %s"), rport['id']) with self.ovn_api.transaction(check_error=True) as txn: for lrouter in del_lrouters_list: LOG.warning(_LW("Router found in OVN but not in " "Neutron, router id=%s"), lrouter['name']) if self.mode == SYNC_MODE_REPAIR: LOG.warning(_LW("Deleting the router %s from OVN NB DB"), lrouter['name']) txn.add(self.ovn_api.delete_lrouter( utils.ovn_name(lrouter['name']))) for lrport_info in del_lrouter_ports_list: LOG.warning(_LW("Router Port found in OVN but not in " "Neutron, port_id=%s"), lrport_info['port']) if self.mode == SYNC_MODE_REPAIR: LOG.warning(_LW("Deleting the port %s from OVN NB DB"), lrport_info['port']) txn.add(self.ovn_api.delete_lrouter_port( utils.ovn_lrouter_port_name(lrport_info['port']), utils.ovn_name(lrport_info['lrouter']), if_exists=False)) for sroute in update_sroutes_list: if sroute['add']: LOG.warning(_LW("Router %(id)s static routes %(route)s " "found in Neutron but not in OVN"), {'id': sroute['id'], 'route': sroute['add']}) if self.mode == SYNC_MODE_REPAIR: LOG.warning(_LW("Add static routes %s to OVN NB DB"), sroute['add']) for route in sroute['add']: txn.add(self.ovn_api.add_static_route( utils.ovn_name(sroute['id']), ip_prefix=route['destination'], nexthop=route['nexthop'])) if sroute['del']: LOG.warning(_LW("Router %(id)s static routes %(route)s " "found in OVN but not in Neutron"), {'id': sroute['id'], 'route': sroute['del']}) if self.mode == SYNC_MODE_REPAIR: LOG.warning(_LW("Delete static routes %s from OVN " "NB DB"), sroute['del']) for route in sroute['del']: txn.add(self.ovn_api.delete_static_route( utils.ovn_name(sroute['id']), ip_prefix=route['destination'], nexthop=route['nexthop'])) LOG.debug('OVN-NB Sync routers and router ports finished')
def diff_list_of_dict(old_list, new_list): return helpers.diff_list_of_dict(old_list, new_list)
def sync_routers_and_rports(self, ctx): """Sync Routers between neutron and NB. @param ctx: neutron context @type ctx: object of type neutron.context.Context @var db_routers: List of Routers from neutron DB @var db_router_ports: List of Router ports from neutron DB @var lrouters: NB dictionary of logical routers and the corresponding logical router ports. vs list-of-acls @var del_lrouters_list: List of Routers that need to be deleted from NB @var del_lrouter_ports_list: List of Router ports that need to be deleted from NB @return: Nothing """ if not config.is_ovn_l3(): LOG.debug("OVN L3 mode is disabled, skipping " "sync routers and router ports") return LOG.debug('OVN-NB Sync Routers and Router ports started') db_routers = {} db_router_ports = {} for router in self.l3_plugin.get_routers(ctx): db_routers[router['id']] = router interfaces = self.l3_plugin._get_sync_interfaces( ctx, db_routers.keys()) for interface in interfaces: db_router_ports[interface['id']] = interface db_router_ports[interface['id']]['networks'] = sorted( self.l3_plugin.get_networks_for_lrouter_port( ctx, interface['fixed_ips'])) lrouters = self.ovn_api.get_all_logical_routers_with_rports() del_lrouters_list = [] del_lrouter_ports_list = [] update_sroutes_list = [] update_lrport_list = [] for lrouter in lrouters: if lrouter['name'] in db_routers: for lrport, lrport_nets in lrouter['ports'].items(): if lrport in db_router_ports: db_lrport_nets = db_router_ports[lrport]['networks'] if db_lrport_nets != sorted(lrport_nets): update_lrport_list.append( (lrouter['name'], db_router_ports[lrport])) del db_router_ports[lrport] else: del_lrouter_ports_list.append({ 'port': lrport, 'lrouter': lrouter['name'] }) if 'routes' in db_routers[lrouter['name']]: db_routes = db_routers[lrouter['name']]['routes'] else: db_routes = [] ovn_routes = lrouter['static_routes'] add_routes, del_routes = helpers.diff_list_of_dict( ovn_routes, db_routes) update_sroutes_list.append({ 'id': lrouter['name'], 'add': add_routes, 'del': del_routes }) del db_routers[lrouter['name']] else: del_lrouters_list.append(lrouter) for r_id, router in db_routers.items(): LOG.warning( _LW("Router found in Neutron but not in " "OVN DB, router id=%s"), router['id']) if self.mode == SYNC_MODE_REPAIR: try: LOG.warning(_LW("Creating the router %s in OVN NB DB"), router['id']) self.l3_plugin.create_lrouter_in_ovn(router) if 'routes' in router: update_sroutes_list.append({ 'id': router['id'], 'add': router['routes'], 'del': [] }) except RuntimeError: LOG.warning( _LW("Create router in OVN NB failed for" " router %s"), router['id']) for rp_id, rrport in db_router_ports.items(): LOG.warning( _LW("Router Port found in Neutron but not in OVN " "DB, router port_id=%s"), rrport['id']) if self.mode == SYNC_MODE_REPAIR: try: LOG.warning( _LW("Creating the router port %s in " "OVN NB DB"), rrport['id']) self.l3_plugin.create_lrouter_port_in_ovn( ctx, rrport['device_id'], rrport) except RuntimeError: LOG.warning( _LW("Create router port in OVN " "NB failed for" " router port %s"), rrport['id']) for router_id, rport in update_lrport_list: LOG.warning( _LW("Router Port port_id=%s needs to be updated" " for networks changed"), rport['id']) if self.mode == SYNC_MODE_REPAIR: try: LOG.warning( _LW("Updating networks on router port %s in " "OVN NB DB"), rport['id']) self.l3_plugin.update_lrouter_port_in_ovn( ctx, router_id, rport, rport['networks']) except RuntimeError: LOG.warning( _LW("Update router port networks in OVN " "NB failed for" " router port %s"), rport['id']) with self.ovn_api.transaction(check_error=True) as txn: for lrouter in del_lrouters_list: LOG.warning( _LW("Router found in OVN but not in " "Neutron, router id=%s"), lrouter['name']) if self.mode == SYNC_MODE_REPAIR: LOG.warning(_LW("Deleting the router %s from OVN NB DB"), lrouter['name']) txn.add( self.ovn_api.delete_lrouter( utils.ovn_name(lrouter['name']))) for lrport_info in del_lrouter_ports_list: LOG.warning( _LW("Router Port found in OVN but not in " "Neutron, port_id=%s"), lrport_info['port']) if self.mode == SYNC_MODE_REPAIR: LOG.warning(_LW("Deleting the port %s from OVN NB DB"), lrport_info['port']) txn.add( self.ovn_api.delete_lrouter_port( utils.ovn_lrouter_port_name(lrport_info['port']), utils.ovn_name(lrport_info['lrouter']), if_exists=False)) for sroute in update_sroutes_list: if sroute['add']: LOG.warning( _LW("Router %(id)s static routes %(route)s " "found in Neutron but not in OVN"), { 'id': sroute['id'], 'route': sroute['add'] }) if self.mode == SYNC_MODE_REPAIR: LOG.warning(_LW("Add static routes %s to OVN NB DB"), sroute['add']) for route in sroute['add']: txn.add( self.ovn_api.add_static_route( utils.ovn_name(sroute['id']), ip_prefix=route['destination'], nexthop=route['nexthop'])) if sroute['del']: LOG.warning( _LW("Router %(id)s static routes %(route)s " "found in OVN but not in Neutron"), { 'id': sroute['id'], 'route': sroute['del'] }) if self.mode == SYNC_MODE_REPAIR: LOG.warning( _LW("Delete static routes %s from OVN " "NB DB"), sroute['del']) for route in sroute['del']: txn.add( self.ovn_api.delete_static_route( utils.ovn_name(sroute['id']), ip_prefix=route['destination'], nexthop=route['nexthop'])) LOG.debug('OVN-NB Sync routers and router ports finished')
def scan_encaps(self, previous, sync): """Scan encap rules and check which rules is new/changed/removed Args: previous(dict): previous encap information {"targets": list "targets_updated": list "targets_removed": list } sync(Bool): If this is true, all current encap rules as new Return: encap_info(dict): same format as previous(dict) """ encap_info = { 'targets': [], 'targets_updated': [], 'targets_removed': [] } updated_encaps = self.rpc_callbacks.get_and_clear_updated_encaps() all_encaps = self.mgr.get_all_encap_rules() if previous is None: previous = { 'targets': [], 'targets_updated': [], 'targets_removed': [] } if sync: LOG.info("Sync all encap rules") encap_nets = self.resource_rpc.bulk_pull( self.context, objects.SRv6EncapNetwork.obj_name()) # NOTE: Fails to get encap_nets.encap_rules so gets encap_rules bulk_encap_rules = self.resource_rpc.bulk_pull( self.context, objects.SRv6EncapRule.obj_name()) current_encaps = [] for encap_net in encap_nets: net_id = encap_net['network_id'] project_id = encap_net['project_id'] network_type = self.network_type_map.get(net_id) if network_type is None: network_info = self.dhcp_rpc.get_network_info(net_id) network_type = network_info["provider:network_type"] self.network_type_map[net_id] = network_type vrf = vrf_utils.get_vrf_name(network_type, project_id, net_id) encap_rules = [] for rule in bulk_encap_rules: if rule.srv6_encap_network_id != encap_net['id']: continue encap_rules.append({ "destination": rule['destination'], "nexthop": rule['nexthop'] }) current_encaps.append({ 'id': encap_net['id'], 'rules': encap_rules, 'vrf': vrf }) for encap in current_encaps: for pre_encap in all_encaps: if encap['id'] == pre_encap['id']: added, removed = helpers.diff_list_of_dict( pre_encap['rules'], encap['rules']) encap_info['targets_updated'].append({ 'id': encap['id'], 'rules': added, 'vrf': encap['vrf'] }) encap_info['targets_removed'].append({ 'id': encap['id'], 'rules': removed, 'vrf': encap['vrf'] }) break else: encap_info['targets_updated'].append({ 'id': encap['id'], 'rules': encap['rules'], 'vrf': encap['vrf'] }) encap_info['targets'] = current_encaps else: for encap in updated_encaps: for pre_encap in previous['targets']: if encap['id'] == pre_encap['id']: added, removed = helpers.diff_list_of_dict( pre_encap['rules'], encap['rules']) encap_info['targets_updated'].append({ 'id': encap['id'], 'rules': added, 'vrf': encap['vrf'] }) encap_info['targets_removed'].append({ 'id': encap['id'], 'rules': removed, 'vrf': encap['vrf'] }) if (len(removed) != len(pre_encap['rules'])) or added: encap_info['targets'].append(encap) previous['targets'].remove(pre_encap) break else: encap_info['targets_updated'].append({ 'id': encap['id'], 'rules': encap['rules'], 'vrf': encap['vrf'] }) encap_info['targets'].append(encap) encap_info['targets'] += previous['targets'] return encap_info
def update_router(self, context, id, router): original_router = self.get_router(context, id) result = super(OVNL3RouterPlugin, self).update_router(context, id, router) gateway_new = result.get(l3.EXTERNAL_GW_INFO) gateway_old = original_router.get(l3.EXTERNAL_GW_INFO) try: if gateway_new and not gateway_old: # Route gateway is set self._add_router_ext_gw(context, result) elif gateway_old and not gateway_new: # router gateway is removed self._delete_router_ext_gw(context, id, original_router) elif gateway_new and gateway_old: # Check if external gateway has changed, if yes, delete the old # gateway and add the new gateway if gateway_old['network_id'] != gateway_new['network_id']: self._delete_router_ext_gw(context, id, original_router) self._add_router_ext_gw(context, result) # Check if snat has been enabled/disabled and update old_snat_state = gateway_old.get('enable_snat', 'True') new_snat_state = gateway_new.get('enable_snat', 'True') if old_snat_state != new_snat_state: networks = self._get_v4_network_of_all_router_ports( context, id) self._update_snat_and_static_routes_for_networks( context, result, networks, nexthop=None, enable_snat=new_snat_state, update_static_routes=False) except Exception: with excutils.save_and_reraise_exception(): revert_router = {} LOG.error(_LE('Unable to update lrouter for %s'), id) revert_router['router'] = original_router super(OVNL3RouterPlugin, self).update_router(context, id, revert_router) # Check for change in admin_state_up update = {} router_name = utils.ovn_name(id) if 'admin_state_up' in router['router']: enabled = router['router']['admin_state_up'] if enabled != original_router['admin_state_up']: update['enabled'] = enabled # Check for change in name if 'name' in router['router']: if router['router']['name'] != original_router['name']: external_ids = {ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: router['router']['name']} update['external_ids'] = external_ids if update: try: self._ovn.update_lrouter(router_name, **update).execute( check_error=True) except Exception: with excutils.save_and_reraise_exception(): LOG.error(_LE('Unable to update lrouter for %s'), id) router['router'] = original_router super(OVNL3RouterPlugin, self).update_router(context, id, router) # Check for route updates added = [] removed = [] if 'routes' in router['router']: routes = router['router']['routes'] added, removed = helpers.diff_list_of_dict( original_router['routes'], routes) if added or removed: try: self._update_lrouter_routes(context, id, added, removed) except Exception: with excutils.save_and_reraise_exception(): LOG.error(_LE('Unable to update static routes in lrouter ' '%s'), id) router['router'] = original_router super(OVNL3RouterPlugin, self).update_router(context, id, router) return result
def sync_routers_and_rports(self, ctx): """Sync Routers between neutron and NB. @param ctx: neutron_lib.context @type ctx: object of type neutron_lib.context.Context @var db_routers: List of Routers from neutron DB @var db_router_ports: List of Router ports from neutron DB @var lrouters: NB dictionary of logical routers and the corresponding logical router ports. vs list-of-acls @var del_lrouters_list: List of Routers that need to be deleted from NB @var del_lrouter_ports_list: List of Router ports that need to be deleted from NB @return: Nothing """ if not config.is_ovn_l3(): LOG.debug("OVN L3 mode is disabled, skipping " "sync routers and router ports") return LOG.debug('OVN-NB Sync Routers and Router ports started @ %s' % str(datetime.now())) db_routers = {} db_extends = {} db_router_ports = {} for router in self.l3_plugin.get_routers(ctx): db_routers[router['id']] = router db_extends[router['id']] = {} db_extends[router['id']]['routes'] = [] db_extends[router['id']]['snats'] = [] db_extends[router['id']]['fips'] = [] if not router.get(l3.EXTERNAL_GW_INFO): continue r_ip, gw_ip = self.l3_plugin.get_external_router_and_gateway_ip( ctx, router) if gw_ip: db_extends[router['id']]['routes'].append({ 'destination': '0.0.0.0/0', 'nexthop': gw_ip }) if r_ip and utils.is_snat_enabled(router): networks = self.l3_plugin._get_v4_network_of_all_router_ports( ctx, router['id']) for network in networks: db_extends[router['id']]['snats'].append({ 'logical_ip': network, 'external_ip': r_ip, 'type': 'snat' }) fips = self.l3_plugin.get_floatingips( ctx, {'router_id': list(db_routers.keys())}) for fip in fips: db_extends[fip['router_id']]['fips'].append({ 'external_ip': fip['floating_ip_address'], 'logical_ip': fip['fixed_ip_address'], 'type': 'dnat_and_snat' }) interfaces = self.l3_plugin._get_sync_interfaces( ctx, db_routers.keys(), [ constants.DEVICE_OWNER_ROUTER_INTF, constants.DEVICE_OWNER_ROUTER_GW ]) for interface in interfaces: db_router_ports[interface['id']] = interface db_router_ports[interface['id']]['networks'] = sorted( self.l3_plugin.get_networks_for_lrouter_port( ctx, interface['fixed_ips'])) lrouters = self.ovn_api.get_all_logical_routers_with_rports() del_lrouters_list = [] del_lrouter_ports_list = [] update_sroutes_list = [] update_lrport_list = [] update_snats_list = [] update_fips_list = [] for lrouter in lrouters: if lrouter['name'] in db_routers: for lrport, lrport_nets in lrouter['ports'].items(): if lrport in db_router_ports: db_lrport_nets = db_router_ports[lrport]['networks'] if db_lrport_nets != sorted(lrport_nets): update_lrport_list.append( (lrouter['name'], db_router_ports[lrport])) del db_router_ports[lrport] else: del_lrouter_ports_list.append({ 'port': lrport, 'lrouter': lrouter['name'] }) if 'routes' in db_routers[lrouter['name']]: db_routes = db_routers[lrouter['name']]['routes'] else: db_routes = [] if 'routes' in db_extends[lrouter['name']]: db_routes.extend(db_extends[lrouter['name']]['routes']) ovn_routes = lrouter['static_routes'] add_routes, del_routes = helpers.diff_list_of_dict( ovn_routes, db_routes) update_sroutes_list.append({ 'id': lrouter['name'], 'add': add_routes, 'del': del_routes }) ovn_fips = lrouter['dnat_and_snats'] db_fips = db_extends[lrouter['name']]['fips'] add_fips, del_fips = helpers.diff_list_of_dict( ovn_fips, db_fips) update_fips_list.append({ 'id': lrouter['name'], 'add': add_fips, 'del': del_fips }) ovn_nats = lrouter['snats'] db_snats = db_extends[lrouter['name']]['snats'] add_snats, del_snats = helpers.diff_list_of_dict( ovn_nats, db_snats) update_snats_list.append({ 'id': lrouter['name'], 'add': add_snats, 'del': del_snats }) del db_routers[lrouter['name']] else: del_lrouters_list.append(lrouter) for r_id, router in db_routers.items(): LOG.warning( _LW("Router found in Neutron but not in " "OVN DB, router id=%s"), router['id']) if self.mode == SYNC_MODE_REPAIR: try: LOG.warning(_LW("Creating the router %s in OVN NB DB"), router['id']) self.l3_plugin.create_lrouter_in_ovn(router) if 'routes' in router: update_sroutes_list.append({ 'id': router['id'], 'add': router['routes'], 'del': [] }) if 'routes' in db_extends[router['id']]: update_sroutes_list.append({ 'id': router['id'], 'add': db_extends[router['id']]['routes'], 'del': [] }) if 'snats' in db_extends[router['id']]: update_snats_list.append({ 'id': router['id'], 'add': db_extends[router['id']]['snats'], 'del': [] }) if 'fips' in db_extends[router['id']]: update_fips_list.append({ 'id': router['id'], 'add': db_extends[router['id']]['fips'], 'del': [] }) except RuntimeError: LOG.warning( _LW("Create router in OVN NB failed for" " router %s"), router['id']) for rp_id, rrport in db_router_ports.items(): LOG.warning( _LW("Router Port found in Neutron but not in OVN " "DB, router port_id=%s"), rrport['id']) if self.mode == SYNC_MODE_REPAIR: try: LOG.warning( _LW("Creating the router port %s in " "OVN NB DB"), rrport['id']) self.l3_plugin.create_lrouter_port_in_ovn( ctx, rrport['device_id'], rrport) except RuntimeError: LOG.warning( _LW("Create router port in OVN " "NB failed for" " router port %s"), rrport['id']) for router_id, rport in update_lrport_list: LOG.warning( _LW("Router Port port_id=%s needs to be updated" " for networks changed"), rport['id']) if self.mode == SYNC_MODE_REPAIR: try: LOG.warning( _LW("Updating networks on router port %s in " "OVN NB DB"), rport['id']) self.l3_plugin.update_lrouter_port_in_ovn( ctx, router_id, rport, rport['networks']) except RuntimeError: LOG.warning( _LW("Update router port networks in OVN " "NB failed for" " router port %s"), rport['id']) with self.ovn_api.transaction(check_error=True) as txn: for lrouter in del_lrouters_list: LOG.warning( _LW("Router found in OVN but not in " "Neutron, router id=%s"), lrouter['name']) if self.mode == SYNC_MODE_REPAIR: LOG.warning(_LW("Deleting the router %s from OVN NB DB"), lrouter['name']) txn.add( self.ovn_api.delete_lrouter( utils.ovn_name(lrouter['name']))) for lrport_info in del_lrouter_ports_list: LOG.warning( _LW("Router Port found in OVN but not in " "Neutron, port_id=%s"), lrport_info['port']) if self.mode == SYNC_MODE_REPAIR: LOG.warning(_LW("Deleting the port %s from OVN NB DB"), lrport_info['port']) txn.add( self.ovn_api.delete_lrouter_port( utils.ovn_lrouter_port_name(lrport_info['port']), utils.ovn_name(lrport_info['lrouter']), if_exists=False)) for sroute in update_sroutes_list: if sroute['add']: LOG.warning( _LW("Router %(id)s static routes %(route)s " "found in Neutron but not in OVN"), { 'id': sroute['id'], 'route': sroute['add'] }) if self.mode == SYNC_MODE_REPAIR: LOG.warning(_LW("Add static routes %s to OVN NB DB"), sroute['add']) for route in sroute['add']: txn.add( self.ovn_api.add_static_route( utils.ovn_name(sroute['id']), ip_prefix=route['destination'], nexthop=route['nexthop'])) if sroute['del']: LOG.warning( _LW("Router %(id)s static routes %(route)s " "found in OVN but not in Neutron"), { 'id': sroute['id'], 'route': sroute['del'] }) if self.mode == SYNC_MODE_REPAIR: LOG.warning( _LW("Delete static routes %s from OVN " "NB DB"), sroute['del']) for route in sroute['del']: txn.add( self.ovn_api.delete_static_route( utils.ovn_name(sroute['id']), ip_prefix=route['destination'], nexthop=route['nexthop'])) for fip in update_fips_list: if fip['del']: LOG.warning( _LW("Router %(id)s floating ips %(fip)s " "found in OVN but not in Neutron"), { 'id': fip['id'], 'fip': fip['del'] }) if self.mode == SYNC_MODE_REPAIR: LOG.warning( _LW("Delete floating ips %s from OVN NB DB"), fip['del']) for nat in fip['del']: txn.add( self.ovn_api.delete_nat_rule_in_lrouter( utils.ovn_name(fip['id']), logical_ip=nat['logical_ip'], external_ip=nat['external_ip'], type='dnat_and_snat')) if fip['add']: LOG.warning( _LW("Router %(id)s floating ips %(fip)s " "found in Neutron but not in OVN"), { 'id': fip['id'], 'fip': fip['add'] }) if self.mode == SYNC_MODE_REPAIR: LOG.warning(_LW("Add floating ips %s to OVN NB DB"), fip['add']) for nat in fip['add']: txn.add( self.ovn_api.add_nat_rule_in_lrouter( utils.ovn_name(fip['id']), logical_ip=nat['logical_ip'], external_ip=nat['external_ip'], type='dnat_and_snat')) for snat in update_snats_list: if snat['del']: LOG.warning( _LW("Router %(id)s snat %(snat)s " "found in OVN but not in Neutron"), { 'id': snat['id'], 'snat': snat['del'] }) if self.mode == SYNC_MODE_REPAIR: LOG.warning(_LW("Delete snats %s from OVN NB DB"), snat['del']) for nat in snat['del']: txn.add( self.ovn_api.delete_nat_rule_in_lrouter( utils.ovn_name(snat['id']), logical_ip=nat['logical_ip'], external_ip=nat['external_ip'], type='snat')) if snat['add']: LOG.warning( _LW("Router %(id)s snat %(snat)s " "found in Neutron but not in OVN"), { 'id': snat['id'], 'snat': snat['add'] }) if self.mode == SYNC_MODE_REPAIR: LOG.warning(_LW("Add snats %s to OVN NB DB"), snat['add']) for nat in snat['add']: txn.add( self.ovn_api.add_nat_rule_in_lrouter( utils.ovn_name(snat['id']), logical_ip=nat['logical_ip'], external_ip=nat['external_ip'], type='snat')) LOG.debug('OVN-NB Sync routers and router ports finished %s' % str(datetime.now()))