def test_get_all_chassis_gateway_bindings(self): self._load_nb_db() bindings = self.nb_ovn_idl.get_all_chassis_gateway_bindings() expected = { 'host-1': [ utils.ovn_lrouter_port_name('orp-id-a1'), utils.ovn_lrouter_port_name('orp-id-a2') ], 'host-2': [utils.ovn_lrouter_port_name('orp-id-b2')], ovn_const.OVN_GATEWAY_INVALID_CHASSIS: [utils.ovn_name('orp-id-a3')] } self.assertItemsEqual(bindings, expected) bindings = self.nb_ovn_idl.get_all_chassis_gateway_bindings([]) self.assertItemsEqual(bindings, expected) bindings = self.nb_ovn_idl.get_all_chassis_gateway_bindings(['host-1']) expected = { 'host-1': [ utils.ovn_lrouter_port_name('orp-id-a1'), utils.ovn_lrouter_port_name('orp-id-a2') ] } self.assertItemsEqual(bindings, expected)
def test_get_unhosted_gateways(self): self._load_nb_db() # Test only host-1 in the valid list unhosted_gateways = self.nb_ovn_idl.get_unhosted_gateways(['host-1']) expected = { utils.ovn_lrouter_port_name('orp-id-b2'): { ovn_const.OVN_GATEWAY_CHASSIS_KEY: 'host-2' }, utils.ovn_lrouter_port_name('orp-id-a3'): { ovn_const.OVN_GATEWAY_CHASSIS_KEY: ovn_const.OVN_GATEWAY_INVALID_CHASSIS } } self.assertItemsEqual(unhosted_gateways, expected) # Test both host-1, host-2 in valid list unhosted_gateways = self.nb_ovn_idl.get_unhosted_gateways( ['host-1', 'host-2']) expected = { utils.ovn_lrouter_port_name('orp-id-a3'): { ovn_const.OVN_GATEWAY_CHASSIS_KEY: ovn_const.OVN_GATEWAY_INVALID_CHASSIS } } self.assertItemsEqual(unhosted_gateways, expected) # Schedule unhosted_gateways on host-2 for unhosted_gateway in unhosted_gateways: router_row = self._find_ovsdb_fake_row(self.lrp_table, 'name', unhosted_gateway) setattr(router_row, 'options', {ovn_const.OVN_GATEWAY_CHASSIS_KEY: 'host-2'}) unhosted_gateways = self.nb_ovn_idl.get_unhosted_gateways( ['host-1', 'host-2']) self.assertItemsEqual(unhosted_gateways, {})
def _disjoin_lrouter_and_gw_lrouter(self, router, transit_net_ports): router_id = router['id'] lrouter_name = utils.ovn_name(router_id) gw_lrouter_name = utils.ovn_gateway_router_name(router_id) gtrp_ip = transit_net_ports['gtsp']['ip'] gtrp_name = utils.ovn_lrouter_port_name(utils.ovn_gtsp_name(router_id)) dtrp_name = utils.ovn_lrouter_port_name(utils.ovn_dtsp_name(router_id)) lswitch_name = utils.ovn_transit_ls_name(router_id) dtsp_name = utils.ovn_dtsp_name(router_id) gtsp_name = utils.ovn_gtsp_name(router_id) with self._ovn.transaction(check_error=True) as txn: # 1. Delete default static route in gateway router txn.add(self._ovn.delete_static_route( lrouter_name, ip_prefix="0.0.0.0/0", nexthop=gtrp_ip)) # 2. Delete gtrp port txn.add(self._ovn.delete_lrouter_port(gtrp_name, gw_lrouter_name)) # 3. Delete dtrp port txn.add(self._ovn.delete_lrouter_port(dtrp_name, lrouter_name)) # 4. Delete gtsp port txn.add(self._ovn.delete_lswitch_port(gtsp_name, lswitch_name)) # 5. Delete dtsp port txn.add(self._ovn.delete_lswitch_port(dtsp_name, lswitch_name)) # 6. Delete transit logical switch txn.add(self._ovn.delete_lswitch(lswitch_name))
def _join_lrouter_and_gw_lrouter(self, router, transit_net_ports): router_id = router['id'] lswitch_name = utils.ovn_transit_ls_name(router_id) dtsp_name = utils.ovn_dtsp_name(router_id) dtsp_addresses = transit_net_ports['dtsp']['addresses'] gtsp_name = utils.ovn_gtsp_name(router_id) gtsp_addresses = transit_net_ports['gtsp']['addresses'] gw_lrouter_name = utils.ovn_gateway_router_name(router_id) lrouter_name = utils.ovn_name(router_id) gtrp_name = utils.ovn_lrouter_port_name(utils.ovn_gtsp_name(router_id)) gtrp_mac = transit_net_ports['gtsp']['mac_address'] gtrp_ip = transit_net_ports['gtsp']['ip'] cidr = netaddr.IPNetwork(self._l3_admin_net_cidr) gtrp_network = "%s/%s" % (gtrp_ip, str(cidr.prefixlen)) dtrp_name = utils.ovn_lrouter_port_name(utils.ovn_dtsp_name(router_id)) dtrp_mac = transit_net_ports['dtsp']['mac_address'] dtrp_ip = transit_net_ports['dtsp']['ip'] dtrp_network = "%s/%s" % (dtrp_ip, str(cidr.prefixlen)) with self._ovn.transaction(check_error=True) as txn: # 1. Create a transit logical switch txn.add(self._ovn.create_lswitch(lswitch_name=lswitch_name)) # 2. Add dtsp port txn.add(self._ovn.create_lswitch_port(lport_name=dtsp_name, lswitch_name=lswitch_name, addresses=dtsp_addresses, enabled='True')) # 3. Add gtsp port txn.add(self._ovn.create_lswitch_port(lport_name=gtsp_name, lswitch_name=lswitch_name, addresses=gtsp_addresses, enabled='True')) # 4. Add dtrp port in logical router txn.add(self._ovn.add_lrouter_port(name=dtrp_name, lrouter=lrouter_name, mac=dtrp_mac, networks=dtrp_network)) txn.add(self._ovn.set_lrouter_port_in_lswitch_port( utils.ovn_dtsp_name(router_id), dtrp_name)) # 5. Add gtrp port in gateway router txn.add(self._ovn.add_lrouter_port(name=gtrp_name, lrouter=gw_lrouter_name, mac=gtrp_mac, networks=gtrp_network)) txn.add(self._ovn.set_lrouter_port_in_lswitch_port( utils.ovn_gtsp_name(router_id), gtrp_name)) # 6. Add default static route in gateway router with nexthop as # gtrp ip txn.add(self._ovn.add_static_route(lrouter_name, ip_prefix='0.0.0.0/0', nexthop=gtrp_ip))
def test_get_gateway_chassis_binding(self): self._load_nb_db() chassis = self.nb_ovn_idl.get_gateway_chassis_binding( utils.ovn_lrouter_port_name('orp-id-a1')) self.assertEqual(chassis, 'host-1') chassis = self.nb_ovn_idl.get_gateway_chassis_binding( utils.ovn_lrouter_port_name('orp-id-b2')) self.assertEqual(chassis, 'host-2') chassis = self.nb_ovn_idl.get_gateway_chassis_binding( utils.ovn_lrouter_port_name('orp-id-a3')) self.assertIsNone(chassis) chassis = self.nb_ovn_idl.get_gateway_chassis_binding( utils.ovn_lrouter_port_name('orp-id-b3')) self.assertIsNone(chassis) chassis = self.nb_ovn_idl.get_gateway_chassis_binding('bad') self.assertIsNone(chassis)
def create_lrouter_port_in_ovn(self, context, router_id, port): """Create lrouter port in OVN @param router id : LRouter ID for the port that needs to be created @param port : LRouter port that needs to be created @return: Nothing """ subnet_id = port['fixed_ips'][0]['subnet_id'] subnet = self._plugin.get_subnet(context, subnet_id) lrouter = utils.ovn_name(router_id) cidr = netaddr.IPNetwork(subnet['cidr']) network = "%s/%s" % (port['fixed_ips'][0]['ip_address'], str(cidr.prefixlen)) lrouter_port_name = utils.ovn_lrouter_port_name(port['id']) with self._ovn.transaction(check_error=True) as txn: txn.add( self._ovn.add_lrouter_port(name=lrouter_port_name, lrouter=lrouter, mac=port['mac_address'], network=network)) txn.add( self._ovn.set_lrouter_port_in_lswitch_port( port['id'], lrouter_port_name))
def test_get_gateway_chassis_binding(self): self._load_nb_db() chassis = self.nb_ovn_idl.get_gateway_chassis_binding( utils.ovn_lrouter_port_name('orp-id-a1')) self.assertEqual(chassis, ['host-1']) chassis = self.nb_ovn_idl.get_gateway_chassis_binding( utils.ovn_lrouter_port_name('orp-id-b2')) self.assertEqual(chassis, ['host-2']) chassis = self.nb_ovn_idl.get_gateway_chassis_binding( utils.ovn_lrouter_port_name('orp-id-a3')) self.assertEqual(chassis, ['neutron-ovn-invalid-chassis']) chassis = self.nb_ovn_idl.get_gateway_chassis_binding( utils.ovn_lrouter_port_name('orp-id-b3')) self.assertEqual(chassis, []) chassis = self.nb_ovn_idl.get_gateway_chassis_binding('bad') self.assertEqual(chassis, [])
def _test_router_port_ipv6_ra_configs_helper( self, cidr='aef0::/64', ip_version=6, address_mode=n_consts.IPV6_SLAAC,): router1 = self._create_router('router1') n1 = self._make_network(self.fmt, 'n1', True) if ip_version == 6: kwargs = {'ip_version': 6, 'cidr': 'aef0::/64', 'ipv6_address_mode': address_mode, 'ipv6_ra_mode': address_mode} else: kwargs = {'ip_version': 4, 'cidr': '10.0.0.0/24'} res = self._create_subnet(self.fmt, n1['network']['id'], **kwargs) n1_s1 = self.deserialize(self.fmt, res) n1_s1_id = n1_s1['subnet']['id'] router_iface_info = self.l3_plugin.add_router_interface( self.context, router1['id'], {'subnet_id': n1_s1_id}) lrp_name = ovn_utils.ovn_lrouter_port_name( router_iface_info['port_id']) if ip_version == 6: expected_ra_configs = { 'address_mode': ovn_utils.get_ovn_ipv6_address_mode( address_mode), 'send_periodic': 'true', 'mtu': '1450'} else: expected_ra_configs = {} self._validate_router_ipv6_ra_configs(lrp_name, expected_ra_configs)
def update_lrouter_port_in_ovn(self, context, router_id, port, networks=None): """Update lrouter port in OVN @param router id : LRouter ID for the port that needs to be updated @param port : LRouter port that needs to be updated @param networks : networks needs to be updated for LRouter port @return: Nothing """ networks = networks or self.get_networks_for_lrouter_port( context, port['fixed_ips']) lrouter_port_name = utils.ovn_lrouter_port_name(port['id']) update = {'networks': networks} with self._ovn.transaction(check_error=True) as txn: txn.add( self._ovn.update_lrouter_port(name=lrouter_port_name, if_exists=False, **update)) txn.add( self._ovn.set_lrouter_port_in_lswitch_port( port['id'], lrouter_port_name))
def get_lrouter_port(self, lrp_name): # TODO(mangelajo): Implement lrp_get() ovsdbapp and use from here if uuidutils.is_uuid_like(lrp_name): lrp_name = utils.ovn_lrouter_port_name(lrp_name) lrp = self.db_find_rows('Logical_Router_Port', ('name', '=', lrp_name)) result = lrp.execute(check_error=True) return result[0] if result else None
def create_lrouter_port_in_ovn(self, context, router_id, port): """Create lrouter port in OVN @param router_id : LRouter ID for the port that needs to be created @param port : LRouter port that needs to be created @return: Nothing """ lrouter = utils.ovn_name(router_id) networks = self.get_networks_for_lrouter_port(context, port['fixed_ips']) lrouter_port_name = utils.ovn_lrouter_port_name(port['id']) is_gw_port = n_const.DEVICE_OWNER_ROUTER_GW == port.get('device_owner') columns = {} if is_gw_port: selected_chassis = self.scheduler.select(self._ovn, self._sb_ovn, lrouter_port_name) columns['options'] = { ovn_const.OVN_GATEWAY_CHASSIS_KEY: selected_chassis } with self._ovn.transaction(check_error=True) as txn: txn.add( self._ovn.add_lrouter_port(name=lrouter_port_name, lrouter=lrouter, mac=port['mac_address'], networks=networks, **columns)) txn.add( self._ovn.set_lrouter_port_in_lswitch_port( port['id'], lrouter_port_name))
def add_router_interface(self, context, router_id, interface_info): router_interface_info = super(OVNPlugin, self).add_router_interface( context, router_id, interface_info) if not config.is_ovn_l3(): LOG.debug("OVN L3 mode is disabled, skipping " "add_router_interface") return router_interface_info port = self.get_port(context, router_interface_info['port_id']) subnet_id = port['fixed_ips'][0]['subnet_id'] subnet = self.get_subnet(context, subnet_id) lrouter = utils.ovn_name(router_id) cidr = netaddr.IPNetwork(subnet['cidr']) network = "%s/%s" % (port['fixed_ips'][0]['ip_address'], str(cidr.prefixlen)) lrouter_port_name = utils.ovn_lrouter_port_name(port['id']) with self._ovn.transaction(check_error=True) as txn: txn.add(self._ovn.add_lrouter_port(name=lrouter_port_name, lrouter=lrouter, mac=port['mac_address'], network=network)) txn.add(self._ovn.set_lrouter_port_in_lport(port['id'], lrouter_port_name)) return router_interface_info
def add_router_interface(self, context, router_id, interface_info): router_interface_info = \ super(OVNL3RouterPlugin, self).add_router_interface( context, router_id, interface_info) port = self._plugin.get_port(context, router_interface_info['port_id']) multi_prefix = False if (len(router_interface_info['subnet_ids']) == 1 and len(port['fixed_ips']) > 1): # NOTE(lizk) It's adding a subnet onto an already existing router # interface port, try to update lrouter port 'networks' column. self.update_lrouter_port_in_ovn(context, router_id, port) multi_prefix = True else: self.create_lrouter_port_in_ovn(context, router_id, port) router = self.get_router(context, router_id) if not router.get(l3.EXTERNAL_GW_INFO): return router_interface_info cidr = None for fixed_ip in port['fixed_ips']: subnet = self._plugin.get_subnet(context, fixed_ip['subnet_id']) if multi_prefix: if 'subnet_id' in interface_info: if subnet['id'] is not interface_info['subnet_id']: continue if subnet['ip_version'] == 4: cidr = subnet['cidr'] if not cidr: return router_interface_info try: transit_net_ports = self._get_transit_network_ports() nexthop = transit_net_ports['dtsp']['ip'] gw_lrouter_name = utils.ovn_gateway_router_name(router_id) if self._is_snat_enabled(router): self._update_snat_and_static_routes_for_networks( context, router, networks=[cidr], nexthop=nexthop, enable_snat=True, update_static_routes=True) else: route = {'destination': cidr, 'nexthop': nexthop} self._update_lrouter_routes( context, router_id, add=[route], remove=[], lrouter_name=gw_lrouter_name) except Exception: with excutils.save_and_reraise_exception(): self._ovn.delete_lrouter_port( utils.ovn_lrouter_port_name(port['id']), utils.ovn_name(router_id)).execute(check_error=True) super(OVNL3RouterPlugin, self).remove_router_interface( context, router_id, router_interface_info) LOG.error(_LE('Error updating snat for subnet %(subnet)s in ' 'router %(router)s'), {'subnet': router_interface_info['subnet_id'], 'router': router_id}) return router_interface_info
def remove_router_interface(self, context, router_id, interface_info): router_interface_info = \ super(OVNL3RouterPlugin, self).remove_router_interface( context, router_id, interface_info) port_id = router_interface_info['port_id'] self._ovn.delete_lrouter_port(utils.ovn_lrouter_port_name(port_id), utils.ovn_name(router_id), if_exists=False ).execute(check_error=True) return router_interface_info
def add_router_interface(self, context, router_id, interface_info): router_interface_info = \ super(OVNL3RouterPlugin, self).add_router_interface( context, router_id, interface_info) port = self._plugin.get_port(context, router_interface_info['port_id']) multi_prefix = False if (len(router_interface_info['subnet_ids']) == 1 and len(port['fixed_ips']) > 1): # NOTE(lizk) It's adding a subnet onto an already existing router # interface port, try to update lrouter port 'networks' column. self.update_lrouter_port_in_ovn(context, router_id, port) multi_prefix = True else: self.create_lrouter_port_in_ovn(context, router_id, port) router = self.get_router(context, router_id) if not router.get(l3.EXTERNAL_GW_INFO): return router_interface_info cidr = None for fixed_ip in port['fixed_ips']: subnet = self._plugin.get_subnet(context, fixed_ip['subnet_id']) if multi_prefix: if 'subnet_id' in interface_info: if subnet['id'] is not interface_info['subnet_id']: continue if subnet['ip_version'] == 4: cidr = subnet['cidr'] if not cidr: return router_interface_info try: if utils.is_snat_enabled(router): self._update_snat_for_networks(context, router, networks=[cidr], enable_snat=True) except Exception: with excutils.save_and_reraise_exception(): self._ovn.delete_lrouter_port( utils.ovn_lrouter_port_name(port['id']), utils.ovn_name(router_id)).execute(check_error=True) super(OVNL3RouterPlugin, self).remove_router_interface(context, router_id, router_interface_info) LOG.error( _LE('Error updating snat for subnet %(subnet)s in ' 'router %(router)s'), { 'subnet': router_interface_info['subnet_id'], 'router': router_id }) return router_interface_info
def remove_router_interface(self, context, router_id, interface_info): router_interface_info = \ super(OVNL3RouterPlugin, self).remove_router_interface( context, router_id, interface_info) router = self.get_router(context, router_id) port_id = router_interface_info['port_id'] multi_prefix = False try: port = self._plugin.get_port(context, port_id) # The router interface port still exists, call ovn to update it. self.update_lrouter_port_in_ovn(context, router_id, port) multi_prefix = True except n_exc.PortNotFound: # The router interface port doesn't exist any more, call ovn to # delete it. self._ovn.delete_lrouter_port( utils.ovn_lrouter_port_name(port_id), utils.ovn_name(router_id), if_exists=False).execute(check_error=True) if not router.get(l3.EXTERNAL_GW_INFO): return router_interface_info try: cidr = None if multi_prefix: subnet = self._plugin.get_subnet(context, interface_info['subnet_id']) if subnet['ip_version'] == 4: cidr = subnet['cidr'] else: subnet_ids = router_interface_info.get('subnet_ids') for subnet_id in subnet_ids: subnet = self._plugin.get_subnet(context, subnet_id) if subnet['ip_version'] == 4: cidr = subnet['cidr'] break if not cidr: return router_interface_info if utils.is_snat_enabled(router): self._update_snat_for_networks(context, router, networks=[cidr], enable_snat=False) except Exception: with excutils.save_and_reraise_exception(): super(OVNL3RouterPlugin, self).add_router_interface(context, router_id, interface_info) LOG.error(_LE('Error is deleting snat')) return router_interface_info
def run_idl(self, txn): # TODO(lucasagomes): Remove this check after OVS 2.8.2 is tagged # (prior to that, the external_ids column didn't exist in this # table). if not self.api.is_col_present('Logical_Router_Static_Route', 'external_ids'): return try: lrouter = idlutils.row_by_value(self.api.idl, 'Logical_Router', 'name', self.lrouter) except idlutils.RowNotFound: if self.if_exists: return msg = _("Logical Router %s does not exist") % self.lrouter raise RuntimeError(msg) lrouter.verify('static_routes') static_routes = getattr(lrouter, 'static_routes', []) for route in static_routes: external_ids = getattr(route, 'external_ids', {}) if ovn_const.OVN_ROUTER_IS_EXT_GW in external_ids: _delvalue_from_list(lrouter, 'static_routes', route) route.delete() break lrouter.verify('nat') nats = getattr(lrouter, 'nat', []) for nat in nats: if nat.type != 'snat': continue _delvalue_from_list(lrouter, 'nat', nat) nat.delete() lrouter_ext_ids = getattr(lrouter, 'external_ids', {}) gw_port_id = lrouter_ext_ids.get(ovn_const.OVN_GW_PORT_EXT_ID_KEY) if not gw_port_id: return try: lrouter_port = idlutils.row_by_value( self.api.idl, 'Logical_Router_Port', 'name', utils.ovn_lrouter_port_name(gw_port_id)) except idlutils.RowNotFound: return _delvalue_from_list(lrouter, 'ports', lrouter_port)
def remove_router_interface(self, context, router_id, interface_info): router_interface_info = \ super(OVNL3RouterPlugin, self).remove_router_interface( context, router_id, interface_info) port_id = router_interface_info['port_id'] try: port = self._plugin.get_port(context, port_id) # The router interface port still exists, call ovn to update it. self.update_lrouter_port_in_ovn(context, router_id, port) except n_exc.PortNotFound: # The router interface port doesn't exist any more, call ovn to # delete it. self._ovn.delete_lrouter_port(utils.ovn_lrouter_port_name(port_id), utils.ovn_name(router_id), if_exists=False ).execute(check_error=True) return router_interface_info
def remove_router_interface(self, context, router_id, interface_info): router_interface_info = \ super(OVNL3RouterPlugin, self).remove_router_interface( context, router_id, interface_info) port_id = router_interface_info['port_id'] try: port = self._plugin.get_port(context, port_id) # The router interface port still exists, call ovn to update it. self.update_lrouter_port_in_ovn(context, router_id, port) except n_exc.PortNotFound: # The router interface port doesn't exist any more, call ovn to # delete it. self._ovn.delete_lrouter_port( utils.ovn_lrouter_port_name(port_id), utils.ovn_name(router_id), if_exists=False).execute(check_error=True) return router_interface_info
def update_lrouter_port_in_ovn(self, context, router_id, port): """Update lrouter port in OVN @param router id : LRouter ID for the port that needs to be updated @param port : LRouter port that needs to be updated @return: Nothing """ lrouter = utils.ovn_name(router_id) networks = self.get_networks_for_lrouter_port(context, port['fixed_ips']) lrouter_port_name = utils.ovn_lrouter_port_name(port['id']) update = {'networks': networks} with self._ovn.transaction(check_error=True) as txn: txn.add(self._ovn.update_lrouter_port(name=lrouter_port_name, lrouter=lrouter, if_exists=False, **update)) txn.add(self._ovn.set_lrouter_port_in_lswitch_port( port['id'], lrouter_port_name))
def create_lrouter_port_in_ovn(self, context, router_id, port): """Create lrouter port in OVN @param router id : LRouter ID for the port that needs to be created @param port : LRouter port that needs to be created @return: Nothing """ lrouter = utils.ovn_name(router_id) networks = self.get_networks_for_lrouter_port(context, port['fixed_ips']) lrouter_port_name = utils.ovn_lrouter_port_name(port['id']) with self._ovn.transaction(check_error=True) as txn: txn.add(self._ovn.add_lrouter_port(name=lrouter_port_name, lrouter=lrouter, mac=port['mac_address'], networks=networks)) txn.add(self._ovn.set_lrouter_port_in_lswitch_port( port['id'], lrouter_port_name))
def _delete_router_ext_gw(self, context, router_id, router, networks=None): gw_port_id = router['gw_port_id'] gw_lrouter_name = utils.ovn_name(router_id) ext_gw_ip = self._get_external_gateway_ip(context, router) router_ip = self._get_router_ip(context, router) # Only get networks when networks is None networks = self._get_v4_network_of_all_router_ports( context, router_id) if networks is None else networks with self._ovn.transaction(check_error=True) as txn: txn.add(self._ovn.delete_static_route(gw_lrouter_name, ip_prefix='0.0.0.0/0', nexthop=ext_gw_ip)) txn.add(self._ovn.delete_lrouter_port( utils.ovn_lrouter_port_name(gw_port_id), gw_lrouter_name)) for network in networks: txn.add(self._ovn.delete_nat_rule_in_lrouter( gw_lrouter_name, type='snat', logical_ip=network, external_ip=router_ip))
def create_lrouter_port_in_ovn(self, context, router_id, port): """Create lrouter port in OVN @param router id : LRouter ID for the port that needs to be created @param port : LRouter port that needs to be created @return: Nothing """ lrouter = utils.ovn_name(router_id) networks = self.get_networks_for_lrouter_port(context, port['fixed_ips']) lrouter_port_name = utils.ovn_lrouter_port_name(port['id']) with self._ovn.transaction(check_error=True) as txn: txn.add( self._ovn.add_lrouter_port(name=lrouter_port_name, lrouter=lrouter, mac=port['mac_address'], networks=networks)) txn.add( self._ovn.set_lrouter_port_in_lswitch_port( port['id'], lrouter_port_name))
def remove_router_interface(self, context, router_id, interface_info): if not config.is_ovn_l3(): LOG.debug("OVN L3 mode is disabled, skipping " "remove_router_interface") return super(OVNPlugin, self).remove_router_interface( context, router_id, interface_info) # TODO(chandrav) # Need to rework this code to get the port_id when the incoming request # contains only the subnet_id. Also need to figure out if OVN needs to # care about multiple prefix subnets on a single router interface. # This code is duplicated from neutron. Probably a better thing to do # is to handle everything in the plugin and just call delete_port # update_port. port_id = None if 'port_id' in interface_info: port_id = interface_info['port_id'] elif 'subnet_id' in interface_info: subnet_id = interface_info['subnet_id'] subnet = self.get_subnet(context, subnet_id) device_filter = {'device_id': [router_id], 'device_owner': [const.DEVICE_OWNER_ROUTER_INTF], 'network_id': [subnet['network_id']]} ports = super(OVNPlugin, self).get_ports(context, filters=device_filter) for p in ports: port_subnets = [fip['subnet_id'] for fip in p['fixed_ips']] if subnet_id in port_subnets and len(port_subnets) == 1: port_id = p['id'] break router_interface_info = super(OVNPlugin, self).remove_router_interface( context, router_id, interface_info) if port_id is not None: self._ovn.delete_lrouter_port(utils.ovn_lrouter_port_name(port_id), utils.ovn_name(router_id), if_exists=False ).execute(check_error=True) return router_interface_info
def _delete_router_ext_gw(self, context, router_id, router, transit_net_ports=None, cleanup=None): transit_net_ports = transit_net_ports or \ self._get_transit_network_ports() cleanup = cleanup or [] gw_port_id = router['gw_port_id'] gw_lrouter_name = utils.ovn_gateway_router_name(router_id) ext_gw_ip = self._get_external_gateway_ip(context, router) if 'join' in cleanup or not cleanup: self._disjoin_lrouter_and_gw_lrouter(router, transit_net_ports) with self._ovn.transaction(check_error=True) as txn: if 'ext_gw_ip_nexthop' in cleanup or not cleanup: txn.add(self._ovn.delete_static_route(gw_lrouter_name, ip_prefix='0.0.0.0/0', nexthop=ext_gw_ip)) if 'ext_gw_port' in cleanup or not cleanup: txn.add(self._ovn.delete_lrouter_port( utils.ovn_lrouter_port_name(gw_port_id), gw_lrouter_name)) if 'gw_router' in cleanup or not cleanup: self._delete_lrouter_in_ovn(router_id, is_gateway_router=True) self._check_and_delete_l3_admin_net(context)
def create_lrouter_port_in_ovn(self, context, router_id, port): """Create lrouter port in OVN @param router id : LRouter ID for the port that needs to be created @param port : LRouter port that needs to be created @return: Nothing """ subnet_id = port['fixed_ips'][0]['subnet_id'] subnet = self._plugin.get_subnet(context, subnet_id) lrouter = utils.ovn_name(router_id) cidr = netaddr.IPNetwork(subnet['cidr']) network = "%s/%s" % (port['fixed_ips'][0]['ip_address'], str(cidr.prefixlen)) lrouter_port_name = utils.ovn_lrouter_port_name(port['id']) with self._ovn.transaction(check_error=True) as txn: txn.add(self._ovn.add_lrouter_port(name=lrouter_port_name, lrouter=lrouter, mac=port['mac_address'], network=network)) txn.add(self._ovn.set_lrouter_port_in_lport(port['id'], lrouter_port_name))
class TestNBImplIdlOvn(TestDBImplIdlOvn): fake_set = { 'lswitches': [{ 'name': utils.ovn_name('ls-id-1'), 'external_ids': { ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY: 'ls-name-1' } }, { 'name': utils.ovn_name('ls-id-2'), 'external_ids': { ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY: 'ls-name-2' } }, { 'name': utils.ovn_name('ls-id-3'), 'external_ids': { ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY: 'ls-name-3' } }, { 'name': 'ls-id-4', 'external_ids': { 'not-neutron:network_name': 'ls-name-4' } }, { 'name': utils.ovn_name('ls-id-5'), 'external_ids': { ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY: 'ls-name-5' } }], 'lswitch_ports': [{ 'name': 'lsp-id-11', 'addresses': ['10.0.1.1'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-11' } }, { 'name': 'lsp-id-12', 'addresses': ['10.0.1.2'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-12' } }, { 'name': 'lsp-rp-id-1', 'addresses': ['10.0.1.254'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-rp-name-1' }, 'options': { 'router-port': utils.ovn_lrouter_port_name('orp-id-a1') } }, { 'name': 'provnet-ls-id-1', 'addresses': ['unknown'], 'external_ids': {}, 'options': { 'network_name': 'physnet1' } }, { 'name': 'lsp-id-21', 'addresses': ['10.0.2.1'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-21' } }, { 'name': 'lsp-id-22', 'addresses': ['10.0.2.2'], 'external_ids': {} }, { 'name': 'lsp-id-23', 'addresses': ['10.0.2.3'], 'external_ids': { 'not-neutron:port_name': 'lsp-name-23' } }, { 'name': 'lsp-rp-id-2', 'addresses': ['10.0.2.254'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-rp-name-2' }, 'options': { 'router-port': utils.ovn_lrouter_port_name('orp-id-a2') } }, { 'name': 'provnet-ls-id-2', 'addresses': ['unknown'], 'external_ids': {}, 'options': { 'network_name': 'physnet2' } }, { 'name': 'lsp-id-31', 'addresses': ['10.0.3.1'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-31' } }, { 'name': 'lsp-id-32', 'addresses': ['10.0.3.2'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-32' } }, { 'name': 'lsp-rp-id-3', 'addresses': ['10.0.3.254'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-rp-name-3' }, 'options': { 'router-port': utils.ovn_lrouter_port_name('orp-id-a3') } }, { 'name': 'lsp-vpn-id-3', 'addresses': ['10.0.3.253'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-vpn-name-3' } }, { 'name': 'lsp-id-41', 'addresses': ['20.0.1.1'], 'external_ids': { 'not-neutron:port_name': 'lsp-name-41' } }, { 'name': 'lsp-rp-id-4', 'addresses': ['20.0.1.254'], 'external_ids': {}, 'options': { 'router-port': 'xrp-id-b1' } }, { 'name': 'lsp-id-51', 'addresses': ['20.0.2.1'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-51' } }, { 'name': 'lsp-id-52', 'addresses': ['20.0.2.2'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-52' } }, { 'name': 'lsp-rp-id-5', 'addresses': ['20.0.2.254'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-rp-name-5' }, 'options': { 'router-port': utils.ovn_lrouter_port_name('orp-id-b2') } }, { 'name': 'lsp-vpn-id-5', 'addresses': ['20.0.2.253'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-vpn-name-5' } }], 'lrouters': [{ 'name': utils.ovn_name('lr-id-a'), 'external_ids': { ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'lr-name-a' } }, { 'name': utils.ovn_name('lr-id-b'), 'external_ids': { ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'lr-name-b' } }, { 'name': utils.ovn_name('lr-id-c'), 'external_ids': { ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'lr-name-c' } }, { 'name': utils.ovn_name('lr-id-d'), 'external_ids': { ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'lr-name-d' } }, { 'name': utils.ovn_name('lr-id-e'), 'external_ids': { ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'lr-name-e' } }], 'lrouter_ports': [{ 'name': utils.ovn_lrouter_port_name('orp-id-a1'), 'external_ids': {}, 'networks': ['10.0.1.0/24'], 'options': { ovn_const.OVN_GATEWAY_CHASSIS_KEY: 'host-1' } }, { 'name': utils.ovn_lrouter_port_name('orp-id-a2'), 'external_ids': {}, 'networks': ['10.0.2.0/24'], 'options': { ovn_const.OVN_GATEWAY_CHASSIS_KEY: 'host-1' } }, { 'name': utils.ovn_lrouter_port_name('orp-id-a3'), 'external_ids': {}, 'networks': ['10.0.3.0/24'], 'options': { ovn_const.OVN_GATEWAY_CHASSIS_KEY: ovn_const.OVN_GATEWAY_INVALID_CHASSIS } }, { 'name': 'xrp-id-b1', 'external_ids': {}, 'networks': ['20.0.1.0/24'] }, { 'name': utils.ovn_lrouter_port_name('orp-id-b2'), 'external_ids': {}, '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'], 'options': {} }], 'static_routes': [{ 'ip_prefix': '20.0.0.0/16', 'nexthop': '10.0.3.253' }, { 'ip_prefix': '10.0.0.0/16', 'nexthop': '20.0.2.253' }], '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', 'type': 'snat' }, { 'external_ip': '20.0.2.4', 'logical_ip': '10.0.0.4', 'type': 'dnat_and_snat', 'external_mac': [], 'logical_port': [] }, { 'external_ip': '20.0.2.5', 'logical_ip': '10.0.0.5', 'type': 'dnat_and_snat', 'external_mac': ['00:01:02:03:04:05'], 'logical_port': ['lsp-id-001'] }], 'acls': [{ 'unit_test_id': 1, 'action': 'allow-related', 'direction': 'from-lport', 'external_ids': { 'neutron:lport': 'lsp-id-11' }, 'match': 'inport == "lsp-id-11" && ip4' }, { 'unit_test_id': 2, 'action': 'allow-related', 'direction': 'to-lport', 'external_ids': { 'neutron:lport': 'lsp-id-11' }, 'match': 'outport == "lsp-id-11" && ip4.src == $as_ip4_id_1' }, { 'unit_test_id': 3, 'action': 'allow-related', 'direction': 'from-lport', 'external_ids': { 'neutron:lport': 'lsp-id-12' }, 'match': 'inport == "lsp-id-12" && ip4' }, { 'unit_test_id': 4, 'action': 'allow-related', 'direction': 'to-lport', 'external_ids': { 'neutron:lport': 'lsp-id-12' }, 'match': 'outport == "lsp-id-12" && ip4.src == $as_ip4_id_1' }, { 'unit_test_id': 5, 'action': 'allow-related', 'direction': 'from-lport', 'external_ids': { 'neutron:lport': 'lsp-id-21' }, 'match': 'inport == "lsp-id-21" && ip4' }, { 'unit_test_id': 6, 'action': 'allow-related', 'direction': 'to-lport', 'external_ids': { 'neutron:lport': 'lsp-id-21' }, 'match': 'outport == "lsp-id-21" && ip4.src == $as_ip4_id_2' }, { 'unit_test_id': 7, 'action': 'allow-related', 'direction': 'from-lport', 'external_ids': { 'neutron:lport': 'lsp-id-41' }, 'match': 'inport == "lsp-id-41" && ip4' }, { 'unit_test_id': 8, 'action': 'allow-related', 'direction': 'to-lport', 'external_ids': { 'neutron:lport': 'lsp-id-41' }, 'match': 'outport == "lsp-id-41" && ip4.src == $as_ip4_id_4' }, { 'unit_test_id': 9, 'action': 'allow-related', 'direction': 'from-lport', 'external_ids': { 'neutron:lport': 'lsp-id-52' }, 'match': 'inport == "lsp-id-52" && ip4' }, { 'unit_test_id': 10, 'action': 'allow-related', 'direction': 'to-lport', 'external_ids': { 'neutron:lport': 'lsp-id-52' }, 'match': 'outport == "lsp-id-52" && ip4.src == $as_ip4_id_5' }], 'dhcp_options': [{ 'cidr': '10.0.1.0/24', 'external_ids': { 'subnet_id': 'subnet-id-10-0-1-0' }, 'options': { 'mtu': '1442', 'router': '10.0.1.254' } }, { 'cidr': '10.0.2.0/24', 'external_ids': { 'subnet_id': 'subnet-id-10-0-2-0' }, 'options': { 'mtu': '1442', 'router': '10.0.2.254' } }, { 'cidr': '10.0.1.0/26', 'external_ids': { 'subnet_id': 'subnet-id-10-0-1-0', 'port_id': 'lsp-vpn-id-3' }, 'options': { 'mtu': '1442', 'router': '10.0.1.1' } }, { 'cidr': '20.0.1.0/24', 'external_ids': { 'subnet_id': 'subnet-id-20-0-1-0' }, 'options': { 'mtu': '1442', 'router': '20.0.1.254' } }, { 'cidr': '20.0.2.0/24', 'external_ids': { 'subnet_id': 'subnet-id-20-0-2-0', 'port_id': 'lsp-vpn-id-5' }, 'options': { 'mtu': '1442', 'router': '20.0.2.254' } }, { 'cidr': '2001:dba::/64', 'external_ids': { 'subnet_id': 'subnet-id-2001-dba', 'port_id': 'lsp-vpn-id-5' }, 'options': { 'server_id': '12:34:56:78:9a:bc' } }, { 'cidr': '30.0.1.0/24', 'external_ids': { 'port_id': 'port-id-30-0-1-0' }, 'options': { 'mtu': '1442', 'router': '30.0.2.254' } }, { 'cidr': '30.0.2.0/24', 'external_ids': {}, 'options': {} }], 'address_sets': [ { 'name': '$as_ip4_id_1', 'addresses': ['10.0.1.1', '10.0.1.2'], 'external_ids': { ovn_const.OVN_SG_EXT_ID_KEY: 'id_1' } }, { 'name': '$as_ip4_id_2', 'addresses': ['10.0.2.1'], 'external_ids': { ovn_const.OVN_SG_EXT_ID_KEY: 'id_2' } }, { 'name': '$as_ip4_id_3', 'addresses': ['10.0.3.1', '10.0.3.2'], 'external_ids': { ovn_const.OVN_SG_EXT_ID_KEY: 'id_3' } }, { 'name': '$as_ip4_id_4', 'addresses': ['20.0.1.1', '20.0.1.2'], 'external_ids': {} }, { 'name': '$as_ip4_id_5', 'addresses': ['20.0.2.1', '20.0.2.2'], 'external_ids': { ovn_const.OVN_SG_EXT_ID_KEY: 'id_5' } }, ] } fake_associations = { 'lstolsp': { utils.ovn_name('ls-id-1'): ['lsp-id-11', 'lsp-id-12', 'lsp-rp-id-1', 'provnet-ls-id-1'], utils.ovn_name('ls-id-2'): [ 'lsp-id-21', 'lsp-id-22', 'lsp-id-23', 'lsp-rp-id-2', 'provnet-ls-id-2' ], utils.ovn_name('ls-id-3'): ['lsp-id-31', 'lsp-id-32', 'lsp-rp-id-3', 'lsp-vpn-id-3'], 'ls-id-4': ['lsp-id-41', 'lsp-rp-id-4'], utils.ovn_name('ls-id-5'): ['lsp-id-51', 'lsp-id-52', 'lsp-rp-id-5', 'lsp-vpn-id-5'] }, 'lrtolrp': { utils.ovn_name('lr-id-a'): [ utils.ovn_lrouter_port_name('orp-id-a1'), utils.ovn_lrouter_port_name('orp-id-a2'), utils.ovn_lrouter_port_name('orp-id-a3') ], utils.ovn_name('lr-id-b'): ['xrp-id-b1', utils.ovn_lrouter_port_name('orp-id-b2')] }, 'lrtosroute': { utils.ovn_name('lr-id-a'): ['20.0.0.0/16'], utils.ovn_name('lr-id-b'): ['10.0.0.0/16'] }, 'lrtonat': { utils.ovn_name('lr-id-a'): ['10.0.3.1'], utils.ovn_name('lr-id-b'): ['20.0.2.1', '20.0.2.4', '20.0.2.5'], }, 'lstoacl': { utils.ovn_name('ls-id-1'): [1, 2, 3, 4], utils.ovn_name('ls-id-2'): [5, 6], 'ls-id-4': [7, 8], utils.ovn_name('ls-id-5'): [9, 10] } } def setUp(self): super(TestNBImplIdlOvn, self).setUp() self.lswitch_table = fakes.FakeOvsdbTable.create_one_ovsdb_table() self.lsp_table = fakes.FakeOvsdbTable.create_one_ovsdb_table() self.lrouter_table = fakes.FakeOvsdbTable.create_one_ovsdb_table() self.lrp_table = fakes.FakeOvsdbTable.create_one_ovsdb_table() self.sroute_table = fakes.FakeOvsdbTable.create_one_ovsdb_table() self.nat_table = fakes.FakeOvsdbTable.create_one_ovsdb_table() self.acl_table = fakes.FakeOvsdbTable.create_one_ovsdb_table() self.dhcp_table = fakes.FakeOvsdbTable.create_one_ovsdb_table() self.address_set_table = fakes.FakeOvsdbTable.create_one_ovsdb_table() self._tables = {} self._tables['Logical_Switch'] = self.lswitch_table self._tables['Logical_Switch_Port'] = self.lsp_table self._tables['Logical_Router'] = self.lrouter_table self._tables['Logical_Router_Port'] = self.lrp_table self._tables['Logical_Router_Static_Route'] = self.sroute_table self._tables['ACL'] = self.acl_table self._tables['DHCP_Options'] = self.dhcp_table self._tables['Address_Set'] = self.address_set_table with mock.patch.object(impl_idl_ovn, 'get_connection', return_value=mock.Mock()): impl_idl_ovn.OvsdbNbOvnIdl.ovsdb_connection = None self.nb_ovn_idl = impl_idl_ovn.OvsdbNbOvnIdl(mock.Mock()) self.nb_ovn_idl.idl.tables = self._tables def _load_nb_db(self): # Load Switches and Switch Ports fake_lswitches = TestNBImplIdlOvn.fake_set['lswitches'] self._load_ovsdb_fake_rows(self.lswitch_table, fake_lswitches) fake_lsps = TestNBImplIdlOvn.fake_set['lswitch_ports'] self._load_ovsdb_fake_rows(self.lsp_table, fake_lsps) # Associate switches and ports self._construct_ovsdb_references( TestNBImplIdlOvn.fake_associations['lstolsp'], self.lswitch_table, self.lsp_table, 'name', 'name', 'ports') # Load Routers and Router Ports fake_lrouters = TestNBImplIdlOvn.fake_set['lrouters'] self._load_ovsdb_fake_rows(self.lrouter_table, fake_lrouters) fake_lrps = TestNBImplIdlOvn.fake_set['lrouter_ports'] self._load_ovsdb_fake_rows(self.lrp_table, fake_lrps) # Associate routers and router ports self._construct_ovsdb_references( TestNBImplIdlOvn.fake_associations['lrtolrp'], self.lrouter_table, self.lrp_table, 'name', 'name', 'ports') # Load static routes fake_sroutes = TestNBImplIdlOvn.fake_set['static_routes'] self._load_ovsdb_fake_rows(self.sroute_table, fake_sroutes) # Associate routers and static routes self._construct_ovsdb_references( TestNBImplIdlOvn.fake_associations['lrtosroute'], self.lrouter_table, self.sroute_table, 'name', 'ip_prefix', 'static_routes') # Load nats fake_nats = TestNBImplIdlOvn.fake_set['nats'] self._load_ovsdb_fake_rows(self.nat_table, fake_nats) # Associate routers and nats self._construct_ovsdb_references( TestNBImplIdlOvn.fake_associations['lrtonat'], self.lrouter_table, self.nat_table, 'name', 'external_ip', 'nat') # Load acls fake_acls = TestNBImplIdlOvn.fake_set['acls'] self._load_ovsdb_fake_rows(self.acl_table, fake_acls) # Associate switches and acls self._construct_ovsdb_references( TestNBImplIdlOvn.fake_associations['lstoacl'], self.lswitch_table, self.acl_table, 'name', 'unit_test_id', 'acls') # Load dhcp options fake_dhcp_options = TestNBImplIdlOvn.fake_set['dhcp_options'] self._load_ovsdb_fake_rows(self.dhcp_table, fake_dhcp_options) # Load address sets fake_address_sets = TestNBImplIdlOvn.fake_set['address_sets'] self._load_ovsdb_fake_rows(self.address_set_table, fake_address_sets) @mock.patch.object(impl_idl_ovn.OvsdbNbOvnIdl, 'ovsdb_connection', None) @mock.patch.object(impl_idl_ovn, 'get_connection', mock.Mock()) def test_setting_ovsdb_probe_timeout_default_value(self): inst = impl_idl_ovn.OvsdbNbOvnIdl(mock.Mock()) inst.idl._session.reconnect.set_probe_interval.assert_called_with( 60000) @mock.patch.object(impl_idl_ovn.OvsdbNbOvnIdl, 'ovsdb_connection', None) @mock.patch.object(impl_idl_ovn, 'get_connection', mock.Mock()) @mock.patch.object(config, 'get_ovn_ovsdb_probe_interval') def test_setting_ovsdb_probe_timeout(self, mock_get_probe_interval): mock_get_probe_interval.return_value = 5000 inst = impl_idl_ovn.OvsdbNbOvnIdl(mock.Mock()) inst.idl._session.reconnect.set_probe_interval.assert_called_with(5000) def test_get_all_logical_switches_with_ports(self): # Test empty mapping = self.nb_ovn_idl.get_all_logical_switches_with_ports() self.assertItemsEqual(mapping, {}) # Test loaded values self._load_nb_db() mapping = self.nb_ovn_idl.get_all_logical_switches_with_ports() expected = [{ 'name': utils.ovn_name('ls-id-1'), 'ports': ['lsp-id-11', 'lsp-id-12', 'lsp-rp-id-1'], 'provnet_port': 'provnet-ls-id-1' }, { 'name': utils.ovn_name('ls-id-2'), 'ports': ['lsp-id-21', 'lsp-rp-id-2'], 'provnet_port': 'provnet-ls-id-2' }, { 'name': utils.ovn_name('ls-id-3'), 'ports': ['lsp-id-31', 'lsp-id-32', 'lsp-rp-id-3', 'lsp-vpn-id-3'], 'provnet_port': None }, { 'name': utils.ovn_name('ls-id-5'), 'ports': ['lsp-id-51', 'lsp-id-52', 'lsp-rp-id-5', 'lsp-vpn-id-5'], 'provnet_port': None }] self.assertItemsEqual(mapping, expected) def test_get_all_logical_routers_with_rports(self): # Test empty mapping = self.nb_ovn_idl.get_all_logical_switches_with_ports() self.assertItemsEqual(mapping, {}) # Test loaded values self._load_nb_db() mapping = self.nb_ovn_idl.get_all_logical_routers_with_rports() expected = [{ 'name': 'lr-id-a', 'ports': { 'orp-id-a1': ['10.0.1.0/24'], 'orp-id-a2': ['10.0.2.0/24'], 'orp-id-a3': ['10.0.3.0/24'] }, 'static_routes': [{ 'destination': '20.0.0.0/16', 'nexthop': '10.0.3.253' }], 'snats': [{ 'external_ip': '10.0.3.1', 'logical_ip': '20.0.0.0/16', 'type': 'snat' }], 'dnat_and_snats': [] }, { 'name': 'lr-id-b', 'ports': { 'xrp-id-b1': ['20.0.1.0/24'], 'orp-id-b2': ['20.0.2.0/24'] }, 'static_routes': [{ 'destination': '10.0.0.0/16', 'nexthop': '20.0.2.253' }], 'snats': [{ 'external_ip': '20.0.2.1', 'logical_ip': '10.0.0.0/24', 'type': 'snat' }], 'dnat_and_snats': [{ 'external_ip': '20.0.2.4', 'logical_ip': '10.0.0.4', 'type': 'dnat_and_snat' }, { 'external_ip': '20.0.2.5', 'logical_ip': '10.0.0.5', 'type': 'dnat_and_snat', 'external_mac': '00:01:02:03:04:05', 'logical_port': 'lsp-id-001' }] }, { 'name': 'lr-id-c', 'ports': {}, 'static_routes': [], 'snats': [], 'dnat_and_snats': [] }, { 'name': 'lr-id-d', 'ports': {}, 'static_routes': [], 'snats': [], 'dnat_and_snats': [] }, { 'name': 'lr-id-e', 'ports': {}, 'static_routes': [], 'snats': [], 'dnat_and_snats': [] }] self.assertItemsEqual(mapping, expected) def test_get_acls_for_lswitches(self): self._load_nb_db() # Test neutron switches lswitches = ['ls-id-1', 'ls-id-2', 'ls-id-3', 'ls-id-5'] acl_values, acl_objs, lswitch_ovsdb_dict = \ self.nb_ovn_idl.get_acls_for_lswitches(lswitches) excepted_acl_values = { 'lsp-id-11': [{ 'action': 'allow-related', 'lport': 'lsp-id-11', 'lswitch': 'neutron-ls-id-1', 'external_ids': { 'neutron:lport': 'lsp-id-11' }, 'direction': 'from-lport', 'match': 'inport == "lsp-id-11" && ip4' }, { 'action': 'allow-related', 'lport': 'lsp-id-11', 'lswitch': 'neutron-ls-id-1', 'external_ids': { 'neutron:lport': 'lsp-id-11' }, 'direction': 'to-lport', 'match': 'outport == "lsp-id-11" && ip4.src == $as_ip4_id_1' }], 'lsp-id-12': [{ 'action': 'allow-related', 'lport': 'lsp-id-12', 'lswitch': 'neutron-ls-id-1', 'external_ids': { 'neutron:lport': 'lsp-id-12' }, 'direction': 'from-lport', 'match': 'inport == "lsp-id-12" && ip4' }, { 'action': 'allow-related', 'lport': 'lsp-id-12', 'lswitch': 'neutron-ls-id-1', 'external_ids': { 'neutron:lport': 'lsp-id-12' }, 'direction': 'to-lport', 'match': 'outport == "lsp-id-12" && ip4.src == $as_ip4_id_1' }], 'lsp-id-21': [{ 'action': 'allow-related', 'lport': 'lsp-id-21', 'lswitch': 'neutron-ls-id-2', 'external_ids': { 'neutron:lport': 'lsp-id-21' }, 'direction': 'from-lport', 'match': 'inport == "lsp-id-21" && ip4' }, { 'action': 'allow-related', 'lport': 'lsp-id-21', 'lswitch': 'neutron-ls-id-2', 'external_ids': { 'neutron:lport': 'lsp-id-21' }, 'direction': 'to-lport', 'match': 'outport == "lsp-id-21" && ip4.src == $as_ip4_id_2' }], 'lsp-id-52': [{ 'action': 'allow-related', 'lport': 'lsp-id-52', 'lswitch': 'neutron-ls-id-5', 'external_ids': { 'neutron:lport': 'lsp-id-52' }, 'direction': 'from-lport', 'match': 'inport == "lsp-id-52" && ip4' }, { 'action': 'allow-related', 'lport': 'lsp-id-52', 'lswitch': 'neutron-ls-id-5', 'external_ids': { 'neutron:lport': 'lsp-id-52' }, 'direction': 'to-lport', 'match': 'outport == "lsp-id-52" && ip4.src == $as_ip4_id_5' }] } self.assertItemsEqual(acl_values, excepted_acl_values) self.assertEqual(len(acl_objs), 8) self.assertEqual(len(lswitch_ovsdb_dict), len(lswitches)) # Test non-neutron switches lswitches = ['ls-id-4'] acl_values, acl_objs, lswitch_ovsdb_dict = \ self.nb_ovn_idl.get_acls_for_lswitches(lswitches) self.assertItemsEqual(acl_values, {}) self.assertEqual(len(acl_objs), 0) self.assertEqual(len(lswitch_ovsdb_dict), 0) def test_get_all_chassis_gateway_bindings(self): self._load_nb_db() bindings = self.nb_ovn_idl.get_all_chassis_gateway_bindings() expected = { 'host-1': [ utils.ovn_lrouter_port_name('orp-id-a1'), utils.ovn_lrouter_port_name('orp-id-a2') ], 'host-2': [utils.ovn_lrouter_port_name('orp-id-b2')], ovn_const.OVN_GATEWAY_INVALID_CHASSIS: [utils.ovn_name('orp-id-a3')] } self.assertItemsEqual(bindings, expected) bindings = self.nb_ovn_idl.get_all_chassis_gateway_bindings([]) self.assertItemsEqual(bindings, expected) bindings = self.nb_ovn_idl.get_all_chassis_gateway_bindings(['host-1']) expected = { 'host-1': [ utils.ovn_lrouter_port_name('orp-id-a1'), utils.ovn_lrouter_port_name('orp-id-a2') ] } self.assertItemsEqual(bindings, expected) def test_get_gateway_chassis_binding(self): self._load_nb_db() chassis = self.nb_ovn_idl.get_gateway_chassis_binding( utils.ovn_lrouter_port_name('orp-id-a1')) self.assertEqual(chassis, ['host-1']) chassis = self.nb_ovn_idl.get_gateway_chassis_binding( utils.ovn_lrouter_port_name('orp-id-b2')) self.assertEqual(chassis, ['host-2']) chassis = self.nb_ovn_idl.get_gateway_chassis_binding( utils.ovn_lrouter_port_name('orp-id-a3')) self.assertEqual(chassis, ['neutron-ovn-invalid-chassis']) chassis = self.nb_ovn_idl.get_gateway_chassis_binding( utils.ovn_lrouter_port_name('orp-id-b3')) self.assertEqual(chassis, []) chassis = self.nb_ovn_idl.get_gateway_chassis_binding('bad') self.assertEqual(chassis, []) def test_get_unhosted_gateways(self): self._load_nb_db() # Test only host-1 in the valid list unhosted_gateways = self.nb_ovn_idl.get_unhosted_gateways( {}, {'host-1': 'physnet1'}, []) expected = [ 'lrp-orp-id-a1', 'lrp-orp-id-a2', 'lrp-orp-id-a3', 'lrp-orp-id-b2' ] self.assertItemsEqual(unhosted_gateways, expected) # Test both host-1, host-2 in valid list unhosted_gateways = self.nb_ovn_idl.get_unhosted_gateways( {}, { 'host-1': 'physnet1', 'host-2': 'physnet2' }, []) self.assertItemsEqual(unhosted_gateways, expected) # Schedule unhosted_gateways on host-2 for unhosted_gateway in unhosted_gateways: router_row = self._find_ovsdb_fake_row(self.lrp_table, 'name', unhosted_gateway) setattr(router_row, 'options', {ovn_const.OVN_GATEWAY_CHASSIS_KEY: 'host-2'}) unhosted_gateways = self.nb_ovn_idl.get_unhosted_gateways( {}, { 'host-1': 'physnet1', 'host-2': 'physnet2' }, []) self.assertItemsEqual(unhosted_gateways, expected) def test_unhosted_gateway_max_chassis(self): gw_chassis_table = fakes.FakeOvsdbTable.create_one_ovsdb_table() self._tables['Gateway_Chassis'] = gw_chassis_table gw_chassis = collections.namedtuple('gw_chassis', 'chassis_name priority') TestNBImplIdlOvn.fake_set['lrouter_ports'][0]['gateway_chassis'] = [ gw_chassis(chassis_name='host-%s' % x, priority=x) for x in range(1, 6) ] for port in TestNBImplIdlOvn.fake_set['lrouter_ports'][1:]: port['gateway_chassis'] = [] self._load_nb_db() unhosted_gateways = self.nb_ovn_idl.get_unhosted_gateways( {}, { 'host-1': 'physnet1', 'host-2': 'physnet2', 'host-3': 'physnet1', 'host-4': 'physnet2', 'host-5': 'physnet1', 'host-6': 'physnet2' }, []) expected = [] self.assertItemsEqual(unhosted_gateways, expected) def test_get_subnet_dhcp_options(self): self._load_nb_db() subnet_options = self.nb_ovn_idl.get_subnet_dhcp_options( 'subnet-id-10-0-2-0') expected_row = self._find_ovsdb_fake_row(self.dhcp_table, 'cidr', '10.0.2.0/24') self.assertEqual( { 'subnet': { 'cidr': expected_row.cidr, 'external_ids': expected_row.external_ids, 'options': expected_row.options, 'uuid': expected_row.uuid }, 'ports': [] }, subnet_options) subnet_options = self.nb_ovn_idl.get_subnet_dhcp_options( 'subnet-id-11-0-2-0')['subnet'] self.assertIsNone(subnet_options) subnet_options = self.nb_ovn_idl.get_subnet_dhcp_options( 'port-id-30-0-1-0')['subnet'] self.assertIsNone(subnet_options) def test_get_subnet_dhcp_options_with_ports(self): # Test empty subnet_options = self.nb_ovn_idl.get_subnet_dhcp_options( 'subnet-id-10-0-1-0', with_ports=True) self.assertItemsEqual({'subnet': None, 'ports': []}, subnet_options) # Test loaded values self._load_nb_db() # Test getting both subnet and port dhcp options subnet_options = self.nb_ovn_idl.get_subnet_dhcp_options( 'subnet-id-10-0-1-0', with_ports=True) dhcp_rows = [ self._find_ovsdb_fake_row(self.dhcp_table, 'cidr', '10.0.1.0/24'), self._find_ovsdb_fake_row(self.dhcp_table, 'cidr', '10.0.1.0/26') ] expected_rows = [{ 'cidr': dhcp_row.cidr, 'external_ids': dhcp_row.external_ids, 'options': dhcp_row.options, 'uuid': dhcp_row.uuid } for dhcp_row in dhcp_rows] self.assertItemsEqual(expected_rows, [subnet_options['subnet']] + subnet_options['ports']) # Test getting only subnet dhcp options subnet_options = self.nb_ovn_idl.get_subnet_dhcp_options( 'subnet-id-10-0-2-0', with_ports=True) dhcp_rows = [ self._find_ovsdb_fake_row(self.dhcp_table, 'cidr', '10.0.2.0/24') ] expected_rows = [{ 'cidr': dhcp_row.cidr, 'external_ids': dhcp_row.external_ids, 'options': dhcp_row.options, 'uuid': dhcp_row.uuid } for dhcp_row in dhcp_rows] self.assertItemsEqual(expected_rows, [subnet_options['subnet']] + subnet_options['ports']) # Test getting no dhcp options subnet_options = self.nb_ovn_idl.get_subnet_dhcp_options( 'subnet-id-11-0-2-0', with_ports=True) self.assertItemsEqual({'subnet': None, 'ports': []}, subnet_options) def test_get_subnets_dhcp_options(self): self._load_nb_db() def get_row_dict(row): return { 'cidr': row.cidr, 'external_ids': row.external_ids, 'options': row.options, 'uuid': row.uuid } subnets_options = self.nb_ovn_idl.get_subnets_dhcp_options( ['subnet-id-10-0-1-0', 'subnet-id-10-0-2-0']) expected_rows = [ get_row_dict( self._find_ovsdb_fake_row(self.dhcp_table, 'cidr', cidr)) for cidr in ('10.0.1.0/24', '10.0.2.0/24') ] self.assertItemsEqual(expected_rows, subnets_options) subnets_options = self.nb_ovn_idl.get_subnets_dhcp_options( ['subnet-id-11-0-2-0', 'subnet-id-20-0-1-0']) expected_row = get_row_dict( self._find_ovsdb_fake_row(self.dhcp_table, 'cidr', '20.0.1.0/24')) self.assertItemsEqual([expected_row], subnets_options) subnets_options = self.nb_ovn_idl.get_subnets_dhcp_options( ['port-id-30-0-1-0', 'fake-not-exist']) self.assertEqual([], subnets_options) def test_get_all_dhcp_options(self): self._load_nb_db() dhcp_options = self.nb_ovn_idl.get_all_dhcp_options() self.assertEqual(len(dhcp_options['subnets']), 3) self.assertEqual(len(dhcp_options['ports_v4']), 2) def test_get_address_sets(self): self._load_nb_db() address_sets = self.nb_ovn_idl.get_address_sets() self.assertEqual(len(address_sets), 4) def test_get_port_group_not_supported(self): self._load_nb_db() # Make sure that PG tables doesn't exist in fake db. self._tables.pop('Port_Group', None) port_group = self.nb_ovn_idl.get_port_group(str(uuid.uuid4())) self.assertIsNone(port_group) def test_get_port_groups_not_supported(self): self._load_nb_db() # Make sure that PG tables doesn't exist in fake db. self._tables.pop('Port_Group', None) port_groups = self.nb_ovn_idl.get_port_groups() self.assertEqual({}, port_groups)
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 lrouters = self.ovn_api.get_all_logical_routers_with_rports() del_lrouters_list = [] del_lrouter_ports_list = [] update_sroutes_list = [] for lrouter in lrouters: if lrouter['name'] in db_routers: for lrport in lrouter['ports']: if lrport in db_router_ports: 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 = n_utils.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']) 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("Router %s static routes %s found in " "Neutron but not in OVN", sroute['id'], 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("Router %s static routes %s found in " "OVN but not in Neutron", sroute['id'], 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 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 = {} db_gateway_ports = {} db_fips = {} for router in self.l3_plugin.get_routers(ctx): db_routers[router['id']] = router db_routers[router['id']]['floating_ips'] = [] db_routers_keys = db_routers.keys() fips = self.l3_plugin.get_floatingips(ctx, {'router_id': db_routers_keys}) interfaces = self.l3_plugin._get_sync_interfaces( ctx, db_routers_keys, [ lib_constants.DEVICE_OWNER_ROUTER_INTF, lib_constants.DEVICE_OWNER_ROUTER_GW ]) for fip in fips: db_routers[fip['router_id']]['floating_ips'].append({ 'floating_ip_address': fip['floating_ip_address'], 'fixed_ip_address': fip['fixed_ip_address'] }) for interface in interfaces: if (interface['device_owner'] == lib_constants.DEVICE_OWNER_ROUTER_INTF): 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'])) else: db_gateway_ports[interface['id']] = interface db_gateway_ports[interface['id']]['networks'] = sorted( self.l3_plugin.get_networks_for_lrouter_port( ctx, interface['fixed_ips'])) LOG.debug("Get neutron routers=%s", db_routers) LOG.debug("Get neutron router ports=%s", db_router_ports) LOG.debug("Get neutron gateway ports=%s", db_gateway_ports) lrouters = self.ovn_api.get_all_logical_routers_with_rports() LOG.debug("Get ovn routers=%s", lrouters) del_lrouters_list = [] del_lrouter_ports_list = [] del_gwrouter_ports_list = [] update_sroutes_list = [] update_fips_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'] }) for gwport, gwport_nets in lrouter['gateway_ports'].items(): if gwport in db_gateway_ports: del db_gateway_ports[gwport] else: del_gwrouter_ports_list.append({ 'port': gwport, 'lrouter': lrouter['name'], 'next_hop': lrouter['next_hop'] }) 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 = n_utils.diff_list_of_dict( ovn_routes, db_routes) update_sroutes_list.append({ 'id': lrouter['name'], 'del': del_routes, 'add': add_routes }) ovn_fips = lrouter['floating_ips'] db_fips = db_routers[lrouter['name']]['floating_ips'] add_fips, del_fips = n_utils.diff_list_of_dict( ovn_fips, db_fips) update_fips_list.append({ 'id': lrouter['name'], 'add': add_fips, 'del': del_fips }) 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 'floating_ips' in router: update_fips_list.append({ 'id': router['id'], 'add': router['floating_ips'], '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']) for gwport_info in del_gwrouter_ports_list: LOG.warning( _LW("Gateway Port found in OVN but not in " "Neutron, port_id=%s"), gwport_info['port']) if self.mode == SYNC_MODE_REPAIR: LOG.warning(_LW("Deleting the port %s from OVN NB DB"), gwport_info['port']) self.l3_plugin.delete_gw_router_port_in_ovn( gwport_info['lrouter'], gwport_info['port'], gwport_info['next_hop']) for gwp_id, gwport in db_gateway_ports.items(): LOG.warning( _LW("Gateway Port found in Neutron but not in OVN " "DB, gateway port_id=%s"), gwport['id']) if self.mode == SYNC_MODE_REPAIR: try: LOG.warning( _LW("Creating the gateway port %s in " "OVN NB DB"), gwport['id']) self.l3_plugin.create_gw_router_port_in_ovn( ctx, gwport['device_id'], gwport) except RuntimeError: LOG.warning( _LW("Create gateway port in OVN " "NB failed for" " gateway port %s"), gwport['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']))) txn.add( self.ovn_api.delete_lrouter( utils.ovn_gateway_name(lrouter['name']))) txn.add( self.ovn_api.delete_lswitch( utils.ovn_transit_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 ifip in fip['del']: txn.add( self.ovn_api.delete_nat( utils.ovn_gateway_name(fip['id']), logical_ip=ifip['fixed_ip_address'], external_ip=ifip['floating_ip_address'], 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 ifip in fip['add']: txn.add( self.ovn_api.add_nat( utils.ovn_gateway_name(fip['id']), logical_ip=ifip['fixed_ip_address'], external_ip=ifip['floating_ip_address'], type='dnat_and_snat')) LOG.debug('OVN-NB Sync routers and router ports finished')
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 """ LOG.debug('OVN-NB Sync Routers and Router ports started') db_routers = {} db_router_ports = {} for router in self.core_plugin.get_routers(ctx): db_routers[router['id']] = router interfaces = self.core_plugin._get_sync_interfaces(ctx, db_routers.keys()) for interface in interfaces: db_router_ports[interface['id']] = interface lrouters = self.ovn_api.get_all_logical_routers_with_rports() del_lrouters_list = [] del_lrouter_ports_list = [] for lrouter in lrouters: if lrouter['name'] in db_routers: for lrport in lrouter['ports']: if lrport in db_router_ports: del db_router_ports[lrport] else: del_lrouter_ports_list.append( {'port': lrport, 'lrouter': lrouter['name']}) 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.core_plugin.create_lrouter_in_ovn(router) 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.core_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']) 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)) LOG.debug('OVN-NB Sync routers and router ports finished')
class TestNBImplIdlOvn(TestDBImplIdlOvn): fake_set = { 'lswitches': [{ 'name': utils.ovn_name('ls-id-1'), 'external_ids': { ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY: 'ls-name-1' } }, { 'name': utils.ovn_name('ls-id-2'), 'external_ids': { ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY: 'ls-name-2' } }, { 'name': utils.ovn_name('ls-id-3'), 'external_ids': { ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY: 'ls-name-3' } }, { 'name': 'ls-id-4', 'external_ids': { 'not-neutron:network_name': 'ls-name-4' } }, { 'name': utils.ovn_name('ls-id-5'), 'external_ids': { ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY: 'ls-name-5' } }], 'lswitch_ports': [{ 'name': 'lsp-id-11', 'addresses': ['10.0.1.1'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-11' } }, { 'name': 'lsp-id-12', 'addresses': ['10.0.1.2'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-12' } }, { 'name': 'lsp-rp-id-1', 'addresses': ['10.0.1.254'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-rp-name-1' }, 'options': { 'router-port': utils.ovn_lrouter_port_name('orp-id-a1') } }, { 'name': 'provnet-ls-id-1', 'addresses': ['unknown'], 'external_ids': {}, 'options': { 'network_name': 'physnet1' } }, { 'name': 'lsp-id-21', 'addresses': ['10.0.2.1'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-21' } }, { 'name': 'lsp-id-22', 'addresses': ['10.0.2.2'], 'external_ids': {} }, { 'name': 'lsp-id-23', 'addresses': ['10.0.2.3'], 'external_ids': { 'not-neutron:port_name': 'lsp-name-23' } }, { 'name': 'lsp-rp-id-2', 'addresses': ['10.0.2.254'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-rp-name-2' }, 'options': { 'router-port': utils.ovn_lrouter_port_name('orp-id-a2') } }, { 'name': 'provnet-ls-id-2', 'addresses': ['unknown'], 'external_ids': {}, 'options': { 'network_name': 'physnet2' } }, { 'name': 'lsp-id-31', 'addresses': ['10.0.3.1'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-31' } }, { 'name': 'lsp-id-32', 'addresses': ['10.0.3.2'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-32' } }, { 'name': 'lsp-rp-id-3', 'addresses': ['10.0.3.254'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-rp-name-3' }, 'options': { 'router-port': utils.ovn_lrouter_port_name('orp-id-a3') } }, { 'name': 'lsp-vpn-id-3', 'addresses': ['10.0.3.253'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-vpn-name-3' } }, { 'name': 'lsp-id-41', 'addresses': ['20.0.1.1'], 'external_ids': { 'not-neutron:port_name': 'lsp-name-41' } }, { 'name': 'lsp-rp-id-4', 'addresses': ['20.0.1.254'], 'external_ids': {}, 'options': { 'router-port': 'xrp-id-b1' } }, { 'name': 'lsp-id-51', 'addresses': ['20.0.2.1'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-51' } }, { 'name': 'lsp-id-52', 'addresses': ['20.0.2.2'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-52' } }, { 'name': 'lsp-rp-id-5', 'addresses': ['20.0.2.254'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-rp-name-5' }, 'options': { 'router-port': utils.ovn_lrouter_port_name('orp-id-b2') } }, { 'name': 'lsp-vpn-id-5', 'addresses': ['20.0.2.253'], 'external_ids': { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-vpn-name-5' } }], 'lrouters': [{ 'name': utils.ovn_name('lr-id-a'), 'external_ids': { ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'lr-name-a' } }, { 'name': utils.ovn_name('lr-id-b'), 'external_ids': { ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'lr-name-b' } }, { 'name': utils.ovn_name('lr-id-c'), 'external_ids': { ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'lr-name-c' } }, { 'name': utils.ovn_name('lr-id-d'), 'external_ids': { ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'lr-name-d' } }, { 'name': utils.ovn_name('lr-id-e'), 'external_ids': { ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'lr-name-e' } }], 'lrouter_ports': [{ 'name': utils.ovn_lrouter_port_name('orp-id-a1'), 'external_ids': {}, 'networks': ['10.0.1.0/24'], 'options': { ovn_const.OVN_GATEWAY_CHASSIS_KEY: 'host-1' } }, { 'name': utils.ovn_lrouter_port_name('orp-id-a2'), 'external_ids': {}, 'networks': ['10.0.2.0/24'], 'options': { ovn_const.OVN_GATEWAY_CHASSIS_KEY: 'host-1' } }, { 'name': utils.ovn_lrouter_port_name('orp-id-a3'), 'external_ids': {}, 'networks': ['10.0.3.0/24'], 'options': { ovn_const.OVN_GATEWAY_CHASSIS_KEY: ovn_const.OVN_GATEWAY_INVALID_CHASSIS } }, { 'name': 'xrp-id-b1', 'external_ids': {}, 'networks': ['20.0.1.0/24'] }, { 'name': utils.ovn_lrouter_port_name('orp-id-b2'), 'external_ids': {}, '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'], 'options': {} }], 'static_routes': [{ 'ip_prefix': '20.0.0.0/16', 'nexthop': '10.0.3.253' }, { 'ip_prefix': '10.0.0.0/16', 'nexthop': '20.0.2.253' }], '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', 'type': 'snat' }, { 'external_ip': '20.0.2.4', 'logical_ip': '10.0.0.4', 'type': 'dnat_and_snat' }], 'acls': [{ 'unit_test_id': 1, 'action': 'allow-related', 'direction': 'from-lport', 'external_ids': { 'neutron:lport': 'lsp-id-11' }, 'match': 'inport == "lsp-id-11" && ip4' }, { 'unit_test_id': 2, 'action': 'allow-related', 'direction': 'to-lport', 'external_ids': { 'neutron:lport': 'lsp-id-11' }, 'match': 'outport == "lsp-id-11" && ip4.src == $as_ip4_id_1' }, { 'unit_test_id': 3, 'action': 'allow-related', 'direction': 'from-lport', 'external_ids': { 'neutron:lport': 'lsp-id-12' }, 'match': 'inport == "lsp-id-12" && ip4' }, { 'unit_test_id': 4, 'action': 'allow-related', 'direction': 'to-lport', 'external_ids': { 'neutron:lport': 'lsp-id-12' }, 'match': 'outport == "lsp-id-12" && ip4.src == $as_ip4_id_1' }, { 'unit_test_id': 5, 'action': 'allow-related', 'direction': 'from-lport', 'external_ids': { 'neutron:lport': 'lsp-id-21' }, 'match': 'inport == "lsp-id-21" && ip4' }, { 'unit_test_id': 6, 'action': 'allow-related', 'direction': 'to-lport', 'external_ids': { 'neutron:lport': 'lsp-id-21' }, 'match': 'outport == "lsp-id-21" && ip4.src == $as_ip4_id_2' }, { 'unit_test_id': 7, 'action': 'allow-related', 'direction': 'from-lport', 'external_ids': { 'neutron:lport': 'lsp-id-41' }, 'match': 'inport == "lsp-id-41" && ip4' }, { 'unit_test_id': 8, 'action': 'allow-related', 'direction': 'to-lport', 'external_ids': { 'neutron:lport': 'lsp-id-41' }, 'match': 'outport == "lsp-id-41" && ip4.src == $as_ip4_id_4' }, { 'unit_test_id': 9, 'action': 'allow-related', 'direction': 'from-lport', 'external_ids': { 'neutron:lport': 'lsp-id-52' }, 'match': 'inport == "lsp-id-52" && ip4' }, { 'unit_test_id': 10, 'action': 'allow-related', 'direction': 'to-lport', 'external_ids': { 'neutron:lport': 'lsp-id-52' }, 'match': 'outport == "lsp-id-52" && ip4.src == $as_ip4_id_5' }], 'dhcp_options': [{ 'cidr': '10.0.1.0/24', 'external_ids': { 'subnet_id': 'subnet-id-10-0-1-0' }, 'options': { 'mtu': '1442', 'router': '10.0.1.254' } }, { 'cidr': '10.0.2.0/24', 'external_ids': { 'subnet_id': 'subnet-id-10-0-2-0' }, 'options': { 'mtu': '1442', 'router': '10.0.2.254' } }, { 'cidr': '10.0.3.0/24', 'external_ids': { 'subnet_id': 'subnet-id-10-0-3-0', 'port_id': 'lsp-vpn-id-3' }, 'options': { 'mtu': '1442', 'router': '10.0.3.254' } }, { 'cidr': '20.0.1.0/24', 'external_ids': { 'subnet_id': 'subnet-id-20-0-1-0' }, 'options': { 'mtu': '1442', 'router': '20.0.1.254' } }, { 'cidr': '20.0.2.0/24', 'external_ids': { 'subnet_id': 'subnet-id-20-0-2-0', 'port_id': 'lsp-vpn-id-5' }, 'options': { 'mtu': '1442', 'router': '20.0.2.254' } }, { 'cidr': '2001:dba::/64', 'external_ids': { 'subnet_id': 'subnet-id-2001-dba', 'port_id': 'lsp-vpn-id-5' }, 'options': { 'server_id': '12:34:56:78:9a:bc' } }, { 'cidr': '30.0.1.0/24', 'external_ids': { 'port_id': 'port-id-30-0-1-0' }, 'options': { 'mtu': '1442', 'router': '30.0.2.254' } }, { 'cidr': '30.0.2.0/24', 'external_ids': {}, 'options': {} }], 'address_sets': [ { 'name': '$as_ip4_id_1', 'addresses': ['10.0.1.1', '10.0.1.2'], 'external_ids': { ovn_const.OVN_SG_NAME_EXT_ID_KEY: 'id_1' } }, { 'name': '$as_ip4_id_2', 'addresses': ['10.0.2.1'], 'external_ids': { ovn_const.OVN_SG_NAME_EXT_ID_KEY: 'id_2' } }, { 'name': '$as_ip4_id_3', 'addresses': ['10.0.3.1', '10.0.3.2'], 'external_ids': { ovn_const.OVN_SG_NAME_EXT_ID_KEY: 'id_3' } }, { 'name': '$as_ip4_id_4', 'addresses': ['20.0.1.1', '20.0.1.2'], 'external_ids': {} }, { 'name': '$as_ip4_id_5', 'addresses': ['20.0.2.1', '20.0.2.2'], 'external_ids': { ovn_const.OVN_SG_NAME_EXT_ID_KEY: 'id_5' } }, ] } fake_associations = { 'lstolsp': { utils.ovn_name('ls-id-1'): ['lsp-id-11', 'lsp-id-12', 'lsp-rp-id-1', 'provnet-ls-id-1'], utils.ovn_name('ls-id-2'): [ 'lsp-id-21', 'lsp-id-22', 'lsp-id-23', 'lsp-rp-id-2', 'provnet-ls-id-2' ], utils.ovn_name('ls-id-3'): ['lsp-id-31', 'lsp-id-32', 'lsp-rp-id-3', 'lsp-vpn-id-3'], 'ls-id-4': ['lsp-id-41', 'lsp-rp-id-4'], utils.ovn_name('ls-id-5'): ['lsp-id-51', 'lsp-id-52', 'lsp-rp-id-5', 'lsp-vpn-id-5'] }, 'lrtolrp': { utils.ovn_name('lr-id-a'): [ utils.ovn_lrouter_port_name('orp-id-a1'), utils.ovn_lrouter_port_name('orp-id-a2'), utils.ovn_lrouter_port_name('orp-id-a3') ], utils.ovn_name('lr-id-b'): ['xrp-id-b1', utils.ovn_lrouter_port_name('orp-id-b2')] }, 'lrtosroute': { utils.ovn_name('lr-id-a'): ['20.0.0.0/16'], utils.ovn_name('lr-id-b'): ['10.0.0.0/16'] }, 'lrtonat': { utils.ovn_name('lr-id-a'): ['10.0.3.1'], utils.ovn_name('lr-id-b'): ['20.0.2.1', '20.0.2.4'], }, 'lstoacl': { utils.ovn_name('ls-id-1'): [1, 2, 3, 4], utils.ovn_name('ls-id-2'): [5, 6], 'ls-id-4': [7, 8], utils.ovn_name('ls-id-5'): [9, 10] } } def setUp(self): super(TestNBImplIdlOvn, self).setUp() self.lswitch_table = fakes.FakeOvsdbTable.create_one_ovsdb_table() self.lsp_table = fakes.FakeOvsdbTable.create_one_ovsdb_table() self.lrouter_table = fakes.FakeOvsdbTable.create_one_ovsdb_table() self.lrp_table = fakes.FakeOvsdbTable.create_one_ovsdb_table() self.sroute_table = fakes.FakeOvsdbTable.create_one_ovsdb_table() self.nat_table = fakes.FakeOvsdbTable.create_one_ovsdb_table() self.acl_table = fakes.FakeOvsdbTable.create_one_ovsdb_table() self.dhcp_table = fakes.FakeOvsdbTable.create_one_ovsdb_table() self.address_set_table = fakes.FakeOvsdbTable.create_one_ovsdb_table() self._tables = {} self._tables['Logical_Switch'] = self.lswitch_table self._tables['Logical_Switch_Port'] = self.lsp_table self._tables['Logical_Router'] = self.lrouter_table self._tables['Logical_Router_Port'] = self.lrp_table self._tables['Logical_Router_Static_Route'] = self.sroute_table self._tables['ACL'] = self.acl_table self._tables['DHCP_Options'] = self.dhcp_table self._tables['Address_Set'] = self.address_set_table with mock.patch.object(impl_idl_ovn, 'get_connection', return_value=mock.Mock()): impl_idl_ovn.OvsdbNbOvnIdl.ovsdb_connection = None self.nb_ovn_idl = impl_idl_ovn.OvsdbNbOvnIdl(self) self.nb_ovn_idl.idl.tables = self._tables def _load_nb_db(self): # Load Switches and Switch Ports fake_lswitches = TestNBImplIdlOvn.fake_set['lswitches'] self._load_ovsdb_fake_rows(self.lswitch_table, fake_lswitches) fake_lsps = TestNBImplIdlOvn.fake_set['lswitch_ports'] self._load_ovsdb_fake_rows(self.lsp_table, fake_lsps) # Associate switches and ports self._construct_ovsdb_references( TestNBImplIdlOvn.fake_associations['lstolsp'], self.lswitch_table, self.lsp_table, 'name', 'name', 'ports') # Load Routers and Router Ports fake_lrouters = TestNBImplIdlOvn.fake_set['lrouters'] self._load_ovsdb_fake_rows(self.lrouter_table, fake_lrouters) fake_lrps = TestNBImplIdlOvn.fake_set['lrouter_ports'] self._load_ovsdb_fake_rows(self.lrp_table, fake_lrps) # Associate routers and router ports self._construct_ovsdb_references( TestNBImplIdlOvn.fake_associations['lrtolrp'], self.lrouter_table, self.lrp_table, 'name', 'name', 'ports') # Load static routes fake_sroutes = TestNBImplIdlOvn.fake_set['static_routes'] self._load_ovsdb_fake_rows(self.sroute_table, fake_sroutes) # Associate routers and static routes self._construct_ovsdb_references( TestNBImplIdlOvn.fake_associations['lrtosroute'], self.lrouter_table, self.sroute_table, 'name', 'ip_prefix', 'static_routes') # Load nats fake_nats = TestNBImplIdlOvn.fake_set['nats'] self._load_ovsdb_fake_rows(self.nat_table, fake_nats) # Associate routers and nats self._construct_ovsdb_references( TestNBImplIdlOvn.fake_associations['lrtonat'], self.lrouter_table, self.nat_table, 'name', 'external_ip', 'nat') # Load acls fake_acls = TestNBImplIdlOvn.fake_set['acls'] self._load_ovsdb_fake_rows(self.acl_table, fake_acls) # Associate switches and acls self._construct_ovsdb_references( TestNBImplIdlOvn.fake_associations['lstoacl'], self.lswitch_table, self.acl_table, 'name', 'unit_test_id', 'acls') # Load dhcp options fake_dhcp_options = TestNBImplIdlOvn.fake_set['dhcp_options'] self._load_ovsdb_fake_rows(self.dhcp_table, fake_dhcp_options) # Load address sets fake_address_sets = TestNBImplIdlOvn.fake_set['address_sets'] self._load_ovsdb_fake_rows(self.address_set_table, fake_address_sets) def test_get_all_logical_switches_with_ports(self): # Test empty mapping = self.nb_ovn_idl.get_all_logical_switches_with_ports() self.assertItemsEqual(mapping, {}) # Test loaded values self._load_nb_db() mapping = self.nb_ovn_idl.get_all_logical_switches_with_ports() expected = [{ 'name': utils.ovn_name('ls-id-1'), 'ports': ['lsp-id-11', 'lsp-id-12', 'lsp-rp-id-1'], 'provnet_port': 'provnet-ls-id-1' }, { 'name': utils.ovn_name('ls-id-2'), 'ports': ['lsp-id-21', 'lsp-rp-id-2'], 'provnet_port': 'provnet-ls-id-2' }, { 'name': utils.ovn_name('ls-id-3'), 'ports': ['lsp-id-31', 'lsp-id-32', 'lsp-rp-id-3', 'lsp-vpn-id-3'], 'provnet_port': None }, { 'name': utils.ovn_name('ls-id-5'), 'ports': ['lsp-id-51', 'lsp-id-52', 'lsp-rp-id-5', 'lsp-vpn-id-5'], 'provnet_port': None }] self.assertItemsEqual(mapping, expected) def test_get_all_logical_routers_with_rports(self): # Test empty mapping = self.nb_ovn_idl.get_all_logical_switches_with_ports() self.assertItemsEqual(mapping, {}) # Test loaded values self._load_nb_db() mapping = self.nb_ovn_idl.get_all_logical_routers_with_rports() expected = [{ 'name': 'lr-id-a', 'ports': { 'orp-id-a1': ['10.0.1.0/24'], 'orp-id-a2': ['10.0.2.0/24'], 'orp-id-a3': ['10.0.3.0/24'] }, 'static_routes': [{ 'destination': '20.0.0.0/16', 'nexthop': '10.0.3.253' }], 'snats': [{ 'external_ip': '10.0.3.1', 'logical_ip': '20.0.0.0/16', 'type': 'snat' }], 'dnat_and_snats': [] }, { 'name': 'lr-id-b', 'ports': { 'xrp-id-b1': ['20.0.1.0/24'], 'orp-id-b2': ['20.0.2.0/24'] }, 'static_routes': [{ 'destination': '10.0.0.0/16', 'nexthop': '20.0.2.253' }], 'snats': [{ 'external_ip': '20.0.2.1', 'logical_ip': '10.0.0.0/24', 'type': 'snat' }], 'dnat_and_snats': [{ 'external_ip': '20.0.2.4', 'logical_ip': '10.0.0.4', 'type': 'dnat_and_snat' }] }, { 'name': 'lr-id-c', 'ports': {}, 'static_routes': [], 'snats': [], 'dnat_and_snats': [] }, { 'name': 'lr-id-d', 'ports': {}, 'static_routes': [], 'snats': [], 'dnat_and_snats': [] }, { 'name': 'lr-id-e', 'ports': {}, 'static_routes': [], 'snats': [], 'dnat_and_snats': [] }] self.assertItemsEqual(mapping, expected) def test_get_acls_for_lswitches(self): self._load_nb_db() # Test neutron switches lswitches = ['ls-id-1', 'ls-id-2', 'ls-id-3', 'ls-id-5'] acl_values, acl_objs, lswitch_ovsdb_dict = \ self.nb_ovn_idl.get_acls_for_lswitches(lswitches) excepted_acl_values = { 'lsp-id-11': [{ 'action': 'allow-related', 'lport': 'lsp-id-11', 'lswitch': 'neutron-ls-id-1', 'external_ids': { 'neutron:lport': 'lsp-id-11' }, 'direction': 'from-lport', 'match': 'inport == "lsp-id-11" && ip4' }, { 'action': 'allow-related', 'lport': 'lsp-id-11', 'lswitch': 'neutron-ls-id-1', 'external_ids': { 'neutron:lport': 'lsp-id-11' }, 'direction': 'to-lport', 'match': 'outport == "lsp-id-11" && ip4.src == $as_ip4_id_1' }], 'lsp-id-12': [{ 'action': 'allow-related', 'lport': 'lsp-id-12', 'lswitch': 'neutron-ls-id-1', 'external_ids': { 'neutron:lport': 'lsp-id-12' }, 'direction': 'from-lport', 'match': 'inport == "lsp-id-12" && ip4' }, { 'action': 'allow-related', 'lport': 'lsp-id-12', 'lswitch': 'neutron-ls-id-1', 'external_ids': { 'neutron:lport': 'lsp-id-12' }, 'direction': 'to-lport', 'match': 'outport == "lsp-id-12" && ip4.src == $as_ip4_id_1' }], 'lsp-id-21': [{ 'action': 'allow-related', 'lport': 'lsp-id-21', 'lswitch': 'neutron-ls-id-2', 'external_ids': { 'neutron:lport': 'lsp-id-21' }, 'direction': 'from-lport', 'match': 'inport == "lsp-id-21" && ip4' }, { 'action': 'allow-related', 'lport': 'lsp-id-21', 'lswitch': 'neutron-ls-id-2', 'external_ids': { 'neutron:lport': 'lsp-id-21' }, 'direction': 'to-lport', 'match': 'outport == "lsp-id-21" && ip4.src == $as_ip4_id_2' }], 'lsp-id-52': [{ 'action': 'allow-related', 'lport': 'lsp-id-52', 'lswitch': 'neutron-ls-id-5', 'external_ids': { 'neutron:lport': 'lsp-id-52' }, 'direction': 'from-lport', 'match': 'inport == "lsp-id-52" && ip4' }, { 'action': 'allow-related', 'lport': 'lsp-id-52', 'lswitch': 'neutron-ls-id-5', 'external_ids': { 'neutron:lport': 'lsp-id-52' }, 'direction': 'to-lport', 'match': 'outport == "lsp-id-52" && ip4.src == $as_ip4_id_5' }] } self.assertItemsEqual(acl_values, excepted_acl_values) self.assertEqual(len(acl_objs), 8) self.assertEqual(len(lswitch_ovsdb_dict), len(lswitches)) # Test non-neutron switches lswitches = ['ls-id-4'] acl_values, acl_objs, lswitch_ovsdb_dict = \ self.nb_ovn_idl.get_acls_for_lswitches(lswitches) self.assertItemsEqual(acl_values, {}) self.assertEqual(len(acl_objs), 0) self.assertEqual(len(lswitch_ovsdb_dict), 0) def test_get_all_chassis_gateway_bindings(self): self._load_nb_db() bindings = self.nb_ovn_idl.get_all_chassis_gateway_bindings() expected = { 'host-1': [ utils.ovn_lrouter_port_name('orp-id-a1'), utils.ovn_lrouter_port_name('orp-id-a2') ], 'host-2': [utils.ovn_lrouter_port_name('orp-id-b2')], ovn_const.OVN_GATEWAY_INVALID_CHASSIS: [utils.ovn_name('orp-id-a3')] } self.assertItemsEqual(bindings, expected) bindings = self.nb_ovn_idl.get_all_chassis_gateway_bindings([]) self.assertItemsEqual(bindings, expected) bindings = self.nb_ovn_idl.get_all_chassis_gateway_bindings(['host-1']) expected = { 'host-1': [ utils.ovn_lrouter_port_name('orp-id-a1'), utils.ovn_lrouter_port_name('orp-id-a2') ] } self.assertItemsEqual(bindings, expected) def test_get_gateway_chassis_binding(self): self._load_nb_db() chassis = self.nb_ovn_idl.get_gateway_chassis_binding( utils.ovn_lrouter_port_name('orp-id-a1')) self.assertEqual(chassis, 'host-1') chassis = self.nb_ovn_idl.get_gateway_chassis_binding( utils.ovn_lrouter_port_name('orp-id-b2')) self.assertEqual(chassis, 'host-2') chassis = self.nb_ovn_idl.get_gateway_chassis_binding( utils.ovn_lrouter_port_name('orp-id-a3')) self.assertIsNone(chassis) chassis = self.nb_ovn_idl.get_gateway_chassis_binding( utils.ovn_lrouter_port_name('orp-id-b3')) self.assertIsNone(chassis) chassis = self.nb_ovn_idl.get_gateway_chassis_binding('bad') self.assertIsNone(chassis) def test_get_unhosted_gateways(self): self._load_nb_db() # Test only host-1 in the valid list unhosted_gateways = self.nb_ovn_idl.get_unhosted_gateways(['host-1']) expected = { utils.ovn_lrouter_port_name('orp-id-b2'): { ovn_const.OVN_GATEWAY_CHASSIS_KEY: 'host-2' }, utils.ovn_lrouter_port_name('orp-id-a3'): { ovn_const.OVN_GATEWAY_CHASSIS_KEY: ovn_const.OVN_GATEWAY_INVALID_CHASSIS } } self.assertItemsEqual(unhosted_gateways, expected) # Test both host-1, host-2 in valid list unhosted_gateways = self.nb_ovn_idl.get_unhosted_gateways( ['host-1', 'host-2']) expected = { utils.ovn_lrouter_port_name('orp-id-a3'): { ovn_const.OVN_GATEWAY_CHASSIS_KEY: ovn_const.OVN_GATEWAY_INVALID_CHASSIS } } self.assertItemsEqual(unhosted_gateways, expected) # Schedule unhosted_gateways on host-2 for unhosted_gateway in unhosted_gateways: router_row = self._find_ovsdb_fake_row(self.lrp_table, 'name', unhosted_gateway) setattr(router_row, 'options', {ovn_const.OVN_GATEWAY_CHASSIS_KEY: 'host-2'}) unhosted_gateways = self.nb_ovn_idl.get_unhosted_gateways( ['host-1', 'host-2']) self.assertItemsEqual(unhosted_gateways, {}) def test_get_subnet_dhcp_options(self): self._load_nb_db() subnet_options = self.nb_ovn_idl.get_subnet_dhcp_options( 'subnet-id-10-0-2-0') expected_row = self._find_ovsdb_fake_row(self.dhcp_table, 'cidr', '10.0.2.0/24') self.assertEqual( { 'cidr': expected_row.cidr, 'external_ids': expected_row.external_ids, 'options': expected_row.options, 'uuid': expected_row.uuid }, subnet_options) subnet_options = self.nb_ovn_idl.get_subnet_dhcp_options( 'subnet-id-11-0-2-0') self.assertIsNone(subnet_options) subnet_options = self.nb_ovn_idl.get_subnet_dhcp_options( 'port-id-30-0-1-0') self.assertIsNone(subnet_options) def test_get_subnets_dhcp_options(self): self._load_nb_db() get_row_dict = lambda row: { 'cidr': row.cidr, 'external_ids': row.external_ids, 'options': row.options, 'uuid': row.uuid } subnets_options = self.nb_ovn_idl.get_subnets_dhcp_options( ['subnet-id-10-0-1-0', 'subnet-id-10-0-2-0']) expected_rows = [ get_row_dict( self._find_ovsdb_fake_row(self.dhcp_table, 'cidr', cidr)) for cidr in ('10.0.1.0/24', '10.0.2.0/24') ] self.assertItemsEqual(expected_rows, subnets_options) subnets_options = self.nb_ovn_idl.get_subnets_dhcp_options( ['subnet-id-11-0-2-0', 'subnet-id-20-0-1-0']) expected_row = get_row_dict( self._find_ovsdb_fake_row(self.dhcp_table, 'cidr', '20.0.1.0/24')) self.assertItemsEqual([expected_row], subnets_options) subnets_options = self.nb_ovn_idl.get_subnets_dhcp_options( ['port-id-30-0-1-0', 'fake-not-exist']) self.assertEqual([], subnets_options) def test_get_all_dhcp_options(self): self._load_nb_db() dhcp_options = self.nb_ovn_idl.get_all_dhcp_options() self.assertEqual(len(dhcp_options['subnets']), 3) self.assertEqual(len(dhcp_options['ports_v4']), 2) def test_compose_dhcp_options_commands(self): # TODO(azbiswas): Implement in seperate patch pass def test_get_address_sets(self): self._load_nb_db() address_sets = self.nb_ovn_idl.get_address_sets() self.assertEqual(len(address_sets), 4)
def remove_router_interface(self, context, router_id, interface_info): router_interface_info = \ super(OVNL3RouterPlugin, self).remove_router_interface( context, router_id, interface_info) router = self.get_router(context, router_id) port_id = router_interface_info['port_id'] multi_prefix = False try: port = self._plugin.get_port(context, port_id) # The router interface port still exists, call ovn to update it. self.update_lrouter_port_in_ovn(context, router_id, port) multi_prefix = True except n_exc.PortNotFound: # The router interface port doesn't exist any more, call ovn to # delete it. self._ovn.delete_lrouter_port(utils.ovn_lrouter_port_name(port_id), utils.ovn_name(router_id), if_exists=False ).execute(check_error=True) if not router.get(l3.EXTERNAL_GW_INFO): return router_interface_info try: cidr = None if multi_prefix: subnet = self._plugin.get_subnet(context, interface_info['subnet_id']) if subnet['ip_version'] == 4: cidr = subnet['cidr'] else: subnet_ids = router_interface_info.get('subnet_ids') for subnet_id in subnet_ids: subnet = self._plugin.get_subnet(context, subnet_id) if subnet['ip_version'] == 4: cidr = subnet['cidr'] break if not cidr: return router_interface_info router_name = utils.ovn_gateway_router_name(router_id) transit_net_ports = self._get_transit_network_ports() nexthop = transit_net_ports['dtsp']['ip'] if self._is_snat_enabled(router): self._update_snat_and_static_routes_for_networks( context, router, networks=[cidr], nexthop=nexthop, enable_snat=False, update_static_routes=True) else: route = {'destination': cidr, 'nexthop': nexthop} self._update_lrouter_routes( context, router_id, add=[route], remove=[], lrouter_name=router_name) except Exception: with excutils.save_and_reraise_exception(): super(OVNL3RouterPlugin, self).add_router_interface( context, router_id, interface_info) LOG.error(_LE('Error is deleting snat')) return router_interface_info
def _find_router_port_row_by_port_id(self, port_id): for row in self.nb_api._tables['Logical_Router_Port'].rows.values(): if row.name == utils.ovn_lrouter_port_name(port_id): return row
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 lrouters = self.ovn_api.get_all_logical_routers_with_rports() del_lrouters_list = [] del_lrouter_ports_list = [] update_sroutes_list = [] for lrouter in lrouters: if lrouter['name'] in db_routers: for lrport in lrouter['ports']: if lrport in db_router_ports: 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 = n_utils.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']) 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 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()))