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: 214 322 66.5 %
Date: 2026-10-05 02:12:29 Functions: 23 33 69.7 %
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       67576 : 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       67576 :     bool vrf_originated)
      33       67576 :     : address_(address),
      34       67576 :       mac_(mac),
      35       67580 :       label_(label),
      36       67580 :       l3_label_(l3_label),
      37       67580 :       origin_vn_index_(-1) {
      38       67579 :       as_t asn = table ? table->server()->autonomous_system() : 0;
      39      135142 :       bool all = table ?
      40       67575 :           table->server()->global_config()->all_tags_are_global() : false;
      41       67567 :     if (large_community != nullptr) {
      42       66720 :         tag_list_ = large_community->GetTagList(all ? 0 : asn);
      43             :     }
      44       67552 :     if (ext_community != nullptr) {
      45       66705 :         encap_ = ext_community->GetTunnelEncap();
      46       66715 :         origin_vn_index_ = ext_community->GetOriginVnIndex();
      47             :     }
      48             : 
      49       67564 :     if (origin_vn_index_ < 0 && vrf_originated) {
      50        5199 :         origin_vn_index_ =
      51        5200 :             table ? table->routing_instance()->virtual_network_index() : 0;
      52             :     }
      53       67563 : }
      54             : 
      55       34427 : int RibOutAttr::NextHop::CompareTo(const NextHop &rhs) const {
      56       34427 :     KEY_COMPARE(address_, rhs.address_);
      57       34424 :     KEY_COMPARE(mac_, rhs.mac_) ;
      58       34426 :     KEY_COMPARE(label_, rhs.label_);
      59       34426 :     KEY_COMPARE(l3_label_, rhs.l3_label_);
      60       34426 :     KEY_COMPARE(source_address_, rhs.source_address_);
      61       34421 :     KEY_COMPARE(origin_vn_index_, rhs.origin_vn_index_);
      62       34421 :     KEY_COMPARE(encap_.size(), rhs.encap_.size());
      63       68270 :     for (size_t idx = 0; idx < encap_.size(); ++idx) {
      64       33847 :         KEY_COMPARE(encap_[idx], rhs.encap_[idx]);
      65             :     }
      66       34414 :     KEY_COMPARE(tag_list_.size(), rhs.tag_list_.size());
      67       34419 :     for (size_t idx = 0; idx < tag_list_.size(); ++idx) {
      68           0 :         KEY_COMPARE(tag_list_[idx], rhs.tag_list_[idx]);
      69             :     }
      70       34419 :     return 0;
      71             : }
      72             : 
      73           0 : bool RibOutAttr::NextHop::operator==(const NextHop &rhs) const {
      74           0 :     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       34428 : bool RibOutAttr::NextHop::operator<(const NextHop &rhs) const {
      82       34428 :     return CompareTo(rhs) < 0;
      83             : }
      84             : 
      85      140676 : RibOutAttr::RibOutAttr()
      86      140660 :     : label_(0),
      87      140660 :       l3_label_(0),
      88      140645 :       is_xmpp_(false),
      89      140676 :       vrf_originated_(false) {
      90      140645 : }
      91             : 
      92             : //
      93             : // Copy constructor.
      94             : // Do not copy the string representation;
      95             : //
      96       76251 : RibOutAttr::RibOutAttr(const RibOutAttr &rhs) {
      97       76247 :     attr_out_ = rhs.attr_out_;
      98       76278 :     nexthop_list_ = rhs.nexthop_list_;
      99       76245 :     label_ = rhs.label_;
     100       76245 :     l3_label_ = rhs.l3_label_;
     101       76245 :     source_address_ = rhs.source_address_;
     102       76246 :     is_xmpp_ = rhs.is_xmpp_;
     103       76246 :     vrf_originated_ = rhs.vrf_originated_;
     104       76246 : }
     105             : 
     106           0 : RibOutAttr::RibOutAttr(const BgpTable *table, const BgpAttr *attr,
     107           0 :     uint32_t label, uint32_t l3_label, bool is_xmpp)
     108           0 :     : attr_out_(attr),
     109           0 :       label_(label),
     110           0 :       l3_label_(l3_label),
     111           0 :       is_xmpp_(is_xmpp),
     112           0 :       vrf_originated_(false) {
     113           0 :     if (attr && is_xmpp) {
     114           0 :         nexthop_list_.push_back(NextHop(table, attr->nexthop(),
     115           0 :             attr->mac_address(), label, l3_label, attr->ext_community(),
     116             :             attr->large_community(), false));
     117             :     }
     118           0 : }
     119             : 
     120           0 : RibOutAttr::RibOutAttr(const BgpTable *table, const BgpRoute *route,
     121           0 :     const BgpAttr *attr, uint32_t label, bool include_nh, bool is_xmpp)
     122           0 :     : attr_out_(attr),
     123           0 :       label_(0),
     124           0 :       l3_label_(0),
     125           0 :       is_xmpp_(is_xmpp),
     126           0 :       vrf_originated_(route->BestPath()->IsVrfOriginated()) {
     127           0 :     if (attr && include_nh) {
     128           0 :         if (is_xmpp) {
     129           0 :             nexthop_list_.push_back(NextHop(table, attr->nexthop(),
     130           0 :                 attr->mac_address(), label, 0, attr->ext_community(),
     131           0 :                 attr->large_community(), vrf_originated_));
     132             :         } else {
     133           0 :             label_ = label;
     134           0 :             l3_label_ = 0;
     135             :         }
     136             :     }
     137           0 : }
     138             : 
     139       91456 : RibOutAttr::RibOutAttr(const BgpRoute *route, const BgpAttr *attr,
     140       91456 :                        bool is_xmpp) :
     141       91456 :         label_(0), l3_label_(0), is_xmpp_(is_xmpp), vrf_originated_(false) {
     142             :     // Attribute should not be set already
     143       91453 :     assert(!attr_out_);
     144             : 
     145       91453 :     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       91449 :     if (!is_xmpp) {
     149       23874 :         set_attr(table, attr, route->BestPath()->GetLabel(),
     150             :             route->BestPath()->GetL3Label(), false, is_xmpp);
     151       23876 :         return;
     152             :     }
     153             : 
     154             :     // Encode ECMP nexthops only for XMPP peers.
     155             :     // Vrf Origination matters only for XMPP peers.
     156       67616 :     set_attr(table, attr, route->BestPath()->GetLabel(),
     157       67575 :         route->BestPath()->GetL3Label(), route->BestPath()->IsVrfOriginated(),
     158             :         is_xmpp);
     159             : 
     160       67686 :     for (Route::PathList::const_iterator it = route->GetPathList().begin();
     161      270507 :         it != route->GetPathList().end(); ++it) {
     162       67633 :         const BgpPath *path = static_cast<const BgpPath *>(it.operator->());
     163             : 
     164             :         // Skip the best path.
     165       67633 :         if (path == route->BestPath())
     166       67630 :             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           0 :         if (route->BestPath()->PathCompare(*path, true))
     171           0 :             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           0 :         NextHop nexthop(table, path->GetAttr()->nexthop(),
     178           0 :             path->GetAttr()->mac_address(), path->GetLabel(),
     179             :             path->GetL3Label(), path->GetAttr()->ext_community(),
     180           0 :             path->GetAttr()->large_community(), path->IsVrfOriginated());
     181             : 
     182             :         // Skip if we have already encoded this next-hop
     183           0 :         if (find(nexthop_list_.begin(), nexthop_list_.end(), nexthop) !=
     184           0 :                 nexthop_list_.end()) {
     185           0 :             continue;
     186             :         }
     187           0 :         nexthop_list_.push_back(nexthop);
     188           0 :     }
     189           0 : }
     190             : 
     191             : //
     192             : // Assignment operator.
     193             : // Do not copy the string representation;
     194             : //
     195       91505 : RibOutAttr &RibOutAttr::operator=(const RibOutAttr &rhs) {
     196       91505 :     attr_out_ = rhs.attr_out_;
     197       91558 :     nexthop_list_ = rhs.nexthop_list_;
     198       91473 :     label_ = rhs.label_;
     199       91473 :     l3_label_ = rhs.l3_label_;
     200       91473 :     source_address_ = rhs.source_address_;
     201       91483 :     is_xmpp_ = rhs.is_xmpp_;
     202       91483 :     vrf_originated_ = rhs.vrf_originated_;
     203       91483 :     return *this;
     204             : }
     205             : 
     206             : //
     207             : // Comparator for RibOutAttr.
     208             : // First compare the BgpAttr and then the nexthops.
     209             : //
     210      127809 : int RibOutAttr::CompareTo(const RibOutAttr &rhs) const {
     211      127809 :     KEY_COMPARE(attr_out_.get(), rhs.attr_out_.get());
     212       25319 :     KEY_COMPARE(nexthop_list_.size(), rhs.nexthop_list_.size());
     213       42531 :     for (size_t idx = 0; idx < nexthop_list_.size(); ++idx) {
     214       17219 :         KEY_COMPARE(nexthop_list_[idx], rhs.nexthop_list_[idx]);
     215             :     }
     216       25310 :     KEY_COMPARE(label_, rhs.label());
     217        8384 :     KEY_COMPARE(l3_label_, rhs.l3_label());
     218        8384 :     KEY_COMPARE(source_address_, rhs.source_address());
     219        8385 :     KEY_COMPARE(is_xmpp_, rhs.is_xmpp());
     220        8385 :     KEY_COMPARE(vrf_originated_, rhs.vrf_originated());
     221        8385 :     return 0;
     222             : }
     223             : 
     224       91554 : 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       91554 :     if (!attr_out_) {
     227       91554 :         attr_out_ = attrp;
     228       91538 :         assert(nexthop_list_.empty());
     229       91508 :         if (is_xmpp) {
     230       67612 :             NextHop nexthop(table, attrp->nexthop(), attrp->mac_address(),
     231             :                 label, l3_label, attrp->ext_community(),
     232      135208 :                 attrp->large_community(), vrf_originated);
     233       67559 :             nexthop_list_.push_back(nexthop);
     234       67571 :         } else {
     235       23875 :             label_ = label;
     236       23875 :             l3_label_ = l3_label;
     237             :         }
     238       91446 :         return;
     239             :     }
     240             : 
     241           0 :     if (!attrp) {
     242           0 :         clear();
     243           0 :         return;
     244             :     }
     245             : 
     246           0 :     assert(attr_out_->nexthop() == attrp->nexthop());
     247           0 :     attr_out_ = attrp;
     248             : }
     249             : 
     250       82931 : RouteState::RouteState() {
     251       82926 : }
     252             : 
     253             : //
     254             : // Move history from RouteState to RouteUpdate.
     255             : //
     256       64688 : void RouteState::MoveHistory(RouteUpdate *rt_update) {
     257       64688 :     AdvertiseSList adv_slist;
     258       64696 :     SwapHistory(adv_slist);
     259       64679 :     rt_update->SwapHistory(adv_slist);
     260       64686 : }
     261             : 
     262             : //
     263             : // Find the AdvertiseInfo element with matching RibOutAttr.
     264             : //
     265       10762 : const AdvertiseInfo *RouteState::FindHistory(
     266             :         const RibOutAttr &roattr) const {
     267       13346 :     for (AdvertiseSList::List::const_iterator iter = advertised_->begin();
     268       26686 :          iter != advertised_->end(); iter++) {
     269       18938 :         if (iter->roattr == roattr) return iter.operator->();
     270             :     }
     271        2578 :     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       59428 : bool RouteState::CompareUpdateInfo(const UpdateInfoSList &uinfo_slist) const {
     285             :     // Both lists must have the same number of elements.
     286       59428 :     if (uinfo_slist->size() != advertised_->size())
     287       48654 :         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       10763 :     for (UpdateInfoSList::List::const_iterator iter = uinfo_slist->begin();
     293       37873 :          iter != uinfo_slist->end(); ++iter) {
     294       10762 :         const AdvertiseInfo *ainfo = FindHistory(iter->roattr);
     295       18936 :         if (!ainfo || iter->target != ainfo->bitset)
     296        2583 :             return false;
     297             :     }
     298             : 
     299        8172 :     return true;
     300             : }
     301             : 
     302             : //
     303             : // Create a new RibOut based on the BgpTable and RibExportPolicy.
     304             : //
     305        1882 : RibOut::RibOut(BgpTable *table, BgpUpdateSender *sender,
     306        1882 :                const RibExportPolicy &policy)
     307        1882 :     : table_(table),
     308        1882 :       sender_(sender),
     309        1882 :       policy_(policy),
     310        1882 :       listener_id_(DBTableBase::kInvalidId),
     311        1882 :       bgp_export_(BgpStaticObjectFactory::Create<BgpExport>(this)) {
     312        1882 :     name_ = "RibOut";
     313        1882 :     if (policy_.type == BgpProto::XMPP) {
     314         920 :         name_ += " Type: XMPP";
     315         962 :     } else if (policy_.type == BgpProto::IBGP) {
     316         388 :         name_ += " Type: IBGP";
     317             :     } else {
     318         574 :         name_ += " Type: EBGP";
     319         574 :         name_ += " (AS " + integerToString(policy_.as_number);
     320         574 :         if (!policy_.nexthop.is_unspecified())
     321           0 :             name_ += " Nexthop " + policy_.nexthop.to_string();
     322         574 :         if (policy_.as_override)
     323           0 :             name_ += " ASOverride";
     324         574 :         name_ += ")";
     325             :     }
     326        9410 :     for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
     327        7528 :         updates_.push_back(BgpStaticObjectFactory::Create<RibOutUpdates>(this, idx));
     328             :     }
     329        1882 : }
     330             : 
     331             : //
     332             : // Destructor for RibOut.  Takes care of unregistering the RibOut from
     333             : // the DBTableBase.
     334             : //
     335        1882 : RibOut::~RibOut() {
     336        1882 :     if (listener_id_ != DBTableBase::kInvalidId) {
     337        1882 :         table_->Unregister(listener_id_);
     338        1882 :         listener_id_ = DBTableBase::kInvalidId;
     339             :     }
     340        1882 :     STLDeleteValues(&updates_);
     341        1882 : }
     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        5746 : void RibOut::RegisterListener() {
     352        5746 :     if (listener_id_ != DBTableBase::kInvalidId)
     353        3864 :         return;
     354        1882 :     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        5746 : void RibOut::Register(IPeerUpdate *peer) {
     366        5746 :     PeerState *ps = state_map_.Locate(peer);
     367        5746 :     assert(ps != NULL);
     368        5746 :     active_peerset_.set(ps->index);
     369        5746 :     sender_->Join(this, peer);
     370       28730 :     for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
     371       22984 :         if (updates_[idx]->QueueJoin(RibOutUpdates::QUPDATE, ps->index))
     372           0 :             sender_->RibOutActive(idx, this, RibOutUpdates::QUPDATE);
     373       22984 :         if (updates_[idx]->QueueJoin(RibOutUpdates::QBULK, ps->index))
     374           0 :             sender_->RibOutActive(idx, this, RibOutUpdates::QBULK);
     375             :     }
     376        5746 : }
     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        5746 : void RibOut::Unregister(IPeerUpdate *peer) {
     387        5746 :     PeerState *ps = state_map_.Find(peer);
     388        5746 :     assert(ps != NULL);
     389        5746 :     assert(!active_peerset_.test(ps->index));
     390             : 
     391       28730 :     for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
     392       22984 :         updates_[idx]->QueueLeave(RibOutUpdates::QUPDATE, ps->index);
     393       22984 :         updates_[idx]->QueueLeave(RibOutUpdates::QBULK, ps->index);
     394             :     }
     395        5746 :     sender_->Leave(this, peer);
     396        5746 :     state_map_.Remove(peer, ps->index);
     397             : 
     398        5746 :     if (state_map_.empty()) {
     399        1882 :         table_->RibOutDelete(policy_);
     400             :     }
     401        5746 : }
     402             : 
     403             : //
     404             : // Return true if the IPeerUpdate is registered to this RibOut.
     405             : //
     406           0 : bool RibOut::IsRegistered(IPeerUpdate *peer) {
     407           0 :     PeerState *ps = state_map_.Find(peer);
     408           0 :     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        5746 : void RibOut::Deactivate(IPeerUpdate *peer) {
     420        5746 :     PeerState *ps = state_map_.Find(peer);
     421        5746 :     assert(ps != NULL);
     422        5746 :     assert(active_peerset_.test(ps->index));
     423        5746 :     active_peerset_.reset(ps->index);
     424        5746 : }
     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           0 : void RibOut::BuildSendReadyBitSet(const RibPeerSet &peerset,
     435             :     RibPeerSet *mready) const {
     436           0 :     for (size_t bit = peerset.find_first(); bit != RibPeerSet::npos;
     437           0 :          bit = peerset.find_next(bit)) {
     438           0 :         IPeerUpdate *peer = GetPeer(bit);
     439           0 :         if (peer->send_ready()) {
     440           0 :             mready->set(bit);
     441             :         }
     442             :     }
     443           0 : }
     444             : 
     445             : //
     446             : // Return the number of peers this route has been advertised to.
     447             : //
     448           0 : int RibOut::RouteAdvertiseCount(const BgpRoute *rt) const {
     449           0 :     const DBState *dbstate = rt->GetState(table_, listener_id_);
     450           0 :     if (dbstate == NULL) {
     451           0 :         return 0;
     452             :     }
     453             : 
     454           0 :     const RouteState *rstate = dynamic_cast<const RouteState *>(dbstate);
     455           0 :     if (rstate != NULL) {
     456           0 :         int count = 0;
     457           0 :         for (AdvertiseSList::List::const_iterator iter =
     458           0 :              rstate->Advertised()->begin();
     459           0 :              iter != rstate->Advertised()->end(); ++iter) {
     460           0 :             count += iter->bitset.count();
     461             :         }
     462           0 :         return count;
     463             :     }
     464             : 
     465           0 :     const RouteUpdate *rt_update = dynamic_cast<const RouteUpdate *>(dbstate);
     466           0 :     if (rt_update != NULL) {
     467           0 :         int count = 0;
     468           0 :         for (AdvertiseSList::List::const_iterator iter =
     469           0 :              rt_update->History()->begin();
     470           0 :              iter != rt_update->History()->end(); ++iter) {
     471           0 :             count += iter->bitset.count();
     472             :         }
     473           0 :         return count;
     474             :     }
     475             : 
     476           0 :     const UpdateList *uplist = dynamic_cast<const UpdateList *>(dbstate);
     477           0 :     if (uplist != NULL) {
     478           0 :         int count = 0;
     479           0 :         for (AdvertiseSList::List::const_iterator iter =
     480           0 :              uplist->History()->begin();
     481           0 :              iter != uplist->History()->end(); ++iter) {
     482           0 :             count += iter->bitset.count();
     483             :         }
     484           0 :         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      208344 : const RibPeerSet &RibOut::PeerSet() const {
     513      208344 :     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           0 : void RibOut::GetSubsetPeerSet(RibPeerSet *peerset,
     521             :     const IPeerUpdate *cpeer) const {
     522           0 :     assert(policy_.type == BgpProto::EBGP);
     523           0 :     IPeerUpdate *peer = const_cast<IPeerUpdate *>(cpeer);
     524           0 :     int index = GetPeerIndex(peer);
     525           0 :     if (index < 0)
     526           0 :         return;
     527           0 :     peerset->reset(index);
     528             : }
     529             : 
     530             : //
     531             : // Return the peer corresponding to the specified bit index.
     532             : //
     533      302004 : IPeerUpdate *RibOut::GetPeer(int index) const {
     534      302004 :     PeerState *ps = state_map_.At(index);
     535      302005 :     if (ps != NULL) {
     536      302009 :         return ps->peer;
     537             :     }
     538           0 :     return NULL;
     539             : }
     540             : 
     541             : //
     542             : // Return the bit index corresponding to the specified peer.
     543             : //
     544      290023 : int RibOut::GetPeerIndex(IPeerUpdate *peer) const {
     545      290023 :     PeerState *ps = state_map_.Find(peer);
     546      289918 :     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