def insert_vrffs_path(self, nlri, communities, is_withdraw=False): assert nlri assert isinstance(communities, list) vrf_conf = self.vrf_conf from ryu.services.protocols.bgp.core import EXPECTED_ORIGIN pattrs = OrderedDict() pattrs[BGP_ATTR_TYPE_ORIGIN] = BGPPathAttributeOrigin(EXPECTED_ORIGIN) pattrs[BGP_ATTR_TYPE_AS_PATH] = BGPPathAttributeAsPath([]) for rt in vrf_conf.export_rts: communities.append(create_rt_extended_community(rt, 2)) for soo in vrf_conf.soo_list: communities.append(create_rt_extended_community(soo, 3)) pattrs[BGP_ATTR_TYPE_EXTENDED_COMMUNITIES] = ( BGPPathAttributeExtendedCommunities(communities=communities)) puid = self.VRF_PATH_CLASS.create_puid(vrf_conf.route_dist, nlri.prefix) path = self.VRF_PATH_CLASS(puid, None, nlri, 0, pattrs=pattrs, is_withdraw=is_withdraw) # Insert the path into VRF table, get affected destination so that we # can process it further. eff_dest = self.insert(path) # Enqueue the eff_dest for further processing. self._signal_bus.dest_changed(eff_dest)
def insert_vrf_path(self, ip_nlri, next_hop=None, gen_lbl=False, is_withdraw=False): assert ip_nlri pattrs = None label_list = [] vrf_conf = self.vrf_conf if not is_withdraw: # Create a dictionary for path-attrs. pattrs = OrderedDict() # MpReachNlri and/or MpUnReachNlri attribute info. is contained # in the path. Hence we do not add these attributes here. from ryu.services.protocols.bgp.core import EXPECTED_ORIGIN pattrs[BGP_ATTR_TYPE_ORIGIN] = BGPPathAttributeOrigin( EXPECTED_ORIGIN) pattrs[BGP_ATTR_TYPE_AS_PATH] = BGPPathAttributeAsPath([]) pattrs[BGP_ATTR_TYPE_EXTENDED_COMMUNITIES] = \ BGPPathAttributeExtendedCommunities( rt_list=vrf_conf.export_rts, soo_list=vrf_conf.soo_list) if vrf_conf.multi_exit_disc: pattrs[BGP_ATTR_TYPE_MULTI_EXIT_DISC] = \ BGPPathAttributeMultiExitDisc(vrf_conf.multi_exit_disc) table_manager = self._core_service.table_manager if gen_lbl and next_hop: # Label per next_hop demands we use a different label # per next_hop. Here connected interfaces are advertised per # VRF. label_key = (vrf_conf.route_dist, next_hop) nh_label = table_manager.get_nexthop_label(label_key) if not nh_label: nh_label = table_manager.get_next_vpnv4_label() table_manager.set_nexthop_label(label_key, nh_label) label_list.append(nh_label) elif gen_lbl: # If we do not have next_hop, get a new label. label_list.append(table_manager.get_next_vpnv4_label()) puid = self.VRF_PATH_CLASS.create_puid(vrf_conf.route_dist, ip_nlri.prefix) path = self.VRF_PATH_CLASS(puid, None, ip_nlri, 0, pattrs=pattrs, nexthop=next_hop, label_list=label_list, is_withdraw=is_withdraw) # Insert the path into VRF table, get affected destination so that we # can process it further. eff_dest = self.insert(path) # Enqueue the eff_dest for further processing. self._signal_bus.dest_changed(eff_dest) return label_list
def get_configured_capabilites(self): """Returns configured capabilities.""" capabilities = OrderedDict() mbgp_caps = [] if self.cap_mbgp_ipv4: mbgp_caps.append(MultiprotocolExtentionCap(RF_IPv4_UC)) if self.cap_mbgp_vpnv4: mbgp_caps.append(MultiprotocolExtentionCap(RF_IPv4_VPN)) if self.cap_mbgp_vpnv6: mbgp_caps.append(MultiprotocolExtentionCap(RF_IPv6_VPN)) if self.cap_rtc: mbgp_caps.append(MultiprotocolExtentionCap(RF_RTC_UC)) if mbgp_caps: capabilities[MultiprotocolExtentionCap.CODE] = mbgp_caps if self.cap_refresh: capabilities[RouteRefreshCap.CODE] = [ RouteRefreshCap.get_singleton() ] if self.cap_enhanced_refresh: capabilities[EnhancedRouteRefreshCap.CODE] = [ EnhancedRouteRefreshCap.get_singleton() ] return capabilities
def get_configured_capabilities(self): """Returns configured capabilities.""" capabilities = OrderedDict() mbgp_caps = [] if self.cap_mbgp_ipv4: mbgp_caps.append( BGPOptParamCapabilityMultiprotocol( RF_IPv4_UC.afi, RF_IPv4_UC.safi)) if self.cap_mbgp_ipv6: mbgp_caps.append( BGPOptParamCapabilityMultiprotocol( RF_IPv6_UC.afi, RF_IPv6_UC.safi)) if self.cap_mbgp_vpnv4: mbgp_caps.append( BGPOptParamCapabilityMultiprotocol( RF_IPv4_VPN.afi, RF_IPv4_VPN.safi)) if self.cap_mbgp_vpnv6: mbgp_caps.append( BGPOptParamCapabilityMultiprotocol( RF_IPv6_VPN.afi, RF_IPv6_VPN.safi)) if self.cap_rtc: mbgp_caps.append( BGPOptParamCapabilityMultiprotocol( RF_RTC_UC.afi, RF_RTC_UC.safi)) if self.cap_mbgp_evpn: mbgp_caps.append( BGPOptParamCapabilityMultiprotocol( RF_L2_EVPN.afi, RF_L2_EVPN.safi)) if mbgp_caps: capabilities[BGP_CAP_MULTIPROTOCOL] = mbgp_caps if self.cap_refresh: capabilities[BGP_CAP_ROUTE_REFRESH] = [ BGPOptParamCapabilityRouteRefresh()] if self.cap_enhanced_refresh: capabilities[BGP_CAP_ENHANCED_ROUTE_REFRESH] = [ BGPOptParamCapabilityEnhancedRouteRefresh()] if self.cap_four_octet_as_number: capabilities[BGP_CAP_FOUR_OCTET_AS_NUMBER] = [ BGPOptParamCapabilityFourOctetAsNumber(self.local_as)] return capabilities
def _add_rt_nlri_for_as(self, rtc_as, route_target, is_withdraw=False): from ryu.services.protocols.bgp.core import EXPECTED_ORIGIN rt_nlri = RtNlri(rtc_as, route_target) # Create a dictionary for path-attrs. pattrs = OrderedDict() if not is_withdraw: # MpReachNlri and/or MpUnReachNlri attribute info. is contained # in the path. Hence we do not add these attributes here. pattrs[Origin.ATTR_NAME] = Origin(EXPECTED_ORIGIN) pattrs[AsPath.ATTR_NAME] = AsPath([]) # Create Path instance and initialize appropriately. path = RtcPath(None, rt_nlri, 0, is_withdraw=is_withdraw, pattrs=pattrs) tm = self._core_service.table_manager tm.learn_path(path)
def get_configured_capabilites(self): """Returns configured capabilities.""" capabilities = OrderedDict() mbgp_caps = [] if self.cap_mbgp_ipv4: mbgp_caps.append( BGPOptParamCapabilityMultiprotocol(RF_IPv4_UC.afi, RF_IPv4_UC.safi)) if self.cap_mbgp_ipv6: mbgp_caps.append( BGPOptParamCapabilityMultiprotocol(RF_IPv6_UC.afi, RF_IPv6_UC.safi)) if self.cap_mbgp_vpnv4: mbgp_caps.append( BGPOptParamCapabilityMultiprotocol(RF_IPv4_VPN.afi, RF_IPv4_VPN.safi)) if self.cap_mbgp_vpnv6: mbgp_caps.append( BGPOptParamCapabilityMultiprotocol(RF_IPv6_VPN.afi, RF_IPv6_VPN.safi)) if self.cap_rtc: mbgp_caps.append( BGPOptParamCapabilityMultiprotocol(RF_RTC_UC.afi, RF_RTC_UC.safi)) if mbgp_caps: capabilities[BGP_CAP_MULTIPROTOCOL] = mbgp_caps if self.cap_refresh: capabilities[BGP_CAP_ROUTE_REFRESH] = [ BGPOptParamCapabilityRouteRefresh() ] if self.cap_enhanced_refresh: capabilities[BGP_CAP_ENHANCED_ROUTE_REFRESH] = [ BGPOptParamCapabilityEnhancedRouteRefresh() ] if self.enable_uri: capabilities[ENABLE_URI] = [BGPOptParamCapabilityEnableUri()] return capabilities
def __init__(self, source, nlri, src_ver_num, pattrs=None, nexthop=None, is_withdraw=False, med_set_by_target_neighbor=False): """Initializes Ipv4 path. If this path is not a withdraw, then path attribute and nexthop both should be provided. Parameters: - `source`: (Peer/str) source of this path. - `nlri`: (Vpnv4) Nlri instance for Vpnv4 route family. - `src_ver_num`: (int) version number of *source* when this path was learned. - `pattrs`: (OrderedDict) various path attributes for this path. - `nexthop`: (str) nexthop advertised for this path. - `is_withdraw`: (bool) True if this represents a withdrawal. """ self.med_set_by_target_neighbor = med_set_by_target_neighbor if nlri.ROUTE_FAMILY != self.__class__.ROUTE_FAMILY: raise ValueError('NLRI and Path route families do not' ' match (%s, %s).' % (nlri.ROUTE_FAMILY, self.__class__.ROUTE_FAMILY)) # Currently paths injected directly into VRF has only one source # src_peer can be None to denote NC else has to be instance of Peer. # Paths can be exported from one VRF and then imported into another # VRF, in such cases it source is denoted as string VPN_TABLE. if not (source is None or hasattr(source, 'version_num') or source in (VRF_TABLE, VPN_TABLE)): raise ValueError('Invalid or Unsupported source for path: %s' % source) # If this path is not a withdraw path, than it should have path- # attributes and nexthop. if not is_withdraw and not (pattrs and nexthop): raise ValueError('Need to provide nexthop and patattrs ' 'for path that is not a withdraw.') # The entity (peer) that gave us this path. self._source = source # Path attribute of this path. if pattrs: self._path_attr_map = copy(pattrs) else: self._path_attr_map = OrderedDict() # NLRI that this path represents. self._nlri = nlri # If given nlri is withdrawn. self._is_withdraw = is_withdraw # @see Source.version_num self._source_version_num = src_ver_num self._nexthop = nexthop # Automatically generated. # # self.next_path # self.prev_path # The Destination from which this path was exported, if any. self._exported_from = None
class Path(object): """Represents a way of reaching an IP destination. Also contains other meta-data given to us by a specific source (such as a peer). """ __metaclass__ = ABCMeta __slots__ = ('_source', '_path_attr_map', '_nlri', '_source_version_num', '_exported_from', '_nexthop', 'next_path', 'prev_path', '_is_withdraw', 'med_set_by_target_neighbor') ROUTE_FAMILY = RF_IPv4_UC def __init__(self, source, nlri, src_ver_num, pattrs=None, nexthop=None, is_withdraw=False, med_set_by_target_neighbor=False): """Initializes Ipv4 path. If this path is not a withdraw, then path attribute and nexthop both should be provided. Parameters: - `source`: (Peer/str) source of this path. - `nlri`: (Vpnv4) Nlri instance for Vpnv4 route family. - `src_ver_num`: (int) version number of *source* when this path was learned. - `pattrs`: (OrderedDict) various path attributes for this path. - `nexthop`: (str) nexthop advertised for this path. - `is_withdraw`: (bool) True if this represents a withdrawal. """ self.med_set_by_target_neighbor = med_set_by_target_neighbor if nlri.ROUTE_FAMILY != self.__class__.ROUTE_FAMILY: raise ValueError('NLRI and Path route families do not' ' match (%s, %s).' % (nlri.ROUTE_FAMILY, self.__class__.ROUTE_FAMILY)) # Currently paths injected directly into VRF has only one source # src_peer can be None to denote NC else has to be instance of Peer. # Paths can be exported from one VRF and then imported into another # VRF, in such cases it source is denoted as string VPN_TABLE. if not (source is None or hasattr(source, 'version_num') or source in (VRF_TABLE, VPN_TABLE)): raise ValueError('Invalid or Unsupported source for path: %s' % source) # If this path is not a withdraw path, than it should have path- # attributes and nexthop. if not is_withdraw and not (pattrs and nexthop): raise ValueError('Need to provide nexthop and patattrs ' 'for path that is not a withdraw.') # The entity (peer) that gave us this path. self._source = source # Path attribute of this path. if pattrs: self._path_attr_map = copy(pattrs) else: self._path_attr_map = OrderedDict() # NLRI that this path represents. self._nlri = nlri # If given nlri is withdrawn. self._is_withdraw = is_withdraw # @see Source.version_num self._source_version_num = src_ver_num self._nexthop = nexthop # Automatically generated. # # self.next_path # self.prev_path # The Destination from which this path was exported, if any. self._exported_from = None @property def source_version_num(self): return self._source_version_num @property def source(self): return self._source @property def route_family(self): return self.__class__.ROUTE_FAMILY @property def nlri(self): return self._nlri @property def is_withdraw(self): return self._is_withdraw @property def pathattr_map(self): return copy(self._path_attr_map) @property def nexthop(self): return self._nexthop def get_pattr(self, pattr_type, default=None): """Returns path attribute of given type. Returns None if we do not attribute of type *pattr_type*. """ return self._path_attr_map.get(pattr_type, default) def clone(self, for_withdrawal=False): pathattrs = None if not for_withdrawal: pathattrs = self.pathattr_map clone = self.__class__( self.source, self.nlri, self.source_version_num, pattrs=pathattrs, nexthop=self.nexthop, is_withdraw=for_withdrawal ) return clone def get_rts(self): extcomm_attr = self._path_attr_map.get( BGP_ATTR_TYPE_EXTENDED_COMMUNITIES) if extcomm_attr is None: rts = [] else: rts = extcomm_attr.rt_list return rts def has_rts_in(self, interested_rts): """Returns True if this `Path` has any `ExtCommunity` attribute route target common with `interested_rts`. """ assert isinstance(interested_rts, set) curr_rts = self.get_rts() # Add default RT to path RTs so that we match interest for peers who # advertised default RT curr_rts.append(RouteTargetMembershipNLRI.DEFAULT_RT) return not interested_rts.isdisjoint(curr_rts) def __str__(self): return ( 'Path(source: %s, nlri: %s, source ver#: %s, ' 'path attrs.: %s, nexthop: %s, is_withdraw: %s)' % ( self._source, self._nlri, self._source_version_num, self._path_attr_map, self._nexthop, self._is_withdraw ) ) def __repr__(self): 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))
def insert_vrf_path(self, nlri, next_hop=None, gen_lbl=False, is_withdraw=False, **kwargs): assert nlri pattrs = None label_list = [] vrf_conf = self.vrf_conf if not is_withdraw: table_manager = self._core_service.table_manager if gen_lbl and next_hop: # Label per next_hop demands we use a different label # per next_hop. Here connected interfaces are advertised per # VRF. label_key = (vrf_conf.route_dist, next_hop) nh_label = table_manager.get_nexthop_label(label_key) if not nh_label: nh_label = table_manager.get_next_vpnv4_label() table_manager.set_nexthop_label(label_key, nh_label) label_list.append(nh_label) elif gen_lbl: # If we do not have next_hop, get a new label. label_list.append(table_manager.get_next_vpnv4_label()) # Set MPLS labels with the generated labels if gen_lbl and isinstance(nlri, EvpnMacIPAdvertisementNLRI): nlri.mpls_labels = label_list[:2] elif gen_lbl and isinstance(nlri, EvpnIpPrefixNLRI): nlri.mpls_label = label_list[0] # Create a dictionary for path-attrs. pattrs = OrderedDict() # MpReachNlri and/or MpUnReachNlri attribute info. is contained # in the path. Hence we do not add these attributes here. from ryu.services.protocols.bgp.core import EXPECTED_ORIGIN pattrs[BGP_ATTR_TYPE_ORIGIN] = BGPPathAttributeOrigin( EXPECTED_ORIGIN) pattrs[BGP_ATTR_TYPE_AS_PATH] = BGPPathAttributeAsPath([]) communities = [] # Set ES-Import Route Target if isinstance(nlri, EvpnEthernetSegmentNLRI): subtype = 2 es_import = nlri.esi.mac_addr communities.append( BGPEvpnEsImportRTExtendedCommunity(subtype=subtype, es_import=es_import)) for rt in vrf_conf.export_rts: communities.append(create_rt_extended_community(rt, 2)) for soo in vrf_conf.soo_list: communities.append(create_rt_extended_community(soo, 3)) # Set Tunnel Encapsulation Attribute tunnel_type = kwargs.get('tunnel_type', None) if tunnel_type: communities.append( BGPEncapsulationExtendedCommunity.from_str(tunnel_type)) # Set ESI Label Extended Community redundancy_mode = kwargs.get('redundancy_mode', None) if redundancy_mode is not None: subtype = 1 flags = 0 from ryu.services.protocols.bgp.api.prefix import ( REDUNDANCY_MODE_SINGLE_ACTIVE) if redundancy_mode == REDUNDANCY_MODE_SINGLE_ACTIVE: flags |= BGPEvpnEsiLabelExtendedCommunity.SINGLE_ACTIVE_BIT vni = kwargs.get('vni', None) if vni is not None: communities.append( BGPEvpnEsiLabelExtendedCommunity(subtype=subtype, flags=flags, vni=vni)) else: communities.append( BGPEvpnEsiLabelExtendedCommunity( subtype=subtype, flags=flags, mpls_label=label_list[0])) pattrs[BGP_ATTR_TYPE_EXTENDED_COMMUNITIES] = \ BGPPathAttributeExtendedCommunities(communities=communities) if vrf_conf.multi_exit_disc: pattrs[BGP_ATTR_TYPE_MULTI_EXIT_DISC] = \ BGPPathAttributeMultiExitDisc(vrf_conf.multi_exit_disc) # Set PMSI Tunnel Attribute pmsi_tunnel_type = kwargs.get('pmsi_tunnel_type', None) if pmsi_tunnel_type is not None: from ryu.services.protocols.bgp.api.prefix import ( PMSI_TYPE_INGRESS_REP) if pmsi_tunnel_type == PMSI_TYPE_INGRESS_REP: tunnel_id = PmsiTunnelIdIngressReplication( tunnel_endpoint_ip=self._core_service.router_id) else: # pmsi_tunnel_type == PMSI_TYPE_NO_TUNNEL_INFO tunnel_id = None pattrs[BGP_ATTR_TYEP_PMSI_TUNNEL_ATTRIBUTE] = \ BGPPathAttributePmsiTunnel(pmsi_flags=0, tunnel_type=pmsi_tunnel_type, tunnel_id=tunnel_id, vni=kwargs.get('vni', None)) puid = self.VRF_PATH_CLASS.create_puid(vrf_conf.route_dist, nlri.prefix) path = self.VRF_PATH_CLASS(puid, None, nlri, 0, pattrs=pattrs, nexthop=next_hop, label_list=label_list, is_withdraw=is_withdraw) # Insert the path into VRF table, get affected destination so that we # can process it further. eff_dest = self.insert(path) # Enqueue the eff_dest for further processing. self._signal_bus.dest_changed(eff_dest) return label_list
def insert_vrf_path(self, nlri, next_hop=None, gen_lbl=False, is_withdraw=False, **kwargs): assert nlri pattrs = None label_list = [] vrf_conf = self.vrf_conf if not is_withdraw: # Create a dictionary for path-attrs. pattrs = OrderedDict() # MpReachNlri and/or MpUnReachNlri attribute info. is contained # in the path. Hence we do not add these attributes here. from ryu.services.protocols.bgp.core import EXPECTED_ORIGIN pattrs[BGP_ATTR_TYPE_ORIGIN] = BGPPathAttributeOrigin( EXPECTED_ORIGIN) pattrs[BGP_ATTR_TYPE_AS_PATH] = BGPPathAttributeAsPath([]) communities = [] for rt in vrf_conf.export_rts: as_num, local_admin = rt.split(':') subtype = 2 communities.append( BGPTwoOctetAsSpecificExtendedCommunity( as_number=int(as_num), local_administrator=int(local_admin), subtype=subtype)) for soo in vrf_conf.soo_list: as_num, local_admin = soo.split(':') subtype = 3 communities.append( BGPTwoOctetAsSpecificExtendedCommunity( as_number=int(as_num), local_administrator=int(local_admin), subtype=subtype)) # Set Tunnel Encapsulation Attribute tunnel_type = kwargs.get('tunnel_type', None) if tunnel_type: communities.append( BGPEncapsulationExtendedCommunity.from_str(tunnel_type)) pattrs[BGP_ATTR_TYPE_EXTENDED_COMMUNITIES] = \ BGPPathAttributeExtendedCommunities(communities=communities) if vrf_conf.multi_exit_disc: pattrs[BGP_ATTR_TYPE_MULTI_EXIT_DISC] = \ BGPPathAttributeMultiExitDisc(vrf_conf.multi_exit_disc) table_manager = self._core_service.table_manager if gen_lbl and next_hop: # Label per next_hop demands we use a different label # per next_hop. Here connected interfaces are advertised per # VRF. label_key = (vrf_conf.route_dist, next_hop) nh_label = table_manager.get_nexthop_label(label_key) if not nh_label: nh_label = table_manager.get_next_vpnv4_label() table_manager.set_nexthop_label(label_key, nh_label) label_list.append(nh_label) elif gen_lbl: # If we do not have next_hop, get a new label. label_list.append(table_manager.get_next_vpnv4_label()) # Set PMSI Tunnel Attribute pmsi_tunnel_type = kwargs.get('pmsi_tunnel_type', None) if pmsi_tunnel_type is not None: from ryu.services.protocols.bgp.api.prefix import ( PMSI_TYPE_INGRESS_REP) if pmsi_tunnel_type == PMSI_TYPE_INGRESS_REP: tunnel_id = PmsiTunnelIdIngressReplication( tunnel_endpoint_ip=self._core_service.router_id) else: # pmsi_tunnel_type == PMSI_TYPE_NO_TUNNEL_INFO tunnel_id = None pattrs[BGP_ATTR_TYEP_PMSI_TUNNEL_ATTRIBUTE] = \ BGPPathAttributePmsiTunnel(pmsi_flags=0, tunnel_type=pmsi_tunnel_type, tunnel_id=tunnel_id) # Set MPLS labels with the generated labels if gen_lbl and isinstance(nlri, EvpnMacIPAdvertisementNLRI): nlri.mpls_labels = label_list[:2] puid = self.VRF_PATH_CLASS.create_puid(vrf_conf.route_dist, nlri.prefix) path = self.VRF_PATH_CLASS(puid, None, nlri, 0, pattrs=pattrs, nexthop=next_hop, label_list=label_list, is_withdraw=is_withdraw) # Insert the path into VRF table, get affected destination so that we # can process it further. eff_dest = self.insert(path) # Enqueue the eff_dest for further processing. self._signal_bus.dest_changed(eff_dest) return label_list