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: 187 199 94.0 %
Date: 2026-06-08 02:02:55 Functions: 14 15 93.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     1266482 : string BgpPath::PathIdString(uint32_t path_id) {
      19     1266482 :     Ip4Address addr(path_id);
      20     2532959 :     return addr.to_string();
      21             : }
      22             : 
      23      918945 : BgpPath::BgpPath(const IPeer *peer, uint32_t path_id, PathSource src,
      24             :                  const BgpAttrPtr ptr, uint32_t flags, uint32_t label,
      25      918945 :                  uint32_t l3_label)
      26      918930 :     : peer_(peer), path_id_(path_id), source_(src), attr_(ptr),
      27      918945 :       original_attr_(ptr), flags_(flags), label_(label), l3_label_(l3_label) {
      28      918974 : }
      29             : 
      30         889 : BgpPath::BgpPath(const IPeer *peer, PathSource src, const BgpAttrPtr ptr,
      31         889 :         uint32_t flags, uint32_t label, uint32_t l3_label)
      32         889 :     : peer_(peer), path_id_(0), source_(src), attr_(ptr), original_attr_(ptr),
      33         889 :       flags_(flags), label_(label), l3_label_(l3_label) {
      34         889 : }
      35             : 
      36       46928 : BgpPath::BgpPath(uint32_t path_id, PathSource src, const BgpAttrPtr ptr,
      37       46928 :         uint32_t flags, uint32_t label, uint32_t l3_label)
      38       46928 :     : peer_(NULL), path_id_(path_id), source_(src), attr_(ptr),
      39       46928 :       original_attr_(ptr), flags_(flags), label_(label), l3_label_(l3_label) {
      40       46928 : }
      41             : 
      42         193 : BgpPath::BgpPath(PathSource src, const BgpAttrPtr ptr,
      43         193 :         uint32_t flags, uint32_t label, uint32_t l3_label)
      44         193 :     : peer_(NULL), path_id_(0), source_(src), attr_(ptr), original_attr_(ptr),
      45         193 :       flags_(flags), label_(label), l3_label_(l3_label) {
      46         193 : }
      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     2371957 : int BgpPath::PathCompare(const BgpPath &rhs, bool allow_ecmp) const {
      59     2371957 :     const BgpAttr *rattr = rhs.GetAttr();
      60             : 
      61             :     // Feasible Path first
      62     2371967 :     KEY_COMPARE(rhs.IsFeasible(), IsFeasible());
      63             : 
      64             :     // Compare local_pref in reverse order as larger is better.
      65     2356628 :     KEY_COMPARE(rattr->local_pref(), attr_->local_pref());
      66             : 
      67             :     // ETree Root path first [compare in reverse order]
      68     2354462 :     BOOL_COMPARE(rattr->etree_leaf(), attr_->etree_leaf());
      69             : 
      70             :     // Sticky paths first
      71     2354410 :     BOOL_COMPARE(rattr->evpn_sticky_mac(), attr_->evpn_sticky_mac());
      72             : 
      73             :     // Compare sequence_number in reverse order as larger is better.
      74     2354400 :     KEY_COMPARE(rattr->sequence_number(), attr_->sequence_number());
      75             : 
      76             :     // Route without LLGR_STALE community is always preferred over one with.
      77     2354438 :     bool llgr_stale = attr_->community() && attr_->community()->ContainsValue(
      78     2354470 :                                                 CommunityType::LlgrStale);
      79     2354470 :     llgr_stale |= IsLlgrStale();
      80             : 
      81     2354480 :     bool rllgr_stale = rattr->community() && rattr->community()->ContainsValue(
      82     2354474 :                                                  CommunityType::LlgrStale);
      83     2354474 :     rllgr_stale |= rhs.IsLlgrStale();
      84             : 
      85     2354471 :     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     2353817 :     const BgpServer *server = attr_->attr_db()->server();
      91     4742278 :     if (!server->ignore_aspath() &&
      92     2388466 :             (!attr_->origin_vn_path() || !rattr->origin_vn_path())) {
      93     2320468 :         KEY_COMPARE(attr_->max_as_path_count(), rattr->max_as_path_count());
      94             :     }
      95             : 
      96     2350498 :     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     4700866 :     if (server->global_config()->always_compare_med() ||
     101     2350438 :         (attr_->neighbor_as() &&
     102      147133 :          attr_->neighbor_as() == rattr->neighbor_as())) {
     103      146110 :         KEY_COMPARE(attr_->med(), rattr->med());
     104             :     }
     105             : 
     106             :     // For ECMP paths, above checks should suffice.
     107     2350418 :     if (allow_ecmp)
     108      553424 :         return 0;
     109             : 
     110             :     // Prefer non-aliased paths.
     111     1796994 :     BOOL_COMPARE(rhs.IsAliased(), IsAliased());
     112             : 
     113             :     // Compare as path length for service chain paths since we bypassed the
     114             :     // check previously.
     115     1796941 :     if (attr_->origin_vn_path() && rattr->origin_vn_path())
     116       11844 :         KEY_COMPARE(attr_->max_as_path_count(), rattr->max_as_path_count());
     117             : 
     118             :     // Prefer locally generated routes over bgp and xmpp routes.
     119     1796941 :     BOOL_COMPARE(peer_ == NULL, rhs.peer_ == NULL);
     120             : 
     121             :     // Compare the source and the path id.
     122     1790823 :     KEY_COMPARE(rhs.GetSource(), GetSource());
     123             : 
     124             :     // Bail if both paths are local since all subsequent checks are
     125             :     // based on IPeer properties.
     126     1789281 :     if (peer_ == NULL && rhs.peer_ == NULL) {
     127     1575633 :         KEY_COMPARE(path_id_, rhs.path_id_);
     128     1561800 :         return 0;
     129             :     }
     130             : 
     131             :     // Prefer xmpp routes over bgp routes.
     132      213648 :     BOOL_COMPARE(peer_->IsXmppPeer(), rhs.peer_->IsXmppPeer());
     133             : 
     134             :     // Path received from EBGP is better than the one received from IBGP
     135      198794 :     KEY_COMPARE(peer_->PeerType() == BgpProto::IBGP,
     136             :                 rhs.peer_->PeerType() == BgpProto::IBGP);
     137             : 
     138      198770 :     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      191169 :     uint32_t orig_id = attr_->originator_id().to_ulong();
     143      191169 :     uint32_t rorig_id = rattr->originator_id().to_ulong();
     144      191169 :     uint32_t id = orig_id ? orig_id : peer_->bgp_identifier();
     145      191169 :     uint32_t rid = rorig_id ? rorig_id : rhs.peer_->bgp_identifier();
     146      191169 :     KEY_COMPARE(id, rid);
     147             : 
     148       80127 :     KEY_COMPARE(attr_->cluster_list_length(), rattr->cluster_list_length());
     149             : 
     150       80123 :     const BgpPeer *lpeer = dynamic_cast<const BgpPeer *>(peer_);
     151       80123 :     const BgpPeer *rpeer = dynamic_cast<const BgpPeer *>(rhs.peer_);
     152       80123 :     if (lpeer != NULL && rpeer != NULL) {
     153         876 :         KEY_COMPARE(lpeer->peer_key(), rpeer->peer_key());
     154             :     }
     155             : 
     156       80067 :     return 0;
     157             : }
     158             : 
     159         186 : bool BgpPath::PathSameNeighborAs(const BgpPath &rhs) const {
     160         186 :     const BgpAttr *rattr = rhs.GetAttr();
     161         186 :     if (!peer_ || peer_->PeerType() != BgpProto::EBGP)
     162           2 :         return false;
     163         184 :     if (!rhs.peer_ || rhs.peer_->PeerType() != BgpProto::EBGP)
     164           2 :         return false;
     165         182 :     return (attr_->neighbor_as() == rattr->neighbor_as());
     166             : }
     167             : 
     168     1932979 : void BgpPath::UpdatePeerRefCount(int count, Address::Family family) const {
     169     1932979 :     if (!peer_)
     170      643456 :         return;
     171     1289523 :     peer_->UpdateTotalPathCount(count);
     172     1289695 :     if (source_ != BGP_XMPP || IsReplicated() || IsResolved() || IsAliased())
     173      804133 :         return;
     174      485523 :     peer_->UpdatePrimaryPathCount(count, family);
     175             : }
     176             : 
     177      815403 : string BgpPath::ToString() const {
     178      815403 :     return peer_ ? peer_->ToString() : "Nil";
     179             : }
     180             : 
     181        6170 : RouteDistinguisher BgpPath::GetSourceRouteDistinguisher() const {
     182        6170 :     if (!attr_->source_rd().IsZero())
     183        6169 :         return attr_->source_rd();
     184           3 :     if (!IsReplicated())
     185           1 :         return RouteDistinguisher::kZeroRd;
     186             : 
     187           2 :     const BgpSecondaryPath *path = static_cast<const BgpSecondaryPath *>(this);
     188           2 :     return path->GetPrimaryRouteDistinguisher();
     189             : }
     190             : 
     191        5585 : vector<string> BgpPath::GetFlagsStringList() const {
     192        5585 :     vector<string> flag_names;
     193        5604 :     if (flags_ == 0) {
     194        5599 :         flag_names.push_back("None");
     195        5581 :         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           5 :     vector<PathFlag> flags;
     202           5 :     if (flags_ & AsPathLooped)
     203           1 :         flags.push_back(AsPathLooped);
     204           5 :     if (flags_ & NoNeighborAs)
     205           1 :         flags.push_back(NoNeighborAs);
     206           5 :     if (flags_ & Stale)
     207           1 :         flags.push_back(Stale);
     208           5 :     if (flags_ & NoTunnelEncap)
     209           1 :         flags.push_back(NoTunnelEncap);
     210           5 :     if (flags_ & OriginatorIdLooped)
     211           1 :         flags.push_back(OriginatorIdLooped);
     212           5 :     if (flags_ & ResolveNexthop)
     213           5 :         flags.push_back(ResolveNexthop);
     214           5 :     if (flags_ & ResolvedPath)
     215           1 :         flags.push_back(ResolvedPath);
     216           5 :     if (flags_ & RoutingPolicyReject)
     217           1 :         flags.push_back(RoutingPolicyReject);
     218           5 :     if (flags_ & LlgrStale)
     219           1 :         flags.push_back(LlgrStale);
     220           5 :     if (flags_ & ClusterListLooped)
     221           1 :         flags.push_back(ClusterListLooped);
     222           5 :     if (flags_ & AliasedPath)
     223           1 :         flags.push_back(AliasedPath);
     224           5 :     if (flags_ & CheckGlobalErmVpnRoute)
     225           1 :         flags.push_back(CheckGlobalErmVpnRoute);
     226             : 
     227          21 :     for (auto flag : flags) {
     228          16 :         switch (flag) {
     229           1 :         case AsPathLooped:
     230           1 :             flag_names.push_back("AsPathLooped");
     231           1 :             break;
     232           1 :         case NoNeighborAs:
     233           1 :             flag_names.push_back("NoNeighborAs");
     234           1 :             break;
     235           1 :         case Stale:
     236           1 :             flag_names.push_back("Stale");
     237           1 :             break;
     238           1 :         case NoTunnelEncap:
     239           1 :             flag_names.push_back("NoTunnelEncap");
     240           1 :             break;
     241           1 :         case OriginatorIdLooped:
     242           1 :             flag_names.push_back("OriginatorIdLooped");
     243           1 :             break;
     244           5 :         case ResolveNexthop:
     245           5 :             flag_names.push_back("ResolveNexthop");
     246           5 :             break;
     247           1 :         case ResolvedPath:
     248           1 :             flag_names.push_back("ResolvedPath");
     249           1 :             break;
     250           1 :         case RoutingPolicyReject:
     251           1 :             flag_names.push_back("RoutingPolicyReject");
     252           1 :             break;
     253           1 :         case LlgrStale:
     254           1 :             flag_names.push_back("LlgrStale");
     255           1 :             break;
     256           1 :         case ClusterListLooped:
     257           1 :             flag_names.push_back("ClusterListLooped");
     258           1 :             break;
     259           1 :         case AliasedPath:
     260           1 :             flag_names.push_back("AliasedPath");
     261           1 :             break;
     262           1 :         case CheckGlobalErmVpnRoute:
     263           1 :             flag_names.push_back("CheckGlobalErmVpnRoute");
     264           1 :             break;
     265             :         }
     266             :     }
     267           5 :     return flag_names;
     268           5 : }
     269             : 
     270        7237 : string BgpPath::GetSourceString(bool combine_bgp_and_xmpp) const {
     271        7237 :     switch (source_) {
     272           2 :     case None:
     273           2 :         return "None";
     274        6466 :     case BGP_XMPP:
     275        6466 :         if (combine_bgp_and_xmpp) {
     276         321 :             return "BGP_XMPP";
     277        6145 :         } else if (peer_) {
     278        5998 :             return(peer_->IsXmppPeer() ? "XMPP" : "BGP");
     279             :         } else {
     280         147 :             return "None";
     281             :         }
     282         482 :     case ServiceChain:
     283         482 :         return "ServiceChain";
     284          34 :     case StaticRoute:
     285          34 :         return "StaticRoute";
     286         190 :     case Aggregate:
     287         190 :         return "Aggregate";
     288          63 :     case Local:
     289          63 :         return "Local";
     290             :     }
     291           0 :     return "None";
     292             : }
     293             : 
     294      579614 : BgpSecondaryPath::BgpSecondaryPath(const IPeer *peer, uint32_t path_id,
     295             :         PathSource src, const BgpAttrPtr ptr, uint32_t flags, uint32_t label,
     296      579614 :         uint32_t l3_label)
     297      579614 :     : BgpPath(peer, path_id, src, ptr, flags, label, l3_label) {
     298      579624 : }
     299             : 
     300           2 : RouteDistinguisher BgpSecondaryPath::GetPrimaryRouteDistinguisher() const {
     301           2 :     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