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

Generated by: LCOV version 1.14