def ryu(routerid, asn, peerip, peerport, peeras): import eventlet from ryu.services.protocols.bgp.bgpspeaker import BGPSpeaker eventlet.monkey_patch() # BGPSpeaker needs sockets patched def dump_remote_best_path_change(event): print('the best path changed:', event.remote_as, event.prefix, event.nexthop, event.is_withdraw) def detect_peer_down(remote_ip, remote_as): print('Peer down:', remote_ip, remote_as) speaker = BGPSpeaker( as_number=int(args.asn), router_id=args.router_id, best_path_change_handler=dump_remote_best_path_change, peer_down_handler=detect_peer_down) # XXX need to fix port arg speaker.neighbor_add(peerip, peeras, peerport) # uncomment the below line if the speaker needs to talk with a bmp server. # speaker.bmp_server_add('192.168.177.2', 11019) # count = 1 while True: eventlet.sleep(30)
def __init__(self, *args, **kwargs): super(SDNIP, self).__init__(*args, **kwargs) self.fwd = kwargs['fwd'] self.hop_db = kwargs['hop_db'] self.cfg_mgr = SDNIPConfigManager() self.waiters = {} self.bgp_speaker =\ BGPSpeaker(self.cfg_mgr.as_number, str(self.cfg_mgr.router_id), bgp_server_port=self.cfg_mgr.listen_port, best_path_change_handler=self.best_path_change_handler, peer_down_handler=self.peer_down_handler, peer_up_handler=self.peer_up_handler) speaker_ids = self.cfg_mgr.get_all_speaker_id() for speaker_id in speaker_ids: self.bgp_speaker.neighbor_add(speaker_id, self.cfg_mgr.as_number, is_next_hop_self=True) hub.spawn(self.prefix_check_loop) if with_dk: dk_plugin.DynamicLoader.register_custom_cmd( 'sdn-ip:info', self.cmd_self_info) dk_plugin.DynamicLoader.register_custom_cmd( 'sdn-ip:routes', self.cmd_list_routes) dk_plugin.DynamicLoader.register_custom_cmd( 'sdn-ip:flows', self.cmd_get_flows)
def start_bgpspeaker(self, asNum, routerId, label_start, label_end): self.myRouterId = routerId self.labelRange = tuple([label_start, label_end]) self.speaker = BGPSpeaker(as_number=asNum, router_id=routerId, best_path_change_handler=self.dump_remote_best_path_change, peer_down_handler=self.detect_peer_down, peer_up_handler=self.detect_peer_up, label_range=self.labelRange)
def main(): reset_flows() sw=discover_switches() resolve_nhops() print "start BGP peering" speaker = BGPSpeaker(**self) speaker.neighbor_add(**neighbor) while True: eventlet.sleep(10)
def _start_speaker(self, settings): """ Starts BGPSpeaker using the given settings. """ # Settings for starting BGPSpeaker bgp_settings = {} # Get required settings. try: bgp_settings['as_number'] = settings.get(LOCAL_AS) bgp_settings['router_id'] = settings.get(ROUTER_ID) except KeyError as e: raise ApplicationException( desc='Required BGP configuration missing: %s' % e) # Set event notify handlers if no corresponding handler specified. bgp_settings['best_path_change_handler'] = settings.get( 'best_path_change_handler', self._notify_best_path_changed_event) bgp_settings['peer_down_handler'] = settings.get( 'peer_down_handler', self._notify_peer_down_event) bgp_settings['peer_up_handler'] = settings.get( 'peer_up_handler', self._notify_peer_up_event) # Get optional settings. bgp_settings[BGP_SERVER_PORT] = settings.get( BGP_SERVER_PORT, DEFAULT_BGP_SERVER_PORT) bgp_settings[REFRESH_STALEPATH_TIME] = settings.get( REFRESH_STALEPATH_TIME, DEFAULT_REFRESH_STALEPATH_TIME) bgp_settings[REFRESH_MAX_EOR_TIME] = settings.get( REFRESH_MAX_EOR_TIME, DEFAULT_REFRESH_MAX_EOR_TIME) bgp_settings[LABEL_RANGE] = settings.get( LABEL_RANGE, DEFAULT_LABEL_RANGE) bgp_settings['allow_local_as_in_count'] = settings.get( 'allow_local_as_in_count', 0) bgp_settings[LOCAL_PREF] = settings.get( LOCAL_PREF, DEFAULT_LOCAL_PREF) # Create BGPSpeaker instance. LOG.debug('Starting BGPSpeaker...') self.speaker = BGPSpeaker(**bgp_settings) # Add neighbors. LOG.debug('Adding neighbors...') self._add_neighbors(settings.get('neighbors', [])) # Add VRFs. LOG.debug('Adding VRFs...') self._add_vrfs(settings.get('vrfs', [])) # Add Networks LOG.debug('Adding routes...') self._add_routes(settings.get('routes', []))
def reset_bgp(self): # TODO: port status changes should cause us to withdraw a route. # TODO: configurable behavior - withdraw routes if peer goes down. for dp_id, valve in self.valves.iteritems(): if dp_id not in self.dp_bgp_speakers: self.dp_bgp_speakers[dp_id] = {} bgp_speakers = self.dp_bgp_speakers[dp_id] for bgp_speaker in bgp_speakers.itervalues(): bgp_speaker.shutdown() for vlan in valve.dp.vlans.itervalues(): if vlan.bgp_as: handler = lambda x: self.bgp_route_handler(x, vlan) bgp_speaker = BGPSpeaker( as_number=vlan.bgp_as, router_id=vlan.bgp_routerid, bgp_server_port=vlan.bgp_port, best_path_change_handler=handler) for controller_ip in vlan.controller_ips: prefix = ipaddr.IPNetwork( '/'.join( (str(controller_ip.ip), str(controller_ip.prefixlen)))) bgp_speaker.prefix_add( prefix=str(prefix), next_hop=controller_ip.ip) for route_table in (vlan.ipv4_routes, vlan.ipv6_routes): for ip_dst, ip_gw in route_table.iteritems(): bgp_speaker.prefix_add( prefix=str(ip_dst), next_hop=str(ip_gw)) bgp_speaker.neighbor_add( address=vlan.bgp_neighbor_address, remote_as=vlan.bgp_neighbor_as) bgp_speakers[vlan] = bgp_speaker
def _create_bgp_speaker_for_vlan(self, vlan): """Set up BGP speaker for an individual VLAN if required. Args: vlan (vlan): VLAN associated with this speaker. Returns: ryu.services.protocols.bgp.bgpspeaker.BGPSpeaker: BGP speaker. """ handler = lambda x: self._bgp_route_handler(x, vlan) bgp_speaker = BGPSpeaker(as_number=vlan.bgp_as, router_id=vlan.bgp_routerid, bgp_server_port=vlan.bgp_port, best_path_change_handler=handler) for faucet_vip in vlan.faucet_vips: prefix = ipaddr.IPNetwork(faucet_vip.exploded) bgp_speaker.prefix_add(prefix=str(prefix), next_hop=str(faucet_vip.ip)) for route_table in (vlan.ipv4_routes, vlan.ipv6_routes): for ip_dst, ip_gw in route_table.iteritems(): bgp_speaker.prefix_add(prefix=str(ip_dst), next_hop=str(ip_gw)) for bgp_neighbor_address in vlan.bgp_neighbor_addresses: bgp_speaker.neighbor_add(address=bgp_neighbor_address, remote_as=vlan.bgp_neighbor_as, local_address=vlan.bgp_local_address, enable_ipv4=True, enable_ipv6=True) return bgp_speaker
def __init__(self, *args, **kwargs): super(SDNIP, self).__init__(*args, **kwargs) self.fwd = kwargs['fwd'] self.hop_db = kwargs['hop_db'] self.cfg_mgr = SDNIPConfigManager() self.waiters = {} self.bgp_speaker =\ BGPSpeaker(self.cfg_mgr.as_number, str(self.cfg_mgr.router_id), bgp_server_port=self.cfg_mgr.listen_port, best_path_change_handler=self.best_path_change_handler, peer_down_handler=self.peer_down_handler, peer_up_handler=self.peer_up_handler) speaker_ids = self.cfg_mgr.get_all_speaker_id() for speaker_id in speaker_ids: self.bgp_speaker.neighbor_add(speaker_id, self.cfg_mgr.as_number, is_next_hop_self=True) hub.spawn(self.prefix_check_loop) if with_dk: dk_plugin.DynamicLoader.register_custom_cmd('sdn-ip:info', self.cmd_self_info) dk_plugin.DynamicLoader.register_custom_cmd('sdn-ip:routes', self.cmd_list_routes) dk_plugin.DynamicLoader.register_custom_cmd('sdn-ip:flows', self.cmd_get_flows)
def _create_bgp_speaker_for_vlan(self, vlan): """Set up BGP speaker for an individual VLAN if required. Args: vlan (vlan): VLAN associated with this speaker. Returns: ryu.services.protocols.bgp.bgpspeaker.BGPSpeaker: BGP speaker. """ handler = lambda x: self._bgp_route_handler(x, vlan) bgp_speaker = BGPSpeaker( as_number=vlan.bgp_as, router_id=vlan.bgp_routerid, bgp_server_port=vlan.bgp_port, best_path_change_handler=handler) for controller_ip in vlan.controller_ips: prefix = ipaddr.IPNetwork( '/'.join((str(controller_ip.ip), str(controller_ip.prefixlen)))) bgp_speaker.prefix_add( prefix=str(prefix), next_hop=controller_ip.ip) for route_table in (vlan.ipv4_routes, vlan.ipv6_routes): for ip_dst, ip_gw in route_table.iteritems(): bgp_speaker.prefix_add( prefix=str(ip_dst), next_hop=str(ip_gw)) for bgp_neighbor_address in vlan.bgp_neighbor_addresses: bgp_speaker.neighbor_add( address=bgp_neighbor_address, remote_as=vlan.bgp_neighbor_as) return bgp_speaker
def reset_bgp(self): # TODO: port status changes should cause us to withdraw a route. # TODO: configurable behavior - withdraw routes if peer goes down. for bgp_speaker in self.bgp_speakers.itervalues(): bgp_speaker.shutdown() for vlan in self.valve.dp.vlans.itervalues(): if vlan.bgp_as: handler = lambda x: self.bgp_route_handler(x, vlan) bgp_speaker = BGPSpeaker( as_number=vlan.bgp_as, router_id=vlan.bgp_routerid, bgp_server_port=vlan.bgp_port, best_path_change_handler=handler) for controller_ip in vlan.controller_ips: prefix = ipaddr.IPNetwork( '/'.join( (str(controller_ip.ip), str(controller_ip.prefixlen)))) bgp_speaker.prefix_add( prefix=str(prefix), next_hop=controller_ip.ip) for route_table in (vlan.ipv4_routes, vlan.ipv6_routes): for ip_dst, ip_gw in route_table.iteritems(): bgp_speaker.prefix_add( prefix=str(ip_dst), next_hop=str(ip_gw)) bgp_speaker.neighbor_add( address=vlan.bgp_neighbor_address, remote_as=vlan.bgp_neighbor_as) self.bgp_speakers[vlan] = bgp_speaker
def _start_speaker(self, settings): """ Starts BGPSpeaker using the given settings. """ # Check required settings. _required_settings = ( LOCAL_AS, ROUTER_ID, ) for required in _required_settings: if required not in settings: raise ApplicationException( desc='Required BGP configuration missing: %s' % required) # Set event notify handlers if no corresponding handler specified. settings.setdefault( 'best_path_change_handler', self._notify_best_path_changed_event) settings.setdefault( 'adj_rib_in_change_handler', self._notify_adj_rib_in_changed_event) settings.setdefault( 'peer_down_handler', self._notify_peer_down_event) settings.setdefault( 'peer_up_handler', self._notify_peer_up_event) # Pop settings other than creating BGPSpeaker instance. neighbors_settings = settings.pop('neighbors', []) vrfs_settings = settings.pop('vrfs', []) routes_settings = settings.pop('routes', []) # Create BGPSpeaker instance. LOG.debug('Starting BGPSpeaker...') settings.setdefault('as_number', settings.pop(LOCAL_AS)) self.speaker = BGPSpeaker(**settings) # Add neighbors. LOG.debug('Adding neighbors...') self._add_neighbors(neighbors_settings) # Add VRFs. LOG.debug('Adding VRFs...') self._add_vrfs(vrfs_settings) # Add routes LOG.debug('Adding routes...') self._add_routes(routes_settings)
def bgp_sender(self): def dump_remote_best_path_change(event): print 'the best path changed:', event.remote_as, event.prefix, \ event.nexthop, event.is_withdraw def detect_peer_down(remote_ip, remote_as): print 'Peer down:', remote_ip, remote_as def detect_peer_up(remote_ip, remote_as, uri_enabled, peer): print 'Peer up', remote_ip, remote_as if uri_enabled: self.uri_enabled_capability = True self.peer[remote_ip] = ( peer, self.uri_enabled_capability ) #Create peer dictionary with key ip and value a tuple of peer and uri_enabled capability self.uri_enabled_capability = False else: self.peer[remote_ip] = (peer, False) self.speaker = BGPSpeaker( as_number=1000, router_id='147.102.13.198', best_path_change_handler=dump_remote_best_path_change, peer_down_handler=detect_peer_down, peer_up_handler=detect_peer_up) #self.speaker = BGPSpeaker(as_number=1000, router_id='2.1.1.1', # best_path_change_handler=dump_remote_best_path_change, # peer_down_handler=detect_peer_down,peer_up_handler=detect_peer_up) self.speaker.neighbor_add('147.102.13.156', 1000, next_hop='192.0.2.1') #self.speaker.neighbor_add('192.168.1.2', 1001,enable_uri=True) #self.speaker.neighbor_add('2.1.1.2', 1000, next_hop='192.0.2.1') #alla = PrefixFilter('0.0.0.0/0',policy=PrefixFilter.POLICY_DENY) #self.speaker.out_filter_set('192.168.1.2',[alla]) #self.speaker.out_filter_set('2.1.1.2',[alla]) #self.drop_to_router(AC(1000).create()) #self.speaker. #eventlet.sleep(20) #self.drop_to_router(['147.102.13.199/32']) ofs = Switch() eventlet.sleep(40) ofs.add_flow("147.102.13.199") """
def __init__(self, *args, **kwargs): super(SDNIP, self).__init__(*args, **kwargs) self.fwd_util = kwargs['fwd'] self.hop_db = kwargs['hop_db'] self.cfg_mgr = SDNIPConfigManager() #获取SDN-IP配置信息 # 在Ryu上运行一个iBGPSpeaker self.bgp_speaker =\ BGPSpeaker(self.cfg_mgr.as_number, #AS号 str(self.cfg_mgr.router_id), #iBGP的router id bgp_server_port=self.cfg_mgr.listen_port, #监听BGP协议的端口号 best_path_change_handler=self.best_path_change_handler, #当路由信息变化时调用此方法 peer_down_handler=self.peer_down_handler, #BGP对等体下线 peer_up_handler=self.peer_up_handler) #BGP对等体上线 speaker_ids = self.cfg_mgr.get_all_speaker_id() # 建立iBGPSpeaker与SDN域内的BGPSpeaker的连接 for speaker_id in speaker_ids: self.bgp_speaker.neighbor_add(speaker_id, self.cfg_mgr.as_number, is_next_hop_self=True)
def bgp_create(self, as_number, router_id): # MUDAR AQUI - INICIO try: self.bgp_speaker = BGPSpeaker( as_number=as_number, router_id=router_id, best_path_change_handler=self.best_path_change_handler, adj_rib_in_change_handler=self.adj_rib_in_change_handler, peer_down_handler=self.peer_down_handler, peer_up_handler=self.peer_up_handler) except Exception as e: print "Error creating bgp speaker: %s" % (e) return (False, 'Failed to create BGP speaker') # MUDAR AQUI - FIM self.bgp_config['as_number'] = as_number self.bgp_config['router_id'] = router_id self.bgp_config['neighbors'] = [] self.bgp_config['adv_prefixes'] = [] self.persist_config() return (True, 'Success')
def __init__(self, *args, **kwargs): super(SDNIP, self).__init__(*args, **kwargs) self.fwd = kwargs['fwd'] self.hop_db = kwargs['hop_db'] self.cfg_mgr = SDNIPConfigManager('config.json') self.bgp_speaker =\ BGPSpeaker(self.cfg_mgr.as_number, self.cfg_mgr.router_id, bgp_server_port=self.cfg_mgr.listen_port, best_path_change_handler=self.best_path_change_handler, peer_down_handler=self.peer_down_handler, peer_up_handler=self.peer_up_handler) speaker_ids = self.cfg_mgr.get_all_speaker_id() for speaker_id in speaker_ids: self.bgp_speaker.neighbor_add(speaker_id, self.cfg_mgr.as_number, is_next_hop_self=True) hub.spawn(self.prefix_check_loop)
def _start_speaker(self, settings): """ Starts BGPSpeaker using the given settings. """ # Settings for starting BGPSpeaker bgp_settings = {} # Get required settings. try: bgp_settings['as_number'] = settings.get(LOCAL_AS) bgp_settings['router_id'] = settings.get(ROUTER_ID) except KeyError as e: raise ApplicationException( desc='Required BGP configuration missing: %s' % e) # Get optional settings. bgp_settings[BGP_SERVER_PORT] = settings.get(BGP_SERVER_PORT, DEFAULT_BGP_SERVER_PORT) bgp_settings[REFRESH_STALEPATH_TIME] = settings.get( REFRESH_STALEPATH_TIME, DEFAULT_REFRESH_STALEPATH_TIME) bgp_settings[REFRESH_MAX_EOR_TIME] = settings.get( REFRESH_MAX_EOR_TIME, DEFAULT_REFRESH_MAX_EOR_TIME) bgp_settings[LABEL_RANGE] = settings.get(LABEL_RANGE, DEFAULT_LABEL_RANGE) # Create BGPSpeaker instance. LOG.debug('Starting BGPSpeaker...') self.speaker = BGPSpeaker(**bgp_settings) # Add neighbors. LOG.debug('Adding neighbors...') self._add_neighbors(settings.get('neighbors', [])) # Add VRFs. LOG.debug('Adding VRFs...') self._add_vrfs(settings.get('vrfs', [])) # Add Networks LOG.debug('Adding routes...') self._add_routes(settings.get('routes', []))
def _create_bgp_speaker_for_vlan(self, vlan, dp_id, vlan_vid): """Set up BGP speaker for an individual VLAN if required. Args: vlan (valve VLAN): VLAN for BGP speaker. dp_id (int): Datapath ID for BGP speaker. vlan_vid (vlan_vid): VLAN VID for BGP speaker. Returns: ryu.services.protocols.bgp.bgpspeaker.BGPSpeaker: BGP speaker. """ handler = lambda x: self._bgp_route_handler(x, dp_id, vlan_vid) bgp_speaker = BGPSpeaker( as_number=vlan.bgp_as, router_id=vlan.bgp_routerid, bgp_server_port=vlan.bgp_port, bgp_server_hosts=vlan.bgp_server_addresses, best_path_change_handler=handler, peer_up_handler=self._bgp_up_handler, peer_down_handler=self._bgp_down_handler) for ip_dst, ip_gw in self._vlan_prefixes(vlan): bgp_speaker.prefix_add(prefix=ip_dst, next_hop=ip_gw) for bgp_neighbor_address in vlan.bgp_neighbor_addresses: bgp_speaker.neighbor_add( connect_mode=vlan.bgp_connect_mode, address=bgp_neighbor_address, remote_as=vlan.bgp_neighbor_as, local_address=vlan.bgp_local_address, enable_ipv4=True, enable_ipv6=True) return bgp_speaker
def _start_speaker(self, settings): """ Starts BGPSpeaker using the given settings. """ # Settings for starting BGPSpeaker bgp_settings = {} # Get required settings. try: bgp_settings['as_number'] = settings.get(LOCAL_AS) bgp_settings['router_id'] = settings.get(ROUTER_ID) except KeyError as e: raise ApplicationException( desc='Required BGP configuration missing: %s' % e) # Set event notify handlers if no corresponding handler specified. bgp_settings['best_path_change_handler'] = settings.get( 'best_path_change_handler', self._notify_best_path_changed_event) bgp_settings['peer_down_handler'] = settings.get( 'peer_down_handler', self._notify_peer_down_event) bgp_settings['peer_up_handler'] = settings.get( 'peer_up_handler', self._notify_peer_up_event) # Get optional settings. bgp_settings[BGP_SERVER_PORT] = settings.get( BGP_SERVER_PORT, DEFAULT_BGP_SERVER_PORT) bgp_settings[REFRESH_STALEPATH_TIME] = settings.get( REFRESH_STALEPATH_TIME, DEFAULT_REFRESH_STALEPATH_TIME) bgp_settings[REFRESH_MAX_EOR_TIME] = settings.get( REFRESH_MAX_EOR_TIME, DEFAULT_REFRESH_MAX_EOR_TIME) bgp_settings[LABEL_RANGE] = settings.get( LABEL_RANGE, DEFAULT_LABEL_RANGE) bgp_settings['allow_local_as_in_count'] = settings.get( 'allow_local_as_in_count', 0) # Create BGPSpeaker instance. LOG.debug('Starting BGPSpeaker...') self.speaker = BGPSpeaker(**bgp_settings) # Add neighbors. LOG.debug('Adding neighbors...') self._add_neighbors(settings.get('neighbors', [])) # Add VRFs. LOG.debug('Adding VRFs...') self._add_vrfs(settings.get('vrfs', [])) # Add Networks LOG.debug('Adding routes...') self._add_routes(settings.get('routes', []))
def _start_speaker(self, settings): """ Starts BGPSpeaker using the given settings. """ # Check required settings. _required_settings = ( LOCAL_AS, ROUTER_ID, ) for required in _required_settings: if required not in settings: raise ApplicationException( desc='Required BGP configuration missing: %s' % required) # Set event notify handlers if no corresponding handler specified. settings.setdefault( 'best_path_change_handler', self._notify_best_path_changed_event) settings.setdefault( 'peer_down_handler', self._notify_peer_down_event) settings.setdefault( 'peer_up_handler', self._notify_peer_up_event) # Pop settings other than creating BGPSpeaker instance. neighbors_settings = settings.pop('neighbors', []) vrfs_settings = settings.pop('vrfs', []) routes_settings = settings.pop('routes', []) # Create BGPSpeaker instance. LOG.debug('Starting BGPSpeaker...') settings.setdefault('as_number', settings.pop(LOCAL_AS)) self.speaker = BGPSpeaker(**settings) # Add neighbors. LOG.debug('Adding neighbors...') self._add_neighbors(neighbors_settings) # Add VRFs. LOG.debug('Adding VRFs...') self._add_vrfs(vrfs_settings) # Add routes LOG.debug('Adding routes...') self._add_routes(routes_settings)
def _start_speaker(self, settings): """ Starts BGPSpeaker using the given settings. """ # Settings for starting BGPSpeaker bgp_settings = {} # Get required settings. try: bgp_settings['as_number'] = settings.get(LOCAL_AS) bgp_settings['router_id'] = settings.get(ROUTER_ID) except KeyError as e: raise ApplicationException( desc='Required BGP configuration missing: %s' % e) # Get optional settings. bgp_settings[BGP_SERVER_PORT] = settings.get( BGP_SERVER_PORT, DEFAULT_BGP_SERVER_PORT) bgp_settings[REFRESH_STALEPATH_TIME] = settings.get( REFRESH_STALEPATH_TIME, DEFAULT_REFRESH_STALEPATH_TIME) bgp_settings[REFRESH_MAX_EOR_TIME] = settings.get( REFRESH_MAX_EOR_TIME, DEFAULT_REFRESH_MAX_EOR_TIME) bgp_settings[LABEL_RANGE] = settings.get( LABEL_RANGE, DEFAULT_LABEL_RANGE) # Create BGPSpeaker instance. LOG.debug('Starting BGPSpeaker...') self.speaker = BGPSpeaker(**bgp_settings) # Add neighbors. LOG.debug('Adding neighbors...') self._add_neighbors(settings.get('neighbors', [])) # Add VRFs. LOG.debug('Adding VRFs...') self._add_vrfs(settings.get('vrfs', [])) # Add Networks LOG.debug('Adding routes...') self._add_routes(settings.get('routes', []))
def _create_bgp_speaker_for_vlan(self, vlan): """Set up BGP speaker for an individual VLAN if required. Args: vlan (vlan): VLAN associated with this speaker. Returns: ryu.services.protocols.bgp.bgpspeaker.BGPSpeaker: BGP speaker. """ handler = lambda x: self._bgp_route_handler(x, vlan) bgp_speaker = BGPSpeaker(as_number=vlan.bgp_as, router_id=vlan.bgp_routerid, bgp_server_port=vlan.bgp_port, best_path_change_handler=handler) for controller_ip in vlan.controller_ips: prefix = ipaddr.IPNetwork('/'.join( (str(controller_ip.ip), str(controller_ip.prefixlen)))) bgp_speaker.prefix_add(prefix=str(prefix), next_hop=controller_ip.ip) for route_table in (vlan.ipv4_routes, vlan.ipv6_routes): for ip_dst, ip_gw in route_table.iteritems(): bgp_speaker.prefix_add(prefix=str(ip_dst), next_hop=str(ip_gw)) bgp_speaker.neighbor_add(address=vlan.bgp_neighbor_address, remote_as=vlan.bgp_neighbor_as) return bgp_speaker
class SDNIP(app_manager.RyuApp): OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] _CONTEXTS = {'fwd': FwdUtil, 'hop_db': HopDB} """ 初始化方法 """ def __init__(self, *args, **kwargs): super(SDNIP, self).__init__(*args, **kwargs) self.fwd_util = kwargs['fwd'] self.hop_db = kwargs['hop_db'] self.cfg_mgr = SDNIPConfigManager() #获取SDN-IP配置信息 # 在Ryu上运行一个iBGPSpeaker self.bgp_speaker =\ BGPSpeaker(self.cfg_mgr.as_number, #AS号 str(self.cfg_mgr.router_id), #iBGP的router id bgp_server_port=self.cfg_mgr.listen_port, #监听BGP协议的端口号 best_path_change_handler=self.best_path_change_handler, #当路由信息变化时调用此方法 peer_down_handler=self.peer_down_handler, #BGP对等体下线 peer_up_handler=self.peer_up_handler) #BGP对等体上线 speaker_ids = self.cfg_mgr.get_all_speaker_id() # 建立iBGPSpeaker与SDN域内的BGPSpeaker的连接 for speaker_id in speaker_ids: self.bgp_speaker.neighbor_add(speaker_id, self.cfg_mgr.as_number, is_next_hop_self=True) # 启动一个线程,用于修复访问外部主机的数据路径 #hub.spawn(self.prefix_check_loop) """ 当路由信息变化时,调用此方法,建立访问外部主机的数据路径。 参数: ev: 路由更新时间,含有访问目的网络的下一跳地址信息。 建立的路径有: 1.穿过本地的流量到外部主机的路径(Transit Traffic ---> Internet) 2.本地主机访问外部主机的路径(Local Host ---> Internet) """ def best_path_change_handler(self, ev): self.logger.info('best path changed:') self.logger.info('remote_as: %d', ev.remote_as) self.logger.info('route_dist: %s', ev.route_dist) self.logger.info('prefix: %s', ev.prefix) self.logger.info('nexthop: %s', ev.nexthop) self.logger.info('label: %s', ev.label) self.logger.info('is_withdraw: %s', ev.is_withdraw) self.logger.info('') # 取网络前缀 prefix_nw = IPNetwork(ev.prefix) # 不处理本地网络更新 for internal_network in self.cfg_mgr.get_internal_networks(): int_nw = IPNetwork(internal_network) if int_nw == prefix_nw: self.logger.info('Internal network, ignored.') return if ev.is_withdraw: self.hop_db.remove_hop(ev.prefix) else: # 记录访问目的网络的下一跳地址信息 self.hop_db.add_hop(ev.prefix, ev.nexthop) """ 建立BGPSpeaker间的连接。 """ @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) def bgp_packet_in_handler(self, ev): msg = ev.msg dp = msg.datapath dpid = dp.id ofproto = dp.ofproto pkt = packet.Packet(msg.data) tcp_header = pkt.get_protocol(tcp.tcp) #只处理BGP数据包,tcp端口为179 if tcp_header is None or (tcp_header.src_port is not 179 and tcp_header.dst_port is not 179): return ipv4_header = pkt.get_protocol(ipv4.ipv4) src_ip = ipv4_header.src dst_ip = ipv4_header.dst self.logger.info("BGP from %s to %s", src_ip, dst_ip) # 获取源、目的主机信息 hosts = topo_api.get_all_host(self) src_host = None dst_host = None for host in hosts: if src_ip in host.ipv4: src_host = host elif dst_ip in host.ipv4: dst_host = host if src_host is None or dst_host is None: return # 建立BGPSpeaker间的数据路径 src_port = src_host.port dst_port = dst_host.port dst_mac = dst_host.mac to_dst_match = dp.ofproto_parser.OFPMatch(eth_dst=dst_mac, ipv4_dst=dst_ip, eth_type=2048) pre_actions = [dp.ofproto_parser.OFPActionSetField(eth_dst=dst_mac)] port_no = self.fwd_util.setup_shortest_path(src_port.dpid, dst_port.dpid, dst_port.port_no, to_dst_match, pre_actions) # 将首个数据包直接递交给目的主机,防止首包丢失 if port_no is None: return self.fwd_util.packet_out(dp, msg, port_no) """ 处理packet-in请求,建立到外部主机的单向数据路径。 """ @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) @packet_in_filter(RequiredTypeFilter, {'types': [ipv4.ipv4]}) def internal_host_route_handler(self, ev): msg = ev.msg dp = msg.datapath dpid = dp.id ofproto = dp.ofproto pkt = packet.Packet(msg.data) ipv4_header = pkt.get_protocol(ipv4.ipv4) src_ip = ipv4_header.src dst_ip = ipv4_header.dst #只处理目的不是本地的访问 if self.cfg_mgr.is_internal_host(dst_ip): return # 获取下一跳信息,若下一条信息不存在,不处理 nexthop_info = self.hop_db.get_nexthop_by_ip(dst_ip) if not nexthop_info: return nexthop_prefix = nexthop_info[0] nexthop = nexthop_info[1] nexthop_host = self.fwd_util.get_host(nexthop) if nexthop_host is None: return # 建立主机间的数据路径 host_match = \ dp.ofproto_parser.OFPMatch(ipv4_dst=(str(nexthop_prefix.ip), str(nexthop_prefix.netmask)), eth_type=2048) pre_actions = [ dp.ofproto_parser.OFPActionSetField(eth_dst=nexthop_host.mac) ] self.logger.info("daowaiwaiwai") self.fwd_util.setup_shortest_path(dpid, nexthop_host.port.dpid, nexthop_host.port.port_no, host_match, pre_actions) # 将首个数据包直接递交给目的主机,防止首包丢失 switch = topo_api.get_switch(self, nexthop_host.port.dpid)[0] self.fwd_util.packet_out(switch.dp, msg, nexthop_host.port.port_no) """ 处理packet-in请求,建立目的主机为本地主机的单向数据路径。 """ @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) @packet_in_filter(RequiredTypeFilter, {'types': [ipv4.ipv4]}) def internet_to_host_route_handler(self, ev): msg = ev.msg dp = msg.datapath dpid = dp.id ofproto = dp.ofproto pkt = packet.Packet(msg.data) ipv4_header = pkt.get_protocol(ipv4.ipv4) src_ip = ipv4_header.src dst_ip = ipv4_header.dst # 若目的主机不是本地主机,不处理 if not self.cfg_mgr.is_internal_host(dst_ip): return #获取目的主机信息,若目的主机不存在,不处理 dst_host = self.fwd_util.get_host(dst_ip) if dst_host is None: return #到本地主机的数据路径 host_match = \ dp.ofproto_parser.OFPMatch(ipv4_dst=dst_ip, eth_type=2048) pre_actions = [ dp.ofproto_parser.OFPActionSetField(eth_dst=dst_host.mac) ] self.logger.info("daoneineinei") self.fwd_util.setup_shortest_path(dpid, dst_host.port.dpid, dst_host.port.port_no, host_match, pre_actions) # 将首个数据包直接递交给目的主机,防止首包丢失 switch = topo_api.get_switch(self, dst_host.port.dpid)[0] self.fwd_util.packet_out(switch.dp, msg, dst_host.port.port_no) def peer_down_handler(self, remote_ip, remote_as): self.logger.info('peer down:') self.logger.info('remote_as: %d', remote_as) self.logger.info('remote ip: %s', remote_ip) self.logger.info('') def peer_up_handler(self, remote_ip, remote_as): self.logger.info('peer up:') self.logger.info('remote_as: %d', remote_as) self.logger.info('remote ip: %s', remote_ip) self.logger.info('') """ 修复访问外部主机的数据路径 """ def prefix_check_loop(self): while True: prefixs_to_install = self.hop_db.get_uninstalled_prefix_list() self.logger.debug("prefix to install: %s", str(prefixs_to_install)) for prefix in prefixs_to_install: prefix_nw = IPNetwork(prefix) for internal_network in self.cfg_mgr.get_internal_networks(): int_nw = IPNetwork(internal_network) if int_nw == prefix_nw: self.logger.info('Internal network, ignored.') continue nexthop = self.hop_db.get_nexthop(prefix) self.install_best_path(prefix, nexthop) hub.sleep(3) """ 根据下一跳地址建立到目的网络的路径[Traffic(dst_ip in prefix) ---> nexthot host] """ def install_best_path(self, prefix, nexthop): # 获取下一跳路由器信息 nexthop_host = self.fwd_util.get_host(nexthop) self.logger.debug("nexthop host: %s", str(nexthop_host)) if nexthop_host is None: return nexthop_port = nexthop_host.port nexthop_mac = nexthop_host.mac nexthop_dpid = nexthop_port.dpid nexthop_port_no = nexthop_port.port_no prefix_ip = str(IPNetwork(prefix).ip) prefix_mask = str(IPNetwork(prefix).netmask) ''' 在通往下一跳主机路径上的每个switch上下发流表: 匹配: 数据包类型为IPV4 目的ipv4网络为prefix 处理: 修改目的Mac为下一跳路由器Mac 将数据包转发往下一跳方向 ''' for dp in self.fwd_util.get_all_datapaths(): from_dpid = dp.id nexthop_match = \ dp.ofproto_parser.OFPMatch(ipv4_dst=(prefix_ip, prefix_mask), eth_type=2048) pre_actions = [ dp.ofproto_parser.OFPActionSetField(eth_dst=nexthop_mac) ] self.fwd_util.setup_shortest_path(from_dpid, nexthop_dpid, nexthop_port_no, nexthop_match, pre_actions) self.hop_db.install_prefix(prefix) #app_manager.require_app('ryu.app.gui_topology.gui_topology')
class SimpleBGPSpeaker(app_manager.RyuApp): def __init__(self, *args, **kwargs): super(SimpleBGPSpeaker, self).__init__(*args, **kwargs) self.bgp_q = hub.Queue() self.name = 'bgps' self.bgpPeerStatus = {} self.target_route_dist = None self.bgp_thread = hub.spawn(self.monitor_target_remotePrefix) def monitor_target_remotePrefix(self): previous_route_dist = None while True: if self.target_route_dist == None: pass elif self.target_route_dist == previous_route_dist: self.target_route_dist = None else: previous_route_dist = self.target_route_dist time.sleep(60) def dump_remote_best_path_change(self, event): remote_prefix = {} prefixInfo = IPNetwork(event.prefix) remote_prefix['remote_as'] = event.remote_as remote_prefix['route_dist'] = event.route_dist remote_prefix['prefix'] = str(prefixInfo.ip) remote_prefix['netmask'] = str(prefixInfo.netmask) remote_prefix['nexthop'] = event.nexthop remote_prefix['label'] = event.label remote_prefix['withdraw'] = event.is_withdraw LOG.debug("remote_prefix=%s"%remote_prefix) if self.filter_regist_remotePrefix(event.route_dist): self.bgp_q.put(remote_prefix) def filter_regist_remotePrefix(self, route_dist): if self.target_route_dist == None: result = True elif self.target_route_dist == route_dist: result = True else: result = False return result def detect_peer_down(self, remote_ip, remote_as): nowtime = datetime.datetime.now() LOG.info("%s: Peer down!![remote_ip: %s, remote_as: %s]"%(nowtime, remote_ip, remote_as)) self.bgpPeerStatus[nowtime] = BgpPeerStatus(nowtime, "Peer Down", self.myRouterId, remote_ip, remote_as) def detect_peer_up(self, remote_ip, remote_as): nowtime = datetime.datetime.now() LOG.info("%s: Peer up!![remote_ip: %s, remote_as: %s]"%(nowtime, remote_ip, remote_as)) self.bgpPeerStatus[nowtime] = BgpPeerStatus(nowtime, "Peer Up", self.myRouterId, remote_ip, remote_as) def start_bgpspeaker(self, asNum, routerId, label_start, label_end): self.myRouterId = routerId self.labelRange = tuple([label_start, label_end]) self.speaker = BGPSpeaker(as_number=asNum, router_id=routerId, best_path_change_handler=self.dump_remote_best_path_change, peer_down_handler=self.detect_peer_down, peer_up_handler=self.detect_peer_up, label_range=self.labelRange) def start_bmpclient(self, address, port): return self.speaker.bmp_server_add(address, port) def stop_bmpclient(self, address, port): return self.speaker.bmp_server_del(address, port) def add_neighbor(self, peerIp, asNumber, med, localPref, filterAsNum): self.speaker.neighbor_add(peerIp, asNumber, is_next_hop_self=True, enable_vpnv4=True, enable_enhanced_refresh=True, multi_exit_disc=med) if filterAsNum: as_path_filter = ASPathFilter(filterAsNum, policy=ASPathFilter.POLICY_TOP) if localPref: attribute_map = AttributeMap([as_path_filter], AttributeMap.ATTR_LOCAL_PREF, localPref) self.speaker.attribute_map_set(peerIp, [attribute_map], route_family='ipv4') def add_vrf(self, routeDist, importList, exportList): self.speaker.vrf_add(routeDist, importList, exportList) self.target_route_dist = routeDist def del_vrf(self, routeDist): self.speaker.vrf_del(routeDist) def add_prefix(self, ipaddress, netmask, nexthop=None, routeDist=None): prefix = IPNetwork(ipaddress + '/' + netmask) local_prefix = str(prefix.cidr) if routeDist: if nexthop: LOG.info("Send BGP UPDATE Message [%s, %s]"%(local_prefix, nexthop)) else: LOG.info("Send BGP UPDATE Message [%s]"%local_prefix) nexthop = "0.0.0.0" result_list = self.speaker.prefix_add(local_prefix, nexthop, routeDist) result = result_list[0] label = result['label'] return label else: if nexthop: LOG.info("Send BGP UPDATE Message [%s, %s]"%(local_prefix, nexthop)) self.speaker.prefix_add(local_prefix, nexthop) else: LOG.info("Send BGP UPDATE Message [%s]"%local_prefix) self.speaker.prefix_add(local_prefix) def remove_prefix(self, ipaddress, netmask, routeDist=None): prefix = IPNetwork(ipaddress + '/' + netmask) local_prefix = str(prefix.cidr) LOG.info("Send BGP UPDATE(withdraw) Message [%s]"%local_prefix) self.speaker.prefix_del(local_prefix, routeDist) def show_rib(self): family ="vpnv4" format = "cli" return self.speaker.rib_get(family, format) def show_vrfs(self): format = "cli" return self.speaker.vrfs_get(format) def show_neighbor(self, routetype, address): format = "cli" return self.speaker.neighbor_get(routetype, address, format) def update_neighbor_med(self, peerIp, med_value): conf_type = 'multi_exit_disc' conf_value = med_value LOG.info("Send BGP UPDATE Message for changing MED[%s]"%med_value) return self.speaker.neighbor_update(peerIp, conf_type, conf_value)
class SDNIP(app_manager.RyuApp): OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] _CONTEXTS = { 'fwd': Fwd, 'hop_db': HopDB } def __init__(self, *args, **kwargs): super(SDNIP, self).__init__(*args, **kwargs) self.fwd = kwargs['fwd'] self.hop_db = kwargs['hop_db'] self.cfg_mgr = SDNIPConfigManager() self.waiters = {} self.bgp_speaker =\ BGPSpeaker(self.cfg_mgr.as_number, str(self.cfg_mgr.router_id), bgp_server_port=self.cfg_mgr.listen_port, best_path_change_handler=self.best_path_change_handler, peer_down_handler=self.peer_down_handler, peer_up_handler=self.peer_up_handler) speaker_ids = self.cfg_mgr.get_all_speaker_id() for speaker_id in speaker_ids: self.bgp_speaker.neighbor_add(speaker_id, self.cfg_mgr.as_number, is_next_hop_self=True) hub.spawn(self.prefix_check_loop) if with_dk: dk_plugin.DynamicLoader.register_custom_cmd('sdn-ip:info', self.cmd_self_info) dk_plugin.DynamicLoader.register_custom_cmd('sdn-ip:routes', self.cmd_list_routes) dk_plugin.DynamicLoader.register_custom_cmd('sdn-ip:flows', self.cmd_get_flows) def best_path_change_handler(self, ev): self.logger.info('best path changed:') self.logger.info('remote_as: %d', ev.remote_as) self.logger.info('route_dist: %s', ev.route_dist) self.logger.info('prefix: %s', ev.prefix) self.logger.info('nexthop: %s', ev.nexthop) self.logger.info('label: %s', ev.label) self.logger.info('is_withdraw: %s', ev.is_withdraw) self.logger.info('') # Ignore internal network prefix_nw = IPNetwork(ev.prefix) for internal_network in self.cfg_mgr.get_internal_networks(): int_nw = IPNetwork(internal_network) if int_nw == prefix_nw: self.logger.info('Internal network, ignored.') return if ev.is_withdraw: self.hop_db.withdraw(ev.prefix) self.uninstall_best_path(ev.prefix, ev.nexthop) else: self.hop_db.add_hop(ev.prefix, ev.nexthop) self.install_best_path(ev.prefix, ev.nexthop) def peer_down_handler(self, remote_ip, remote_as): self.logger.info('peer down:') self.logger.info('remote_as: %d', remote_as) self.logger.info('remote ip: %s', remote_ip) self.logger.info('') def peer_up_handler(self, remote_ip, remote_as): self.logger.info('peer up:') self.logger.info('remote_as: %d', remote_as) self.logger.info('remote ip: %s', remote_ip) self.logger.info('') def get_host(self, ip): hosts = topo_api.get_all_host(self) for host in hosts: if ip in host.ipv4: return host return None def prefix_check_loop(self): while True: prefixs_to_install = self.hop_db.get_uninstalled_prefix_list() self.logger.debug("prefix to install: %s", str(prefixs_to_install)) for prefix in prefixs_to_install: nexthop = self.hop_db.get_nexthop(prefix) self.install_best_path(prefix, nexthop) hub.sleep(3) def install_best_path(self, prefix, nexthop): nexthop_host = self.get_host(nexthop) self.logger.debug("nexthop host: %s", str(nexthop_host)) if nexthop_host is None: self.logger.debug("Can't find nexthop host: %s", str(nexthop_host)) return nexthop_port = nexthop_host.port nexthop_mac = nexthop_host.mac nexthop_dpid = nexthop_port.dpid nexthop_port_no = nexthop_port.port_no prefix_ip = str(IPNetwork(prefix).ip) prefix_mask = str(IPNetwork(prefix).netmask) for dp in self.fwd.get_all_datapaths(): from_dpid = dp.id nexthop_match =\ dp.ofproto_parser.OFPMatch(ipv4_dst=(prefix_ip, prefix_mask), eth_type=2048) pre_actions = [ dp.ofproto_parser.OFPActionSetField(eth_dst=nexthop_mac) ] self.fwd.setup_shortest_path(from_dpid, nexthop_dpid, nexthop_port_no, nexthop_match, pre_actions) self.hop_db.install_prefix(prefix) def uninstall_best_path(self, prefix, nexthop): prefix_ip = str(IPNetwork(prefix).ip) prefix_mask = str(IPNetwork(prefix).netmask) # remove all flow rule for this prefix for dp in self.fwd.get_all_datapaths(): match =\ dp.ofproto_parser.OFPMatch(ipv4_dst=(prefix_ip, prefix_mask), eth_type=2048) flow_del = dp.ofproto_parser.OFPFlowMod(datapath=dp, command=OFPFC_DELETE, match=match) dp.send_msg(flow_del) def install_internal_host_path(self, ip): host = self.get_host(ip) if host is None: return for dp in self.fwd.get_all_datapaths(): from_dpid = dp.id host_match =\ dp.ofproto_parser.OFPMatch(ipv4_dst=ip, eth_type=2048) pre_actions = [ dp.ofproto_parser.OFPActionSetField(eth_dst=host.mac) ] self.fwd.setup_shortest_path(from_dpid, host.port.dpid, host.port.port_no, host_match, pre_actions) @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) @packet_in_filter(RequiredTypeFilter, {'types': [ipv4.ipv4]}) def internal_host_route_handler(self, ev): ''' Handle internal network host routing ''' msg = ev.msg dp = msg.datapath dpid = dp.id ofproto = dp.ofproto pkt = packet.Packet(msg.data) ipv4_header = pkt.get_protocol(ipv4.ipv4) src_ip = ipv4_header.src dst_ip = ipv4_header.dst if not self.cfg_mgr.is_internal_host(dst_ip): return self.install_internal_host_path(dst_ip) @set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER) def flow_status_reply_handler(self, ev): msg = ev.msg dp = msg.datapath if dp.id not in self.waiters: return if msg.xid not in self.waiters[dp.id]: return lock, msgs = self.waiters[dp.id][msg.xid] msgs.append(msg) flags = 0 flags = dp.ofproto.OFPMPF_REPLY_MORE if msg.flags & flags: return del self.waiters[dp.id][msg.xid] lock.set() # commands def cmd_self_info(self): information = "AS number : {}\n" + \ "Router ID: {}\n" + \ "BGP port: {}\n" information = information.format(self.cfg_mgr.as_number, str(self.cfg_mgr.router_id), self.cfg_mgr.listen_port) return information def cmd_list_routes(self): prefix_list = self.hop_db.get_all_prefixes() result = "{:<20}{:<17}{}\n".format("Prefix", "Next Hop", "Path installed") result = result + "=" * 40 + "\n" for prefix in prefix_list: result = result + "{:<20}".format(prefix) _next_hop = self.hop_db.hops.get(prefix) if _next_hop is None: _next_hop = "None" result = result + "{:<17}".format(_next_hop) result = result + str(self.hop_db.is_prefix_installed(prefix)) result = result + "\n" return result def cmd_get_flows(self): result = "" for dp in self.fwd.get_all_datapaths(): flows = ofctl_v1_3.get_flow_stats(dp, self.waiters, {}) result = result + "{:0>16}:\n".format(dp.id) result = result + "=" * 17 + "\n" for flow in flows: result = result + json.dumps(flow) + "\n" return result
class SDNIP(app_manager.RyuApp): OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] _CONTEXTS = {'fwd': Fwd, 'hop_db': HopDB} def __init__(self, *args, **kwargs): super(SDNIP, self).__init__(*args, **kwargs) self.fwd = kwargs['fwd'] self.hop_db = kwargs['hop_db'] self.cfg_mgr = SDNIPConfigManager() self.waiters = {} self.bgp_speaker =\ BGPSpeaker(self.cfg_mgr.as_number, str(self.cfg_mgr.router_id), bgp_server_port=self.cfg_mgr.listen_port, best_path_change_handler=self.best_path_change_handler, peer_down_handler=self.peer_down_handler, peer_up_handler=self.peer_up_handler) speaker_ids = self.cfg_mgr.get_all_speaker_id() for speaker_id in speaker_ids: self.bgp_speaker.neighbor_add(speaker_id, self.cfg_mgr.as_number, is_next_hop_self=True) hub.spawn(self.prefix_check_loop) if with_dk: dk_plugin.DynamicLoader.register_custom_cmd( 'sdn-ip:info', self.cmd_self_info) dk_plugin.DynamicLoader.register_custom_cmd( 'sdn-ip:routes', self.cmd_list_routes) dk_plugin.DynamicLoader.register_custom_cmd( 'sdn-ip:flows', self.cmd_get_flows) def best_path_change_handler(self, ev): self.logger.info('best path changed:') self.logger.info('remote_as: %d', ev.remote_as) self.logger.info('route_dist: %s', ev.route_dist) self.logger.info('prefix: %s', ev.prefix) self.logger.info('nexthop: %s', ev.nexthop) self.logger.info('label: %s', ev.label) self.logger.info('is_withdraw: %s', ev.is_withdraw) self.logger.info('') # Ignore internal network prefix_nw = IPNetwork(ev.prefix) for internal_network in self.cfg_mgr.get_internal_networks(): int_nw = IPNetwork(internal_network) if int_nw == prefix_nw: self.logger.info('Internal network, ignored.') return if ev.is_withdraw: self.hop_db.withdraw(ev.prefix) self.uninstall_best_path(ev.prefix, ev.nexthop) else: self.hop_db.add_hop(ev.prefix, ev.nexthop) self.install_best_path(ev.prefix, ev.nexthop) def peer_down_handler(self, remote_ip, remote_as): self.logger.info('peer down:') self.logger.info('remote_as: %d', remote_as) self.logger.info('remote ip: %s', remote_ip) self.logger.info('') def peer_up_handler(self, remote_ip, remote_as): self.logger.info('peer up:') self.logger.info('remote_as: %d', remote_as) self.logger.info('remote ip: %s', remote_ip) self.logger.info('') def get_host(self, ip): hosts = topo_api.get_all_host(self) for host in hosts: if ip in host.ipv4: return host return None def prefix_check_loop(self): while True: prefixs_to_install = self.hop_db.get_uninstalled_prefix_list() self.logger.debug("prefix to install: %s", str(prefixs_to_install)) for prefix in prefixs_to_install: nexthop = self.hop_db.get_nexthop(prefix) self.install_best_path(prefix, nexthop) hub.sleep(3) def install_best_path(self, prefix, nexthop): nexthop_host = self.get_host(nexthop) self.logger.debug("nexthop host: %s", str(nexthop_host)) if nexthop_host is None: self.logger.debug("Can't find nexthop host: %s", str(nexthop_host)) return nexthop_port = nexthop_host.port nexthop_mac = nexthop_host.mac nexthop_dpid = nexthop_port.dpid nexthop_port_no = nexthop_port.port_no prefix_ip = str(IPNetwork(prefix).ip) prefix_mask = str(IPNetwork(prefix).netmask) for dp in self.fwd.get_all_datapaths(): from_dpid = dp.id nexthop_match =\ dp.ofproto_parser.OFPMatch(ipv4_dst=(prefix_ip, prefix_mask), eth_type=2048) pre_actions = [ dp.ofproto_parser.OFPActionSetField(eth_dst=nexthop_mac) ] self.fwd.setup_shortest_path(from_dpid, nexthop_dpid, nexthop_port_no, nexthop_match, pre_actions) self.hop_db.install_prefix(prefix) def uninstall_best_path(self, prefix, nexthop): prefix_ip = str(IPNetwork(prefix).ip) prefix_mask = str(IPNetwork(prefix).netmask) # remove all flow rule for this prefix for dp in self.fwd.get_all_datapaths(): match =\ dp.ofproto_parser.OFPMatch(ipv4_dst=(prefix_ip, prefix_mask), eth_type=2048) flow_del = dp.ofproto_parser.OFPFlowMod(datapath=dp, command=OFPFC_DELETE, match=match) dp.send_msg(flow_del) def install_internal_host_path(self, ip): host = self.get_host(ip) if host is None: return for dp in self.fwd.get_all_datapaths(): from_dpid = dp.id host_match =\ dp.ofproto_parser.OFPMatch(ipv4_dst=ip, eth_type=2048) pre_actions = [ dp.ofproto_parser.OFPActionSetField(eth_dst=host.mac) ] self.fwd.setup_shortest_path(from_dpid, host.port.dpid, host.port.port_no, host_match, pre_actions) @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) @packet_in_filter(RequiredTypeFilter, {'types': [ipv4.ipv4]}) def internal_host_route_handler(self, ev): ''' Handle internal network host routing ''' msg = ev.msg dp = msg.datapath dpid = dp.id ofproto = dp.ofproto pkt = packet.Packet(msg.data) ipv4_header = pkt.get_protocol(ipv4.ipv4) src_ip = ipv4_header.src dst_ip = ipv4_header.dst if not self.cfg_mgr.is_internal_host(dst_ip): return self.install_internal_host_path(dst_ip) @set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER) def flow_status_reply_handler(self, ev): msg = ev.msg dp = msg.datapath if dp.id not in self.waiters: return if msg.xid not in self.waiters[dp.id]: return lock, msgs = self.waiters[dp.id][msg.xid] msgs.append(msg) flags = 0 flags = dp.ofproto.OFPMPF_REPLY_MORE if msg.flags & flags: return del self.waiters[dp.id][msg.xid] lock.set() # commands def cmd_self_info(self): information = "AS number : {}\n" + \ "Router ID: {}\n" + \ "BGP port: {}\n" information = information.format(self.cfg_mgr.as_number, str(self.cfg_mgr.router_id), self.cfg_mgr.listen_port) return information def cmd_list_routes(self): prefix_list = self.hop_db.get_all_prefixes() result = "{:<20}{:<17}{}\n".format("Prefix", "Next Hop", "Path installed") result = result + "=" * 40 + "\n" for prefix in prefix_list: result = result + "{:<20}".format(prefix) _next_hop = self.hop_db.hops.get(prefix) if _next_hop is None: _next_hop = "None" result = result + "{:<17}".format(_next_hop) result = result + str(self.hop_db.is_prefix_installed(prefix)) result = result + "\n" return result def cmd_get_flows(self): result = "" for dp in self.fwd.get_all_datapaths(): flows = ofctl_v1_3.get_flow_stats(dp, self.waiters, {}) result = result + "{:0>16}:\n".format(dp.id) result = result + "=" * 17 + "\n" for flow in flows: result = result + json.dumps(flow) + "\n" return result
class RyuBGPSpeaker(RyuApp): """ Base application for implementing BGP applications. This application will notifies - ``EventBestPathChanged`` - ``EventPeerDown`` - ``EventPeerUp`` to other BGP applications. To catch these events, specify ``@set_ev_cls()`` decorator to the event handlers in the Ryu applications. Example:: ... from ryu.base import app_manager from ryu.controller.handler import set_ev_cls from ryu.services.protocols.bgp import application as bgp_application ... class MyBGPApp(app_manager.RyuApp): _CONTEXTS = { 'ryubgpspeaker': bgp_application.RyuBGPSpeaker, } ... @set_ev_cls(bgp_application.EventBestPathChanged) def _best_patch_changed_handler(self, ev): self.logger.info( 'Best path changed: is_withdraw=%s, path=%s', ev.is_withdraw, ev.path) """ _EVENTS = [ EventBestPathChanged, EventPeerDown, EventPeerUp, ] def __init__(self, *args, **kwargs): super(RyuBGPSpeaker, self).__init__(*args, **kwargs) self.config_file = CONF.config_file # BGPSpeaker instance (not instantiated yet) self.speaker = None def start(self): super(RyuBGPSpeaker, self).start() # If configuration file was provided and loaded successfully, we start # BGPSpeaker using the given settings. # If no configuration file is provided or if any minimum required # setting is missing, BGPSpeaker will not be started. if self.config_file: LOG.debug('Loading config file %s...', self.config_file) settings = load_config(self.config_file) # Configure logging settings, if available. if hasattr(settings, 'LOGGING'): # Not implemented yet. LOG.debug('Loading LOGGING settings... (NOT implemented yet)') # from logging.config import dictConfig # logging_settings = dictConfig(settings.LOGGING) # Configure BGP settings, if available. if hasattr(settings, 'BGP'): LOG.debug('Loading BGP settings...') self._start_speaker(settings.BGP) # Configure SSH settings, if available. if hasattr(settings, 'SSH'): LOG.debug('Loading SSH settings...') # Note: paramiko used in bgp.operator.ssh is the optional # requirements, imports bgp.operator.ssh here. from ryu.services.protocols.bgp.operator import ssh hub.spawn(ssh.SSH_CLI_CONTROLLER.start, **settings.SSH) # Start RPC server with the given RPC settings. rpc_settings = { NC_RPC_BIND_PORT: CONF.rpc_port, NC_RPC_BIND_IP: validate_rpc_host(CONF.rpc_host), } return hub.spawn(NET_CONTROLLER.start, **rpc_settings) def _start_speaker(self, settings): """ Starts BGPSpeaker using the given settings. """ # Settings for starting BGPSpeaker bgp_settings = {} # Get required settings. try: bgp_settings['as_number'] = settings.get(LOCAL_AS) bgp_settings['router_id'] = settings.get(ROUTER_ID) except KeyError as e: raise ApplicationException( desc='Required BGP configuration missing: %s' % e) # Set event notify handlers if no corresponding handler specified. bgp_settings['best_path_change_handler'] = settings.get( 'best_path_change_handler', self._notify_best_path_changed_event) bgp_settings['peer_down_handler'] = settings.get( 'peer_down_handler', self._notify_peer_down_event) bgp_settings['peer_up_handler'] = settings.get( 'peer_up_handler', self._notify_peer_up_event) # Get optional settings. bgp_settings[BGP_SERVER_PORT] = settings.get(BGP_SERVER_PORT, DEFAULT_BGP_SERVER_PORT) bgp_settings[REFRESH_STALEPATH_TIME] = settings.get( REFRESH_STALEPATH_TIME, DEFAULT_REFRESH_STALEPATH_TIME) bgp_settings[REFRESH_MAX_EOR_TIME] = settings.get( REFRESH_MAX_EOR_TIME, DEFAULT_REFRESH_MAX_EOR_TIME) bgp_settings[LABEL_RANGE] = settings.get(LABEL_RANGE, DEFAULT_LABEL_RANGE) bgp_settings['allow_local_as_in_count'] = settings.get( 'allow_local_as_in_count', 0) # Create BGPSpeaker instance. LOG.debug('Starting BGPSpeaker...') self.speaker = BGPSpeaker(**bgp_settings) # Add neighbors. LOG.debug('Adding neighbors...') self._add_neighbors(settings.get('neighbors', [])) # Add VRFs. LOG.debug('Adding VRFs...') self._add_vrfs(settings.get('vrfs', [])) # Add Networks LOG.debug('Adding routes...') self._add_routes(settings.get('routes', [])) def _notify_best_path_changed_event(self, ev): ev = EventBestPathChanged(ev.path, ev.is_withdraw) self.send_event_to_observers(ev) def _notify_peer_down_event(self, remote_ip, remote_as): ev = EventPeerDown(remote_ip, remote_as) self.send_event_to_observers(ev) def _notify_peer_up_event(self, remote_ip, remote_as): ev = EventPeerUp(remote_ip, remote_as) self.send_event_to_observers(ev) def _add_neighbors(self, settings): """ Add BGP neighbors from the given settings. All valid neighbors are loaded. Miss-configured neighbors are ignored and errors are logged. """ for neighbor_settings in settings: LOG.debug('Adding neighbor settings: %s', neighbor_settings) try: self.speaker.neighbor_add(**neighbor_settings) except RuntimeConfigError as e: LOG.exception(e) def _add_vrfs(self, settings): """ Add BGP VRFs from the given settings. All valid VRFs are loaded. Miss-configured VRFs are ignored and errors are logged. """ for vrf_settings in settings: LOG.debug('Adding VRF settings: %s', vrf_settings) try: self.speaker.vrf_add(**vrf_settings) except RuntimeConfigError as e: LOG.exception(e) def _add_routes(self, settings): """ Add BGP routes from given settings. All valid routes are loaded. Miss-configured routes are ignored and errors are logged. """ for route_settings in settings: if 'prefix' in route_settings: prefix_add = self.speaker.prefix_add elif 'route_type' in route_settings: prefix_add = self.speaker.evpn_prefix_add else: LOG.debug('Skip invalid route settings: %s', route_settings) continue LOG.debug('Adding route settings: %s', route_settings) try: prefix_add(**route_settings) except RuntimeConfigError as e: LOG.exception(e)
log.addHandler(logging.StreamHandler(sys.stderr)) from ryu.services.protocols.bgp.bgpspeaker import BGPSpeaker def dump_remote_best_path_change(event): print 'the best path changed:', event.remote_as, event.prefix, event.nexthop, event.is_withdraw def detect_peer_down(remote_ip, remote_as): print 'Peer down:', remote_ip, remote_as if __name__ == "__main__": speaker = BGPSpeaker(as_number=20, router_id='1.1.1.1', best_path_change_handler=dump_remote_best_path_change, peer_down_handler=detect_peer_down) speaker.neighbor_add("10.108.90.1", 10) speaker.neighbor_add("10.108.91.1", 30) #speaker.neighbor_add("10.108.92.1",40) #print speaker.rib_get() #speaker.neighbor_add("10.108.91.1",30) #uncomment the below line if the speaker needs to talk with a bmp server #speaker.bmp_server_add('192.168.177.2',11019) count = 1 while True: eventlet.sleep(10) prefix = '10.108.' + str(count) + '.0/24'
class SDNIP(app_manager.RyuApp): OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] _CONTEXTS = { 'fwd': Fwd, 'hop_db': HopDB } def __init__(self, *args, **kwargs): super(SDNIP, self).__init__(*args, **kwargs) self.fwd = kwargs['fwd'] self.hop_db = kwargs['hop_db'] self.cfg_mgr = SDNIPConfigManager('config.json') self.bgp_speaker =\ BGPSpeaker(self.cfg_mgr.as_number, self.cfg_mgr.router_id, bgp_server_port=self.cfg_mgr.listen_port, best_path_change_handler=self.best_path_change_handler, peer_down_handler=self.peer_down_handler, peer_up_handler=self.peer_up_handler) speaker_ids = self.cfg_mgr.get_all_speaker_id() for speaker_id in speaker_ids: self.bgp_speaker.neighbor_add(speaker_id, self.cfg_mgr.as_number, is_next_hop_self=True) hub.spawn(self.prefix_check_loop) def best_path_change_handler(self, ev): self.logger.info('best path changed:') self.logger.info('remote_as: %d', ev.remote_as) self.logger.info('route_dist: %s', ev.route_dist) self.logger.info('prefix: %s', ev.prefix) self.logger.info('nexthop: %s', ev.nexthop) self.logger.info('label: %s', ev.label) self.logger.info('is_withdraw: %s', ev.is_withdraw) self.logger.info('') self.hop_db.add_hop(ev.prefix, ev.nexthop) self.install_best_path(ev.prefix, ev.nexthop) def peer_down_handler(self, remote_ip, remote_as): self.logger.info('peer down:') self.logger.info('remote_as: %d', remote_as) self.logger.info('remote ip: %s', remote_ip) self.logger.info('') def peer_up_handler(self, remote_ip, remote_as): self.logger.info('peer up:') self.logger.info('remote_as: %d', remote_as) self.logger.info('remote ip: %s', remote_ip) self.logger.info('') def get_nexthop_host(self, ip): hosts = topo_api.get_all_host(self) for host in hosts: if ip in host.ipv4: return host return None def prefix_check_loop(self): while True: prefixs_to_install = self.hop_db.get_uninstalled_prefix_list() self.logger.debug("prefix to install: %s", str(prefixs_to_install)) for prefix in prefixs_to_install: nexthop = self.hop_db.get_nexthop(prefix) self.install_best_path(prefix, nexthop) hub.sleep(3) def install_best_path(self, prefix, nexthop): nexthop_host = self.get_nexthop_host(nexthop) self.logger.debug("nexthop host: %s", str(nexthop_host)) if nexthop_host is None: return nexthop_port = nexthop_host.port nexthop_mac = nexthop_host.mac nexthop_dpid = nexthop_port.dpid nexthop_port_no = nexthop_port.port_no prefix_ip = str(IPNetwork(prefix).ip) prefix_mask = str(IPNetwork(prefix).netmask) for dp in self.fwd.get_all_datapaths(): from_dpid = dp.id nexthop_match =\ dp.ofproto_parser.OFPMatch(ipv4_dst=(prefix_ip, prefix_mask), eth_type=2048) pre_actions = [ dp.ofproto_parser.OFPActionSetField(eth_dst=nexthop_mac) ] self.fwd.setup_shortest_path(from_dpid, nexthop_dpid, nexthop_port_no, nexthop_match, pre_actions) self.hop_db.install_prefix(prefix)
class RyuBGPSpeaker(RyuApp): def __init__(self, *args, **kwargs): super(RyuBGPSpeaker, self).__init__(*args, **kwargs) self.config_file = CONF.config_file # BGPSpeaker instance (not instantiated yet) self.speaker = None def start(self): super(RyuBGPSpeaker, self).start() # If configuration file was provided and loaded successfully, we start # BGPSpeaker using the given settings. # If no configuration file is provided or if any minimum required # setting is missing, BGPSpeaker will not be started. if self.config_file: LOG.debug('Loading config file %s...', self.config_file) settings = load_config(self.config_file) # Configure logging settings, if available. if hasattr(settings, 'LOGGING'): # Not implemented yet. LOG.debug('Loading LOGGING settings... (NOT implemented yet)') # from logging.config import dictConfig # logging_settings = dictConfig(settings.LOGGING) # Configure BGP settings, if available. if hasattr(settings, 'BGP'): LOG.debug('Loading BGP settings...') self._start_speaker(settings.BGP) # Configure SSH settings, if available. if hasattr(settings, 'SSH'): LOG.debug('Loading SSH settings...') hub.spawn(SSH_CLI_CONTROLLER.start, **settings.SSH) # Start RPC server with the given RPC settings. rpc_settings = { NC_RPC_BIND_PORT: CONF.rpc_port, NC_RPC_BIND_IP: validate_rpc_host(CONF.rpc_host), } return hub.spawn(NET_CONTROLLER.start, **rpc_settings) def _start_speaker(self, settings): """ Starts BGPSpeaker using the given settings. """ # Settings for starting BGPSpeaker bgp_settings = {} # Get required settings. try: bgp_settings['as_number'] = settings.get(LOCAL_AS) bgp_settings['router_id'] = settings.get(ROUTER_ID) except KeyError as e: raise ApplicationException( desc='Required BGP configuration missing: %s' % e) # Get optional settings. bgp_settings[BGP_SERVER_PORT] = settings.get( BGP_SERVER_PORT, DEFAULT_BGP_SERVER_PORT) bgp_settings[REFRESH_STALEPATH_TIME] = settings.get( REFRESH_STALEPATH_TIME, DEFAULT_REFRESH_STALEPATH_TIME) bgp_settings[REFRESH_MAX_EOR_TIME] = settings.get( REFRESH_MAX_EOR_TIME, DEFAULT_REFRESH_MAX_EOR_TIME) bgp_settings[LABEL_RANGE] = settings.get( LABEL_RANGE, DEFAULT_LABEL_RANGE) # Create BGPSpeaker instance. LOG.debug('Starting BGPSpeaker...') self.speaker = BGPSpeaker(**bgp_settings) # Add neighbors. LOG.debug('Adding neighbors...') self._add_neighbors(settings.get('neighbors', [])) # Add VRFs. LOG.debug('Adding VRFs...') self._add_vrfs(settings.get('vrfs', [])) # Add Networks LOG.debug('Adding routes...') self._add_routes(settings.get('routes', [])) def _add_neighbors(self, settings): """ Add BGP neighbors from the given settings. All valid neighbors are loaded. Miss-configured neighbors are ignored and errors are logged. """ for neighbor_settings in settings: LOG.debug('Adding neighbor settings: %s', neighbor_settings) try: self.speaker.neighbor_add(**neighbor_settings) except RuntimeConfigError as e: LOG.exception(e) def _add_vrfs(self, settings): """ Add BGP VRFs from the given settings. All valid VRFs are loaded. Miss-configured VRFs are ignored and errors are logged. """ for vrf_settings in settings: LOG.debug('Adding VRF settings: %s', vrf_settings) try: self.speaker.vrf_add(**vrf_settings) except RuntimeConfigError as e: LOG.exception(e) def _add_routes(self, settings): """ Add BGP routes from given settings. All valid routes are loaded. Miss-configured routes are ignored and errors are logged. """ for route_settings in settings: if 'prefix' in route_settings: prefix_add = self.speaker.prefix_add elif 'route_type' in route_settings: prefix_add = self.speaker.evpn_prefix_add else: LOG.debug('Skip invalid route settings: %s', route_settings) continue LOG.debug('Adding route settings: %s', route_settings) try: prefix_add(**route_settings) except RuntimeConfigError as e: LOG.exception(e)
event.nexthop, event.is_withdraw def detect_peer_down(remote_ip, remote_as): print 'Peer down:', remote_ip, remote_as SSH = { 'ssh_port': 4990, 'ssh_host': 'localhost', 'ssh_host_key': '/etc/ssh_host_rsa_key', 'ssh_username': '******', 'ssh_password': '******', } if __name__ == "__main__": speaker = BGPSpeaker(as_number=65005, router_id='172.16.1.174', best_path_change_handler=dump_remote_best_path_change, peer_down_handler=detect_peer_down) speaker.neighbor_add('172.16.1.175', 65003) count = 0 while True: eventlet.sleep(5) prefix = '192.168.' + str(count) + '.0/24' print "add a new prefix", prefix speaker.prefix_add(prefix) count += 1 print("Neighbors: ", speaker.neighbors_get()) print("Routes: ", speaker.rib_get())
from ryu.services.protocols.bgp.bgpspeaker import BGPSpeaker ''' sudo /usr/bin/python2.7 "/home/walber/Dropbox/SDN - Controllers/ryu/ryu/app/COOL/topology_management/bgp_tester.py" ''' def dump_remote_best_path_change(event): print 'the best path changed:', event.remote_as, event.prefix,\ event.nexthop, event.is_withdraw def detect_peer_down(remote_ip, remote_as): print 'Peer down:', remote_ip, remote_as if __name__ == "__main__": speaker = BGPSpeaker(as_number=65001, router_id='192.168.25.7', best_path_change_handler=dump_remote_best_path_change, peer_down_handler=detect_peer_down) speaker.neighbor_add('192.168.25.2', 65002) # uncomment the below line if the speaker needs to talk with a bmp server. # speaker.bmp_server_add('192.168.177.2', 11019) count = 1 while True: print "Oi" eventlet.sleep(30) prefix = '10.20.' + str(count) + '.0/24' print "add a new prefix", prefix speaker.prefix_add(prefix) count += 1 if count == 4: speaker.shutdown()
class RyuBGPSpeaker(RyuApp): """ Base application for implementing BGP applications. """ _EVENTS = [ EventBestPathChanged, EventAdjRibInChanged, EventPeerDown, EventPeerUp, ] def __init__(self, *args, **kwargs): super(RyuBGPSpeaker, self).__init__(*args, **kwargs) self.config_file = CONF.config_file # BGPSpeaker instance (not instantiated yet) self.speaker = None def start(self): super(RyuBGPSpeaker, self).start() # If configuration file was provided and loaded successfully, we start # BGPSpeaker using the given settings. # If no configuration file is provided or if any minimum required # setting is missing, BGPSpeaker will not be started. if self.config_file: LOG.debug('Loading config file %s...', self.config_file) settings = load_config(self.config_file) # Configure logging settings, if available. if hasattr(settings, 'LOGGING'): # Not implemented yet. LOG.debug('Loading LOGGING settings... (NOT implemented yet)') # from logging.config import dictConfig # logging_settings = dictConfig(settings.LOGGING) # Configure BGP settings, if available. if hasattr(settings, 'BGP'): LOG.debug('Loading BGP settings...') self._start_speaker(settings.BGP) # Configure SSH settings, if available. if hasattr(settings, 'SSH'): LOG.debug('Loading SSH settings...') # Note: paramiko used in bgp.operator.ssh is the optional # requirements, imports bgp.operator.ssh here. from ryu.services.protocols.bgp.operator import ssh hub.spawn(ssh.SSH_CLI_CONTROLLER.start, **settings.SSH) # Start RPC server with the given RPC settings. rpc_settings = { NC_RPC_BIND_PORT: CONF.rpc_port, NC_RPC_BIND_IP: validate_rpc_host(CONF.rpc_host), } return hub.spawn(NET_CONTROLLER.start, **rpc_settings) def _start_speaker(self, settings): """ Starts BGPSpeaker using the given settings. """ # Check required settings. _required_settings = ( LOCAL_AS, ROUTER_ID, ) for required in _required_settings: if required not in settings: raise ApplicationException( desc='Required BGP configuration missing: %s' % required) # Set event notify handlers if no corresponding handler specified. settings.setdefault('best_path_change_handler', self._notify_best_path_changed_event) settings.setdefault('adj_rib_in_change_handler', self._notify_adj_rib_in_changed_event) settings.setdefault('peer_down_handler', self._notify_peer_down_event) settings.setdefault('peer_up_handler', self._notify_peer_up_event) # Pop settings other than creating BGPSpeaker instance. neighbors_settings = settings.pop('neighbors', []) vrfs_settings = settings.pop('vrfs', []) routes_settings = settings.pop('routes', []) # Create BGPSpeaker instance. LOG.debug('Starting BGPSpeaker...') settings.setdefault('as_number', settings.pop(LOCAL_AS)) self.speaker = BGPSpeaker(**settings) # Add neighbors. LOG.debug('Adding neighbors...') self._add_neighbors(neighbors_settings) # Add VRFs. LOG.debug('Adding VRFs...') self._add_vrfs(vrfs_settings) # Add routes LOG.debug('Adding routes...') self._add_routes(routes_settings) def _notify_best_path_changed_event(self, ev): ev = EventBestPathChanged(ev.path, ev.is_withdraw) self.send_event_to_observers(ev) def _notify_adj_rib_in_changed_event(self, ev, peer_ip, peer_as): ev = EventAdjRibInChanged(ev.path, ev.is_withdraw, peer_ip, peer_as) self.send_event_to_observers(ev) def _notify_peer_down_event(self, remote_ip, remote_as): ev = EventPeerDown(remote_ip, remote_as) self.send_event_to_observers(ev) def _notify_peer_up_event(self, remote_ip, remote_as): ev = EventPeerUp(remote_ip, remote_as) self.send_event_to_observers(ev) def _add_neighbors(self, settings): """ Add BGP neighbors from the given settings. All valid neighbors are loaded. Miss-configured neighbors are ignored and errors are logged. """ for neighbor_settings in settings: LOG.debug('Adding neighbor settings: %s', neighbor_settings) try: self.speaker.neighbor_add(**neighbor_settings) except RuntimeConfigError as e: LOG.exception(e) def _add_vrfs(self, settings): """ Add BGP VRFs from the given settings. All valid VRFs are loaded. Miss-configured VRFs are ignored and errors are logged. """ for vrf_settings in settings: LOG.debug('Adding VRF settings: %s', vrf_settings) try: self.speaker.vrf_add(**vrf_settings) except RuntimeConfigError as e: LOG.exception(e) def _add_routes(self, settings): """ Add BGP routes from given settings. All valid routes are loaded. Miss-configured routes are ignored and errors are logged. """ for route_settings in settings: if 'prefix' in route_settings: prefix_add = self.speaker.prefix_add elif 'route_type' in route_settings: prefix_add = self.speaker.evpn_prefix_add elif 'flowspec_family' in route_settings: prefix_add = self.speaker.flowspec_prefix_add else: LOG.debug('Skip invalid route settings: %s', route_settings) continue LOG.debug('Adding route settings: %s', route_settings) try: prefix_add(**route_settings) except RuntimeConfigError as e: LOG.exception(e)
import sys log = logging.getLogger() log.addHandler(logging.StreamHandler(sys.stderr)) from ryu.services.protocols.bgp.bgpspeaker import BGPSpeaker def dump_remote_best_path_change(event): print 'the best path changed:',event.remote_as,event.prefix,event.nexthop,event.is_withdraw def detect_peer_down(remote_ip,remote_as): print 'Peer down:',remote_ip,remote_as if __name__=="__main__": speaker = BGPSpeaker(as_number=20,router_id='1.1.1.1', best_path_change_handler=dump_remote_best_path_change, peer_down_handler=detect_peer_down ) speaker.neighbor_add("10.108.90.1",10) speaker.neighbor_add("10.108.91.1",30) #speaker.neighbor_add("10.108.92.1",40) #print speaker.rib_get() #speaker.neighbor_add("10.108.91.1",30) #uncomment the below line if the speaker needs to talk with a bmp server #speaker.bmp_server_add('192.168.177.2',11019)
import eventlet import json eventlet.monkey_patch() import logging import sys log = logging.getLogger() log.addHandler(logging.StreamHandler(sys.stderr)) log.setLevel(logging.DEBUG) from ryu.services.protocols.bgp.bgpspeaker import BGPSpeaker if __name__ == "__main__": speaker = BGPSpeaker(as_number=10, router_id='10.0.0.1', ssh_console=True) speaker.neighbor_add('10.9.10.1', 9) speaker.neighbor_add('10.5.10.1', 5) prefix = '10.0.0.0/8' print "add a new prefix", prefix speaker.prefix_add(prefix) while True: eventlet.sleep(5)
class BGP_Speaker(app_manager.RyuApp): OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] def __init__(self, hosts=None, networks=None, *args, **kwargs): super(BGP_Speaker, self).__init__(*args, **kwargs) self.networks = networks self.hosts = hosts # Configuring AS 65501: self.as_number = 65001 #self.remote_as = 65501 self.router_id = '192.168.25.7' self.router_next_hop = "10.0.254.254" # The source IP of the BGP self.listen_port = 179 self.bgp_speaker = \ BGPSpeaker(self.as_number, self.router_id, bgp_server_port=self.listen_port, best_path_change_handler=self.best_path_change_handler, peer_down_handler=self.peer_down_handler, peer_up_handler=self.peer_up_handler) # print "<<<<<<<<<",self.bgp_speaker # speaker = BGPSpeaker(as_number=65001, router_id='192.168.25.7', # best_path_change_handler=dump_remote_best_path_change, # peer_down_handler=detect_peer_down) self.neighbor1 = Neighbor(ip="192.168.25.2", asn=65002, next_hop="10.0.1.254", border_switch=2, sw_port=1, controller_ip="10.0.1.254") #self.neighbor2 = Neighbor(ip="10.0.2.2", asn=65002,next_hop="10.0.1.254", border_switch=2, sw_port=2, controller_ip="10.0.1.254") # self.neighbor = {"10.0.1.1": {'asn': 65001,'switch':2, 'port': 1,'controller_ip':"10.0.1.254"}, # "10.0.2.2": {'asn': 65002,'switch':2, 'port': 2,'controller_ip':"10.0.2.254"}, # } self.neighbors = [self.neighbor1] #,self.neighbor2] #self.local_networks = {"192.168.2.0/24":{'controller_ip':"192.168.2.254"}} self.prefix_add(prefix="192.168.2.0/24", next_hop="192.168.2.254") # Adding neighbors: #TODO: Verify the option of next_hop for neighbor in self.neighbors: # self.bgp_speaker.neighbor_add(address=neighbor, remote_as=self.neighbor[neighbor]['asn'], # next_hop=self.router_next_hop, # is_next_hop_self=True) self.neighbors_add(neighbor) # for network in self.local_networks: # # Adding prefixes: # self.bgp_speaker.prefix_add(network, self.neighbor[neighbor]['controller_ip']) # next_hop (how to reach the network) # #self.bgp_speaker.prefix_add("192.168.2.0/24", "10.0.2.254") # next_hop (how to reach the network) # # self.bgp_speaker.prefix_add("10.0.0.0/24", "10.0.1.1") # "10.0.3.1": 'fe:00:00:00:00:03'} # self.arp_controller = '00:00:00:00:00:fe' # self.monitor_thread = hub.spawn(self._monitor) # self.best_paths ={} self.prefix_learned = {} # "198.51.100.0/24",'10.0.1.0/24'} self.is_load_balancer_active = False self.load_balancer = {} #self.monitor_thread = hub.spawn(self.stand_alone) print "BGP Speaker started! ;)" self.stand_alone() def stand_alone(self): #print "Oi" while True: eventlet.sleep(3) """ This method returns the BGP adj-RIB-in/adj-RIB-out information in a json format.""" #print "Sent routes:",self.bgp_speaker.neighbor_get(route_type='sent-routes', address=self.neighbor1.get_IP(), # format='json') #print '\nReceived-routes:',self.bgp_speaker.neighbor_get(route_type='received-routes',address=self.neighbor1.get_IP(),format='json') self.prefix_add("10.0.0.0/24", "10.0.0.1") #print self.get_cool_rib(),"\n\n\n" def prefix_add(self, prefix, next_hop): '''``prefix`` must be the string representation of an IP network (e.g., 10.1.1.0/24). ``next_hop`` specifies the next hop address for this prefix. This parameter is necessary for only VPNv4 and VPNv6 address families.''' self.bgp_speaker.prefix_add(prefix, next_hop) def neighbors_add(self, neighbor): if isinstance(neighbor, Neighbor): self.bgp_speaker.neighbor_add( address=neighbor.get_IP(), #neighbor, remote_as=neighbor.get_ASN(), #self.neighbor[neighbor]['asn'], next_hop=neighbor.get_next_hop(), #self.router_next_hop, is_next_hop_self=True) else: print "Object is not the type Neighbor! type:", type( neighbor), type(Neighbor), neighbor def get_cool_rib(self): # from ryu.services.protocols.bgp.api.base import call # show = { # 'params': ['rib', 'ipv4'], # 'format': format # } # # call('operator.show', **show) from ryu.services.protocols.bgp.operator.internal_api import InternalApi INTERNAL_API = InternalApi() #_init_log_handler()) # table_manager = self.get_core_service().table_manager # gtable = table_manager.get_global_table_by_route_family(rf) return INTERNAL_API.get_single_rib_routes('ipv4') def update_networks_from_rib(self): from ryu.services.protocols.bgp.operator.internal_api import InternalApi INTERNAL_API = InternalApi() rib_bgp = INTERNAL_API.get_single_rib_routes('ipv4') print rib_bgp to_delete = {} for route in rib_bgp: prefix = route['prefix'] paths = route['paths'] best_hop = None list_of_next_hops = [] for index, path in enumerate(paths): aspath = path['aspath'] if aspath == []: continue nexthop = path['nexthop'] list_of_next_hops.append(nexthop) is_best_route = path['best'] if is_best_route: best_hop = nexthop ip = IPNetwork(prefix) # ("172.16.0.0/24") ip_network = str(ip.network) # mask_value = ip.prefixlen # netmask = ip.netmask #print prefix,'\n\n\n' if ip_network not in self.networks: switch = self.neighbor[nexthop]['switch'] port = self.neighbor[nexthop]['port'] controller_ip = None if aspath == []: # aspath = [] means that this prefix is local controller_ip = self.local_networks[prefix][ 'controller_ip'] else: controller_ip = self.hosts['neighbors'][nexthop][ 'controller_ip'] self.networks[ip_network] = { 'mask': str(ip.netmask), 'controller_ip': controller_ip, 'next_hop': { nexthop: { 'switch': switch, 'port': port, 'bandwidth': 0, 'congested': 0 } }, 'as_path': aspath, 'best_hop': nexthop } else: best_next_hop = self.networks[ip_network]['best_hop'] if best_hop != best_next_hop: self.networks[ip_network]['next_hop'][ 'best_hop'] = best_hop if nexthop not in self.networks[ip_network]['next_hop']: switch = self.neighbor[nexthop]['switch'] port = self.neighbor[nexthop]['port'] controller_ip = None if aspath == []: # aspath = [] means that this prefix is local controller_ip = self.local_networks[prefix][ 'controller_ip'] else: controller_ip = self.hosts['neighbors'][nexthop][ 'controller_ip'] self.networks[ip_network]['next_hop'][nexthop] = { 'switch': switch, 'port': port, 'bandwidth': 0, 'congested': 0 } else: #I dont know if it is necessary to change pass self.networks[ip_network]['as_path'] = aspath ip = IPNetwork(prefix) # ("172.16.0.0/24") ip_network = str(ip.network) if ip_network in self.networks: for nexthop in self.networks[ip_network]['next_hop']: if nexthop not in list_of_next_hops: del self.networks[ip_network]['next_hop'][nexthop] # How it should be: # networks = {'10.0.2.0': {'controller_ip':"10.0.2.254",'mask': '255.255.255.0', # 'next_hop': {"10.0.2.2": {'switch': 2, 'port': 2,'bandwidth': 0,'congested':0}},'best_hop':"10.0.2.2"}, # '10.0.1.0': {'controller_ip':"10.0.1.254",'mask': '255.255.255.0', # 'next_hop': {"10.0.1.1": {'switch': 2, 'port': 1,'bandwidth': 0,'congested':0}},'best_hop':"10.0.1.1"}, # '172.16.0.0': {'controller_ip':"10.0.1.254",'mask': '255.255.255.0', # 'next_hop': {"10.0.1.1": {'switch': 2, 'port': 1,'bandwidth': 0,'congested':0}, # "10.0.2.2": {'switch': 2, 'port': 2,'bandwidth': 0,'congested':0}}, # 'best_hop': "10.0.1.1"}, # '10.0.254.0': {'controller_ip':"10.0.254.254",'mask': '255.255.255.0', # 'next_hop': {"10.0.254.1": {'switch': 2, 'port': 6,'bandwidth': 0,'congested':0}},'best_hop':"10.0.254.1"} # } def peer_down_handler(self, remote_ip, remote_as): print "peer_down_handler" self.logger.info('peer down:') self.logger.info('remote_as: %d', remote_as) self.logger.info('remote ip: %s', remote_ip) self.logger.info('') for network in self.networks.keys(): for next_hop in self.networks[network]['next_hop'].keys(): if str(remote_ip) == next_hop: del self.networks[network]['next_hop'][next_hop] def peer_up_handler(self, remote_ip, remote_as): print "peer_up_handler" self.logger.info('peer up:') self.logger.info('remote_as: %d', remote_as) self.logger.info('remote ip: %s', remote_ip) self.logger.info('') def best_path_change_handler(self, ev): print "Best paht changed! ", ev #self.update_networks_from_rib() #self.prefix_learned["OI"] = "Path changed!" self.logger.info('best path changed:') self.logger.info('remote_as: %d', ev.remote_as) self.logger.info('route_dist: %s', ev.route_dist) self.logger.info('prefix: %s', ev.prefix) self.logger.info('nexthop: %s', ev.nexthop) self.logger.info('label: %s', ev.label) self.logger.info('path: %s', ev.path) self.logger.info('peer: %s %s' % (ev.path._source, type(ev.path._source))) self.logger.info('peer ip: %s' % ev.path._source.ip_address) if True: return self.logger.info('Port: %s' % self.neighbor[ev.path._source.ip_address]['port']) self.logger.info('is_withdraw: %s', ev.is_withdraw) self.logger.info('') """ ev.path: data: {'path': Path(Peer(ip: 192.168.25.51, asn: 65501) peer: Peer(ip: 192.168.25.51, asn: 65501) NLRI: network layer reachability information. For IPv4 is all about send prefix information. With other addresses families it can carry other types of information Received msg from ('10.0.1.51', '46426') << BGPUpdate(len=52,nlri=[BGPNLRI(addr='198.51.100.0',length=24)],path_attributes=[BGPPathAttributeOrigin(flags=64,length=1,type=1,value=0), BGPPathAttributeAsPath(flags=80,length=10,type=2,value=[[65501, 65500]]), BGPPathAttributeNextHop(flags=64,length=4,type=3,value='10.0.1.51')],total_path_attribute_len=25,type=2,withdrawn_routes=[],withdrawn_routes_len=0) NLRI: BGPNLRI(addr='198.51.100.0',length=24) Extracted paths from Update msg.: Path(source: Peer(ip: 10.0.1.51, asn: 65501), nlri: BGPNLRI(addr='198.51.100.0',length=24), source ver#: 1, path attrs.: {1: BGPPathAttributeOrigin(flags=64,length=1,type=1,value=0), 2: BGPPathAttributeAsPath(flags=80,length=10,type=2,value=[[65501, 65500]]), 3: BGPPathAttributeNextHop(flags=64,length=4,type=3,value='10.0.1.51')}, nexthop: 10.0.1.51, is_withdraw: False) return ('Path(%s, %s, %s, %s, %s, %s)' % ( self._source, self._nlri, self._source_version_num, self._path_attr_map, self._nexthop, self._is_withdraw)) Used to pass an update on any best remote path to best_path_change_handler. ================ ====================================================== Attribute Description ================ ====================================================== remote_as The AS number of a peer that caused this change route_dist None in the case of IPv4 or IPv6 family prefix A prefix was changed nexthop The nexthop of the changed prefix label MPLS label for VPNv4, VPNv6 or EVPN prefix path An instance of ``info_base.base.Path`` subclass is_withdraw True if this prefix has gone otherwise False ================ ====================================================== """ print "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nCreate a rule for %s with next hop %s and port %s" % ( ev.prefix, ev.nexthop, self.neighbor[ev.path._source.ip_address]['port']) print "AS path:", ev.path print "AS path attributes:", ev.path._path_attr_map print "AS path attributes, AS_Path:", ev.path.get_pattr( bgp.BGP_ATTR_TYPE_AS_PATH) print "AS path attributes, AS_Path value:", ev.path.get_pattr( bgp.BGP_ATTR_TYPE_AS_PATH).value # Check if the prefix already has been learned if ev.prefix not in self.prefix_learned: ip = IPNetwork(ev.prefix) #("172.16.0.0/24") #print ip.network, ip.prefixlen??? switch = self.neighbor[ev.path._source.ip_address]['switch'] port = self.neighbor[ev.path._source.ip_address]['port'] as_path = ev.path.get_pattr(bgp.BGP_ATTR_TYPE_AS_PATH).value self.prefix_learned[ev.prefix] = { 'next_hop': { ev.nexthop: { 'switch': switch, 'port': port, 'as_path': as_path, 'neighbor': ev.path._source.ip_address } } } else: switch = self.neighbor[ev.path._source.ip_address]['switch'] port = self.neighbor[ev.path._source.ip_address]['port'] as_path = ev.path.get_pattr(bgp.BGP_ATTR_TYPE_AS_PATH).value if ev.nexthop not in self.prefix_learned[ev.prefix]['next_hop']: self.prefix_learned[ev.prefix]['next_hop'] = { ev.nexthop: { 'switch': switch, 'port': port, 'as_path': as_path, 'neighbor': ev.path._source.ip_address } } else: self.prefix_learned[ev.prefix]['next_hop'][ev.nexthop] = { 'switch': switch, 'port': port, 'as_path': as_path, 'neighbor': ev.path._source.ip_address } #{'172.16.0.0/24': {'paths': [[65001, 65501]], 'next_hop': '10.0.1.1', 'port': 1, 'neighbor': '10.0.1.1'}}" #How it should be: # networks = {'10.0.2.0': {'controller_ip':"10.0.2.254",'mask': '255.255.255.0', # 'next_hop': {"10.0.2.2": {'switch': 2, 'port': 2,'bandwidth': 0,'congested':0}},'best_hop':"10.0.2.2"}, # '10.0.1.0': {'controller_ip':"10.0.1.254",'mask': '255.255.255.0', # 'next_hop': {"10.0.1.1": {'switch': 2, 'port': 1,'bandwidth': 0,'congested':0}},'best_hop':"10.0.1.1"}, # '172.16.0.0': {'controller_ip':"10.0.1.254",'mask': '255.255.255.0', # 'next_hop': {"10.0.1.1": {'switch': 2, 'port': 1,'bandwidth': 0,'congested':0}, # "10.0.2.2": {'switch': 2, 'port': 2,'bandwidth': 0,'congested':0}}, # 'best_hop': "10.0.1.1"}, # '10.0.254.0': {'controller_ip':"10.0.254.254",'mask': '255.255.255.0', # 'next_hop': {"10.0.254.1": {'switch': 2, 'port': 6,'bandwidth': 0,'congested':0}},'best_hop':"10.0.254.1"} # } # self.prefix_learned[ev.prefix]['next_hop'] = ev.nexthop # self.prefix_learned[ev.prefix]['neighbor'] = ev.path._source.ip_address # self.prefix_learned[ev.prefix]["port"] = self.neighbor[ev.path._source.ip_address]['port'], # self.prefix_learned[ev.prefix]['paths'] += ev.path.get_pattr(bgp.BGP_ATTR_TYPE_AS_PATH).value # The result self.prefix_learned: # {'172.16.0.0/24': {'paths': [[65001]], 'next_hop': '192.168.25.101', 'port': 1, 'neighbor': '192.168.25.101'}} if ev.is_withdraw: # Remove prefix that is withdraw ip = IPNetwork(ev.prefix) # ("172.16.0.0/24") ip_network = str(ip.network) next_hop = ev.nexthop
command += '/super/noreturn' command += ' 2> /dev/null' return command class bgpevent(event.EventBase): def __init__(self,ev): self.remote_as = ev.remote_as self.prefix = ev.prefix self.nexthop = ev.nexthop #self.is_withdraw = ev.is_withdraw if __name__=="__main__": speaker = BGPSpeaker(as_number=20,router_id='1.1.1.2', best_path_change_handler=dump_remote_best_path_change, peer_down_handler=detect_peer_down ) #speaker.neighbor_add("10.108.90.1",10) speaker.neighbor_add("10.108.91.1",30) speaker.neighbor_add("10.108.92.1",10) print 111111 print speaker.rib_get() print 222222 #speaker.neighbor_add("10.108.91.1",30) #uncomment the below line if the speaker needs to talk with a bmp server
def __init__(self, hosts=None, networks=None, *args, **kwargs): super(BGP_Speaker, self).__init__(*args, **kwargs) self.networks = networks self.hosts = hosts # Configuring AS 65501: self.as_number = 65001 #self.remote_as = 65501 self.router_id = '192.168.25.7' self.router_next_hop = "10.0.254.254" # The source IP of the BGP self.listen_port = 179 self.bgp_speaker = \ BGPSpeaker(self.as_number, self.router_id, bgp_server_port=self.listen_port, best_path_change_handler=self.best_path_change_handler, peer_down_handler=self.peer_down_handler, peer_up_handler=self.peer_up_handler) # print "<<<<<<<<<",self.bgp_speaker # speaker = BGPSpeaker(as_number=65001, router_id='192.168.25.7', # best_path_change_handler=dump_remote_best_path_change, # peer_down_handler=detect_peer_down) self.neighbor1 = Neighbor(ip="192.168.25.2", asn=65002, next_hop="10.0.1.254", border_switch=2, sw_port=1, controller_ip="10.0.1.254") #self.neighbor2 = Neighbor(ip="10.0.2.2", asn=65002,next_hop="10.0.1.254", border_switch=2, sw_port=2, controller_ip="10.0.1.254") # self.neighbor = {"10.0.1.1": {'asn': 65001,'switch':2, 'port': 1,'controller_ip':"10.0.1.254"}, # "10.0.2.2": {'asn': 65002,'switch':2, 'port': 2,'controller_ip':"10.0.2.254"}, # } self.neighbors = [self.neighbor1] #,self.neighbor2] #self.local_networks = {"192.168.2.0/24":{'controller_ip':"192.168.2.254"}} self.prefix_add(prefix="192.168.2.0/24", next_hop="192.168.2.254") # Adding neighbors: #TODO: Verify the option of next_hop for neighbor in self.neighbors: # self.bgp_speaker.neighbor_add(address=neighbor, remote_as=self.neighbor[neighbor]['asn'], # next_hop=self.router_next_hop, # is_next_hop_self=True) self.neighbors_add(neighbor) # for network in self.local_networks: # # Adding prefixes: # self.bgp_speaker.prefix_add(network, self.neighbor[neighbor]['controller_ip']) # next_hop (how to reach the network) # #self.bgp_speaker.prefix_add("192.168.2.0/24", "10.0.2.254") # next_hop (how to reach the network) # # self.bgp_speaker.prefix_add("10.0.0.0/24", "10.0.1.1") # "10.0.3.1": 'fe:00:00:00:00:03'} # self.arp_controller = '00:00:00:00:00:fe' # self.monitor_thread = hub.spawn(self._monitor) # self.best_paths ={} self.prefix_learned = {} # "198.51.100.0/24",'10.0.1.0/24'} self.is_load_balancer_active = False self.load_balancer = {} #self.monitor_thread = hub.spawn(self.stand_alone) print "BGP Speaker started! ;)" self.stand_alone()
def dump_remote_best_path_change(event): prefix = {"remote_as": event.remote_as, "prefix": event.prefix, "nexthop": event.nexthop} prefix_list.append(prefix) print "the best path changed:", event.remote_as, event.prefix, event.nexthop, event.is_withdraw def detect_peer_down(remote_ip, remote_as): print "Peer down:", remote_ip, remote_as if __name__ == "__main__": speaker = BGPSpeaker( as_number=65000, router_id="172.0.255.254", best_path_change_handler=dump_remote_best_path_change, peer_down_handler=detect_peer_down, ) speaker.neighbor_add("172.0.0.1", 65000, enable_ipv4=True, enable_vpnv4=True, is_next_hop_self=True) speaker.neighbor_add("172.0.0.2", 65000, enable_ipv4=True, enable_vpnv4=True, is_next_hop_self=True) speaker.neighbor_add("172.0.0.3", 65000, enable_ipv4=True, enable_vpnv4=True, is_next_hop_self=True) # uncomment the below line if the speaker needs to talk with a bmp server. # speaker.bmp_server_add('192.168.177.2', 11019) count = 1 i_prefix_list = True while True: eventlet.sleep(5) print prefix_list if i_prefix_list: for prefix in prefix_list:
null = '' true = 'True' false = 'False' Flag = False status_bgp = speaker.neighbor_state_get() status = json.loads(status_bgp) for key in status.keys(): if status[key]['info']['bgp_state'] != 'Established': logging.info('neighbor is abornamal .please check peer {}'.format(key)) Flag = True return Flag if __name__ == "__main__": speaker = BGPSpeaker(as_number=100, router_id='10.0.0.82', best_path_change_handler=dump_remote_best_path_change, peer_down_handler=detect_peer_down) speaker.neighbor_add('10.0.0.81', 100) # uncomment the below line if the speaker needs to talk with a bmp server. # speaker.bmp_server_add('192.168.177.2', 11019) time.sleep(5) while True: print(datetime.datetime.now()) if (get_bgp_status()): logging.warning("~~~~~~~~~~~~~~~~~~~~~") db_from_bgp.clear() else: compare_db() eventlet.sleep(6)
class RyuBGPSpeaker(RyuApp): def __init__(self, *args, **kwargs): super(RyuBGPSpeaker, self).__init__(*args, **kwargs) self.config_file = CONF.config_file # BGPSpeaker instance (not instantiated yet) self.speaker = None def start(self): super(RyuBGPSpeaker, self).start() # If configuration file was provided and loaded successfully, we start # BGPSpeaker using the given settings. # If no configuration file is provided or if any minimum required # setting is missing, BGPSpeaker will not be started. if self.config_file: LOG.debug('Loading config file %s...', self.config_file) settings = load_config(self.config_file) # Configure logging settings, if available. if hasattr(settings, 'LOGGING'): # Not implemented yet. LOG.debug('Loading LOGGING settings... (NOT implemented yet)') # from logging.config import dictConfig # logging_settings = dictConfig(settings.LOGGING) # Configure BGP settings, if available. if hasattr(settings, 'BGP'): LOG.debug('Loading BGP settings...') self._start_speaker(settings.BGP) # Configure SSH settings, if available. if hasattr(settings, 'SSH'): LOG.debug('Loading SSH settings...') hub.spawn(SSH_CLI_CONTROLLER.start, **settings.SSH) # Start RPC server with the given RPC settings. rpc_settings = { NC_RPC_BIND_PORT: CONF.rpc_port, NC_RPC_BIND_IP: validate_rpc_host(CONF.rpc_host), } return hub.spawn(NET_CONTROLLER.start, **rpc_settings) def _start_speaker(self, settings): """ Starts BGPSpeaker using the given settings. """ # Settings for starting BGPSpeaker bgp_settings = {} # Get required settings. try: bgp_settings['as_number'] = settings.get(LOCAL_AS) bgp_settings['router_id'] = settings.get(ROUTER_ID) except KeyError as e: raise ApplicationException( desc='Required BGP configuration missing: %s' % e) # Get optional settings. bgp_settings[BGP_SERVER_PORT] = settings.get(BGP_SERVER_PORT, DEFAULT_BGP_SERVER_PORT) bgp_settings[REFRESH_STALEPATH_TIME] = settings.get( REFRESH_STALEPATH_TIME, DEFAULT_REFRESH_STALEPATH_TIME) bgp_settings[REFRESH_MAX_EOR_TIME] = settings.get( REFRESH_MAX_EOR_TIME, DEFAULT_REFRESH_MAX_EOR_TIME) bgp_settings[LABEL_RANGE] = settings.get(LABEL_RANGE, DEFAULT_LABEL_RANGE) # Create BGPSpeaker instance. LOG.debug('Starting BGPSpeaker...') self.speaker = BGPSpeaker(**bgp_settings) # Add neighbors. LOG.debug('Adding neighbors...') self._add_neighbors(settings.get('neighbors', [])) # Add VRFs. LOG.debug('Adding VRFs...') self._add_vrfs(settings.get('vrfs', [])) # Add Networks LOG.debug('Adding routes...') self._add_routes(settings.get('routes', [])) def _add_neighbors(self, settings): """ Add BGP neighbors from the given settings. All valid neighbors are loaded. Miss-configured neighbors are ignored and errors are logged. """ for neighbor_settings in settings: LOG.debug('Adding neighbor settings: %s', neighbor_settings) try: self.speaker.neighbor_add(**neighbor_settings) except RuntimeConfigError as e: LOG.exception(e) def _add_vrfs(self, settings): """ Add BGP VRFs from the given settings. All valid VRFs are loaded. Miss-configured VRFs are ignored and errors are logged. """ for vrf_settings in settings: LOG.debug('Adding VRF settings: %s', vrf_settings) try: self.speaker.vrf_add(**vrf_settings) except RuntimeConfigError as e: LOG.exception(e) def _add_routes(self, settings): """ Add BGP routes from given settings. All valid routes are loaded. Miss-configured routes are ignored and errors are logged. """ for route_settings in settings: if 'prefix' in route_settings: prefix_add = self.speaker.prefix_add elif 'route_type' in route_settings: prefix_add = self.speaker.evpn_prefix_add else: LOG.debug('Skip invalid route settings: %s', route_settings) continue LOG.debug('Adding route settings: %s', route_settings) try: prefix_add(**route_settings) except RuntimeConfigError as e: LOG.exception(e)
class RyuBGPSpeaker(RyuApp): """ Base application for implementing BGP applications. This application will notifies - ``EventBestPathChanged`` - ``EventPeerDown`` - ``EventPeerUp`` to other BGP applications. To catch these events, specify ``@set_ev_cls()`` decorator to the event handlers in the Ryu applications. Example:: ... from ryu.base import app_manager from ryu.controller.handler import set_ev_cls from ryu.services.protocols.bgp import application as bgp_application ... class MyBGPApp(app_manager.RyuApp): _CONTEXTS = { 'ryubgpspeaker': bgp_application.RyuBGPSpeaker, } ... @set_ev_cls(bgp_application.EventBestPathChanged) def _best_patch_changed_handler(self, ev): self.logger.info( 'Best path changed: is_withdraw=%s, path=%s', ev.is_withdraw, ev.path) """ _EVENTS = [ EventBestPathChanged, EventPeerDown, EventPeerUp, ] def __init__(self, *args, **kwargs): super(RyuBGPSpeaker, self).__init__(*args, **kwargs) self.config_file = CONF.config_file # BGPSpeaker instance (not instantiated yet) self.speaker = None def start(self): super(RyuBGPSpeaker, self).start() # If configuration file was provided and loaded successfully, we start # BGPSpeaker using the given settings. # If no configuration file is provided or if any minimum required # setting is missing, BGPSpeaker will not be started. if self.config_file: LOG.debug('Loading config file %s...', self.config_file) settings = load_config(self.config_file) # Configure logging settings, if available. if hasattr(settings, 'LOGGING'): # Not implemented yet. LOG.debug('Loading LOGGING settings... (NOT implemented yet)') # from logging.config import dictConfig # logging_settings = dictConfig(settings.LOGGING) # Configure BGP settings, if available. if hasattr(settings, 'BGP'): LOG.debug('Loading BGP settings...') self._start_speaker(settings.BGP) # Configure SSH settings, if available. if hasattr(settings, 'SSH'): LOG.debug('Loading SSH settings...') # Note: paramiko used in bgp.operator.ssh is the optional # requirements, imports bgp.operator.ssh here. from ryu.services.protocols.bgp.operator import ssh hub.spawn(ssh.SSH_CLI_CONTROLLER.start, **settings.SSH) # Start RPC server with the given RPC settings. rpc_settings = { NC_RPC_BIND_PORT: CONF.rpc_port, NC_RPC_BIND_IP: validate_rpc_host(CONF.rpc_host), } return hub.spawn(NET_CONTROLLER.start, **rpc_settings) def _start_speaker(self, settings): """ Starts BGPSpeaker using the given settings. """ # Check required settings. _required_settings = ( LOCAL_AS, ROUTER_ID, ) for required in _required_settings: if required not in settings: raise ApplicationException( desc='Required BGP configuration missing: %s' % required) # Set event notify handlers if no corresponding handler specified. settings.setdefault( 'best_path_change_handler', self._notify_best_path_changed_event) settings.setdefault( 'peer_down_handler', self._notify_peer_down_event) settings.setdefault( 'peer_up_handler', self._notify_peer_up_event) # Pop settings other than creating BGPSpeaker instance. neighbors_settings = settings.pop('neighbors', []) vrfs_settings = settings.pop('vrfs', []) routes_settings = settings.pop('routes', []) # Create BGPSpeaker instance. LOG.debug('Starting BGPSpeaker...') settings.setdefault('as_number', settings.pop(LOCAL_AS)) self.speaker = BGPSpeaker(**settings) # Add neighbors. LOG.debug('Adding neighbors...') self._add_neighbors(neighbors_settings) # Add VRFs. LOG.debug('Adding VRFs...') self._add_vrfs(vrfs_settings) # Add routes LOG.debug('Adding routes...') self._add_routes(routes_settings) def _notify_best_path_changed_event(self, ev): ev = EventBestPathChanged(ev.path, ev.is_withdraw) self.send_event_to_observers(ev) def _notify_peer_down_event(self, remote_ip, remote_as): ev = EventPeerDown(remote_ip, remote_as) self.send_event_to_observers(ev) def _notify_peer_up_event(self, remote_ip, remote_as): ev = EventPeerUp(remote_ip, remote_as) self.send_event_to_observers(ev) def _add_neighbors(self, settings): """ Add BGP neighbors from the given settings. All valid neighbors are loaded. Miss-configured neighbors are ignored and errors are logged. """ for neighbor_settings in settings: LOG.debug('Adding neighbor settings: %s', neighbor_settings) try: self.speaker.neighbor_add(**neighbor_settings) except RuntimeConfigError as e: LOG.exception(e) def _add_vrfs(self, settings): """ Add BGP VRFs from the given settings. All valid VRFs are loaded. Miss-configured VRFs are ignored and errors are logged. """ for vrf_settings in settings: LOG.debug('Adding VRF settings: %s', vrf_settings) try: self.speaker.vrf_add(**vrf_settings) except RuntimeConfigError as e: LOG.exception(e) def _add_routes(self, settings): """ Add BGP routes from given settings. All valid routes are loaded. Miss-configured routes are ignored and errors are logged. """ for route_settings in settings: if 'prefix' in route_settings: prefix_add = self.speaker.prefix_add elif 'route_type' in route_settings: prefix_add = self.speaker.evpn_prefix_add elif 'flowspec_family' in route_settings: prefix_add = self.speaker.flowspec_prefix_add else: LOG.debug('Skip invalid route settings: %s', route_settings) continue LOG.debug('Adding route settings: %s', route_settings) try: prefix_add(**route_settings) except RuntimeConfigError as e: LOG.exception(e)
class SDNIPSApp(app_manager.RyuApp): OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION] _CONTEXTS = {'wsgi': WSGIApplication} def __init__(self, *args, **kwargs): super(SDNIPSApp, self).__init__(*args, **kwargs) self.net = nx.DiGraph() wsgi = kwargs['wsgi'] wsgi.register(SDNIPSWSGIApp, {myapp_name: self}) self.eline_map = {} self.bgp_config = {} self.bgp_speaker = None self.rcv_prefixes = [] self.flows = {} self.contention_vrf = {} self.quarantine = {} load_config_thread = Thread(target=self.load_config, args=()) load_config_thread.start() def __exit__(self, exc_type, exc_value, traceback): for prefix in self.rcv_prefixes: os.system('/sbin/ip route del %s' % prefix) def load_config(self): try: with open('sdn-ips-config.json', 'r') as fp: data = jsonpickle.decode(fp.read()) except Exception as e: print "Fail to load SDN-IPS config. Error: %s" % (e) return retry = 0 sleep(15) while set(data['nodes']) != set(self.net.nodes()) and retry < 10: print "Nodes are missing or topology is different! Trying in 15s.." sleep(15) retry += 1 if retry == 10: print "Could not load config because some nodes are missing or topology is different!" return # Reinstall flows for dpid in data.get('flows', []): for flow in data['flows'][dpid]: dp = self.net.node[int(dpid)]['conn'] self.add_flow(dp, flow['priority'], flow['match'], flow['actions']) # Recreate BGP speaker if 'as_number' in data['bgp'] and 'router_id' in data['bgp']: self.bgp_create(data['bgp']['as_number'], str(data['bgp']['router_id'])) for neigh in data['bgp'].get('neighbors', []): neigh['address'] = str(neigh['address']) self.bgp_add_neighbor(**neigh) for prefix in data['bgp'].get('adv_prefixes', []): self.bgp_add_prefix(str(prefix)) # save contention VRF self.contention_vrf = data['contention_vrf'] def persist_config(self): data = {} # Topology information data['nodes'] = self.net.nodes() # BGP config data['bgp'] = self.bgp_config # OpenFlow rules data['flows'] = self.flows # Contention VRF data['contention_vrf'] = self.contention_vrf try: with open('sdn-ips-config.json', 'w') as fp: fp.write(jsonpickle.encode(data)) except Exception as e: print "Fail to save SDN-IPS config! Error: %s" % (e) @set_ev_cls(dpset.EventDP, dpset.DPSET_EV_DISPATCHER) def datapath_handler(self, ev): ofproto = ev.dp.ofproto if ev.enter: ports = {} for p in ev.ports: if p.port_no != ofproto.OFPP_LOCAL: ports[p.port_no] = {'name': p.name, 'hw_addr': p.hw_addr} self.net.add_node(ev.dp.id, **{'ports': ports, 'conn': ev.dp}) print 'OFPStateChange switch entered: dpid=%s' % ( dpid_lib.dpid_to_str(ev.dp.id)) else: print 'OFPStateChange switch leaves: dpid=%s' % ( dpid_lib.dpid_to_str(ev.dp.id)) self.net.remove_node(ev.dp.id) topo_events = [ event.EventSwitchEnter, event.EventPortAdd, event.EventLinkAdd ] @set_ev_cls(topo_events) def get_topology_data(self, ev): switch_list = get_switch(self, None) links_list = get_link(self, None) links = [] for link in links_list: # check for unwanted nodes and links if link.src.dpid not in self.net.nodes( ) or link.dst.dpid not in self.net.nodes(): continue if self.net.has_edge(link.src.dpid, link.dst.dpid): continue links.append((link.src.dpid, link.dst.dpid, { 'sport': link.src.port_no, 'dport': link.dst.port_no })) if not links: return print "Update graph edges:" for l in links: print "==> %s:%d <-> %s:%d" % (dpid_lib.dpid_to_str( l[0]), l[2]['sport'], dpid_lib.dpid_to_str( l[1]), l[2]['dport']) self.net.add_edges_from(links) @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) def switch_features_handler(self, ev): datapath = ev.msg.datapath ofproto = datapath.ofproto parser = datapath.ofproto_parser # invalidate all previews rules clear = parser.OFPFlowMod(datapath=datapath, command=ofproto.OFPFC_DELETE) datapath.send_msg(clear) # install table-miss flow entry match = {} actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER)] self.add_flow(datapath, 65530, match, actions, visible=False) @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) def _packet_in_handler(self, ev): msg = ev.msg dpid = msg.datapath.id pkt = packet.Packet(msg.data) eth_pkt = pkt.get_protocol(ethernet.ethernet) if eth_pkt.ethertype == ether_types.ETH_TYPE_LLDP: return ip_pkt = pkt.get_protocol(ipv4.ipv4) if ip_pkt and str(ip_pkt.src) in self.quarantine: vlan_pkt = pkt.get_protocol(vlan.vlan) vlan_id = 0 if vlan_pkt: vlan_id = vlan_pkt.vid if vlan_id not in self.eline_map: print "Error: packet received from an infected host but with wrong vlanid" return redirect_to = self.quarantine[str(ip_pkt.src)] self.contention_quarantine_redirect(msg.datapath, ip_pkt, redirect_to, vlan_id) return print "PacketIn dpid=%s inport=%s src=%s dst=%s ethertype=0x%04x" % \ (dpid, msg.in_port, eth_pkt.src, eth_pkt.dst, eth_pkt.ethertype) def get_access_ports(self, sw): if sw not in self.net.nodes(): return None ports = self.net.node[sw]['ports'].keys() for e in self.net.edge[sw]: ports.remove(self.net.edge[sw][e]['sport']) return ports def add_flow(self, datapath, priority, match, actions, idle_timeout=0, visible=True): ofproto = datapath.ofproto parser = datapath.ofproto_parser match_ofp = self.build_match(datapath, **match) mod = parser.OFPFlowMod(datapath=datapath, priority=priority, idle_timeout=idle_timeout, match=match_ofp, actions=actions) datapath.send_msg(mod) if visible: self.flows.setdefault(datapath.id, []) self.flows[datapath.id].append({ 'match': match, 'priority': priority, 'actions': actions }) self.persist_config() def build_match(self, datapath, in_port=0, dl_type=0, dl_src=0, dl_dst=0, dl_vlan=0, nw_src=0, src_mask=32, nw_dst=0, dst_mask=32, nw_proto=0, nw_tos=None, tp_src=0, tp_dst=0): ofp = datapath.ofproto ofp_parser = datapath.ofproto_parser # Match nw_tos = 0 wildcards = ofp.OFPFW_ALL if in_port: wildcards &= ~ofp.OFPFW_IN_PORT if dl_type: wildcards &= ~ofp.OFPFW_DL_TYPE if dl_src: wildcards &= ~ofp.OFPFW_DL_SRC if dl_dst: wildcards &= ~ofp.OFPFW_DL_DST if dl_vlan: wildcards &= ~ofp.OFPFW_DL_VLAN if nw_tos: wildcards &= ~ofp.OFPFW_NW_TOS if nw_src: v = (32 - src_mask) << ofp.OFPFW_NW_SRC_SHIFT | \ ~ofp.OFPFW_NW_SRC_MASK wildcards &= v if nw_dst: v = (32 - dst_mask) << ofp.OFPFW_NW_DST_SHIFT | \ ~ofp.OFPFW_NW_DST_MASK wildcards &= v if nw_proto: wildcards &= ~ofp.OFPFW_NW_PROTO if tp_src: wildcards &= ~ofp.OFPFW_TP_SRC if tp_dst: wildcards &= ~ofp.OFPFW_TP_DST match = ofp_parser.OFPMatch(wildcards, in_port, dl_src, dl_dst, dl_vlan, 0, dl_type, nw_tos, nw_proto, nw_src, nw_dst, tp_src, tp_dst, src_mask, dst_mask) return match def create_eline(self, uniA_sw, uniA_port, uniB_sw, uniB_port, vlanid): # sanity check if vlanid in self.eline_map: return ( False, "E-line already exists with the same vlan_id! Choose another vlanid" ) path = nx.shortest_path(self.net, uniA_sw, uniB_sw) print "==> create_eline(UNI-A=%s:%s, UNI-B=%s:%s, vlanid=%d): %s" % \ (uniA_sw, uniA_port, uniB_sw, uniB_port, vlanid, path) for i in range(len(path)): sw = path[i] buff_id = None if i == 0: # first switch match_in_port = uniA_port else: prev_sw = path[i - 1] match_in_port = self.net.edge[prev_sw][sw]['dport'] if i == len(path) - 1: action_out_port = uniB_port else: next_sw = path[i + 1] action_out_port = self.net.edge[sw][next_sw]['sport'] dp = self.net.node[sw]['conn'] # uniA -> uniB self.logger.info( "==> add_flow sw=%s (->) in_port=%s vlanid=%d action_out_port=%s", sw, match_in_port, vlanid, action_out_port) match = {'in_port': match_in_port, 'dl_vlan': vlanid} actions = [dp.ofproto_parser.OFPActionOutput(action_out_port)] self.add_flow(dp, 65533, match, actions) # uniB -> uniA match_in_port, action_out_port = action_out_port, match_in_port self.logger.info( "==> add_flow sw=%s (<-) in_port=%s vlanid=%d action_out_port=%s", sw, match_in_port, vlanid, action_out_port) match = {'in_port': match_in_port, 'dl_vlan': vlanid} actions = [dp.ofproto_parser.OFPActionOutput(action_out_port)] self.add_flow(dp, 65533, match, actions) uniA_bkbport = self.net.edge[uniA_sw][path[1]]['sport'] uniB_bkbport = self.net.edge[path[-2]][uniB_sw]['dport'] self.eline_map.setdefault(vlanid, {}) self.eline_map[vlanid][uniA_sw] = { 'access_port': uniA_port, 'bkb_port': uniA_bkbport } self.eline_map[vlanid][uniB_sw] = { 'access_port': uniB_port, 'bkb_port': uniB_bkbport } return (True, 'Success') def bgp_create(self, as_number, router_id): # MUDAR AQUI - INICIO try: self.bgp_speaker = BGPSpeaker( as_number=as_number, router_id=router_id, best_path_change_handler=self.best_path_change_handler, adj_rib_in_change_handler=self.adj_rib_in_change_handler, peer_down_handler=self.peer_down_handler, peer_up_handler=self.peer_up_handler) except Exception as e: print "Error creating bgp speaker: %s" % (e) return (False, 'Failed to create BGP speaker') # MUDAR AQUI - FIM self.bgp_config['as_number'] = as_number self.bgp_config['router_id'] = router_id self.bgp_config['neighbors'] = [] self.bgp_config['adv_prefixes'] = [] self.persist_config() return (True, 'Success') def bgp_add_neighbor(self, address, remote_as, enable_ipv4=True, enable_ipv6=False, enable_ipv4fs=False, enable_ipv6fs=False): # MUDAR AQUI - INICIO try: self.bgp_speaker.neighbor_add(address, remote_as, enable_ipv4=enable_ipv4, enable_ipv6=enable_ipv6, enable_ipv4fs=enable_ipv4fs, enable_ipv6fs=enable_ipv6fs) except Exception as e: print "Error on bgp_add_neighbor: %s" % (e) return (False, 'Failed to add BGP neighbor') # MUDAR AQUI - FIM self.bgp_config['neighbors'].append({ 'address': address, 'remote_as': remote_as, 'enable_ipv4': enable_ipv4, 'enable_ipv6': enable_ipv6, 'enable_ipv4fs': enable_ipv4fs, 'enable_ipv6fs': enable_ipv6fs }) self.persist_config() return (True, 'Success') def bgp_add_prefix(self, prefix): # MUDAR AQUI - INICIO try: self.bgp_speaker.prefix_add(prefix) except Exception as e: print "Error on bgp_add_prefix: %s" % (e) return (False, 'Failed to add prefix') # MUDAR AQUI - FIM self.bgp_config['adv_prefixes'].append(prefix) self.persist_config() return (True, 'Success') def best_path_change_handler(self, event): action = 'del' if event.is_withdraw else 'add' print 'the best path changed: remote-as=%s prefix=%s next-hop=%s action=%s' % \ (event.remote_as, event.prefix, event.nexthop, action) os.system('/sbin/sysctl net.ipv4.ip_forward=1') os.system('/sbin/ip route %s %s via %s' % (action, event.prefix, event.nexthop)) if event.is_withdraw: try: self.rcv_prefixes.remove(event.prefix) except: pass else: self.rcv_prefixes.append(event.prefix) def adj_rib_in_change_handler(self, event, peer_ip, peer_asn): if isinstance(event.path, (IPv4FlowSpecPath, IPv6FlowSpecPath)): #print "formatted_nlri=%s" % (event.path.nlri.formatted_nlri_str) #print "path=%s" % (event.path) #print "pattrs=%s" % (event.path.pathattr_map) extcomm = event.path.get_pattr( bgp.BGP_ATTR_TYPE_EXTENDED_COMMUNITIES, []) if extcomm: extcomm = extcomm.communities #print "BGPExtendedCommunities=%s" % (extcomm) self.bgp_update_flowspec(event.path.nlri.rules, extcomm) def bgp_update_flowspec(self, nlri_rules, extcomm): matches = {} for rule in nlri_rules: if isinstance(rule, bgp.FlowSpecDestPrefix): matches['nw_dst'] = rule.addr matches['dst_mask'] = rule.length elif isinstance(rule, bgp.FlowSpecSrcPrefix): matches['nw_src'] = rule.addr matches['src_mask'] = rule.length elif isinstance(rule, bgp.FlowSpecIPProtocol): matches['nw_proto'] = rule.value elif isinstance(rule, bgp.FlowSpecPort): #TODO: since openflow rules does not have an operator to OR (dst port # or src port), then we should create two rules: one for src port and # other for dst port pass elif isinstance(rule, bgp.FlowSpecDestPort): matches['tp_dst'] = rule.value elif isinstance(rule, bgp.FlowSpecSrcPort): matches['tp_src'] = rule.value print "matches: %s" % (matches) actions = {} for c in extcomm: if isinstance(c, bgp.BGPFlowSpecTrafficRateCommunity): if c.rate_info > 0.0: actions['rate-limit'] = c.rate_info # TODO: implement rate-limit when QoS queues is available else: actions['discard'] = True # TODO: make use of the other matches attributes such as tp_dst, proto,... self.contention_block(matches['nw_src']) elif isinstance(c, bgp.BGPFlowSpecRedirectCommunity): rtcomm = "%d:%d" % (c.as_number, c.local_administrator) nexthop = self.contention_vrf.get(rtcomm, None) if nexthop: actions['redirect-to-nexthop'] = nexthop # TODO: make use of the other matches attributes such as tp_dst, proto,... self.contention_quarantine(matches['nw_src'], nexthop) print "actions: %s" % (actions) def peer_down_handler(self, remote_ip, remote_as): print 'Peer down:', remote_ip, remote_as def peer_up_handler(self, remote_ip, remote_as): print 'Peer up:', remote_ip, remote_as def flow_create_mirror(self, dpid, flow, to_port): try: dp = self.net.node[dpid]['conn'] except: return (False, 'dpid not found!') parser = dp.ofproto_parser new_action = parser.OFPActionOutput(to_port) # check if the port is already on flow actions, and just return # in this case since we have nothing to do if new_action in flow['actions']: return (True, 'Success - to_port already in flow actions') flow['actions'].append(new_action) try: match_ofp = self.build_match(dp, **flow['match']) mod = parser.OFPFlowMod(datapath=dp, priority=flow['priority'], command=dp.ofproto.OFPFC_MODIFY_STRICT, match=match_ofp, actions=flow['actions']) dp.send_msg(mod) except Exception as e: return (False, 'Error installing flow_mod: %s' % (e)) return (True, 'Success') def flows_create_mirror(self, dpid, flows, target_sw, target_port): try: path = nx.shortest_path(self.net, dpid, target_sw) except: return ( False, 'Failed to create mirror! Could not find a path from %s to %s' % (dpid_lib.dpid_to_str(dpid), dpid_lib.dpid_to_str(target_sw))) # determine the first output port for remote mirroring if len(path) == 1: return ( False, 'Failed to create mirror. Currently we dont support mirror to the same switch' ) # for the first switch, we just modify the openflow rules adding a new action # to output the traffic to the next switch (remote mirroring) next_sw = path[1] first_port = self.net.edge[dpid][next_sw]['sport'] for flow in flows: self.flow_create_mirror(dpid, flow, first_port) for i in range(1, len(path)): sw = path[i] dp = self.net.node[sw]['conn'] prev_sw = path[i - 1] match_in_port = self.net.edge[prev_sw][sw]['dport'] actions = [] if i == len(path) - 1: action_out_port = target_port actions.append( dp.ofproto_parser.OFPActionSetDlDst( mac.haddr_to_bin('ff:ff:ff:ff:ff:ff'))) else: next_sw = path[i + 1] action_out_port = self.net.edge[sw][next_sw]['sport'] match = {'in_port': match_in_port} actions.append(dp.ofproto_parser.OFPActionOutput(action_out_port)) self.add_flow(dp, 65533, match, actions) return (True, 'Success') # contention_add_vrf(rtcomm, nexthop) # - rtcomm: Route-Target Community, describes the VRF # - nexthop: ipv4 address which will be used for redirect # # Add a fake VRF which will be used just for traffic # redirection to a nexthop. Usefull for FlowSpec redirect # action, since draft-simpson-idr-flowspec-redirect-02 is # not yet avaliable def contention_add_vrf(self, rtcomm, nexthop): self.contention_vrf[rtcomm] = nexthop self.persist_config() return (True, 'Success') def contention_quarantine(self, ipaddr, redirect_to): for sw in self.net.nodes(): dp = self.net.node[sw]['conn'] actions = [ dp.ofproto_parser.OFPActionOutput(dp.ofproto.OFPP_CONTROLLER) ] for port in self.get_access_ports(sw): for vlan in self.eline_map: # the dl_vlan match is a workaround because flowvisor seems to bug when using # dl_type=0x0800 match = { 'in_port': port, 'dl_type': 0x0800, 'dl_vlan': vlan, 'nw_src': ipaddr } self.add_flow(dp, 65534, match, actions) self.quarantine[ipaddr] = redirect_to return (True, 'Success') def contention_block(self, ipaddr): print "==> contention_block ipaddr=%s in all switches" % (ipaddr) actions = [] for sw in self.net.nodes(): dp = self.net.node[sw]['conn'] for port in self.get_access_ports(sw): for vlan in self.eline_map: # the dl_vlan match is a workaround because flowvisor seems to bug when using # dl_type=0x0800 match = { 'in_port': port, 'dl_type': 0x0800, 'dl_vlan': vlan, 'nw_src': ipaddr } self.add_flow(dp, 65534, match, actions) return (True, 'Success') def contention_quarantine_redirect(self, dp, ip_pkt, redirect_to, vlan_id): print "==> create contention_quarantine_redirect in dpid=%s src=%s dst=%s redirect_to=%s" % ( dpid_lib.dpid_to_str(dp.id), ip_pkt.src, ip_pkt.dst, redirect_to) # the dl_vlan match is a workaround because flowvisor seems to bug when using # dl_type=0x0800 match = { 'nw_src': ip_pkt.src, 'nw_dst': ip_pkt.dst, 'dl_type': 0x0800, 'dl_vlan': vlan_id } actions = [] actions.append(dp.ofproto_parser.OFPActionSetNwDst(redirect_to)) actions.append( dp.ofproto_parser.OFPActionOutput( self.eline_map[vlan_id][dp.id]['bkb_port'])) self.add_flow(dp, 65535, match, actions, idle_timeout=120) match = { 'nw_src': redirect_to, 'nw_dst': ip_pkt.src, 'dl_type': 0x0800, 'dl_vlan': vlan_id } actions = [] actions.append(dp.ofproto_parser.OFPActionSetNwSrc(str(ip_pkt.dst))) actions.append( dp.ofproto_parser.OFPActionOutput( self.eline_map[vlan_id][dp.id]['access_port'])) self.add_flow(dp, 65535, match, actions, idle_timeout=120)
from ryu.services.protocols.bgp.bgpspeaker import BGPSpeaker def dump_remote_best_path_change(event): print 'the best path changed:', event.remote_as, event.prefix,\ event.nexthop, event.is_withdraw def detect_peer_down(remote_ip, remote_as): print 'Peer down:', remote_ip, remote_as if __name__ == "__main__": print "BHKA" speaker = BGPSpeaker(as_number=64517, router_id='10.0.0.2', best_path_change_handler=dump_remote_best_path_change, peer_down_handler=detect_peer_down) print 'gamiesai' speaker.neighbor_add('192.168.1.4', 64518) # uncomment the below line ifthe speaker needs to talk with a bmp server. # speaker.bmp_server_add('192.168.177.2', 11019) count = 1 while True: eventlet.sleep(30) prefix = '10.20.' + str(count) + '.0/24' print "add a new prefix", prefix speaker.prefix_add(prefix) count += 1 if count == 4: speaker.shutdown() break