LCOV - code coverage report
Current view: top level - bgp - bgp_ribout.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 303 322 94.1 %
Date: 2026-11-09 02:10:49 Functions: 30 33 90.9 %
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_ribout.h"
       7             : 
       8             : #include <boost/bind/bind.hpp>
       9             : 
      10             : #include <algorithm>
      11             : 
      12             : #include "sandesh/sandesh_trace.h"
      13             : #include "base/string_util.h"
      14             : #include "bgp/bgp_peer_types.h"
      15             : #include "bgp/bgp_ribout_updates.h"
      16             : #include "bgp/bgp_export.h"
      17             : #include "bgp/bgp_factory.h"
      18             : #include "bgp/bgp_route.h"
      19             : #include "bgp/bgp_server.h"
      20             : #include "bgp/bgp_table.h"
      21             : #include "bgp/bgp_update.h"
      22             : #include "bgp/bgp_update_sender.h"
      23             : #include "bgp/ipeer.h"
      24             : #include "bgp/routing-instance/routing_instance.h"
      25             : #include "db/db.h"
      26             : 
      27             : using std::find;
      28             : using namespace boost::placeholders;
      29             : 
      30      462934 : RibOutAttr::NextHop::NextHop(const BgpTable *table, IpAddress address,
      31             :     const MacAddress &mac, uint32_t label, uint32_t l3_label,
      32             :     const ExtCommunity *ext_community, const LargeCommunity *large_community,
      33      462934 :     bool vrf_originated)
      34      462934 :     : address_(address),
      35      462950 :       mac_(mac),
      36      462951 :       label_(label),
      37      462951 :       l3_label_(l3_label),
      38      462951 :       origin_vn_index_(-1) {
      39      462946 :       as_t asn = table ? table->server()->autonomous_system() : 0;
      40      925820 :       bool all = table ?
      41      462896 :           table->server()->global_config()->all_tags_are_global() : false;
      42      462924 :     if (large_community != nullptr) {
      43      445567 :         tag_list_ = large_community->GetTagList(all ? 0 : asn);
      44             :     }
      45      462852 :     if (ext_community != nullptr) {
      46      449307 :         encap_ = ext_community->GetTunnelEncap();
      47      449223 :         origin_vn_index_ = ext_community->GetOriginVnIndex();
      48             :     }
      49             : 
      50      462793 :     if (origin_vn_index_ < 0 && vrf_originated) {
      51       51681 :         origin_vn_index_ =
      52       51681 :             table ? table->routing_instance()->virtual_network_index() : 0;
      53             :     }
      54      462793 : }
      55             : 
      56      317146 : int RibOutAttr::NextHop::CompareTo(const NextHop &rhs) const {
      57      317146 :     KEY_COMPARE(address_, rhs.address_);
      58      313757 :     KEY_COMPARE(mac_, rhs.mac_) ;
      59      313763 :     KEY_COMPARE(label_, rhs.label_);
      60      312880 :     KEY_COMPARE(l3_label_, rhs.l3_label_);
      61      312864 :     KEY_COMPARE(source_address_, rhs.source_address_);
      62      312841 :     KEY_COMPARE(origin_vn_index_, rhs.origin_vn_index_);
      63      312795 :     KEY_COMPARE(encap_.size(), rhs.encap_.size());
      64      615303 :     for (size_t idx = 0; idx < encap_.size(); ++idx) {
      65      302518 :         KEY_COMPARE(encap_[idx], rhs.encap_[idx]);
      66             :     }
      67      312725 :     KEY_COMPARE(tag_list_.size(), rhs.tag_list_.size());
      68      312767 :     for (size_t idx = 0; idx < tag_list_.size(); ++idx) {
      69           2 :         KEY_COMPARE(tag_list_[idx], rhs.tag_list_[idx]);
      70             :     }
      71      312761 :     return 0;
      72             : }
      73             : 
      74        7193 : bool RibOutAttr::NextHop::operator==(const NextHop &rhs) const {
      75        7193 :     return CompareTo(rhs) == 0;
      76             : }
      77             : 
      78           0 : bool RibOutAttr::NextHop::operator!=(const NextHop &rhs) const {
      79           0 :     return CompareTo(rhs) != 0;
      80             : }
      81             : 
      82      309941 : bool RibOutAttr::NextHop::operator<(const NextHop &rhs) const {
      83      309941 :     return CompareTo(rhs) < 0;
      84             : }
      85             : 
      86     1097620 : RibOutAttr::RibOutAttr()
      87     1097503 :     : label_(0),
      88     1097503 :       l3_label_(0),
      89     1097462 :       is_xmpp_(false),
      90     1097620 :       vrf_originated_(false) {
      91     1097461 : }
      92             : 
      93             : //
      94             : // Copy constructor.
      95             : // Do not copy the string representation;
      96             : //
      97      596444 : RibOutAttr::RibOutAttr(const RibOutAttr &rhs) {
      98      596416 :     attr_out_ = rhs.attr_out_;
      99      596506 :     nexthop_list_ = rhs.nexthop_list_;
     100      596327 :     label_ = rhs.label_;
     101      596327 :     l3_label_ = rhs.l3_label_;
     102      596327 :     source_address_ = rhs.source_address_;
     103      596332 :     is_xmpp_ = rhs.is_xmpp_;
     104      596332 :     vrf_originated_ = rhs.vrf_originated_;
     105      596332 : }
     106             : 
     107        9750 : RibOutAttr::RibOutAttr(const BgpTable *table, const BgpAttr *attr,
     108        9750 :     uint32_t label, uint32_t l3_label, bool is_xmpp)
     109        9750 :     : attr_out_(attr),
     110        9750 :       label_(label),
     111        9750 :       l3_label_(l3_label),
     112        9750 :       is_xmpp_(is_xmpp),
     113        9750 :       vrf_originated_(false) {
     114        9750 :     if (attr && is_xmpp) {
     115         768 :         nexthop_list_.push_back(NextHop(table, attr->nexthop(),
     116         768 :             attr->mac_address(), label, l3_label, attr->ext_community(),
     117             :             attr->large_community(), false));
     118             :     }
     119        9750 : }
     120             : 
     121        8335 : RibOutAttr::RibOutAttr(const BgpTable *table, const BgpRoute *route,
     122        8335 :     const BgpAttr *attr, uint32_t label, bool include_nh, bool is_xmpp)
     123        8335 :     : attr_out_(attr),
     124        8335 :       label_(0),
     125        8335 :       l3_label_(0),
     126        8335 :       is_xmpp_(is_xmpp),
     127        8335 :       vrf_originated_(route->BestPath()->IsVrfOriginated()) {
     128        8335 :     if (attr && include_nh) {
     129        3469 :         if (is_xmpp) {
     130        6938 :             nexthop_list_.push_back(NextHop(table, attr->nexthop(),
     131        6938 :                 attr->mac_address(), label, 0, attr->ext_community(),
     132        3469 :                 attr->large_community(), vrf_originated_));
     133             :         } else {
     134           0 :             label_ = label;
     135           0 :             l3_label_ = 0;
     136             :         }
     137             :     }
     138        8335 : }
     139             : 
     140      701482 : RibOutAttr::RibOutAttr(const BgpRoute *route, const BgpAttr *attr,
     141      701482 :                        bool is_xmpp) :
     142      701482 :         label_(0), l3_label_(0), is_xmpp_(is_xmpp), vrf_originated_(false) {
     143             :     // Attribute should not be set already
     144      701490 :     assert(!attr_out_);
     145             : 
     146      701481 :     const BgpTable *table = static_cast<const BgpTable *>(route->get_table());
     147             : 
     148             :     // Always encode best path's attributes (including it's nexthop) and label.
     149      701472 :     if (!is_xmpp) {
     150      248809 :         set_attr(table, attr, route->BestPath()->GetLabel(),
     151             :             route->BestPath()->GetL3Label(), false, is_xmpp);
     152      248818 :         return;
     153             :     }
     154             : 
     155             :     // Encode ECMP nexthops only for XMPP peers.
     156             :     // Vrf Origination matters only for XMPP peers.
     157      452795 :     set_attr(table, attr, route->BestPath()->GetLabel(),
     158      452663 :         route->BestPath()->GetL3Label(), route->BestPath()->IsVrfOriginated(),
     159             :         is_xmpp);
     160             : 
     161      452967 :     for (Route::PathList::const_iterator it = route->GetPathList().begin();
     162     1823848 :         it != route->GetPathList().end(); ++it) {
     163      462327 :         const BgpPath *path = static_cast<const BgpPath *>(it.operator->());
     164             : 
     165             :         // Skip the best path.
     166      462327 :         if (path == route->BestPath())
     167      456401 :             continue;
     168             : 
     169             :         // Check if the path is ECMP eligible. If not, bail out, as the paths
     170             :         // are sorted in cost order anyways.
     171        9599 :         if (route->BestPath()->PathCompare(*path, true))
     172        3146 :             break;
     173             : 
     174             :         // We have an eligible ECMP path.
     175             :         // Remember if the path was originated in the VRF.  This is used to
     176             :         // determine if VRF's VN name can be used as the origin VN for the
     177             :         // nexthop.
     178        6447 :         NextHop nexthop(table, path->GetAttr()->nexthop(),
     179        6447 :             path->GetAttr()->mac_address(), path->GetLabel(),
     180             :             path->GetL3Label(), path->GetAttr()->ext_community(),
     181       12894 :             path->GetAttr()->large_community(), path->IsVrfOriginated());
     182             : 
     183             :         // Skip if we have already encoded this next-hop
     184        6446 :         if (find(nexthop_list_.begin(), nexthop_list_.end(), nexthop) !=
     185       12894 :                 nexthop_list_.end()) {
     186        3650 :             continue;
     187             :         }
     188        2797 :         nexthop_list_.push_back(nexthop);
     189        6447 :     }
     190           0 : }
     191             : 
     192             : //
     193             : // Assignment operator.
     194             : // Do not copy the string representation;
     195             : //
     196      709822 : RibOutAttr &RibOutAttr::operator=(const RibOutAttr &rhs) {
     197      709822 :     attr_out_ = rhs.attr_out_;
     198      710079 :     nexthop_list_ = rhs.nexthop_list_;
     199      709780 :     label_ = rhs.label_;
     200      709780 :     l3_label_ = rhs.l3_label_;
     201      709780 :     source_address_ = rhs.source_address_;
     202      709798 :     is_xmpp_ = rhs.is_xmpp_;
     203      709798 :     vrf_originated_ = rhs.vrf_originated_;
     204      709798 :     return *this;
     205             : }
     206             : 
     207             : //
     208             : // Comparator for RibOutAttr.
     209             : // First compare the BgpAttr and then the nexthops.
     210             : //
     211     1101617 : int RibOutAttr::CompareTo(const RibOutAttr &rhs) const {
     212     1101617 :     KEY_COMPARE(attr_out_.get(), rhs.attr_out_.get());
     213      278018 :     KEY_COMPARE(nexthop_list_.size(), rhs.nexthop_list_.size());
     214      430767 :     for (size_t idx = 0; idx < nexthop_list_.size(); ++idx) {
     215      155197 :         KEY_COMPARE(nexthop_list_[idx], rhs.nexthop_list_[idx]);
     216             :     }
     217      275553 :     KEY_COMPARE(label_, rhs.label());
     218      125038 :     KEY_COMPARE(l3_label_, rhs.l3_label());
     219      125021 :     KEY_COMPARE(source_address_, rhs.source_address());
     220      125021 :     KEY_COMPARE(is_xmpp_, rhs.is_xmpp());
     221      125019 :     KEY_COMPARE(vrf_originated_, rhs.vrf_originated());
     222      125018 :     return 0;
     223             : }
     224             : 
     225      710444 : void RibOutAttr::set_attr(const BgpTable *table, const BgpAttrPtr &attrp,
     226             :     uint32_t label, uint32_t l3_label, bool vrf_originated, bool is_xmpp) {
     227      710444 :     if (!attr_out_) {
     228      706304 :         attr_out_ = attrp;
     229      706267 :         assert(nexthop_list_.empty());
     230      706183 :         if (is_xmpp) {
     231      452758 :             NextHop nexthop(table, attrp->nexthop(), attrp->mac_address(),
     232             :                 label, l3_label, attrp->ext_community(),
     233      905458 :                 attrp->large_community(), vrf_originated);
     234      452494 :             nexthop_list_.push_back(nexthop);
     235      452595 :         } else {
     236      253365 :             label_ = label;
     237      253365 :             l3_label_ = l3_label;
     238             :         }
     239      705962 :         return;
     240             :     }
     241             : 
     242        4139 :     if (!attrp) {
     243           0 :         clear();
     244           0 :         return;
     245             :     }
     246             : 
     247        4139 :     assert(attr_out_->nexthop() == attrp->nexthop());
     248        4139 :     attr_out_ = attrp;
     249             : }
     250             : 
     251      598977 : RouteState::RouteState() {
     252      598994 : }
     253             : 
     254             : //
     255             : // Move history from RouteState to RouteUpdate.
     256             : //
     257      486645 : void RouteState::MoveHistory(RouteUpdate *rt_update) {
     258      486645 :     AdvertiseSList adv_slist;
     259      486626 :     SwapHistory(adv_slist);
     260      486569 :     rt_update->SwapHistory(adv_slist);
     261      486567 : }
     262             : 
     263             : //
     264             : // Find the AdvertiseInfo element with matching RibOutAttr.
     265             : //
     266      173668 : const AdvertiseInfo *RouteState::FindHistory(
     267             :         const RibOutAttr &roattr) const {
     268      229385 :     for (AdvertiseSList::List::const_iterator iter = advertised_->begin();
     269      458737 :          iter != advertised_->end(); iter++) {
     270      293979 :         if (iter->roattr == roattr) return iter.operator->();
     271             :     }
     272       54485 :     return NULL;
     273             : }
     274             : 
     275             : //
     276             : // Compare AdevrtiseInfos in this RouteState with the UpdateInfo elements
     277             : // in the given list.
     278             : //
     279             : // Uses brute force since the UpdateInfo and AdvertiseInfo lists typically
     280             : // contain just a single element.
     281             : //
     282             : // Return true if the information in the RouteState is same as that in the
     283             : // UpdateInfoSList.
     284             : //
     285      545810 : bool RouteState::CompareUpdateInfo(const UpdateInfoSList &uinfo_slist) const {
     286             :     // Both lists must have the same number of elements.
     287      545810 :     if (uinfo_slist->size() != advertised_->size())
     288      379143 :         return false;
     289             : 
     290             :     // Compare the peerset for each UpdateInfo in the UpdateInfoSList to
     291             :     // the peerset for the corresponding AdvertiseInfo in the advertised
     292             :     // list.
     293      166714 :     for (UpdateInfoSList::List::const_iterator iter = uinfo_slist->begin();
     294      557454 :          iter != uinfo_slist->end(); ++iter) {
     295      166702 :         const AdvertiseInfo *ainfo = FindHistory(iter->roattr);
     296      278774 :         if (!ainfo || iter->target != ainfo->bitset)
     297       54593 :             return false;
     298             :     }
     299             : 
     300      111983 :     return true;
     301             : }
     302             : 
     303             : //
     304             : // Create a new RibOut based on the BgpTable and RibExportPolicy.
     305             : //
     306       34970 : RibOut::RibOut(BgpTable *table, BgpUpdateSender *sender,
     307       34970 :                const RibExportPolicy &policy)
     308       34970 :     : table_(table),
     309       34970 :       sender_(sender),
     310       34970 :       policy_(policy),
     311       34970 :       listener_id_(DBTableBase::kInvalidId),
     312       34970 :       bgp_export_(BgpStaticObjectFactory::Create<BgpExport>(this)) {
     313       34970 :     name_ = "RibOut";
     314       34970 :     if (policy_.type == BgpProto::XMPP) {
     315       24119 :         name_ += " Type: XMPP";
     316       10851 :     } else if (policy_.type == BgpProto::IBGP) {
     317        5851 :         name_ += " Type: IBGP";
     318             :     } else {
     319        5000 :         name_ += " Type: EBGP";
     320        5000 :         name_ += " (AS " + integerToString(policy_.as_number);
     321        5000 :         if (!policy_.nexthop.is_unspecified())
     322         211 :             name_ += " Nexthop " + policy_.nexthop.to_string();
     323        5000 :         if (policy_.as_override)
     324          64 :             name_ += " ASOverride";
     325        5000 :         name_ += ")";
     326             :     }
     327      170986 :     for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
     328      136016 :         updates_.push_back(BgpStaticObjectFactory::Create<RibOutUpdates>(this, idx));
     329             :     }
     330       34970 : }
     331             : 
     332             : //
     333             : // Destructor for RibOut.  Takes care of unregistering the RibOut from
     334             : // the DBTableBase.
     335             : //
     336       34970 : RibOut::~RibOut() {
     337       34970 :     if (listener_id_ != DBTableBase::kInvalidId) {
     338       33694 :         table_->Unregister(listener_id_);
     339       33694 :         listener_id_ = DBTableBase::kInvalidId;
     340             :     }
     341       34970 :     STLDeleteValues(&updates_);
     342       34970 : }
     343             : 
     344             : //
     345             : // Register the RibOut as a listener with the underlying DBTableBase. This
     346             : // is separated out from the constructor to let the unit testing code work
     347             : // using the bare bones RibOut functionality.
     348             : //
     349             : // Note that the corresponding unregister from the DBTableBase will happen
     350             : // implicitly from the destructor.
     351             : //
     352       81679 : void RibOut::RegisterListener() {
     353       81679 :     if (listener_id_ != DBTableBase::kInvalidId)
     354       47985 :         return;
     355       33694 :     listener_id_ = table_->Register(
     356             :         boost::bind(&BgpExport::Export, bgp_export_.get(), _1, _2),
     357             :         ToString());
     358             : }
     359             : 
     360             : //
     361             : // Register a new peer to the RibOut. If the peer is not present in the
     362             : // PeerStateMap, create a new PeerState and add it to the map.
     363             : // Join the IPeerUpdate to the UPDATE and BULK queues for all RibOutUpdates
     364             : // associated with the RibOut.
     365             : //
     366       93135 : void RibOut::Register(IPeerUpdate *peer) {
     367       93135 :     PeerState *ps = state_map_.Locate(peer);
     368       93135 :     assert(ps != NULL);
     369       93135 :     active_peerset_.set(ps->index);
     370       93135 :     sender_->Join(this, peer);
     371      460956 :     for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
     372      367821 :         if (updates_[idx]->QueueJoin(RibOutUpdates::QUPDATE, ps->index))
     373          58 :             sender_->RibOutActive(idx, this, RibOutUpdates::QUPDATE);
     374      367821 :         if (updates_[idx]->QueueJoin(RibOutUpdates::QBULK, ps->index))
     375          85 :             sender_->RibOutActive(idx, this, RibOutUpdates::QBULK);
     376             :     }
     377       93135 : }
     378             : 
     379             : //
     380             : // Unregister a IPeerUpdate from the RibOut.
     381             : // Leave the IPeerUpdate from the UPDATE and BULK queues for all RibOutUpdates
     382             : // associated with the RibOut.
     383             : // Removes the IPeerUpdate from the PeerStateMap.
     384             : // If this was the last IPeerUpdate in the RibOut, remove the RibOut from the
     385             : // BgpTable.  That will cause this RibOut itself to get destroyed.
     386             : //
     387       93135 : void RibOut::Unregister(IPeerUpdate *peer) {
     388       93135 :     PeerState *ps = state_map_.Find(peer);
     389       93135 :     assert(ps != NULL);
     390       93135 :     assert(!active_peerset_.test(ps->index));
     391             : 
     392      460956 :     for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
     393      367821 :         updates_[idx]->QueueLeave(RibOutUpdates::QUPDATE, ps->index);
     394      367821 :         updates_[idx]->QueueLeave(RibOutUpdates::QBULK, ps->index);
     395             :     }
     396       93135 :     sender_->Leave(this, peer);
     397       93135 :     state_map_.Remove(peer, ps->index);
     398             : 
     399       93135 :     if (state_map_.empty()) {
     400       34897 :         table_->RibOutDelete(policy_);
     401             :     }
     402       93135 : }
     403             : 
     404             : //
     405             : // Return true if the IPeerUpdate is registered to this RibOut.
     406             : //
     407        7049 : bool RibOut::IsRegistered(IPeerUpdate *peer) {
     408        7049 :     PeerState *ps = state_map_.Find(peer);
     409        7049 :     return (ps != NULL);
     410             : }
     411             : 
     412             : //
     413             : // Deactivate a IPeerUpdate from the RibOut. Removes it from the RibPeerSet of
     414             : // active peers without removing it from the PeerStateMap.
     415             : //
     416             : // This must be called when the peer starts the process of leaving the RibOut
     417             : // in order to prevent any new or existing routes from getting exported while
     418             : // the route table walk for the leave processing is in progress.
     419             : //
     420       93135 : void RibOut::Deactivate(IPeerUpdate *peer) {
     421       93135 :     PeerState *ps = state_map_.Find(peer);
     422       93135 :     assert(ps != NULL);
     423       93135 :     assert(active_peerset_.test(ps->index));
     424       93135 :     active_peerset_.reset(ps->index);
     425       93135 : }
     426             : 
     427           0 : bool RibOut::IsActive(IPeerUpdate *peer) const {
     428           0 :     int index = GetPeerIndex(peer);
     429           0 :     return (index < 0 ? false : active_peerset_.test(index));
     430             : }
     431             : 
     432             : //
     433             : // Build the subset of given RibPeerSet in this RibOut that are send ready.
     434             : //
     435         103 : void RibOut::BuildSendReadyBitSet(const RibPeerSet &peerset,
     436             :     RibPeerSet *mready) const {
     437         320 :     for (size_t bit = peerset.find_first(); bit != RibPeerSet::npos;
     438         217 :          bit = peerset.find_next(bit)) {
     439         217 :         IPeerUpdate *peer = GetPeer(bit);
     440         217 :         if (peer->send_ready()) {
     441         209 :             mready->set(bit);
     442             :         }
     443             :     }
     444         103 : }
     445             : 
     446             : //
     447             : // Return the number of peers this route has been advertised to.
     448             : //
     449        1332 : int RibOut::RouteAdvertiseCount(const BgpRoute *rt) const {
     450        1332 :     const DBState *dbstate = rt->GetState(table_, listener_id_);
     451        1332 :     if (dbstate == NULL) {
     452         289 :         return 0;
     453             :     }
     454             : 
     455        1043 :     const RouteState *rstate = dynamic_cast<const RouteState *>(dbstate);
     456        1043 :     if (rstate != NULL) {
     457         225 :         int count = 0;
     458         225 :         for (AdvertiseSList::List::const_iterator iter =
     459         225 :              rstate->Advertised()->begin();
     460        1484 :              iter != rstate->Advertised()->end(); ++iter) {
     461         517 :             count += iter->bitset.count();
     462             :         }
     463         225 :         return count;
     464             :     }
     465             : 
     466         818 :     const RouteUpdate *rt_update = dynamic_cast<const RouteUpdate *>(dbstate);
     467         818 :     if (rt_update != NULL) {
     468         608 :         int count = 0;
     469         608 :         for (AdvertiseSList::List::const_iterator iter =
     470         608 :              rt_update->History()->begin();
     471        2454 :              iter != rt_update->History()->end(); ++iter) {
     472         619 :             count += iter->bitset.count();
     473             :         }
     474         608 :         return count;
     475             :     }
     476             : 
     477         210 :     const UpdateList *uplist = dynamic_cast<const UpdateList *>(dbstate);
     478         210 :     if (uplist != NULL) {
     479         210 :         int count = 0;
     480         210 :         for (AdvertiseSList::List::const_iterator iter =
     481         210 :              uplist->History()->begin();
     482         910 :              iter != uplist->History()->end(); ++iter) {
     483         245 :             count += iter->bitset.count();
     484             :         }
     485         210 :         return count;
     486             :     }
     487             : 
     488           0 :     return 0;
     489             : }
     490             : 
     491             : //
     492             : // Return the total queue size across all RibOutUpdates and UpdateQueues.
     493             : //
     494           0 : uint32_t RibOut::GetQueueSize() const {
     495           0 :     uint32_t queue_size = 0;
     496           0 :     for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
     497           0 :         const RibOutUpdates *updates = updates_[idx];
     498           0 :         for (int qid = RibOutUpdates::QFIRST; qid < RibOutUpdates::QCOUNT;
     499             :              ++qid) {
     500           0 :             queue_size += updates->queue_size(qid);
     501             :         }
     502             :     }
     503           0 :     return queue_size;
     504             : }
     505             : 
     506             : //
     507             : // Return the active RibPeerSet for this RibOut.  We keep track of the active
     508             : // peers via the calls to Register and Deactivate.
     509             : //
     510             : // The active RibPeerSet is always a subset of the registered RibPeerSet that
     511             : // is in the PeerStateMap.
     512             : //
     513     1791126 : const RibPeerSet &RibOut::PeerSet() const {
     514     1791126 :     return active_peerset_;
     515             : }
     516             : 
     517             : //
     518             : // Clear the bit index corresponding to the specified peer.
     519             : // Used to implement split horizon within an EBGP Ribout.
     520             : //
     521          40 : void RibOut::GetSubsetPeerSet(RibPeerSet *peerset,
     522             :     const IPeerUpdate *cpeer) const {
     523          40 :     assert(policy_.type == BgpProto::EBGP);
     524          40 :     IPeerUpdate *peer = const_cast<IPeerUpdate *>(cpeer);
     525          40 :     int index = GetPeerIndex(peer);
     526          40 :     if (index < 0)
     527          20 :         return;
     528          20 :     peerset->reset(index);
     529             : }
     530             : 
     531             : //
     532             : // Return the peer corresponding to the specified bit index.
     533             : //
     534     2245660 : IPeerUpdate *RibOut::GetPeer(int index) const {
     535     2245660 :     PeerState *ps = state_map_.At(index);
     536     2245733 :     if (ps != NULL) {
     537     2245752 :         return ps->peer;
     538             :     }
     539           0 :     return NULL;
     540             : }
     541             : 
     542             : //
     543             : // Return the bit index corresponding to the specified peer.
     544             : //
     545     2050603 : int RibOut::GetPeerIndex(IPeerUpdate *peer) const {
     546     2050603 :     PeerState *ps = state_map_.Find(peer);
     547     2050215 :     return (ps ? ps->index : -1);
     548             : }
     549             : 
     550             : //
     551             : // Fill introspect information.
     552             : // Accumulate counters from all RibOutUpdates.
     553             : //
     554           2 : void RibOut::FillStatisticsInfo(vector<ShowRibOutStatistics> *sros_list) const {
     555           6 :     for (int qid = RibOutUpdates::QFIRST; qid < RibOutUpdates::QCOUNT; ++qid) {
     556             :         RibOutUpdates::Stats stats;
     557           4 :         memset(&stats, 0, sizeof(stats));
     558           4 :         size_t queue_size = 0;
     559           4 :         size_t queue_marker_count = 0;
     560          20 :         for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
     561          16 :             const RibOutUpdates *updates = updates_[idx];
     562          16 :             updates->AddStatisticsInfo(qid, &stats);
     563          16 :             queue_size += updates->queue_size(qid);
     564          16 :             queue_marker_count += updates->queue_marker_count(qid);
     565             :         }
     566             : 
     567           4 :         ShowRibOutStatistics sros;
     568           4 :         sros.set_table(table_->name());
     569           4 :         sros.set_encoding(EncodingString());
     570           4 :         sros.set_peer_type(BgpProto::BgpPeerTypeString(peer_type()));
     571           4 :         sros.set_peer_as(peer_as());
     572           4 :         sros.set_peers(state_map_.size());
     573           4 :         sros.set_queue(qid == RibOutUpdates::QBULK ? "BULK" : "UPDATE");
     574           4 :         sros.set_pending_updates(queue_size);
     575           4 :         sros.set_markers(queue_marker_count);
     576           4 :         sros.set_messages_built(stats.messages_built_count_);
     577           4 :         sros.set_messages_sent(stats.messages_sent_count_);
     578           4 :         sros.set_reach(stats.reach_count_);
     579           4 :         sros.set_unreach(stats.unreach_count_);
     580           4 :         sros.set_tail_dequeues(stats.tail_dequeue_count_);
     581           4 :         sros.set_peer_dequeues(stats.peer_dequeue_count_);
     582           4 :         sros.set_marker_splits(stats.marker_split_count_);
     583           4 :         sros.set_marker_merges(stats.marker_merge_count_);
     584           4 :         sros.set_marker_moves(stats.marker_move_count_);
     585           4 :         sros_list->push_back(sros);
     586           4 :     }
     587           2 : }

Generated by: LCOV version 1.14