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

Generated by: LCOV version 1.14