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-06-04 02:06:09 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             :  */
       4             : 
       5             : #include "bgp/bgp_ribout.h"
       6             : 
       7             : #include <boost/bind/bind.hpp>
       8             : 
       9             : #include <algorithm>
      10             : 
      11             : #include "sandesh/sandesh_trace.h"
      12             : #include "base/string_util.h"
      13             : #include "bgp/bgp_peer_types.h"
      14             : #include "bgp/bgp_ribout_updates.h"
      15             : #include "bgp/bgp_export.h"
      16             : #include "bgp/bgp_factory.h"
      17             : #include "bgp/bgp_route.h"
      18             : #include "bgp/bgp_server.h"
      19             : #include "bgp/bgp_table.h"
      20             : #include "bgp/bgp_update.h"
      21             : #include "bgp/bgp_update_sender.h"
      22             : #include "bgp/ipeer.h"
      23             : #include "bgp/routing-instance/routing_instance.h"
      24             : #include "db/db.h"
      25             : 
      26             : using std::find;
      27             : using namespace boost::placeholders;
      28             : 
      29      463078 : RibOutAttr::NextHop::NextHop(const BgpTable *table, IpAddress address,
      30             :     const MacAddress &mac, uint32_t label, uint32_t l3_label,
      31             :     const ExtCommunity *ext_community, const LargeCommunity *large_community,
      32      463078 :     bool vrf_originated)
      33      463078 :     : address_(address),
      34      463088 :       mac_(mac),
      35      463086 :       label_(label),
      36      463086 :       l3_label_(l3_label),
      37      463086 :       origin_vn_index_(-1) {
      38      463082 :       as_t asn = table ? table->server()->autonomous_system() : 0;
      39      926111 :       bool all = table ?
      40      463048 :           table->server()->global_config()->all_tags_are_global() : false;
      41      463063 :     if (large_community != nullptr) {
      42      445475 :         tag_list_ = large_community->GetTagList(all ? 0 : asn);
      43             :     }
      44      462993 :     if (ext_community != nullptr) {
      45      449227 :         encap_ = ext_community->GetTunnelEncap();
      46      449142 :         origin_vn_index_ = ext_community->GetOriginVnIndex();
      47             :     }
      48             : 
      49      462893 :     if (origin_vn_index_ < 0 && vrf_originated) {
      50       51929 :         origin_vn_index_ =
      51       51928 :             table ? table->routing_instance()->virtual_network_index() : 0;
      52             :     }
      53      462894 : }
      54             : 
      55      314706 : int RibOutAttr::NextHop::CompareTo(const NextHop &rhs) const {
      56      314706 :     KEY_COMPARE(address_, rhs.address_);
      57      311267 :     KEY_COMPARE(mac_, rhs.mac_) ;
      58      311260 :     KEY_COMPARE(label_, rhs.label_);
      59      310685 :     KEY_COMPARE(l3_label_, rhs.l3_label_);
      60      310669 :     KEY_COMPARE(source_address_, rhs.source_address_);
      61      310653 :     KEY_COMPARE(origin_vn_index_, rhs.origin_vn_index_);
      62      310615 :     KEY_COMPARE(encap_.size(), rhs.encap_.size());
      63      610538 :     for (size_t idx = 0; idx < encap_.size(); ++idx) {
      64      299928 :         KEY_COMPARE(encap_[idx], rhs.encap_[idx]);
      65             :     }
      66      310574 :     KEY_COMPARE(tag_list_.size(), rhs.tag_list_.size());
      67      310606 :     for (size_t idx = 0; idx < tag_list_.size(); ++idx) {
      68           0 :         KEY_COMPARE(tag_list_[idx], rhs.tag_list_[idx]);
      69             :     }
      70      310605 :     return 0;
      71             : }
      72             : 
      73        7285 : bool RibOutAttr::NextHop::operator==(const NextHop &rhs) const {
      74        7285 :     return CompareTo(rhs) == 0;
      75             : }
      76             : 
      77           0 : bool RibOutAttr::NextHop::operator!=(const NextHop &rhs) const {
      78           0 :     return CompareTo(rhs) != 0;
      79             : }
      80             : 
      81      307423 : bool RibOutAttr::NextHop::operator<(const NextHop &rhs) const {
      82      307423 :     return CompareTo(rhs) < 0;
      83             : }
      84             : 
      85     1093929 : RibOutAttr::RibOutAttr()
      86     1093851 :     : label_(0),
      87     1093851 :       l3_label_(0),
      88     1093836 :       is_xmpp_(false),
      89     1093929 :       vrf_originated_(false) {
      90     1093830 : }
      91             : 
      92             : //
      93             : // Copy constructor.
      94             : // Do not copy the string representation;
      95             : //
      96      596540 : RibOutAttr::RibOutAttr(const RibOutAttr &rhs) {
      97      596610 :     attr_out_ = rhs.attr_out_;
      98      596718 :     nexthop_list_ = rhs.nexthop_list_;
      99      596597 :     label_ = rhs.label_;
     100      596597 :     l3_label_ = rhs.l3_label_;
     101      596597 :     source_address_ = rhs.source_address_;
     102      596600 :     is_xmpp_ = rhs.is_xmpp_;
     103      596600 :     vrf_originated_ = rhs.vrf_originated_;
     104      596600 : }
     105             : 
     106        9750 : RibOutAttr::RibOutAttr(const BgpTable *table, const BgpAttr *attr,
     107        9750 :     uint32_t label, uint32_t l3_label, bool is_xmpp)
     108        9750 :     : attr_out_(attr),
     109        9750 :       label_(label),
     110        9750 :       l3_label_(l3_label),
     111        9750 :       is_xmpp_(is_xmpp),
     112        9750 :       vrf_originated_(false) {
     113        9750 :     if (attr && is_xmpp) {
     114         768 :         nexthop_list_.push_back(NextHop(table, attr->nexthop(),
     115         768 :             attr->mac_address(), label, l3_label, attr->ext_community(),
     116             :             attr->large_community(), false));
     117             :     }
     118        9750 : }
     119             : 
     120        8418 : RibOutAttr::RibOutAttr(const BgpTable *table, const BgpRoute *route,
     121        8418 :     const BgpAttr *attr, uint32_t label, bool include_nh, bool is_xmpp)
     122        8418 :     : attr_out_(attr),
     123        8418 :       label_(0),
     124        8418 :       l3_label_(0),
     125        8418 :       is_xmpp_(is_xmpp),
     126        8418 :       vrf_originated_(route->BestPath()->IsVrfOriginated()) {
     127        8418 :     if (attr && include_nh) {
     128        3598 :         if (is_xmpp) {
     129        7196 :             nexthop_list_.push_back(NextHop(table, attr->nexthop(),
     130        7196 :                 attr->mac_address(), label, 0, attr->ext_community(),
     131        3598 :                 attr->large_community(), vrf_originated_));
     132             :         } else {
     133           0 :             label_ = label;
     134           0 :             l3_label_ = 0;
     135             :         }
     136             :     }
     137        8418 : }
     138             : 
     139      700722 : RibOutAttr::RibOutAttr(const BgpRoute *route, const BgpAttr *attr,
     140      700722 :                        bool is_xmpp) :
     141      700722 :         label_(0), l3_label_(0), is_xmpp_(is_xmpp), vrf_originated_(false) {
     142             :     // Attribute should not be set already
     143      700715 :     assert(!attr_out_);
     144             : 
     145      700711 :     const BgpTable *table = static_cast<const BgpTable *>(route->get_table());
     146             : 
     147             :     // Always encode best path's attributes (including it's nexthop) and label.
     148      700708 :     if (!is_xmpp) {
     149      248067 :         set_attr(table, attr, route->BestPath()->GetLabel(),
     150             :             route->BestPath()->GetL3Label(), false, is_xmpp);
     151      248071 :         return;
     152             :     }
     153             : 
     154             :     // Encode ECMP nexthops only for XMPP peers.
     155             :     // Vrf Origination matters only for XMPP peers.
     156      452768 :     set_attr(table, attr, route->BestPath()->GetLabel(),
     157      452641 :         route->BestPath()->GetL3Label(), route->BestPath()->IsVrfOriginated(),
     158             :         is_xmpp);
     159             : 
     160      452934 :     for (Route::PathList::const_iterator it = route->GetPathList().begin();
     161     1823883 :         it != route->GetPathList().end(); ++it) {
     162      462366 :         const BgpPath *path = static_cast<const BgpPath *>(it.operator->());
     163             : 
     164             :         // Skip the best path.
     165      462366 :         if (path == route->BestPath())
     166      456491 :             continue;
     167             : 
     168             :         // Check if the path is ECMP eligible. If not, bail out, as the paths
     169             :         // are sorted in cost order anyways.
     170        9615 :         if (route->BestPath()->PathCompare(*path, true))
     171        3155 :             break;
     172             : 
     173             :         // We have an eligible ECMP path.
     174             :         // Remember if the path was originated in the VRF.  This is used to
     175             :         // determine if VRF's VN name can be used as the origin VN for the
     176             :         // nexthop.
     177        6460 :         NextHop nexthop(table, path->GetAttr()->nexthop(),
     178        6460 :             path->GetAttr()->mac_address(), path->GetLabel(),
     179             :             path->GetL3Label(), path->GetAttr()->ext_community(),
     180       12920 :             path->GetAttr()->large_community(), path->IsVrfOriginated());
     181             : 
     182             :         // Skip if we have already encoded this next-hop
     183        6460 :         if (find(nexthop_list_.begin(), nexthop_list_.end(), nexthop) !=
     184       12920 :                 nexthop_list_.end()) {
     185        3738 :             continue;
     186             :         }
     187        2722 :         nexthop_list_.push_back(nexthop);
     188        6460 :     }
     189           0 : }
     190             : 
     191             : //
     192             : // Assignment operator.
     193             : // Do not copy the string representation;
     194             : //
     195      709174 : RibOutAttr &RibOutAttr::operator=(const RibOutAttr &rhs) {
     196      709174 :     attr_out_ = rhs.attr_out_;
     197      709393 :     nexthop_list_ = rhs.nexthop_list_;
     198      709151 :     label_ = rhs.label_;
     199      709151 :     l3_label_ = rhs.l3_label_;
     200      709151 :     source_address_ = rhs.source_address_;
     201      709170 :     is_xmpp_ = rhs.is_xmpp_;
     202      709170 :     vrf_originated_ = rhs.vrf_originated_;
     203      709170 :     return *this;
     204             : }
     205             : 
     206             : //
     207             : // Comparator for RibOutAttr.
     208             : // First compare the BgpAttr and then the nexthops.
     209             : //
     210     1094011 : int RibOutAttr::CompareTo(const RibOutAttr &rhs) const {
     211     1094011 :     KEY_COMPARE(attr_out_.get(), rhs.attr_out_.get());
     212      275401 :     KEY_COMPARE(nexthop_list_.size(), rhs.nexthop_list_.size());
     213      427201 :     for (size_t idx = 0; idx < nexthop_list_.size(); ++idx) {
     214      153861 :         KEY_COMPARE(nexthop_list_[idx], rhs.nexthop_list_[idx]);
     215             :     }
     216      273323 :     KEY_COMPARE(label_, rhs.label());
     217      123917 :     KEY_COMPARE(l3_label_, rhs.l3_label());
     218      123909 :     KEY_COMPARE(source_address_, rhs.source_address());
     219      123911 :     KEY_COMPARE(is_xmpp_, rhs.is_xmpp());
     220      123912 :     KEY_COMPARE(vrf_originated_, rhs.vrf_originated());
     221      123912 :     return 0;
     222             : }
     223             : 
     224      709667 : void RibOutAttr::set_attr(const BgpTable *table, const BgpAttrPtr &attrp,
     225             :     uint32_t label, uint32_t l3_label, bool vrf_originated, bool is_xmpp) {
     226      709667 :     if (!attr_out_) {
     227      705525 :         attr_out_ = attrp;
     228      705478 :         assert(nexthop_list_.empty());
     229      705390 :         if (is_xmpp) {
     230      452743 :             NextHop nexthop(table, attrp->nexthop(), attrp->mac_address(),
     231             :                 label, l3_label, attrp->ext_community(),
     232      905406 :                 attrp->large_community(), vrf_originated);
     233      452458 :             nexthop_list_.push_back(nexthop);
     234      452612 :         } else {
     235      252620 :             label_ = label;
     236      252620 :             l3_label_ = l3_label;
     237             :         }
     238      705262 :         return;
     239             :     }
     240             : 
     241        4130 :     if (!attrp) {
     242           0 :         clear();
     243           0 :         return;
     244             :     }
     245             : 
     246        4131 :     assert(attr_out_->nexthop() == attrp->nexthop());
     247        4131 :     attr_out_ = attrp;
     248             : }
     249             : 
     250      599418 : RouteState::RouteState() {
     251      599416 : }
     252             : 
     253             : //
     254             : // Move history from RouteState to RouteUpdate.
     255             : //
     256      484426 : void RouteState::MoveHistory(RouteUpdate *rt_update) {
     257      484426 :     AdvertiseSList adv_slist;
     258      484401 :     SwapHistory(adv_slist);
     259      484366 :     rt_update->SwapHistory(adv_slist);
     260      484340 : }
     261             : 
     262             : //
     263             : // Find the AdvertiseInfo element with matching RibOutAttr.
     264             : //
     265      172944 : const AdvertiseInfo *RouteState::FindHistory(
     266             :         const RibOutAttr &roattr) const {
     267      228984 :     for (AdvertiseSList::List::const_iterator iter = advertised_->begin();
     268      457957 :          iter != advertised_->end(); iter++) {
     269      292269 :         if (iter->roattr == roattr) return iter.operator->();
     270             :     }
     271       54805 :     return NULL;
     272             : }
     273             : 
     274             : //
     275             : // Compare AdevrtiseInfos in this RouteState with the UpdateInfo elements
     276             : // in the given list.
     277             : //
     278             : // Uses brute force since the UpdateInfo and AdvertiseInfo lists typically
     279             : // contain just a single element.
     280             : //
     281             : // Return true if the information in the RouteState is same as that in the
     282             : // UpdateInfoSList.
     283             : //
     284      542520 : bool RouteState::CompareUpdateInfo(const UpdateInfoSList &uinfo_slist) const {
     285             :     // Both lists must have the same number of elements.
     286      542520 :     if (uinfo_slist->size() != advertised_->size())
     287      376481 :         return false;
     288             : 
     289             :     // Compare the peerset for each UpdateInfo in the UpdateInfoSList to
     290             :     // the peerset for the corresponding AdvertiseInfo in the advertised
     291             :     // list.
     292      165992 :     for (UpdateInfoSList::List::const_iterator iter = uinfo_slist->begin();
     293      553987 :          iter != uinfo_slist->end(); ++iter) {
     294      165984 :         const AdvertiseInfo *ainfo = FindHistory(iter->roattr);
     295      277093 :         if (!ainfo || iter->target != ainfo->bitset)
     296       54917 :             return false;
     297             :     }
     298             : 
     299      110978 :     return true;
     300             : }
     301             : 
     302             : //
     303             : // Create a new RibOut based on the BgpTable and RibExportPolicy.
     304             : //
     305       34966 : RibOut::RibOut(BgpTable *table, BgpUpdateSender *sender,
     306       34966 :                const RibExportPolicy &policy)
     307       34966 :     : table_(table),
     308       34966 :       sender_(sender),
     309       34966 :       policy_(policy),
     310       34966 :       listener_id_(DBTableBase::kInvalidId),
     311       34966 :       bgp_export_(BgpStaticObjectFactory::Create<BgpExport>(this)) {
     312       34966 :     name_ = "RibOut";
     313       34966 :     if (policy_.type == BgpProto::XMPP) {
     314       24128 :         name_ += " Type: XMPP";
     315       10838 :     } else if (policy_.type == BgpProto::IBGP) {
     316        5841 :         name_ += " Type: IBGP";
     317             :     } else {
     318        4997 :         name_ += " Type: EBGP";
     319        4997 :         name_ += " (AS " + integerToString(policy_.as_number);
     320        4997 :         if (!policy_.nexthop.is_unspecified())
     321         211 :             name_ += " Nexthop " + policy_.nexthop.to_string();
     322        4997 :         if (policy_.as_override)
     323          64 :             name_ += " ASOverride";
     324        4997 :         name_ += ")";
     325             :     }
     326      170966 :     for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
     327      136000 :         updates_.push_back(BgpStaticObjectFactory::Create<RibOutUpdates>(this, idx));
     328             :     }
     329       34966 : }
     330             : 
     331             : //
     332             : // Destructor for RibOut.  Takes care of unregistering the RibOut from
     333             : // the DBTableBase.
     334             : //
     335       34966 : RibOut::~RibOut() {
     336       34966 :     if (listener_id_ != DBTableBase::kInvalidId) {
     337       33690 :         table_->Unregister(listener_id_);
     338       33690 :         listener_id_ = DBTableBase::kInvalidId;
     339             :     }
     340       34966 :     STLDeleteValues(&updates_);
     341       34966 : }
     342             : 
     343             : //
     344             : // Register the RibOut as a listener with the underlying DBTableBase. This
     345             : // is separated out from the constructor to let the unit testing code work
     346             : // using the bare bones RibOut functionality.
     347             : //
     348             : // Note that the corresponding unregister from the DBTableBase will happen
     349             : // implicitly from the destructor.
     350             : //
     351       81680 : void RibOut::RegisterListener() {
     352       81680 :     if (listener_id_ != DBTableBase::kInvalidId)
     353       47990 :         return;
     354       33690 :     listener_id_ = table_->Register(
     355             :         boost::bind(&BgpExport::Export, bgp_export_.get(), _1, _2),
     356             :         ToString());
     357             : }
     358             : 
     359             : //
     360             : // Register a new peer to the RibOut. If the peer is not present in the
     361             : // PeerStateMap, create a new PeerState and add it to the map.
     362             : // Join the IPeerUpdate to the UPDATE and BULK queues for all RibOutUpdates
     363             : // associated with the RibOut.
     364             : //
     365       93136 : void RibOut::Register(IPeerUpdate *peer) {
     366       93136 :     PeerState *ps = state_map_.Locate(peer);
     367       93136 :     assert(ps != NULL);
     368       93136 :     active_peerset_.set(ps->index);
     369       93136 :     sender_->Join(this, peer);
     370      460961 :     for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
     371      367825 :         if (updates_[idx]->QueueJoin(RibOutUpdates::QUPDATE, ps->index))
     372          40 :             sender_->RibOutActive(idx, this, RibOutUpdates::QUPDATE);
     373      367825 :         if (updates_[idx]->QueueJoin(RibOutUpdates::QBULK, ps->index))
     374          61 :             sender_->RibOutActive(idx, this, RibOutUpdates::QBULK);
     375             :     }
     376       93136 : }
     377             : 
     378             : //
     379             : // Unregister a IPeerUpdate from the RibOut.
     380             : // Leave the IPeerUpdate from the UPDATE and BULK queues for all RibOutUpdates
     381             : // associated with the RibOut.
     382             : // Removes the IPeerUpdate from the PeerStateMap.
     383             : // If this was the last IPeerUpdate in the RibOut, remove the RibOut from the
     384             : // BgpTable.  That will cause this RibOut itself to get destroyed.
     385             : //
     386       93136 : void RibOut::Unregister(IPeerUpdate *peer) {
     387       93136 :     PeerState *ps = state_map_.Find(peer);
     388       93136 :     assert(ps != NULL);
     389       93136 :     assert(!active_peerset_.test(ps->index));
     390             : 
     391      460961 :     for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
     392      367825 :         updates_[idx]->QueueLeave(RibOutUpdates::QUPDATE, ps->index);
     393      367825 :         updates_[idx]->QueueLeave(RibOutUpdates::QBULK, ps->index);
     394             :     }
     395       93136 :     sender_->Leave(this, peer);
     396       93136 :     state_map_.Remove(peer, ps->index);
     397             : 
     398       93136 :     if (state_map_.empty()) {
     399       34893 :         table_->RibOutDelete(policy_);
     400             :     }
     401       93136 : }
     402             : 
     403             : //
     404             : // Return true if the IPeerUpdate is registered to this RibOut.
     405             : //
     406        7169 : bool RibOut::IsRegistered(IPeerUpdate *peer) {
     407        7169 :     PeerState *ps = state_map_.Find(peer);
     408        7169 :     return (ps != NULL);
     409             : }
     410             : 
     411             : //
     412             : // Deactivate a IPeerUpdate from the RibOut. Removes it from the RibPeerSet of
     413             : // active peers without removing it from the PeerStateMap.
     414             : //
     415             : // This must be called when the peer starts the process of leaving the RibOut
     416             : // in order to prevent any new or existing routes from getting exported while
     417             : // the route table walk for the leave processing is in progress.
     418             : //
     419       93136 : void RibOut::Deactivate(IPeerUpdate *peer) {
     420       93136 :     PeerState *ps = state_map_.Find(peer);
     421       93136 :     assert(ps != NULL);
     422       93136 :     assert(active_peerset_.test(ps->index));
     423       93136 :     active_peerset_.reset(ps->index);
     424       93136 : }
     425             : 
     426           0 : bool RibOut::IsActive(IPeerUpdate *peer) const {
     427           0 :     int index = GetPeerIndex(peer);
     428           0 :     return (index < 0 ? false : active_peerset_.test(index));
     429             : }
     430             : 
     431             : //
     432             : // Build the subset of given RibPeerSet in this RibOut that are send ready.
     433             : //
     434         103 : void RibOut::BuildSendReadyBitSet(const RibPeerSet &peerset,
     435             :     RibPeerSet *mready) const {
     436         320 :     for (size_t bit = peerset.find_first(); bit != RibPeerSet::npos;
     437         217 :          bit = peerset.find_next(bit)) {
     438         217 :         IPeerUpdate *peer = GetPeer(bit);
     439         217 :         if (peer->send_ready()) {
     440         209 :             mready->set(bit);
     441             :         }
     442             :     }
     443         103 : }
     444             : 
     445             : //
     446             : // Return the number of peers this route has been advertised to.
     447             : //
     448        1332 : int RibOut::RouteAdvertiseCount(const BgpRoute *rt) const {
     449        1332 :     const DBState *dbstate = rt->GetState(table_, listener_id_);
     450        1332 :     if (dbstate == NULL) {
     451         289 :         return 0;
     452             :     }
     453             : 
     454        1043 :     const RouteState *rstate = dynamic_cast<const RouteState *>(dbstate);
     455        1043 :     if (rstate != NULL) {
     456         225 :         int count = 0;
     457         225 :         for (AdvertiseSList::List::const_iterator iter =
     458         225 :              rstate->Advertised()->begin();
     459        1484 :              iter != rstate->Advertised()->end(); ++iter) {
     460         517 :             count += iter->bitset.count();
     461             :         }
     462         225 :         return count;
     463             :     }
     464             : 
     465         818 :     const RouteUpdate *rt_update = dynamic_cast<const RouteUpdate *>(dbstate);
     466         818 :     if (rt_update != NULL) {
     467         608 :         int count = 0;
     468         608 :         for (AdvertiseSList::List::const_iterator iter =
     469         608 :              rt_update->History()->begin();
     470        2454 :              iter != rt_update->History()->end(); ++iter) {
     471         619 :             count += iter->bitset.count();
     472             :         }
     473         608 :         return count;
     474             :     }
     475             : 
     476         210 :     const UpdateList *uplist = dynamic_cast<const UpdateList *>(dbstate);
     477         210 :     if (uplist != NULL) {
     478         210 :         int count = 0;
     479         210 :         for (AdvertiseSList::List::const_iterator iter =
     480         210 :              uplist->History()->begin();
     481         910 :              iter != uplist->History()->end(); ++iter) {
     482         245 :             count += iter->bitset.count();
     483             :         }
     484         210 :         return count;
     485             :     }
     486             : 
     487           0 :     return 0;
     488             : }
     489             : 
     490             : //
     491             : // Return the total queue size across all RibOutUpdates and UpdateQueues.
     492             : //
     493           0 : uint32_t RibOut::GetQueueSize() const {
     494           0 :     uint32_t queue_size = 0;
     495           0 :     for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
     496           0 :         const RibOutUpdates *updates = updates_[idx];
     497           0 :         for (int qid = RibOutUpdates::QFIRST; qid < RibOutUpdates::QCOUNT;
     498             :              ++qid) {
     499           0 :             queue_size += updates->queue_size(qid);
     500             :         }
     501             :     }
     502           0 :     return queue_size;
     503             : }
     504             : 
     505             : //
     506             : // Return the active RibPeerSet for this RibOut.  We keep track of the active
     507             : // peers via the calls to Register and Deactivate.
     508             : //
     509             : // The active RibPeerSet is always a subset of the registered RibPeerSet that
     510             : // is in the PeerStateMap.
     511             : //
     512     1750469 : const RibPeerSet &RibOut::PeerSet() const {
     513     1750469 :     return active_peerset_;
     514             : }
     515             : 
     516             : //
     517             : // Clear the bit index corresponding to the specified peer.
     518             : // Used to implement split horizon within an EBGP Ribout.
     519             : //
     520          40 : void RibOut::GetSubsetPeerSet(RibPeerSet *peerset,
     521             :     const IPeerUpdate *cpeer) const {
     522          40 :     assert(policy_.type == BgpProto::EBGP);
     523          40 :     IPeerUpdate *peer = const_cast<IPeerUpdate *>(cpeer);
     524          40 :     int index = GetPeerIndex(peer);
     525          40 :     if (index < 0)
     526          20 :         return;
     527          20 :     peerset->reset(index);
     528             : }
     529             : 
     530             : //
     531             : // Return the peer corresponding to the specified bit index.
     532             : //
     533     2273785 : IPeerUpdate *RibOut::GetPeer(int index) const {
     534     2273785 :     PeerState *ps = state_map_.At(index);
     535     2273773 :     if (ps != NULL) {
     536     2273767 :         return ps->peer;
     537             :     }
     538           6 :     return NULL;
     539             : }
     540             : 
     541             : //
     542             : // Return the bit index corresponding to the specified peer.
     543             : //
     544     2077237 : int RibOut::GetPeerIndex(IPeerUpdate *peer) const {
     545     2077237 :     PeerState *ps = state_map_.Find(peer);
     546     2076808 :     return (ps ? ps->index : -1);
     547             : }
     548             : 
     549             : //
     550             : // Fill introspect information.
     551             : // Accumulate counters from all RibOutUpdates.
     552             : //
     553           2 : void RibOut::FillStatisticsInfo(vector<ShowRibOutStatistics> *sros_list) const {
     554           6 :     for (int qid = RibOutUpdates::QFIRST; qid < RibOutUpdates::QCOUNT; ++qid) {
     555             :         RibOutUpdates::Stats stats;
     556           4 :         memset(&stats, 0, sizeof(stats));
     557           4 :         size_t queue_size = 0;
     558           4 :         size_t queue_marker_count = 0;
     559          20 :         for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
     560          16 :             const RibOutUpdates *updates = updates_[idx];
     561          16 :             updates->AddStatisticsInfo(qid, &stats);
     562          16 :             queue_size += updates->queue_size(qid);
     563          16 :             queue_marker_count += updates->queue_marker_count(qid);
     564             :         }
     565             : 
     566           4 :         ShowRibOutStatistics sros;
     567           4 :         sros.set_table(table_->name());
     568           4 :         sros.set_encoding(EncodingString());
     569           4 :         sros.set_peer_type(BgpProto::BgpPeerTypeString(peer_type()));
     570           4 :         sros.set_peer_as(peer_as());
     571           4 :         sros.set_peers(state_map_.size());
     572           4 :         sros.set_queue(qid == RibOutUpdates::QBULK ? "BULK" : "UPDATE");
     573           4 :         sros.set_pending_updates(queue_size);
     574           4 :         sros.set_markers(queue_marker_count);
     575           4 :         sros.set_messages_built(stats.messages_built_count_);
     576           4 :         sros.set_messages_sent(stats.messages_sent_count_);
     577           4 :         sros.set_reach(stats.reach_count_);
     578           4 :         sros.set_unreach(stats.unreach_count_);
     579           4 :         sros.set_tail_dequeues(stats.tail_dequeue_count_);
     580           4 :         sros.set_peer_dequeues(stats.peer_dequeue_count_);
     581           4 :         sros.set_marker_splits(stats.marker_split_count_);
     582           4 :         sros.set_marker_merges(stats.marker_merge_count_);
     583           4 :         sros.set_marker_moves(stats.marker_move_count_);
     584           4 :         sros_list->push_back(sros);
     585           4 :     }
     586           2 : }

Generated by: LCOV version 1.14