LCOV - code coverage report
Current view: top level - bgp - bgp_path.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 46 199 23.1 %
Date: 2026-09-21 02:11:39 Functions: 5 15 33.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include "bgp/bgp_path.h"
       6             : 
       7             : #include <boost/foreach.hpp>
       8             : 
       9             : #include "bgp/bgp_peer.h"
      10             : #include "bgp/bgp_route.h"
      11             : #include "bgp/bgp_server.h"
      12             : #include "bgp/extended-community/sub_cluster.h"
      13             : #include "net/community_type.h"
      14             : 
      15             : using std::string;
      16             : using std::vector;
      17             : 
      18           0 : string BgpPath::PathIdString(uint32_t path_id) {
      19           0 :     Ip4Address addr(path_id);
      20           0 :     return addr.to_string();
      21             : }
      22             : 
      23         564 : BgpPath::BgpPath(const IPeer *peer, uint32_t path_id, PathSource src,
      24             :                  const BgpAttrPtr ptr, uint32_t flags, uint32_t label,
      25         564 :                  uint32_t l3_label)
      26         564 :     : peer_(peer), path_id_(path_id), source_(src), attr_(ptr),
      27         564 :       original_attr_(ptr), flags_(flags), label_(label), l3_label_(l3_label) {
      28         564 : }
      29             : 
      30           0 : BgpPath::BgpPath(const IPeer *peer, PathSource src, const BgpAttrPtr ptr,
      31           0 :         uint32_t flags, uint32_t label, uint32_t l3_label)
      32           0 :     : peer_(peer), path_id_(0), source_(src), attr_(ptr), original_attr_(ptr),
      33           0 :       flags_(flags), label_(label), l3_label_(l3_label) {
      34           0 : }
      35             : 
      36          32 : BgpPath::BgpPath(uint32_t path_id, PathSource src, const BgpAttrPtr ptr,
      37          32 :         uint32_t flags, uint32_t label, uint32_t l3_label)
      38          32 :     : peer_(NULL), path_id_(path_id), source_(src), attr_(ptr),
      39          32 :       original_attr_(ptr), flags_(flags), label_(label), l3_label_(l3_label) {
      40          32 : }
      41             : 
      42           0 : BgpPath::BgpPath(PathSource src, const BgpAttrPtr ptr,
      43           0 :         uint32_t flags, uint32_t label, uint32_t l3_label)
      44           0 :     : peer_(NULL), path_id_(0), source_(src), attr_(ptr), original_attr_(ptr),
      45           0 :       flags_(flags), label_(label), l3_label_(l3_label) {
      46           0 : }
      47             : 
      48             : // True is better
      49             : #define BOOL_COMPARE(CondA, CondB)   \
      50             :     do {                                \
      51             :         if (CondA) {                    \
      52             :             if (!(CondB)) return -1;    \
      53             :         } else {                        \
      54             :             if (CondB) return 1;        \
      55             :         }                               \
      56             :     } while (0)
      57             : 
      58         544 : int BgpPath::PathCompare(const BgpPath &rhs, bool allow_ecmp) const {
      59         544 :     const BgpAttr *rattr = rhs.GetAttr();
      60             : 
      61             :     // Feasible Path first
      62         544 :     KEY_COMPARE(rhs.IsFeasible(), IsFeasible());
      63             : 
      64             :     // Compare local_pref in reverse order as larger is better.
      65         544 :     KEY_COMPARE(rattr->local_pref(), attr_->local_pref());
      66             : 
      67             :     // ETree Root path first [compare in reverse order]
      68         544 :     BOOL_COMPARE(rattr->etree_leaf(), attr_->etree_leaf());
      69             : 
      70             :     // Sticky paths first
      71         544 :     BOOL_COMPARE(rattr->evpn_sticky_mac(), attr_->evpn_sticky_mac());
      72             : 
      73             :     // Compare sequence_number in reverse order as larger is better.
      74         544 :     KEY_COMPARE(rattr->sequence_number(), attr_->sequence_number());
      75             : 
      76             :     // Route without LLGR_STALE community is always preferred over one with.
      77         544 :     bool llgr_stale = attr_->community() && attr_->community()->ContainsValue(
      78         544 :                                                 CommunityType::LlgrStale);
      79         544 :     llgr_stale |= IsLlgrStale();
      80             : 
      81         544 :     bool rllgr_stale = rattr->community() && rattr->community()->ContainsValue(
      82         544 :                                                  CommunityType::LlgrStale);
      83         544 :     rllgr_stale |= rhs.IsLlgrStale();
      84             : 
      85         544 :     KEY_COMPARE(llgr_stale, rllgr_stale);
      86             : 
      87             :     // Do not compare as path length for service chain paths at this point.
      88             :     // We want to treat service chain paths as ECMP irrespective of as path
      89             :     // length.
      90         544 :     const BgpServer *server = attr_->attr_db()->server();
      91        1088 :     if (!server->ignore_aspath() &&
      92         544 :             (!attr_->origin_vn_path() || !rattr->origin_vn_path())) {
      93         544 :         KEY_COMPARE(attr_->max_as_path_count(), rattr->max_as_path_count());
      94             :     }
      95             : 
      96         544 :     KEY_COMPARE(attr_->origin(), rattr->origin());
      97             : 
      98             :     // Compare med if always compare med knob is enabled or if both paths are
      99             :     // learnt from the same neighbor as.
     100        1088 :     if (server->global_config()->always_compare_med() ||
     101         544 :         (attr_->neighbor_as() &&
     102          98 :          attr_->neighbor_as() == rattr->neighbor_as())) {
     103          98 :         KEY_COMPARE(attr_->med(), rattr->med());
     104             :     }
     105             : 
     106             :     // For ECMP paths, above checks should suffice.
     107         544 :     if (allow_ecmp)
     108         544 :         return 0;
     109             : 
     110             :     // Prefer non-aliased paths.
     111           0 :     BOOL_COMPARE(rhs.IsAliased(), IsAliased());
     112             : 
     113             :     // Compare as path length for service chain paths since we bypassed the
     114             :     // check previously.
     115           0 :     if (attr_->origin_vn_path() && rattr->origin_vn_path())
     116           0 :         KEY_COMPARE(attr_->max_as_path_count(), rattr->max_as_path_count());
     117             : 
     118             :     // Prefer locally generated routes over bgp and xmpp routes.
     119           0 :     BOOL_COMPARE(peer_ == NULL, rhs.peer_ == NULL);
     120             : 
     121             :     // Compare the source and the path id.
     122           0 :     KEY_COMPARE(rhs.GetSource(), GetSource());
     123             : 
     124             :     // Bail if both paths are local since all subsequent checks are
     125             :     // based on IPeer properties.
     126           0 :     if (peer_ == NULL && rhs.peer_ == NULL) {
     127           0 :         KEY_COMPARE(path_id_, rhs.path_id_);
     128           0 :         return 0;
     129             :     }
     130             : 
     131             :     // Prefer xmpp routes over bgp routes.
     132           0 :     BOOL_COMPARE(peer_->IsXmppPeer(), rhs.peer_->IsXmppPeer());
     133             : 
     134             :     // Path received from EBGP is better than the one received from IBGP
     135           0 :     KEY_COMPARE(peer_->PeerType() == BgpProto::IBGP,
     136             :                 rhs.peer_->PeerType() == BgpProto::IBGP);
     137             : 
     138           0 :     KEY_COMPARE(path_id_, rhs.path_id_);
     139             : 
     140             :     // Lower router id is better. Substitute originator id for router id
     141             :     // if the path has an originator id.
     142           0 :     uint32_t orig_id = attr_->originator_id().to_ulong();
     143           0 :     uint32_t rorig_id = rattr->originator_id().to_ulong();
     144           0 :     uint32_t id = orig_id ? orig_id : peer_->bgp_identifier();
     145           0 :     uint32_t rid = rorig_id ? rorig_id : rhs.peer_->bgp_identifier();
     146           0 :     KEY_COMPARE(id, rid);
     147             : 
     148           0 :     KEY_COMPARE(attr_->cluster_list_length(), rattr->cluster_list_length());
     149             : 
     150           0 :     const BgpPeer *lpeer = dynamic_cast<const BgpPeer *>(peer_);
     151           0 :     const BgpPeer *rpeer = dynamic_cast<const BgpPeer *>(rhs.peer_);
     152           0 :     if (lpeer != NULL && rpeer != NULL) {
     153           0 :         KEY_COMPARE(lpeer->peer_key(), rpeer->peer_key());
     154             :     }
     155             : 
     156           0 :     return 0;
     157             : }
     158             : 
     159           0 : bool BgpPath::PathSameNeighborAs(const BgpPath &rhs) const {
     160           0 :     const BgpAttr *rattr = rhs.GetAttr();
     161           0 :     if (!peer_ || peer_->PeerType() != BgpProto::EBGP)
     162           0 :         return false;
     163           0 :     if (!rhs.peer_ || rhs.peer_->PeerType() != BgpProto::EBGP)
     164           0 :         return false;
     165           0 :     return (attr_->neighbor_as() == rattr->neighbor_as());
     166             : }
     167             : 
     168        1192 : void BgpPath::UpdatePeerRefCount(int count, Address::Family family) const {
     169        1192 :     if (!peer_)
     170         448 :         return;
     171         744 :     peer_->UpdateTotalPathCount(count);
     172         744 :     if (source_ != BGP_XMPP || IsReplicated() || IsResolved() || IsAliased())
     173         376 :         return;
     174         368 :     peer_->UpdatePrimaryPathCount(count, family);
     175             : }
     176             : 
     177           0 : string BgpPath::ToString() const {
     178           0 :     return peer_ ? peer_->ToString() : "Nil";
     179             : }
     180             : 
     181           0 : RouteDistinguisher BgpPath::GetSourceRouteDistinguisher() const {
     182           0 :     if (!attr_->source_rd().IsZero())
     183           0 :         return attr_->source_rd();
     184           0 :     if (!IsReplicated())
     185           0 :         return RouteDistinguisher::kZeroRd;
     186             : 
     187           0 :     const BgpSecondaryPath *path = static_cast<const BgpSecondaryPath *>(this);
     188           0 :     return path->GetPrimaryRouteDistinguisher();
     189             : }
     190             : 
     191           0 : vector<string> BgpPath::GetFlagsStringList() const {
     192           0 :     vector<string> flag_names;
     193           0 :     if (flags_ == 0) {
     194           0 :         flag_names.push_back("None");
     195           0 :         return flag_names;
     196             :     }
     197             : 
     198             :     // First we form a list of enums and then iterate over it to get their
     199             :     // string forms using switch. This lets compiler tell us when ever we add a
     200             :     // new enumeration to PathFlag.
     201           0 :     vector<PathFlag> flags;
     202           0 :     if (flags_ & AsPathLooped)
     203           0 :         flags.push_back(AsPathLooped);
     204           0 :     if (flags_ & NoNeighborAs)
     205           0 :         flags.push_back(NoNeighborAs);
     206           0 :     if (flags_ & Stale)
     207           0 :         flags.push_back(Stale);
     208           0 :     if (flags_ & NoTunnelEncap)
     209           0 :         flags.push_back(NoTunnelEncap);
     210           0 :     if (flags_ & OriginatorIdLooped)
     211           0 :         flags.push_back(OriginatorIdLooped);
     212           0 :     if (flags_ & ResolveNexthop)
     213           0 :         flags.push_back(ResolveNexthop);
     214           0 :     if (flags_ & ResolvedPath)
     215           0 :         flags.push_back(ResolvedPath);
     216           0 :     if (flags_ & RoutingPolicyReject)
     217           0 :         flags.push_back(RoutingPolicyReject);
     218           0 :     if (flags_ & LlgrStale)
     219           0 :         flags.push_back(LlgrStale);
     220           0 :     if (flags_ & ClusterListLooped)
     221           0 :         flags.push_back(ClusterListLooped);
     222           0 :     if (flags_ & AliasedPath)
     223           0 :         flags.push_back(AliasedPath);
     224           0 :     if (flags_ & CheckGlobalErmVpnRoute)
     225           0 :         flags.push_back(CheckGlobalErmVpnRoute);
     226             : 
     227           0 :     for (auto flag : flags) {
     228           0 :         switch (flag) {
     229           0 :         case AsPathLooped:
     230           0 :             flag_names.push_back("AsPathLooped");
     231           0 :             break;
     232           0 :         case NoNeighborAs:
     233           0 :             flag_names.push_back("NoNeighborAs");
     234           0 :             break;
     235           0 :         case Stale:
     236           0 :             flag_names.push_back("Stale");
     237           0 :             break;
     238           0 :         case NoTunnelEncap:
     239           0 :             flag_names.push_back("NoTunnelEncap");
     240           0 :             break;
     241           0 :         case OriginatorIdLooped:
     242           0 :             flag_names.push_back("OriginatorIdLooped");
     243           0 :             break;
     244           0 :         case ResolveNexthop:
     245           0 :             flag_names.push_back("ResolveNexthop");
     246           0 :             break;
     247           0 :         case ResolvedPath:
     248           0 :             flag_names.push_back("ResolvedPath");
     249           0 :             break;
     250           0 :         case RoutingPolicyReject:
     251           0 :             flag_names.push_back("RoutingPolicyReject");
     252           0 :             break;
     253           0 :         case LlgrStale:
     254           0 :             flag_names.push_back("LlgrStale");
     255           0 :             break;
     256           0 :         case ClusterListLooped:
     257           0 :             flag_names.push_back("ClusterListLooped");
     258           0 :             break;
     259           0 :         case AliasedPath:
     260           0 :             flag_names.push_back("AliasedPath");
     261           0 :             break;
     262           0 :         case CheckGlobalErmVpnRoute:
     263           0 :             flag_names.push_back("CheckGlobalErmVpnRoute");
     264           0 :             break;
     265             :         }
     266             :     }
     267           0 :     return flag_names;
     268           0 : }
     269             : 
     270           0 : string BgpPath::GetSourceString(bool combine_bgp_and_xmpp) const {
     271           0 :     switch (source_) {
     272           0 :     case None:
     273           0 :         return "None";
     274           0 :     case BGP_XMPP:
     275           0 :         if (combine_bgp_and_xmpp) {
     276           0 :             return "BGP_XMPP";
     277           0 :         } else if (peer_) {
     278           0 :             return(peer_->IsXmppPeer() ? "XMPP" : "BGP");
     279             :         } else {
     280           0 :             return "None";
     281             :         }
     282           0 :     case ServiceChain:
     283           0 :         return "ServiceChain";
     284           0 :     case StaticRoute:
     285           0 :         return "StaticRoute";
     286           0 :     case Aggregate:
     287           0 :         return "Aggregate";
     288           0 :     case Local:
     289           0 :         return "Local";
     290             :     }
     291           0 :     return "None";
     292             : }
     293             : 
     294         284 : BgpSecondaryPath::BgpSecondaryPath(const IPeer *peer, uint32_t path_id,
     295             :         PathSource src, const BgpAttrPtr ptr, uint32_t flags, uint32_t label,
     296         284 :         uint32_t l3_label)
     297         284 :     : BgpPath(peer, path_id, src, ptr, flags, label, l3_label) {
     298         284 : }
     299             : 
     300           0 : RouteDistinguisher BgpSecondaryPath::GetPrimaryRouteDistinguisher() const {
     301           0 :     return src_entry_->GetRouteDistinguisher();
     302             : }
     303             : 
     304           0 : void BgpPath::AddExtCommunitySubCluster(uint32_t subcluster_id) {
     305           0 :     BgpAttr *attr = new BgpAttr(*(GetOriginalAttr()));
     306           0 :     BgpServer *server = attr->attr_db()->server();
     307           0 :     ExtCommunityPtr ext_community = attr->ext_community();
     308             : 
     309           0 :     SubCluster sc(server->autonomous_system(), subcluster_id);
     310             :     ext_community = server->extcomm_db()->
     311           0 :         ReplaceSubClusterAndLocate(ext_community.get(),
     312           0 :                 sc.GetExtCommunity());
     313             :     BgpAttrPtr modified_attr = server->attr_db()->
     314           0 :         ReplaceExtCommunityAndLocate(attr, ext_community);
     315             :     // Since routing policies are applied only to original attribute hence
     316             :     // we are updating original_attr with subcluster extended community.
     317             :     // Also we need to set modified_attr in attr as well as orignal_attr,
     318             :     // because there may or may not be a policy but we still need to add this
     319             :     // community.
     320             :     // Modifying original attr should be done judiciously and only if required.
     321           0 :     if (modified_attr) {
     322           0 :         SetAttr(modified_attr, modified_attr);
     323             :     }
     324           0 : }

Generated by: LCOV version 1.14