LCOV - code coverage report
Current view: top level - bgp - bgp_membership.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 738 775 95.2 %
Date: 2026-11-09 02:10:49 Functions: 88 89 98.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : #include "bgp/bgp_membership.h"
       7             : 
       8             : #include <boost/foreach.hpp>
       9             : 
      10             : #include "base/task_annotations.h"
      11             : #include "base/task_trigger.h"
      12             : #include "bgp/bgp_export.h"
      13             : #include "bgp/bgp_log.h"
      14             : #include "bgp/bgp_peer_types.h"
      15             : #include "bgp/bgp_route.h"
      16             : #include "bgp/bgp_server.h"
      17             : #include "bgp/bgp_update_sender.h"
      18             : #include "bgp/routing-instance/routing_instance.h"
      19             : 
      20             : using std::list;
      21             : using std::make_pair;
      22             : using std::string;
      23             : using std::vector;
      24             : 
      25             : //
      26             : // Constructor for BgpMembershipManager.
      27             : //
      28        9743 : BgpMembershipManager::BgpMembershipManager(BgpServer *server)
      29        9743 :     : server_(server),
      30        9743 :       walker_(new Walker(this)),
      31       19486 :       event_queue_(new WorkQueue<Event *>(
      32       19486 :           TaskScheduler::GetInstance()->GetTaskId("bgp::PeerMembership"), 0,
      33       29229 :           boost::bind(&BgpMembershipManager::EventCallback, this, _1))) {
      34        9743 :     current_jobs_count_ = 0;
      35        9743 :     total_jobs_count_ = 0;
      36        9743 : }
      37             : 
      38             : //
      39             : // Destructor for BgpMembershipManager.
      40             : //
      41       19450 : BgpMembershipManager::~BgpMembershipManager() {
      42        9743 :     assert(current_jobs_count_ == 0);
      43        9743 :     assert(rib_state_map_.empty());
      44        9743 :     assert(peer_state_map_.empty());
      45       19450 : }
      46             : 
      47       38972 : int BgpMembershipManager::RegisterPeerRegistrationCallback(
      48             :     PeerRegistrationCallback callback) {
      49       38972 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
      50             : 
      51       38972 :     size_t id = registration_bmap_.find_first();
      52       38972 :     if (id == registration_bmap_.npos) {
      53       38972 :         id = registration_callbacks_.size();
      54       38972 :         registration_callbacks_.push_back(callback);
      55             :     } else {
      56           0 :         registration_bmap_.reset(id);
      57           0 :         if (registration_bmap_.none()) {
      58           0 :             registration_bmap_.clear();
      59             :         }
      60           0 :         registration_callbacks_[id] = callback;
      61             :     }
      62       38972 :     return id;
      63       38972 : }
      64             : 
      65       38556 : void BgpMembershipManager::UnregisterPeerRegistrationCallback(int id) {
      66       38556 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
      67             : 
      68       38556 :     registration_callbacks_[id] = NULL;
      69       38556 :     if ((size_t) id == registration_callbacks_.size() - 1) {
      70       88793 :         while (!registration_callbacks_.empty() &&
      71       39577 :                registration_callbacks_.back() == NULL) {
      72       38556 :             registration_callbacks_.pop_back();
      73             :         }
      74       10660 :         if (registration_bmap_.size() > registration_callbacks_.size()) {
      75       10412 :             registration_bmap_.resize(registration_callbacks_.size());
      76             :         }
      77             :     } else {
      78       27896 :         if ((size_t) id >= registration_bmap_.size()) {
      79       27860 :             registration_bmap_.resize(id + 1);
      80             :         }
      81       27896 :         registration_bmap_.set(id);
      82             :     }
      83       38556 : }
      84             : 
      85      163398 : void BgpMembershipManager::NotifyPeerRegistration(IPeer *peer, BgpTable *table,
      86             :     bool unregister) {
      87      163398 :     CHECK_CONCURRENCY("bgp::PeerMembership");
      88             : 
      89      163398 :     if (!peer->IsXmppPeer())
      90       26042 :         return;
      91             : 
      92      137356 :     for (PeerRegistrationListenerList::iterator iter =
      93      137356 :          registration_callbacks_.begin();
      94      686300 :          iter != registration_callbacks_.end(); ++iter) {
      95      548944 :         if (*iter != NULL) {
      96      548944 :             PeerRegistrationCallback callback = *iter;
      97      548944 :             (callback)(peer, table, unregister);
      98      548944 :         }
      99             :     }
     100             : }
     101             : 
     102       81718 : bool BgpMembershipManager::AssertRegister(PeerRibState *prs, bool do_assert) {
     103       81718 :     if (prs->action() != NONE) {
     104           1 :         if (do_assert)
     105           0 :             assert(prs->action() == NONE);
     106           1 :         return false;
     107             :     }
     108             : 
     109       81719 :     if (prs->ribout_registered()) {
     110           1 :         if (do_assert)
     111           0 :             assert(!prs->ribout_registered());
     112           1 :         return false;
     113             :     }
     114             : 
     115       81718 :     return true;
     116             : }
     117             : 
     118             : // Register the IPeer to the BgpTable.
     119             : // Post a REGISTER_RIB event to deal with concurrency issues with RibOut.
     120       81717 : void BgpMembershipManager::Register(IPeer *peer, BgpTable *table,
     121             :     const RibExportPolicy &policy, int instance_id) {
     122       81717 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper",
     123             :         "bgp::StateMachine", "xmpp::StateMachine");
     124             : 
     125       81717 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
     126       81720 :     PeerRibState *prs = LocatePeerRibState(peer, table);
     127       81720 :     if (!AssertRegister(prs))
     128           2 :         return;
     129       81718 :     current_jobs_count_++;
     130       81718 :     total_jobs_count_++;
     131       81717 :     prs->set_ribin_registered(true);
     132       81718 :     prs->set_action(RIBOUT_ADD);
     133       81718 :     Event *event = new Event(REGISTER_RIB, peer, table, policy, instance_id);
     134       81714 :     EnqueueEvent(event);
     135       81721 : }
     136             : 
     137        6983 : bool BgpMembershipManager::AssertRegisterRibIn(PeerRibState *prs, IPeer *peer,
     138             :                                                bool do_assert) {
     139        6983 :     if (prs->action() != NONE) {
     140           1 :         if (do_assert)
     141           0 :             assert(prs->action() == NONE);
     142           1 :         return false;
     143             :     }
     144             : 
     145        6982 :     if (prs->ribin_registered() && !peer->IsInGRTimerWaitState()) {
     146           3 :         if (do_assert)
     147           0 :             assert(!prs->ribin_registered() || peer->IsInGRTimerWaitState());
     148           3 :         return false;
     149             :     }
     150             : 
     151        6979 :     if (prs->ribout_registered()) {
     152           0 :         if (do_assert)
     153           0 :             assert(!prs->ribout_registered());
     154           0 :         return false;
     155             :     }
     156             : 
     157        6979 :     return true;
     158             : }
     159             : 
     160             : // Synchronously register the IPeer to the BgpTable for RIBIN.
     161        6983 : void BgpMembershipManager::RegisterRibIn(IPeer *peer, BgpTable *table) {
     162        6983 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper",
     163             :         "bgp::StateMachine", "xmpp::StateMachine");
     164             : 
     165        6983 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
     166        6983 :     PeerRibState *prs = LocatePeerRibState(peer, table);
     167        6983 :     if (!AssertRegisterRibIn(prs, peer))
     168           4 :         return;
     169        6979 :     prs->set_ribin_registered(true);
     170        6983 : }
     171             : 
     172       77682 : bool BgpMembershipManager::AssertUnregister(PeerRibState *prs, bool do_assert) {
     173       77682 :     if (!prs || prs->action() != NONE) {
     174           4 :         if (do_assert)
     175           0 :             assert(prs && prs->action() == NONE);
     176           4 :         return false;
     177             :     }
     178             : 
     179       77678 :     if (!prs->ribin_registered()) {
     180           0 :         if (do_assert)
     181           0 :             assert(prs->ribin_registered());
     182           0 :         return false;
     183             :     }
     184             : 
     185       77678 :     return true;
     186             : }
     187             : 
     188             : // Unregister the IPeer from the BgpTable.
     189             : // Post an UNREGISTER_RIB event to deal with concurrency issues with RibOut.
     190       77682 : void BgpMembershipManager::Unregister(IPeer *peer, BgpTable *table) {
     191       77682 :     CHECK_CONCURRENCY("bgp::Config", "bgp::StateMachine", "xmpp::StateMachine");
     192             : 
     193       77682 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
     194       77682 :     PeerRibState *prs = FindPeerRibState(peer, table);
     195       77682 :     if (!AssertUnregister(prs))
     196           4 :         return;
     197             : 
     198       77678 :     current_jobs_count_++;
     199       77678 :     total_jobs_count_++;
     200             : 
     201       77678 :     if (!prs->ribout_registered()) {
     202         346 :         UnregisterRibInUnlocked(prs);
     203         346 :         return;
     204             :     }
     205             : 
     206       77332 :     prs->set_action(RIBIN_DELETE_RIBOUT_DELETE);
     207       77332 :     prs->set_ribin_registered(false);
     208       77332 :     prs->set_instance_id(-1);
     209       77332 :     prs->set_subscription_gen_id(0);
     210       77332 :     Event *event = new Event(UNREGISTER_RIB, peer, table);
     211       77332 :     EnqueueEvent(event);
     212       77682 : }
     213             : 
     214             : //
     215             : // Unregister the IPeer from the BgpTable for RIBIN.
     216             : //
     217        1804 : void BgpMembershipManager::UnregisterRibIn(IPeer *peer, BgpTable *table) {
     218        1804 :     CHECK_CONCURRENCY("bgp::Config", "bgp::StateMachine", "xmpp::StateMachine");
     219             : 
     220        1804 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
     221        1804 :     current_jobs_count_++;
     222        1804 :     total_jobs_count_++;
     223        1804 :     PeerRibState *prs = FindPeerRibState(peer, table);
     224        1804 :     assert(prs && prs->action() == NONE);
     225        1804 :     assert(prs->ribin_registered() && !prs->ribout_registered());
     226        1804 :     UnregisterRibInUnlocked(prs);
     227        1804 : }
     228             : 
     229             : //
     230             : // Common routine to handle unregister of IPeer from Table for RIBIN.
     231             : //
     232        2150 : void BgpMembershipManager::UnregisterRibInUnlocked(PeerRibState *prs) {
     233        2150 :     prs->set_ribin_registered(false);
     234        2150 :     prs->set_instance_id(-1);
     235        2150 :     prs->set_subscription_gen_id(0);
     236        2150 :     prs->set_action(RIBIN_DELETE);
     237        2150 :     prs->UnregisterRibIn();
     238        5945 :     BGP_LOG_PEER_TABLE(prs->peer(), SandeshLevel::SYS_DEBUG,
     239             :         BGP_LOG_FLAG_SYSLOG, prs->table(),
     240             :         "Unregister table requested for action " << prs->action());
     241        2150 : }
     242             : 
     243             : //
     244             : // Unregister the IPeer from the BgpTable.
     245             : // Post an UNREGISTER_RIB event to deal with concurrency issues with RibOut.
     246             : // The action is set to RIBIN_WALK_RIBOUT_DELETE.
     247             : // This API is to be used when handling graceful restart of the peer.
     248             : //
     249        4387 : void BgpMembershipManager::UnregisterRibOut(IPeer *peer, BgpTable *table) {
     250        4387 :     CHECK_CONCURRENCY("bgp::Config", "bgp::StateMachine", "xmpp::StateMachine");
     251             : 
     252        4387 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
     253        4387 :     current_jobs_count_++;
     254        4387 :     total_jobs_count_++;
     255        4387 :     PeerRibState *prs = FindPeerRibState(peer, table);
     256        4387 :     assert(prs && prs->action() == NONE);
     257        4387 :     assert(prs->ribin_registered());
     258        4387 :     assert(prs->ribout_registered());
     259        4387 :     prs->set_instance_id(-1);
     260        4387 :     prs->set_subscription_gen_id(0);
     261        4387 :     prs->set_action(RIBIN_WALK_RIBOUT_DELETE);
     262        4387 :     Event *event = new Event(UNREGISTER_RIB, peer, table);
     263        4387 :     EnqueueEvent(event);
     264        4387 : }
     265             : 
     266        3827 : bool BgpMembershipManager::AssertWalkRibIn(PeerRibState *prs, bool do_assert) {
     267        3827 :     if (!prs || prs->action() != NONE) {
     268           4 :         if (do_assert)
     269           0 :             assert(prs && prs->action() == NONE);
     270           4 :         return false;
     271             :     }
     272             : 
     273        3823 :     if (!prs->ribin_registered()) {
     274           0 :         if (do_assert)
     275           0 :             assert(prs->ribin_registered());
     276           0 :         return false;
     277             :     }
     278             : 
     279        3823 :     return true;
     280             : }
     281             : 
     282             : //
     283             : // Trigger a walk of IPeer's RIBIN for the BgpTable.
     284             : // This API can be used when sweeping paths as part of graceful restart.
     285             : // It can also be used in future when re-evaluating import policy for a peer.
     286             : //
     287        3827 : void BgpMembershipManager::WalkRibIn(IPeer *peer, BgpTable *table) {
     288        3827 :     CHECK_CONCURRENCY("bgp::Config", "bgp::StateMachine", "xmpp::StateMachine");
     289             : 
     290        3827 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
     291        3827 :     PeerRibState *prs = FindPeerRibState(peer, table);
     292        3827 :     if (!AssertWalkRibIn(prs))
     293           4 :         return;
     294        3823 :     current_jobs_count_++;
     295        3823 :     total_jobs_count_++;
     296        3823 :     prs->set_action(RIBIN_WALK);
     297        3823 :     prs->WalkRibIn();
     298        9648 :     BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
     299             :         table, "Walk table requested for action " << prs->action());
     300        3827 : }
     301             : 
     302             : //
     303             : // Fill in the registration info of the IPeer for the BgpTable.
     304             : // Return true if the IPeer is registered with the BgpTable, false otherwise.
     305             : //
     306      101343 : bool BgpMembershipManager::GetRegistrationInfo(
     307             :     const IPeer *peer, const BgpTable *table,
     308             :     int *instance_id, uint64_t *subscription_gen_id) const {
     309      101343 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     310      101344 :     const PeerRibState *prs = FindPeerRibState(peer, table);
     311      101323 :     if (!prs)
     312       32934 :         return false;
     313       68389 :     if (instance_id)
     314       68352 :         *instance_id = prs->instance_id();
     315       68389 :     if (subscription_gen_id)
     316       66850 :         *subscription_gen_id = prs->subscription_gen_id();
     317       68389 :     return true;
     318      101323 : }
     319             : 
     320             : //
     321             : // Update the registration info of the IPeer for the BgpTable.
     322             : //
     323       68255 : void BgpMembershipManager::SetRegistrationInfo(
     324             :     const IPeer *peer, const BgpTable *table,
     325             :     int instance_id, uint64_t subscription_gen_id) {
     326       68255 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     327       68255 :     PeerRibState *prs = FindPeerRibState(peer, table);
     328       68248 :     if (!prs)
     329           0 :         return;
     330       68248 :     prs->set_instance_id(instance_id);
     331       68248 :     prs->set_subscription_gen_id(subscription_gen_id);
     332       68248 : }
     333             : 
     334             : //
     335             : // Return true if the IPeer is registered to the BgpTable.
     336             : //
     337      189124 : bool BgpMembershipManager::IsRegistered(const IPeer *peer,
     338             :     const BgpTable *table) const {
     339      189124 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     340      189124 :     const PeerRibState *prs = FindPeerRibState(peer, table);
     341      378248 :     return (prs && prs->ribin_registered() && prs->ribout_registered());
     342      189124 : }
     343             : 
     344             : //
     345             : // Return true if the IPeer is registered to the BgpTable for RibIn.
     346             : //
     347        3995 : bool BgpMembershipManager::IsRibInRegistered(const IPeer *peer,
     348             :     const BgpTable *table) const {
     349        3995 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     350        3995 :     const PeerRibState *prs = FindPeerRibState(peer, table);
     351        7990 :     return (prs && prs->ribin_registered());
     352        3995 : }
     353             : 
     354             : //
     355             : // Return true if the IPeer is registered to the BgpTable for RibOut.
     356             : //
     357       68228 : bool BgpMembershipManager::IsRibOutRegistered(const IPeer *peer,
     358             :     const BgpTable *table) const {
     359       68228 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     360       68234 :     const PeerRibState *prs = FindPeerRibState(peer, table);
     361      136465 :     return (prs && prs->ribout_registered());
     362       68228 : }
     363             : 
     364             : //
     365             : // Return RibOut's output queue depth.
     366             : //
     367           0 : uint32_t BgpMembershipManager::GetRibOutQueueDepth(const IPeer *peer,
     368             :     const BgpTable *table) const {
     369           0 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     370           0 :     const PeerRibState *prs = FindPeerRibState(peer, table);
     371           0 :     if (!prs || !prs->ribout_registered())
     372           0 :         return 0;
     373           0 :     RibOut *ribout = prs->ribout();
     374           0 :     if (!ribout)
     375           0 :         return 0;
     376           0 :     return ribout->GetQueueSize();
     377           0 : }
     378             : 
     379             : //
     380             : // Fill in the list of registered BgpTables for given IPeer.
     381             : //
     382       20302 : void BgpMembershipManager::GetRegisteredRibs(const IPeer *peer,
     383             :     list<BgpTable *> *table_list) const {
     384       20302 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     385       20302 :     table_list->clear();
     386       20302 :     const PeerState *ps = FindPeerState(peer);
     387       20302 :     if (ps)
     388        9873 :         ps->GetRegisteredRibs(table_list);
     389       20302 : }
     390             : 
     391             : //
     392             : //
     393             : // Fill membership introspect information for a BgpTable.
     394             : //
     395        1093 : void BgpMembershipManager::FillRoutingInstanceTableInfo(
     396             :     ShowRoutingInstanceTable *srit, const BgpTable *table) const {
     397        1093 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     398        1093 :     BgpTable *nc_table = const_cast<BgpTable *>(table);
     399        1093 :     const RibState *rs = FindRibState(nc_table);
     400        1093 :     if (rs)
     401         980 :         rs->FillRoutingInstanceTableInfo(srit);
     402        1093 : }
     403             : 
     404             : //
     405             : // Fill membership introspect information for an IPeer.
     406             : //
     407         543 : void BgpMembershipManager::FillPeerMembershipInfo(const IPeer *peer,
     408             :         BgpNeighborResp *resp) const {
     409         543 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     410         543 :     assert(resp->get_routing_tables().empty());
     411         543 :     IPeer *nc_peer = const_cast<IPeer *>(peer);
     412             : 
     413         543 :     BgpUpdateSender *sender = server_->update_sender();
     414         543 :     if (sender->PeerIsRegistered(nc_peer)) {
     415        1058 :         resp->set_send_state(
     416         529 :             sender->PeerInSync(nc_peer) ? "in sync" : "not in sync");
     417             :     } else {
     418          14 :         resp->set_send_state("not advertising");
     419             :     }
     420             : 
     421         543 :     const PeerState *ps = FindPeerState(nc_peer);
     422         543 :     if (ps)
     423         529 :         ps->FillPeerMembershipInfo(resp);
     424         543 : }
     425             : 
     426             : //
     427             : // Return true if no pending work in the BgpMembershipManager itself and
     428             : // in the Walker.
     429             : //
     430     1718838 : bool BgpMembershipManager::IsQueueEmpty() const {
     431     1718838 :     return (event_queue_->IsQueueEmpty() && walker_->IsQueueEmpty());
     432             : }
     433             : 
     434             : //
     435             : // Return number of PeerRibStates.
     436             : //
     437         170 : size_t BgpMembershipManager::GetMembershipCount() const {
     438         170 :     size_t count = 0;
     439         170 :     for (PeerStateMap::const_iterator loc = peer_state_map_.begin();
     440        1107 :          loc != peer_state_map_.end(); ++loc) {
     441         937 :         const PeerState *ps = loc->second;
     442         937 :         count += ps->GetMembershipCount();
     443             :     }
     444         170 :     return count;
     445             : }
     446             : 
     447             : //
     448             : // Find or create the PeerState for given IPeer.
     449             : //
     450       88703 : BgpMembershipManager::PeerState *BgpMembershipManager::LocatePeerState(
     451             :     IPeer *peer) {
     452       88703 :     PeerStateMap::iterator loc = peer_state_map_.find(peer);
     453       88697 :     if (loc == peer_state_map_.end()) {
     454        8665 :         PeerState *ps = new PeerState(this, peer);
     455        8665 :         peer_state_map_.insert(make_pair(peer, ps));
     456        8665 :         return ps;
     457             :     } else {
     458       80034 :         return loc->second;
     459             :     }
     460             : }
     461             : 
     462             : //
     463             : // Find the PeerState for given IPeer.
     464             : //
     465      488764 : BgpMembershipManager::PeerState *BgpMembershipManager::FindPeerState(
     466             :     const IPeer *peer) {
     467      488764 :     PeerStateMap::iterator loc = peer_state_map_.find(peer);
     468      488757 :     return (loc != peer_state_map_.end() ? loc->second : NULL);
     469             : }
     470             : 
     471             : //
     472             : // Find the PeerState for given IPeer.
     473             : // Const version.
     474             : //
     475      383540 : const BgpMembershipManager::PeerState *BgpMembershipManager::FindPeerState(
     476             :     const IPeer *peer) const {
     477      383540 :     PeerStateMap::const_iterator loc = peer_state_map_.find(peer);
     478      383525 :     return (loc != peer_state_map_.end() ? loc->second : NULL);
     479             : }
     480             : 
     481             : //
     482             : // Destroy the given PeerState.
     483             : //
     484        8665 : void BgpMembershipManager::DestroyPeerState(PeerState *ps) {
     485        8665 :     peer_state_map_.erase(ps->peer());
     486        8665 :     delete ps;
     487        8665 : }
     488             : 
     489             : //
     490             : // Find or create the RibState for given BgpTable.
     491             : //
     492       88698 : BgpMembershipManager::RibState *BgpMembershipManager::LocateRibState(
     493             :     BgpTable *table) {
     494       88698 :     RibStateMap::iterator loc = rib_state_map_.find(table);
     495       88691 :     if (loc == rib_state_map_.end()) {
     496       31224 :         RibState *rs = new RibState(this, table);
     497       31224 :         rib_state_map_.insert(make_pair(table, rs));
     498       31224 :         return rs;
     499             :     } else {
     500       57474 :         return loc->second;
     501             :     }
     502             : }
     503             : 
     504             : //
     505             : // Find the RibState for given BgpTable.
     506             : //
     507      488758 : BgpMembershipManager::RibState *BgpMembershipManager::FindRibState(
     508             :     const BgpTable *table) {
     509      488758 :     RibStateMap::iterator loc = rib_state_map_.find(table);
     510      488757 :     return (loc != rib_state_map_.end() ? loc->second : NULL);
     511             : }
     512             : 
     513             : //
     514             : // Find the RibState for given BgpTable.
     515             : // Const version.
     516             : //
     517      363769 : const BgpMembershipManager::RibState *BgpMembershipManager::FindRibState(
     518             :     const BgpTable *table) const {
     519      363769 :     RibStateMap::const_iterator loc = rib_state_map_.find(table);
     520      363766 :     return (loc != rib_state_map_.end() ? loc->second : NULL);
     521             : }
     522             : 
     523             : //
     524             : // Destroy the given RibState.
     525             : //
     526       31224 : void BgpMembershipManager::DestroyRibState(RibState *rs) {
     527       31224 :     rib_state_map_.erase(rs->table());
     528       31224 :     delete rs;
     529       31224 : }
     530             : 
     531             : //
     532             : // Request the Walker to schedule a table walk for the given RibState.
     533             : // Note that the Walker accumulates requests and starts walks asynchronously.
     534             : //
     535      169331 : void BgpMembershipManager::EnqueueRibState(RibState *rs) {
     536      169331 :     walker_->Enqueue(rs);
     537      169331 : }
     538             : 
     539             : //
     540             : // Find or create the PeerRibState for given (IPeer, BgpTable).
     541             : //
     542       88703 : BgpMembershipManager::PeerRibState *BgpMembershipManager::LocatePeerRibState(
     543             :     IPeer *peer, BgpTable *table) {
     544       88703 :     PeerState *ps = LocatePeerState(peer);
     545       88698 :     RibState *rs = LocateRibState(table);
     546       88698 :     PeerRibState *prs = ps->LocatePeerRibState(rs);
     547       88698 :     rs->InsertPeerRibState(prs);
     548       88703 :     return prs;
     549             : }
     550             : 
     551             : //
     552             : // Find the PeerRibState for given (IPeer, BgpTable).
     553             : //
     554      488764 : BgpMembershipManager::PeerRibState *BgpMembershipManager::FindPeerRibState(
     555             :     const IPeer *peer, const BgpTable *table) {
     556      488764 :     PeerState *ps = FindPeerState(peer);
     557      488758 :     RibState *rs = FindRibState(table);
     558      488757 :     return (ps && rs ? ps->FindPeerRibState(rs) : NULL);
     559             : }
     560             : 
     561             : //
     562             : // Find the PeerRibState for given (IPeer, BgpTable).
     563             : // Const version.
     564             : //
     565             : const BgpMembershipManager::PeerRibState *
     566      362696 : BgpMembershipManager::FindPeerRibState(
     567             :     const IPeer *peer, const BgpTable *table) const {
     568      362696 :     const PeerState *ps = FindPeerState(peer);
     569      362677 :     const RibState *rs = FindRibState(table);
     570      362672 :     return (ps && rs ? ps->FindPeerRibState(rs) : NULL);
     571             : }
     572             : 
     573             : //
     574             : // Destroy the given PeerRibState.
     575             : // Also destroy the PeerState and/or RibState if they are no longer required.
     576             : //
     577       79482 : void BgpMembershipManager::DestroyPeerRibState(PeerRibState *prs) {
     578       79482 :     PeerState *ps = prs->peer_state();
     579       79482 :     RibState *rs = prs->rib_state();
     580       79482 :     if (ps->RemovePeerRibState(prs))
     581        8665 :         DestroyPeerState(ps);
     582       79482 :     if (rs->RemovePeerRibState(prs))
     583       31224 :         DestroyRibState(rs);
     584       79482 :     delete prs;
     585       79482 : }
     586             : 
     587             : //
     588             : // Trigger REGISTER_RIB_COMPLETE event.
     589             : //
     590       81679 : void BgpMembershipManager::TriggerRegisterRibCompleteEvent(IPeer *peer,
     591             :     BgpTable *table) {
     592       81679 :     Event *event = new Event(REGISTER_RIB_COMPLETE, peer, table);
     593       81679 :     EnqueueEvent(event);
     594       81679 : }
     595             : 
     596             : //
     597             : // Trigger UNREGISTER_RIB_COMPLETE event.
     598             : //
     599       81719 : void BgpMembershipManager::TriggerUnregisterRibCompleteEvent(IPeer *peer,
     600             :     BgpTable *table) {
     601       81719 :     Event *event = new Event(UNREGISTER_RIB_COMPLETE, peer, table);
     602       81719 :     EnqueueEvent(event);
     603       81719 : }
     604             : 
     605             : //
     606             : // Trigger WALK_RIB_COMPLETE event.
     607             : //
     608        5973 : void BgpMembershipManager::TriggerWalkRibCompleteEvent(IPeer *peer,
     609             :     BgpTable *table) {
     610        5973 :     Event *event = new Event(WALK_RIB_COMPLETE, peer, table);
     611        5973 :     EnqueueEvent(event);
     612        5973 : }
     613             : 
     614             : //
     615             : // Process REGISTER_RIB event.
     616             : //
     617       81719 : void BgpMembershipManager::ProcessRegisterRibEvent(Event *event) {
     618       81719 :     IPeer *peer = event->peer;
     619       81719 :     BgpTable *table = event->table;
     620       81719 :     PeerRibState *prs = FindPeerRibState(peer, table);
     621       81719 :     assert(prs && prs->action() == RIBOUT_ADD);
     622       81719 :     assert(prs->ribin_registered());
     623       81719 :     prs->set_instance_id(event->instance_id);
     624             : 
     625             :     // Notify completion right away if the table is marked for deletion.
     626             :     // Mark the ribout as registered even though no RibOut gets created.
     627             :     // The unregister code path handles a PeerRibState without a RibOut.
     628       81719 :     if (table->IsDeleted()) {
     629          40 :         prs->set_ribout_registered(true);
     630          40 :         prs->clear_action();
     631          40 :         peer->MembershipRequestCallback(table);
     632          40 :         current_jobs_count_--;
     633          40 :         return;
     634             :     }
     635             : 
     636       81679 :     prs->RegisterRibOut(event->policy);
     637      118005 :     BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
     638             :         table, "Register table requested for action " << prs->action());
     639             : }
     640             : 
     641             : 
     642             : //
     643             : // Process REGISTER_RIB_COMPLETE event.
     644             : //
     645       81679 : void BgpMembershipManager::ProcessRegisterRibCompleteEvent(Event *event) {
     646       81679 :     IPeer *peer = event->peer;
     647       81679 :     BgpTable *table = event->table;
     648       81679 :     PeerRibState *prs = FindPeerRibState(peer, table);
     649       81679 :     assert(prs && prs->action() == RIBOUT_ADD);
     650       81679 :     assert(prs->ribin_registered());
     651       81679 :     assert(prs->ribout_registered());
     652      118005 :     BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
     653             :         table, "Register table completed for action " << prs->action());
     654       81679 :     prs->clear_action();
     655       81679 :     peer->MembershipRequestCallback(table);
     656       81679 :     NotifyPeerRegistration(peer, table, false);
     657       81679 :     current_jobs_count_--;
     658       81679 : }
     659             : 
     660             : //
     661             : // Process UNREGISTER_RIB event.
     662             : //
     663       81719 : void BgpMembershipManager::ProcessUnregisterRibEvent(Event *event) {
     664       81719 :     IPeer *peer = event->peer;
     665       81719 :     BgpTable *table = event->table;
     666       81719 :     PeerRibState *prs = FindPeerRibState(peer, table);
     667       81719 :     assert(prs);
     668       81719 :     assert(prs->action() == RIBIN_DELETE_RIBOUT_DELETE ||
     669             :         prs->action() == RIBIN_WALK_RIBOUT_DELETE);
     670       81719 :     if (prs->action() == RIBIN_DELETE_RIBOUT_DELETE)
     671       77332 :         assert(!prs->ribin_registered());
     672       81719 :     if (prs->action() == RIBIN_WALK_RIBOUT_DELETE)
     673        4387 :         assert(prs->ribin_registered());
     674       81719 :     assert(prs->ribout_registered());
     675             : 
     676       81719 :     prs->DeactivateRibOut();
     677      118125 :     BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
     678             :         table, "Unregister table requested for action " << prs->action());
     679       81719 : }
     680             : 
     681             : //
     682             : // Process UNREGISTER_RIB_COMPLETE event.
     683             : //
     684       81719 : void BgpMembershipManager::ProcessUnregisterRibCompleteEvent(Event *event) {
     685       81719 :     IPeer *peer = event->peer;
     686       81719 :     BgpTable *table = event->table;
     687       81719 :     PeerRibState *prs = FindPeerRibState(peer, table);
     688       81719 :     assert(prs);
     689       81719 :     assert(prs->action() == RIBIN_DELETE_RIBOUT_DELETE ||
     690             :         prs->action() == RIBIN_WALK_RIBOUT_DELETE);
     691       81719 :     if (prs->action() == RIBIN_DELETE_RIBOUT_DELETE)
     692       77332 :         assert(!prs->ribin_registered());
     693       81719 :     if (prs->action() == RIBIN_WALK_RIBOUT_DELETE)
     694        4387 :         assert(prs->ribin_registered());
     695             : 
     696       81719 :     prs->UnregisterRibOut();
     697      118125 :     BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
     698             :         table, "Unregister table completed for action " << prs->action());
     699       81719 :     prs->clear_action();
     700       81719 :     if (!prs->ribin_registered() && !prs->ribout_registered())
     701       77332 :         DestroyPeerRibState(prs);
     702             : 
     703       81719 :     peer->MembershipRequestCallback(table);
     704       81719 :     NotifyPeerRegistration(peer, table, true);
     705       81719 :     current_jobs_count_--;
     706       81719 : }
     707             : 
     708             : //
     709             : // Process WALK_RIB_COMPLETE event.
     710             : //
     711        5973 : void BgpMembershipManager::ProcessWalkRibCompleteEvent(Event *event) {
     712        5973 :     IPeer *peer = event->peer;
     713        5973 :     BgpTable *table = event->table;
     714        5973 :     PeerRibState *prs = FindPeerRibState(peer, table);
     715        5973 :     assert(prs);
     716        5973 :     assert(prs->action() == RIBIN_WALK || prs->action() == RIBIN_DELETE);
     717        5973 :     if (prs->action() == RIBIN_WALK) {
     718        3823 :         assert(prs->ribin_registered());
     719        9648 :         BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
     720             :             table, "Walk table completed for action " << prs->action());
     721             :     } else {
     722        2150 :         assert(!prs->ribin_registered());
     723        5945 :         BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
     724             :             table, "Unregister table completed for action " << prs->action());
     725             :     }
     726        5973 :     prs->clear_action();
     727        5973 :     if (!prs->ribin_registered() && !prs->ribout_registered())
     728        2150 :         DestroyPeerRibState(prs);
     729        5973 :     peer->MembershipRequestCallback(table);
     730        5973 :     current_jobs_count_--;
     731        5973 : }
     732             : 
     733             : //
     734             : // Internal handler for an Event.
     735             : // Exists so that test code can override it.
     736             : //
     737      332809 : bool BgpMembershipManager::EventCallbackInternal(Event *event) {
     738      332809 :     switch (event->event_type) {
     739       81719 :     case REGISTER_RIB:
     740       81719 :         ProcessRegisterRibEvent(event);
     741       81719 :         break;
     742       81679 :     case REGISTER_RIB_COMPLETE:
     743       81679 :         ProcessRegisterRibCompleteEvent(event);
     744       81679 :         break;
     745       81719 :     case UNREGISTER_RIB:
     746       81719 :         ProcessUnregisterRibEvent(event);
     747       81719 :         break;
     748       81719 :     case UNREGISTER_RIB_COMPLETE:
     749       81719 :         ProcessUnregisterRibCompleteEvent(event);
     750       81719 :         break;
     751        5973 :     case WALK_RIB_COMPLETE:
     752        5973 :         ProcessWalkRibCompleteEvent(event);
     753        5973 :         break;
     754           0 :     default:
     755           0 :         assert(false);
     756             :         break;
     757             :     }
     758             : 
     759      332809 :     delete event;
     760      332809 :     return true;
     761             : }
     762             : 
     763             : //
     764             : // Handler for an Event.
     765             : //
     766      332809 : bool BgpMembershipManager::EventCallback(Event *event) {
     767      332809 :     CHECK_CONCURRENCY("bgp::PeerMembership");
     768      332809 :     return EventCallbackInternal(event);
     769             : }
     770             : 
     771             : //
     772             : // Constructor.
     773             : //`
     774      251090 : BgpMembershipManager::Event::Event(EventType event_type, IPeer *peer,
     775      251090 :     BgpTable *table)
     776      251090 :     : event_type(event_type),
     777      251090 :       peer(peer),
     778      251090 :       table(table),
     779      251090 :       instance_id(-1) {
     780      251090 : }
     781             : 
     782             : //
     783             : // Constructor.
     784             : //`
     785       81717 : BgpMembershipManager::Event::Event(EventType event_type, IPeer *peer,
     786       81717 :     BgpTable *table, const RibExportPolicy &policy, int instance_id)
     787       81717 :     : event_type(event_type),
     788       81717 :       peer(peer),
     789       81717 :       table(table),
     790       81717 :       policy(policy),
     791       81714 :       instance_id(instance_id) {
     792       81714 : }
     793             : 
     794             : //
     795             : // Constructor.
     796             : //`
     797        8665 : BgpMembershipManager::PeerState::PeerState(BgpMembershipManager *manager,
     798        8665 :     IPeer *peer)
     799        8665 :     : manager_(manager),
     800        8665 :       peer_(peer) {
     801        8665 : }
     802             : 
     803             : //
     804             : // Destructor.
     805             : //`
     806        8665 : BgpMembershipManager::PeerState::~PeerState() {
     807        8665 :     assert(rib_map_.empty());
     808        8665 : }
     809             : 
     810             : //
     811             : // Find or create the PeerRibState for given RibState.
     812             : //
     813             : BgpMembershipManager::PeerRibState *
     814       88698 : BgpMembershipManager::PeerState::LocatePeerRibState(RibState *rs) {
     815       88698 :     PeerRibStateMap::iterator loc = rib_map_.find(rs);
     816       88696 :     if (loc == rib_map_.end()) {
     817       79480 :         PeerRibState *prs = new PeerRibState(manager_, this, rs);
     818       79481 :         rib_map_.insert(make_pair(rs, prs));
     819       79482 :         return prs;
     820             :     } else {
     821        9217 :         return loc->second;
     822             :     }
     823             : }
     824             : 
     825             : //
     826             : // Find the PeerRibState for given RibState.
     827             : //
     828             : BgpMembershipManager::PeerRibState *
     829      488755 : BgpMembershipManager::PeerState::FindPeerRibState(const RibState *rs) {
     830      488755 :     PeerRibStateMap::iterator loc = rib_map_.find(rs);
     831      488757 :     return (loc != rib_map_.end() ? loc->second : NULL);
     832             : }
     833             : 
     834             : //
     835             : // Find the PeerRibState for given RibState.
     836             : // Const version.
     837             : //
     838             : const BgpMembershipManager::PeerRibState *
     839      246660 : BgpMembershipManager::PeerState::FindPeerRibState(const RibState *rs) const {
     840      246660 :     PeerRibStateMap::const_iterator loc = rib_map_.find(rs);
     841      246658 :     return (loc != rib_map_.end() ? loc->second : NULL);
     842             : }
     843             : 
     844             : //
     845             : // Remove given PeerRibState from PeerRibStateMap.
     846             : // Return true if the PeerState itself can we deleted.
     847             : //
     848       79482 : bool BgpMembershipManager::PeerState::RemovePeerRibState(PeerRibState *prs) {
     849       79482 :     PeerRibStateMap::iterator loc = rib_map_.find(prs->rib_state());
     850       79482 :     if (loc != rib_map_.end())
     851       79482 :         rib_map_.erase(loc);
     852      158964 :     return rib_map_.empty();
     853             : }
     854             : 
     855             : //
     856             : // Fill in the list of registered BgpTables.
     857             : //
     858        9873 : void BgpMembershipManager::PeerState::GetRegisteredRibs(
     859             :     list<BgpTable *> *table_list) const {
     860        9873 :     for (PeerRibStateMap::const_iterator loc = rib_map_.begin();
     861       93354 :          loc != rib_map_.end(); ++loc) {
     862       83481 :         const RibState *rs = loc->first;
     863       83481 :         table_list->push_back(rs->table());
     864             :     }
     865        9873 : }
     866             : 
     867             : //
     868             : // Fill introspect information.
     869             : //
     870         529 : void BgpMembershipManager::PeerState::FillPeerMembershipInfo(
     871             :     BgpNeighborResp *resp) const {
     872         529 :     vector<BgpNeighborRoutingTable> table_list;
     873         529 :     for (PeerRibStateMap::const_iterator loc = rib_map_.begin();
     874       10083 :          loc != rib_map_.end(); ++loc) {
     875        9554 :         const RibState *rs = loc->first;
     876        9554 :         BgpNeighborRoutingTable table;
     877        9554 :         table.set_name(rs->table()->name());
     878        9554 :         table.set_current_state("subscribed");
     879        9554 :         table_list.push_back(table);
     880        9554 :     }
     881         529 :     resp->set_routing_tables(table_list);
     882         529 : }
     883             : 
     884             : //
     885             : // Constructor.
     886             : //
     887       31223 : BgpMembershipManager::RibState::RibState(BgpMembershipManager *manager,
     888       31223 :     BgpTable *table)
     889       31223 :     : manager_(manager),
     890       31223 :       table_(table),
     891       31223 :       request_count_(0),
     892       31223 :       walk_count_(0),
     893       31223 :       table_delete_ref_(this, table->deleter()) {
     894       31224 : }
     895             : 
     896             : //
     897             : // Destructor.
     898             : //
     899       31224 : BgpMembershipManager::RibState::~RibState() {
     900       31224 :     assert(peer_rib_list_.empty());
     901       31224 :     assert(pending_peer_rib_list_.empty());
     902       31224 : }
     903             : 
     904             : //
     905             : // Enqueue given PeerRibState into the pending PeerRibStateList.
     906             : //
     907      169331 : void BgpMembershipManager::RibState::EnqueuePeerRibState(PeerRibState *prs) {
     908      169331 :     request_count_++;
     909      169331 :     pending_peer_rib_list_.insert(prs);
     910      169331 :     manager_->EnqueueRibState(this);
     911      169331 : }
     912             : 
     913             : //
     914             : // Clear the pending PeerRibStateList.
     915             : //
     916      130103 : void BgpMembershipManager::RibState::ClearPeerRibStateList() {
     917      130103 :     pending_peer_rib_list_.clear();
     918      130103 : }
     919             : 
     920             : //
     921             : // Insert given PeerRibState into the regular PeerRibStateList.
     922             : //
     923       88698 : void BgpMembershipManager::RibState::InsertPeerRibState(PeerRibState *prs) {
     924       88698 :     peer_rib_list_.insert(prs);
     925       88703 : }
     926             : 
     927             : //
     928             : // Remove given PeerRibState from the regular PeerRibStateList.
     929             : //
     930       79482 : bool BgpMembershipManager::RibState::RemovePeerRibState(PeerRibState *prs) {
     931       79482 :     peer_rib_list_.erase(prs);
     932       79482 :     return peer_rib_list_.empty();
     933             : }
     934             : 
     935             : //
     936             : // Fill introspect information.
     937             : //
     938         980 : void BgpMembershipManager::RibState::FillRoutingInstanceTableInfo(
     939             :     ShowRoutingInstanceTable *srit) const {
     940         980 :     ShowTableMembershipInfo stmi;
     941         980 :     stmi.set_requests(request_count_);
     942         980 :     stmi.set_walks(walk_count_);
     943         980 :     vector<ShowMembershipPeerInfo> peers;
     944         980 :     for (PeerRibList::const_iterator it = peer_rib_list_.begin();
     945        2940 :          it != peer_rib_list_.end(); ++it) {
     946        1960 :         const PeerRibState *prs = *it;
     947        1960 :         ShowMembershipPeerInfo smpi;
     948        1960 :         prs->FillMembershipInfo(&smpi);
     949        1960 :         peers.push_back(smpi);
     950        1960 :     }
     951         980 :     stmi.set_peers(peers);
     952         980 :     srit->set_membership(stmi);
     953         980 : }
     954             : 
     955             : //
     956             : // Constructor.
     957             : //
     958       79481 : BgpMembershipManager::PeerRibState::PeerRibState(BgpMembershipManager *manager,
     959       79481 :     PeerState *ps, RibState *rs)
     960       79481 :     : manager_(manager),
     961       79481 :       ps_(ps),
     962       79481 :       rs_(rs),
     963       79481 :       ribout_(NULL),
     964       79481 :       ribout_index_(-1),
     965       79481 :       action_(BgpMembershipManager::NONE),
     966       79481 :       ribin_registered_(false),
     967       79481 :       ribout_registered_(false),
     968       79481 :       instance_id_(-1),
     969       79481 :       subscription_gen_id_(0) {
     970       79481 : }
     971             : 
     972             : //
     973             : // Destructor.
     974             : //
     975       79482 : BgpMembershipManager::PeerRibState::~PeerRibState() {
     976       79482 :     assert(!ribout_);
     977       79482 :     assert(ribout_index_ == -1);
     978       79482 :     assert(action_ == BgpMembershipManager::NONE);
     979       79482 :     assert(!ribin_registered_);
     980       79482 :     assert(!ribout_registered_);
     981       79482 :     assert(instance_id_ == -1);
     982       79482 :     assert(subscription_gen_id_ == 0);
     983       79482 : }
     984             : 
     985             : //
     986             : // Create RibOut for this PeerRibState and registers the RibOut as a listener
     987             : // for the BgpTable.
     988             : //
     989             : // Register the IPeer to the RibOut.
     990             : // This PeerRibState is added to the pending PeerRibStateList of RibState
     991             : // so that Join processing is handled when walking the BgpTable.
     992             : //
     993       81679 : void BgpMembershipManager::PeerRibState::RegisterRibOut(
     994             :     const RibExportPolicy &policy) {
     995       81679 :     CHECK_CONCURRENCY("bgp::PeerMembership");
     996             : 
     997       81679 :     BgpUpdateSender *sender = manager_->server()->update_sender();
     998       81679 :     ribout_ = rs_->table()->RibOutLocate(sender, policy);
     999       81679 :     ribout_->RegisterListener();
    1000       81679 :     ribout_->Register(ps_->peer());
    1001       81679 :     ribout_index_ = ribout_->GetPeerIndex(ps_->peer());
    1002       81679 :     ribout_registered_ = true;
    1003       81679 :     rs_->EnqueuePeerRibState(this);
    1004       81679 : }
    1005             : 
    1006             : //
    1007             : // Deactivate the IPeer in the RibOut.
    1008             : // This ensures that the IPeer will stop exporting routes from now onwards.
    1009             : //
    1010             : // Note that this is called before Leave processing for the IPeer is started.
    1011             : //
    1012             : // Bypass the Walker and directly post an UNREGISTER_RIB_COMPLETE event if
    1013             : // there's no RibOut. This happens if the table was marked deleted when the
    1014             : // register was processed.
    1015             : //
    1016       81719 : void BgpMembershipManager::PeerRibState::DeactivateRibOut() {
    1017       81719 :     CHECK_CONCURRENCY("bgp::PeerMembership");
    1018       81719 :     if (ribout_) {
    1019       81679 :         ribout_->Deactivate(ps_->peer());
    1020       81679 :         rs_->EnqueuePeerRibState(this);
    1021             :     } else {
    1022          40 :         assert(ribout_index_ == -1);
    1023          40 :         ribout_registered_ = false;
    1024          40 :         manager_->TriggerUnregisterRibCompleteEvent(ps_->peer(), rs_->table());
    1025             :     }
    1026       81719 : }
    1027             : 
    1028             : //
    1029             : // Unregister the IPeer from the BgpTable.
    1030             : // Unregister the IPeer from the RibOut, which may result in deletion of the
    1031             : // RibOut itself.
    1032             : //
    1033             : // Note that this is called only after Leave processing for the IPeer has been
    1034             : // completed.
    1035             : //
    1036       81719 : void BgpMembershipManager::PeerRibState::UnregisterRibOut() {
    1037       81719 :     CHECK_CONCURRENCY("bgp::PeerMembership");
    1038             : 
    1039       81719 :     if (!ribout_)
    1040          40 :         return;
    1041       81679 :     assert(ribout_index_ != -1);
    1042       81679 :     ribout_->Unregister(ps_->peer());
    1043       81679 :     ribout_ = NULL;
    1044       81679 :     ribout_index_ = -1;
    1045       81679 :     ribout_registered_ = false;
    1046             : }
    1047             : 
    1048             : //
    1049             : // Unregister the RibIn for the IPeer.
    1050             : //
    1051        2150 : void BgpMembershipManager::PeerRibState::UnregisterRibIn() {
    1052        2150 :     rs_->EnqueuePeerRibState(this);
    1053        2150 : }
    1054             : 
    1055             : //
    1056             : // Walk the RibIn for the IPeer.
    1057             : //
    1058        3823 : void BgpMembershipManager::PeerRibState::WalkRibIn() {
    1059        3823 :     rs_->EnqueuePeerRibState(this);
    1060        3823 : }
    1061             : 
    1062             : //
    1063             : // Fill introspect information.
    1064             : //
    1065        1960 : void BgpMembershipManager::PeerRibState::FillMembershipInfo(
    1066             :     ShowMembershipPeerInfo *smpi) const {
    1067        1960 :     smpi->set_peer(ps_->peer()->ToString());
    1068        1960 :     smpi->set_ribin_registered(ribin_registered_);
    1069        1960 :     smpi->set_ribout_registered(ribout_registered_);
    1070        1960 :     smpi->set_instance_id(instance_id_);
    1071        1960 :     smpi->set_generation_id(subscription_gen_id_);
    1072        1960 : }
    1073             : 
    1074             : //
    1075             : // Constructor.
    1076             : //
    1077        9743 : BgpMembershipManager::Walker::Walker(BgpMembershipManager *manager)
    1078        9743 :     : manager_(manager),
    1079       19486 :       trigger_(new TaskTrigger(
    1080             :           boost::bind(&BgpMembershipManager::Walker::WalkTrigger, this),
    1081       19486 :           TaskScheduler::GetInstance()->GetTaskId("bgp::PeerMembership"), 0)),
    1082        9743 :       postpone_walk_(false),
    1083        9743 :       walk_started_(false),
    1084        9743 :       walk_completed_(false),
    1085        9743 :       rs_(NULL),
    1086        9743 :       rib_state_list_size_(0),
    1087       19486 :       ribout_state_list_size_(0) {
    1088        9743 : }
    1089             : 
    1090             : //
    1091             : // Destructor.
    1092             : //
    1093        9743 : BgpMembershipManager::Walker::~Walker() {
    1094        9743 :     assert(rib_state_set_.empty());
    1095        9743 :     assert(rib_state_list_.empty());
    1096        9743 :     assert(!postpone_walk_);
    1097        9743 :     assert(!rs_);
    1098        9743 :     assert(walk_ref_ == NULL);
    1099        9743 :     assert(peer_rib_list_.empty());
    1100        9743 :     assert(peer_list_.empty());
    1101        9743 :     assert(ribout_state_map_.empty());
    1102        9743 :     assert(ribout_state_list_.empty());
    1103        9743 : }
    1104             : 
    1105             : //
    1106             : // Add the given RibState to the RibStateList if it's not already present.
    1107             : // Trigger processing of the RibStateList if a walk is not already in progress.
    1108             : //
    1109      169331 : void BgpMembershipManager::Walker::Enqueue(RibState *rs) {
    1110      169331 :     if (rib_state_set_.find(rs) != rib_state_set_.end())
    1111       39228 :         return;
    1112      130103 :     rib_state_set_.insert(rs);
    1113      130103 :     rib_state_list_.push_back(rs);
    1114      130103 :     rib_state_list_size_++;
    1115      130103 :     if (!walk_started_)
    1116      119156 :         trigger_->Set();
    1117             : }
    1118             : 
    1119             : //
    1120             : // Return true if the Walk does not have any pending items.
    1121             : //
    1122     1702443 : bool BgpMembershipManager::Walker::IsQueueEmpty() const {
    1123     1702443 :     return (rib_state_list_.empty() && !trigger_->IsSet() && !rs_);
    1124             : }
    1125             : 
    1126             : //
    1127             : // Find or create the RibOutState for given RibOut.
    1128             : //
    1129             : BgpMembershipManager::Walker::RibOutState *
    1130      163358 : BgpMembershipManager::Walker::LocateRibOutState(RibOut *ribout) {
    1131      163358 :     RibOutStateMap::iterator loc = ribout_state_map_.find(ribout);
    1132      163358 :     if (loc == ribout_state_map_.end()) {
    1133      126280 :         RibOutState *ros = new RibOutState(ribout);
    1134      126280 :         ribout_state_map_.insert(make_pair(ribout, ros));
    1135      126280 :         ribout_state_list_.push_back(ros);
    1136      126280 :         ribout_state_list_size_++;
    1137      126280 :         return ros;
    1138             :     } else {
    1139       37078 :         return loc->second;
    1140             :     }
    1141             : }
    1142             : 
    1143             : //
    1144             : // Process table walk callback from DB infrastructure.
    1145             : //
    1146      590392 : bool BgpMembershipManager::Walker::WalkCallback(DBTablePartBase *tpart,
    1147             :     DBEntryBase *db_entry) {
    1148      590392 :     CHECK_CONCURRENCY("db::DBTable");
    1149             : 
    1150             :     // Walk all RibOutStates and handle join/leave processing.
    1151      590289 :     for (RibOutStateList::iterator it = ribout_state_list_.begin();
    1152     1044096 :          it != ribout_state_list_.end(); ++it) {
    1153      453570 :         RibOutState *ros = *it;
    1154      453547 :         RibOut *ribout = ros->ribout();
    1155      453534 :         ribout->bgp_export()->Join(tpart, ros->join_bitset(), db_entry);
    1156      453625 :         ribout->bgp_export()->Leave(tpart, ros->leave_bitset(), db_entry);
    1157             :     }
    1158             : 
    1159             :     // Bail if there's no peers that need RibIn processing.
    1160      590513 :     if (peer_list_.empty())
    1161      103815 :         return true;
    1162             : 
    1163             :     // Walk through all eligible paths and notify the source peer if needed.
    1164      486667 :     bool notify = false;
    1165      486667 :     BgpRoute *route = static_cast<BgpRoute *>(db_entry);
    1166      973350 :     for (Route::PathList::iterator it = route->GetPathList().begin(), next = it;
    1167     1886586 :          it != route->GetPathList().end(); it = next) {
    1168      456663 :         next++;
    1169             : 
    1170      456663 :         BgpPath *path = static_cast<BgpPath *>(it.operator->());
    1171      456663 :         IPeer *peer = path->GetPeer();
    1172             : 
    1173             :         // Skip resolved paths - PathResolver is responsible for them.
    1174      456761 :         if (path->IsResolved())
    1175      356118 :             continue;
    1176             : 
    1177             :         // Skip aliased paths - EvpnManager is responsible for them.
    1178      454617 :         if (path->IsAliased())
    1179           0 :             continue;
    1180             : 
    1181             :         // Skip secondary paths.
    1182      454607 :         if (dynamic_cast<BgpSecondaryPath *>(path))
    1183      263875 :             continue;
    1184             : 
    1185             :         // Skip if there's no walk requested for this IPeer.
    1186      190732 :         if (!peer || peer_list_.find(peer) == peer_list_.end())
    1187       90125 :             continue;
    1188             : 
    1189      100481 :         notify |= peer->MembershipPathCallback(tpart, route, path);
    1190             :     }
    1191             : 
    1192      486408 :     rs_->table()->InputCommonPostProcess(tpart, route, notify);
    1193      486789 :     return true;
    1194             : }
    1195             : 
    1196             : //
    1197             : // Process table walk done callback from DB infrastructure.
    1198             : // Just note that the walk has completed and trigger processing from the
    1199             : // bgp::PeerMembership task.
    1200             : //
    1201      130103 : void BgpMembershipManager::Walker::WalkDoneCallback(DBTableBase *table_base) {
    1202      130103 :     CHECK_CONCURRENCY("db::Walker");
    1203      130103 :     assert(rs_->table() == table_base);
    1204      130103 :     walk_completed_ = true;
    1205      130103 :     trigger_->Set();
    1206      130103 : }
    1207             : 
    1208             : //
    1209             : // Start a walk for the BgpTable corresponding to the next RibState in the
    1210             : // RibStateList.
    1211             : //
    1212      155866 : void BgpMembershipManager::Walker::WalkStart() {
    1213      155866 :     CHECK_CONCURRENCY("bgp::PeerMembership");
    1214             : 
    1215      155866 :     assert(walk_ref_ == NULL);
    1216      155866 :     assert(!rs_);
    1217      155866 :     assert(peer_rib_list_.empty());
    1218      155866 :     assert(peer_list_.empty());
    1219      155866 :     assert(ribout_state_map_.empty());
    1220      155866 :     assert(ribout_state_list_.empty());
    1221      155866 :     assert(rib_state_list_size_ == rib_state_set_.size());
    1222             : 
    1223             :     // Bail if the list if empty.
    1224      155866 :     if (rib_state_list_.empty())
    1225       25763 :         return;
    1226             : 
    1227             :     // Get and remove the first RibState from the RibStateList.
    1228      130103 :     rs_ = rib_state_list_.front();
    1229      130103 :     rib_state_list_.pop_front();
    1230      130103 :     rib_state_list_size_--;
    1231      130103 :     assert(rib_state_set_.erase(rs_) == 1);
    1232             : 
    1233             :     // Process all pending PeerRibStates for chosen RibState.
    1234             :     // Insert the PeerRibStates into PeerRibList for post processing when
    1235             :     // table walk is complete.
    1236      299434 :     for (RibState::iterator it = rs_->begin(); it != rs_->end(); ++it) {
    1237      169331 :         PeerRibState *prs = *it;
    1238      169331 :         peer_rib_list_.insert(prs);
    1239             : 
    1240             :         // Update PeerList for RIBIN actions and RibOutStateMap for RIBOUT
    1241             :         // actions.
    1242      169331 :         switch (prs->action()) {
    1243       81679 :         case RIBOUT_ADD: {
    1244       81679 :             RibOutState *ros = LocateRibOutState(prs->ribout());
    1245       81679 :             ros->JoinPeer(prs->ribout_index());
    1246       81679 :             break;
    1247             :         }
    1248        5973 :         case RIBIN_DELETE:
    1249             :         case RIBIN_WALK: {
    1250        5973 :             IPeer *peer = prs->peer_state()->peer();
    1251        5973 :             peer_list_.insert(peer);
    1252        5973 :             break;
    1253             :         }
    1254       81679 :         case RIBIN_WALK_RIBOUT_DELETE:
    1255             :         case RIBIN_DELETE_RIBOUT_DELETE: {
    1256       81679 :             IPeer *peer = prs->peer_state()->peer();
    1257       81679 :             peer_list_.insert(peer);
    1258       81679 :             RibOutState *ros = LocateRibOutState(prs->ribout());
    1259       81679 :             ros->LeavePeer(prs->ribout_index());
    1260       81679 :             break;
    1261             :         }
    1262           0 :         default: {
    1263           0 :             assert(false);
    1264             :             break;
    1265             :         }
    1266             :         }
    1267             :     }
    1268             : 
    1269             :     // Clear the pending PeerRibStates in the RibState.
    1270             :     // This allows the RibState to accumulate new PeerRibStates for a future
    1271             :     // walk of it's BgpTable.
    1272      130103 :     rs_->ClearPeerRibStateList();
    1273             : 
    1274             :     // Start the walk.
    1275      130103 :     rs_->increment_walk_count();
    1276      130103 :     BgpTable *table = rs_->table();
    1277      260206 :     walk_ref_ = table->AllocWalker(
    1278             :         boost::bind(&BgpMembershipManager::Walker::WalkCallback, this, _1, _2),
    1279      130103 :         boost::bind(&BgpMembershipManager::Walker::WalkDoneCallback, this, _2));
    1280      130103 :     walk_started_ = true;
    1281      130103 :     if (!postpone_walk_)
    1282      130097 :         table->WalkTable(walk_ref_);
    1283             : }
    1284             : 
    1285             : //
    1286             : // Finish processing of the walk of BgpTable for current RibState.
    1287             : //
    1288             : // The walk complete notification is handled by WalkDoneCallback but all the
    1289             : // book-keeping and triggering of Events is handled by this method since it
    1290             : // needs to happen in bgp::PeerMembership task.
    1291             : //
    1292      130103 : void BgpMembershipManager::Walker::WalkFinish() {
    1293      130103 :     CHECK_CONCURRENCY("bgp::PeerMembership");
    1294             : 
    1295      130103 :     assert(walk_ref_ != NULL);
    1296      130103 :     assert(rs_);
    1297      130103 :     assert(!peer_rib_list_.empty());
    1298      130103 :     assert(!peer_list_.empty() || !ribout_state_map_.empty());
    1299      130103 :     assert(rib_state_list_size_ == rib_state_set_.size());
    1300      130103 :     assert(ribout_state_list_size_ == ribout_state_map_.size());
    1301             : 
    1302      130103 :     BgpTable *table = rs_->table();
    1303      130103 :     for (PeerRibList::iterator it = peer_rib_list_.begin();
    1304      299434 :          it != peer_rib_list_.end(); ++it) {
    1305      169331 :         PeerRibState *prs = *it;
    1306      169331 :         IPeer *peer = prs->peer_state()->peer();
    1307             : 
    1308      169331 :         switch (prs->action()) {
    1309       81679 :         case RIBOUT_ADD:
    1310       81679 :             manager_->TriggerRegisterRibCompleteEvent(peer, table);
    1311       81679 :             break;
    1312        5973 :         case RIBIN_DELETE:
    1313             :         case RIBIN_WALK:
    1314        5973 :             manager_->TriggerWalkRibCompleteEvent(peer, table);
    1315        5973 :             break;
    1316       81679 :         case RIBIN_WALK_RIBOUT_DELETE:
    1317             :         case RIBIN_DELETE_RIBOUT_DELETE:
    1318       81679 :             manager_->TriggerUnregisterRibCompleteEvent(peer, table);
    1319       81679 :             break;
    1320           0 :         default:
    1321           0 :             assert(false);
    1322             :             break;
    1323             :         }
    1324             :     }
    1325             : 
    1326      130103 :     table->ReleaseWalker(walk_ref_);
    1327      130103 :     rs_ = NULL;
    1328      130103 :     peer_rib_list_.clear();
    1329      130103 :     peer_list_.clear();
    1330      130103 :     ribout_state_list_.clear();
    1331      130103 :     ribout_state_list_size_ = 0;
    1332      130103 :     STLDeleteElements(&ribout_state_map_);
    1333             : 
    1334      130103 :     walk_started_ = false;
    1335      130103 :     walk_completed_ = false;
    1336      130103 : }
    1337             : 
    1338             : //
    1339             : // Handler for TaskTrigger.
    1340             : // Start a new walk or finish processing for the current walk and start a new
    1341             : // one.
    1342             : //
    1343      155866 : bool BgpMembershipManager::Walker::WalkTrigger() {
    1344      155866 :     CHECK_CONCURRENCY("bgp::PeerMembership");
    1345             : 
    1346      155866 :     if (!walk_started_) {
    1347       25763 :         assert(!walk_completed_);
    1348       25763 :         WalkStart();
    1349      130103 :     } else if (walk_completed_) {
    1350      130103 :         WalkFinish();
    1351      130103 :         WalkStart();
    1352             :     }
    1353      155866 :     return true;
    1354             : }
    1355             : 
    1356             : //
    1357             : // Disable the TaskTrigger so that the Walker can accumulate RibStates in the
    1358             : // RibStateList.
    1359             : // Testing only.
    1360             : //
    1361          28 : void BgpMembershipManager::Walker::SetQueueDisable(bool value) {
    1362          28 :     if (value) {
    1363          14 :         trigger_->set_disable();
    1364             :     } else {
    1365          14 :         trigger_->set_enable();
    1366             :     }
    1367          28 : }
    1368             : 
    1369             : //
    1370             : // Force the Walker to trigger walks that are postponed.
    1371             : // Testing only.
    1372             : //
    1373           6 : void BgpMembershipManager::Walker::PostponeWalk() {
    1374           6 :     assert(!walk_started_);
    1375           6 :     assert(walk_ref_ == NULL);
    1376           6 :     postpone_walk_ = true;
    1377           6 : }
    1378             : 
    1379             : //
    1380             : // Tell the DBTableWalkMgr to resume walk that was postponed previously.
    1381             : // Testing only.
    1382             : //
    1383           6 : void BgpMembershipManager::Walker::ResumeWalk() {
    1384           6 :     assert(walk_started_);
    1385           6 :     assert(!walk_completed_);
    1386           6 :     assert(walk_ref_ != NULL);
    1387           6 :     postpone_walk_ = false;
    1388           6 :     BgpTable *table = rs_->table();
    1389           6 :     table->WalkTable(walk_ref_);
    1390           6 : }

Generated by: LCOV version 1.14