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))