def delete_gw_router_port_in_ovn(self, router_id, gw_port_id, provnet_gw_ip): LOG.debug("Class OVNL3RouterPlugin:::") # delete default route on dvr-router if exists. dvr_default_route = { 'destination': ovn_const.OVN_DEFAULT_ROUTE_CIDR, 'nexthop': ovn_const.OVN_GATEWAY_TRANSIT_PORT_IP } dvr_router_name = utils.ovn_name(router_id) gw_router_name = utils.ovn_gateway_name(router_id) with self._ovn.transaction(check_error=True) as txn: # 1. clear default route of dvr-router. txn.add( self._ovn.delete_static_route( dvr_router_name, ip_prefix=dvr_default_route['destination'], nexthop=dvr_default_route['nexthop'])) # 2. remove gw port of gw-router. txn.add( self._ovn.delete_lrouter_port('lrp-%s' % gw_port_id, lrouter=gw_router_name)) # 3. clear default snat on gw-router. txn.add( self._ovn.delete_nat(gw_router_name, logical_ip='0.0.0.0/0')) # 4. clear default route on gw-router. txn.add( self._ovn.delete_static_route( gw_router_name, ip_prefix=ovn_const.OVN_DEFAULT_ROUTE_CIDR, nexthop=provnet_gw_ip))
def create_gw_router_port_in_ovn(self, context, router_id, gw_port): """Create lrouter in OVN @param context: @param router_id: neutron Router id for the port that needs to be created @param chassis: chassis where gateway Router to be created @param gw_port: neutorn gw port @return: Nothing """ dvr_router_name = utils.ovn_name(router_id) gw_router_name = utils.ovn_gateway_name(router_id) gw_port_name = 'lrp-%s' % gw_port['id'] with self._ovn.transaction(check_error=True) as txn: txn.add( self._ovn.add_lrouter_port( name=gw_port_name, lrouter=gw_router_name, mac=gw_port['mac_address'], networks=self.get_networks_for_lrouter_port( context, gw_port['fixed_ips']))) # connect Gateway to provnet txn.add( self._ovn.set_lrouter_port_in_lswitch_port( lswitch_port=gw_port['id'], lrouter_port=gw_port_name)) # add static route for gw_router and dvr-router. dvr_default_route = { 'destination': ovn_const.OVN_DEFAULT_ROUTE_CIDR, 'nexthop': ovn_const.OVN_GATEWAY_TRANSIT_PORT_IP } gw_default_gateway = self.get_subnet_gateway_ips( context, gw_port['fixed_ips'])[0] gw_default_route = { 'destination': ovn_const.OVN_DEFAULT_ROUTE_CIDR, 'nexthop': gw_default_gateway } with self._ovn.transaction(check_error=True) as txn: # add default route for two ovn-router. txn.add( self._ovn.add_static_route( dvr_router_name, ip_prefix=dvr_default_route['destination'], nexthop=dvr_default_route['nexthop'])) txn.add( self._ovn.add_static_route( gw_router_name, ip_prefix=gw_default_route['destination'], nexthop=gw_default_route['nexthop'])) # add default snat to gw_router . txn.add( self._ovn.add_nat( gw_router_name, logical_ip='0.0.0.0/0', external_ip=gw_port['fixed_ips'][0]['ip_address'], type='snat'))
def disassociate_floatingip(self, context, router_id, floatingip): LOG.debug('OVNL3RouterPlugin::') fixed_ip = floatingip['fixed_ip_address'] floating_ip = floatingip['floating_ip_address'] gw_router_name = utils.ovn_gateway_name(router_id) with self._ovn.transaction(check_error=True) as txn: txn.add( self._ovn.delete_nat(gw_router_name, logical_ip=fixed_ip, external_ip=floating_ip, type='dnat_and_snat'))
def delete_router(self, context, id): router_name = utils.ovn_name(id) ret_val = super(OVNL3RouterPlugin, self).delete_router(context, id) self._ovn.delete_lrouter(router_name).execute(check_error=True) # NOTE(zhoucx): here we needn't delete gw_info(neutron gw_port) , # parent class will do it if gw_port exists(by call update_router_gw_info). # (zhoucx)delete gw_router and transit_switch. gw_router_name = utils.ovn_gateway_name(id) switch_name = utils.ovn_transit_name(id) self._ovn.delete_lrouter(gw_router_name).execute(check_error=True) self._ovn.delete_lswitch(switch_name).execute(check_error=True) return ret_val
def del_returned_route_on_gw(self, context, router_id, subnet_id): """del static route for subnet that ports located in on gw-router. @param router id : LRouter ID for the port @param subnet_id : subnet_id router-interface belongs to @return: Nothing """ LOG.debug('OVNL3RouterPlugin::') ovn_router_name = utils.ovn_gateway_name(router_id) subnet = self._plugin.get_subnet(context, subnet_id) route = {'destination': subnet['cidr'], 'nexthop': '169.254.128.2'} with self._ovn.transaction(check_error=True) as txn: txn.add( self._ovn.delete_static_route(ovn_router_name, ip_prefix=route['destination'], nexthop=route['nexthop']))
def add_returned_route_on_gw(self, context, router_id, port): """add static route for subnet that ports located in on gw-router. @param router id : LRouter ID for the port @param port : LRouter port @return: Nothing """ LOG.debug('OVNL3RouterPlugin::') ovn_router_name = utils.ovn_gateway_name(router_id) for fixed_ip in port['fixed_ips']: subnet_id = fixed_ip['subnet_id'] subnet = self._plugin.get_subnet(context, subnet_id) route = { 'destination': subnet['cidr'], 'nexthop': ovn_const.OVN_LROUTER_TRANSIT_PORT_IP } with self._ovn.transaction(check_error=True) as txn: txn.add( self._ovn.add_static_route(ovn_router_name, ip_prefix=route['destination'], nexthop=route['nexthop']))
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 create_lrouter_in_ovn(self, router): """Create lrouter in OVN @param router: Router to be created in OVN @return: Nothing """ router_name = utils.ovn_name(router['id']) external_ids = { ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: router.get('name', 'no_router_name') } enabled = router.get('admin_state_up') with self._ovn.transaction(check_error=True) as txn: txn.add( self._ovn.create_lrouter(router_name, external_ids=external_ids, enabled=enabled)) # todo(zhoucx): create gw resource. selected_chassis = self.scheduler.select(self._ovn, self._sb_ovn, None) # NOTE(zhoucx) here we can ignore selected_chassis == ovn_const.OVN_GATEWAY_INVALID_CHASSIS, # schedule_unhosted_routers() will update it . gw_router_name = utils.ovn_gateway_name(router['id']) router_options = {'chassis': selected_chassis} txn.add( self._ovn.create_lrouter(gw_router_name, external_ids={ ovn_const.OVN_GATEWAY_EXT_ID_KEY: router['name'] }, options=router_options, enabled=True)) # create transit switch transit_switch_name = 'transit-' + router['id'] txn.add( self._ovn.create_lswitch( lswitch_name=transit_switch_name, external_ids={ ovn_const.OVN_TRANSIT_NETWORK_EXT_ID_KEY: router['name'] })) # create with self._ovn.transaction(check_error=True) as txn: base_mac = n_cfg.CONF.base_mac.split(':') dvr_to_transit_port = { 'mac_address': n_utils.get_random_mac(base_mac), 'networks': ovn_const.OVN_LROUTER_TRANSIT_PORT_NETWORK, 'ip_address': ovn_const.OVN_LROUTER_TRANSIT_PORT_IP } txn.add( self._ovn.add_lrouter_port( name='dvr-to-transit-%s' % router['id'], lrouter=router_name, mac=dvr_to_transit_port['mac_address'], networks=dvr_to_transit_port['networks'])) txn.add( self._ovn.create_lswitch_port( lport_name='transit-to-dvr-%s' % router['id'], lswitch_name=transit_switch_name, addresses=[ dvr_to_transit_port['mac_address'] + ' ' + dvr_to_transit_port['ip_address'] ], external_ids=None, type='router')) gw_to_transit_port = { 'mac_address': n_utils.get_random_mac(base_mac), 'networks': ovn_const.OVN_GATEWAY_TRANSIT_PORT_NETWORK, 'ip_address': ovn_const.OVN_GATEWAY_TRANSIT_PORT_IP } txn.add( self._ovn.add_lrouter_port( name='gw-to-transit-%s' % router['id'], lrouter=gw_router_name, mac=gw_to_transit_port['mac_address'], networks=gw_to_transit_port['networks'])) txn.add( self._ovn.create_lswitch_port( lport_name='transit-to-gw-%s' % router['id'], lswitch_name=transit_switch_name, addresses=[ gw_to_transit_port['mac_address'] + ' ' + gw_to_transit_port['ip_address'] ], external_ids=None, type='router')) # connect them. with self._ovn.transaction(check_error=True) as txn: txn.add( self._ovn.set_lrouter_port_in_lswitch_port( lswitch_port='transit-to-dvr-%s' % router['id'], lrouter_port='dvr-to-transit-%s' % router['id'])) txn.add( self._ovn.set_lrouter_port_in_lswitch_port( lswitch_port='transit-to-gw-%s' % router['id'], lrouter_port='gw-to-transit-%s' % router['id']))