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: 632 775 81.5 %
Date: 2026-10-05 02:12:29 Functions: 79 89 88.8 %
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         418 : BgpMembershipManager::BgpMembershipManager(BgpServer *server)
      28         418 :     : server_(server),
      29         418 :       walker_(new Walker(this)),
      30         836 :       event_queue_(new WorkQueue<Event *>(
      31         836 :           TaskScheduler::GetInstance()->GetTaskId("bgp::PeerMembership"), 0,
      32        1254 :           boost::bind(&BgpMembershipManager::EventCallback, this, _1))) {
      33         418 :     current_jobs_count_ = 0;
      34         418 :     total_jobs_count_ = 0;
      35         418 : }
      36             : 
      37             : //
      38             : // Destructor for BgpMembershipManager.
      39             : //
      40         836 : BgpMembershipManager::~BgpMembershipManager() {
      41         418 :     assert(current_jobs_count_ == 0);
      42         418 :     assert(rib_state_map_.empty());
      43         418 :     assert(peer_state_map_.empty());
      44         836 : }
      45             : 
      46        1672 : int BgpMembershipManager::RegisterPeerRegistrationCallback(
      47             :     PeerRegistrationCallback callback) {
      48        1672 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
      49             : 
      50        1672 :     size_t id = registration_bmap_.find_first();
      51        1672 :     if (id == registration_bmap_.npos) {
      52        1672 :         id = registration_callbacks_.size();
      53        1672 :         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        1672 :     return id;
      62        1672 : }
      63             : 
      64        1672 : void BgpMembershipManager::UnregisterPeerRegistrationCallback(int id) {
      65        1672 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
      66             : 
      67        1672 :     registration_callbacks_[id] = NULL;
      68        1672 :     if ((size_t) id == registration_callbacks_.size() - 1) {
      69        3762 :         while (!registration_callbacks_.empty() &&
      70        1672 :                registration_callbacks_.back() == NULL) {
      71        1672 :             registration_callbacks_.pop_back();
      72             :         }
      73         418 :         if (registration_bmap_.size() > registration_callbacks_.size()) {
      74         418 :             registration_bmap_.resize(registration_callbacks_.size());
      75             :         }
      76             :     } else {
      77        1254 :         if ((size_t) id >= registration_bmap_.size()) {
      78        1254 :             registration_bmap_.resize(id + 1);
      79             :         }
      80        1254 :         registration_bmap_.set(id);
      81             :     }
      82        1672 : }
      83             : 
      84       11492 : void BgpMembershipManager::NotifyPeerRegistration(IPeer *peer, BgpTable *table,
      85             :     bool unregister) {
      86       11492 :     CHECK_CONCURRENCY("bgp::PeerMembership");
      87             : 
      88       11492 :     if (!peer->IsXmppPeer())
      89        3372 :         return;
      90             : 
      91        8120 :     for (PeerRegistrationListenerList::iterator iter =
      92        8120 :          registration_callbacks_.begin();
      93       40600 :          iter != registration_callbacks_.end(); ++iter) {
      94       32480 :         if (*iter != NULL) {
      95       32480 :             PeerRegistrationCallback callback = *iter;
      96       32480 :             (callback)(peer, table, unregister);
      97       32480 :         }
      98             :     }
      99             : }
     100             : 
     101        5745 : bool BgpMembershipManager::AssertRegister(PeerRibState *prs, bool do_assert) {
     102        5745 :     if (prs->action() != NONE) {
     103           0 :         if (do_assert)
     104           0 :             assert(prs->action() == NONE);
     105           0 :         return false;
     106             :     }
     107             : 
     108        5744 :     if (prs->ribout_registered()) {
     109           0 :         if (do_assert)
     110           0 :             assert(!prs->ribout_registered());
     111           0 :         return false;
     112             :     }
     113             : 
     114        5745 :     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        5746 : void BgpMembershipManager::Register(IPeer *peer, BgpTable *table,
     120             :     const RibExportPolicy &policy, int instance_id) {
     121        5746 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper",
     122             :         "bgp::StateMachine", "xmpp::StateMachine");
     123             : 
     124        5745 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
     125        5746 :     PeerRibState *prs = LocatePeerRibState(peer, table);
     126        5745 :     if (!AssertRegister(prs))
     127           0 :         return;
     128        5745 :     current_jobs_count_++;
     129        5745 :     total_jobs_count_++;
     130        5746 :     prs->set_ribin_registered(true);
     131        5746 :     prs->set_action(RIBOUT_ADD);
     132        5746 :     Event *event = new Event(REGISTER_RIB, peer, table, policy, instance_id);
     133        5745 :     EnqueueEvent(event);
     134        5746 : }
     135             : 
     136         440 : bool BgpMembershipManager::AssertRegisterRibIn(PeerRibState *prs, IPeer *peer,
     137             :                                                bool do_assert) {
     138         440 :     if (prs->action() != NONE) {
     139           0 :         if (do_assert)
     140           0 :             assert(prs->action() == NONE);
     141           0 :         return false;
     142             :     }
     143             : 
     144         440 :     if (prs->ribin_registered() && !peer->IsInGRTimerWaitState()) {
     145           0 :         if (do_assert)
     146           0 :             assert(!prs->ribin_registered() || peer->IsInGRTimerWaitState());
     147           0 :         return false;
     148             :     }
     149             : 
     150         440 :     if (prs->ribout_registered()) {
     151           0 :         if (do_assert)
     152           0 :             assert(!prs->ribout_registered());
     153           0 :         return false;
     154             :     }
     155             : 
     156         440 :     return true;
     157             : }
     158             : 
     159             : // Synchronously register the IPeer to the BgpTable for RIBIN.
     160         440 : void BgpMembershipManager::RegisterRibIn(IPeer *peer, BgpTable *table) {
     161         440 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper",
     162             :         "bgp::StateMachine", "xmpp::StateMachine");
     163             : 
     164         440 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
     165         440 :     PeerRibState *prs = LocatePeerRibState(peer, table);
     166         440 :     if (!AssertRegisterRibIn(prs, peer))
     167           0 :         return;
     168         440 :     prs->set_ribin_registered(true);
     169         440 : }
     170             : 
     171        4832 : bool BgpMembershipManager::AssertUnregister(PeerRibState *prs, bool do_assert) {
     172        4832 :     if (!prs || prs->action() != NONE) {
     173           0 :         if (do_assert)
     174           0 :             assert(prs && prs->action() == NONE);
     175           0 :         return false;
     176             :     }
     177             : 
     178        4832 :     if (!prs->ribin_registered()) {
     179           0 :         if (do_assert)
     180           0 :             assert(prs->ribin_registered());
     181           0 :         return false;
     182             :     }
     183             : 
     184        4832 :     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        4832 : void BgpMembershipManager::Unregister(IPeer *peer, BgpTable *table) {
     190        4832 :     CHECK_CONCURRENCY("bgp::Config", "bgp::StateMachine", "xmpp::StateMachine");
     191             : 
     192        4832 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
     193        4832 :     PeerRibState *prs = FindPeerRibState(peer, table);
     194        4832 :     if (!AssertUnregister(prs))
     195           0 :         return;
     196             : 
     197        4832 :     current_jobs_count_++;
     198        4832 :     total_jobs_count_++;
     199             : 
     200        4832 :     if (!prs->ribout_registered()) {
     201           0 :         UnregisterRibInUnlocked(prs);
     202           0 :         return;
     203             :     }
     204             : 
     205        4832 :     prs->set_action(RIBIN_DELETE_RIBOUT_DELETE);
     206        4832 :     prs->set_ribin_registered(false);
     207        4832 :     prs->set_instance_id(-1);
     208        4832 :     prs->set_subscription_gen_id(0);
     209        4832 :     Event *event = new Event(UNREGISTER_RIB, peer, table);
     210        4832 :     EnqueueEvent(event);
     211        4832 : }
     212             : 
     213             : //
     214             : // Unregister the IPeer from the BgpTable for RIBIN.
     215             : //
     216         454 : void BgpMembershipManager::UnregisterRibIn(IPeer *peer, BgpTable *table) {
     217         454 :     CHECK_CONCURRENCY("bgp::Config", "bgp::StateMachine", "xmpp::StateMachine");
     218             : 
     219         454 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
     220         454 :     current_jobs_count_++;
     221         454 :     total_jobs_count_++;
     222         454 :     PeerRibState *prs = FindPeerRibState(peer, table);
     223         454 :     assert(prs && prs->action() == NONE);
     224         454 :     assert(prs->ribin_registered() && !prs->ribout_registered());
     225         454 :     UnregisterRibInUnlocked(prs);
     226         454 : }
     227             : 
     228             : //
     229             : // Common routine to handle unregister of IPeer from Table for RIBIN.
     230             : //
     231         454 : void BgpMembershipManager::UnregisterRibInUnlocked(PeerRibState *prs) {
     232         454 :     prs->set_ribin_registered(false);
     233         454 :     prs->set_instance_id(-1);
     234         454 :     prs->set_subscription_gen_id(0);
     235         454 :     prs->set_action(RIBIN_DELETE);
     236         454 :     prs->UnregisterRibIn();
     237        1270 :     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         454 : }
     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         914 : void BgpMembershipManager::UnregisterRibOut(IPeer *peer, BgpTable *table) {
     249         914 :     CHECK_CONCURRENCY("bgp::Config", "bgp::StateMachine", "xmpp::StateMachine");
     250             : 
     251         914 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
     252         914 :     current_jobs_count_++;
     253         914 :     total_jobs_count_++;
     254         914 :     PeerRibState *prs = FindPeerRibState(peer, table);
     255         914 :     assert(prs && prs->action() == NONE);
     256         914 :     assert(prs->ribin_registered());
     257         914 :     assert(prs->ribout_registered());
     258         914 :     prs->set_instance_id(-1);
     259         914 :     prs->set_subscription_gen_id(0);
     260         914 :     prs->set_action(RIBIN_WALK_RIBOUT_DELETE);
     261         914 :     Event *event = new Event(UNREGISTER_RIB, peer, table);
     262         914 :     EnqueueEvent(event);
     263         914 : }
     264             : 
     265         572 : bool BgpMembershipManager::AssertWalkRibIn(PeerRibState *prs, bool do_assert) {
     266         572 :     if (!prs || prs->action() != NONE) {
     267           0 :         if (do_assert)
     268           0 :             assert(prs && prs->action() == NONE);
     269           0 :         return false;
     270             :     }
     271             : 
     272         572 :     if (!prs->ribin_registered()) {
     273           0 :         if (do_assert)
     274           0 :             assert(prs->ribin_registered());
     275           0 :         return false;
     276             :     }
     277             : 
     278         572 :     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         572 : void BgpMembershipManager::WalkRibIn(IPeer *peer, BgpTable *table) {
     287         572 :     CHECK_CONCURRENCY("bgp::Config", "bgp::StateMachine", "xmpp::StateMachine");
     288             : 
     289         572 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
     290         572 :     PeerRibState *prs = FindPeerRibState(peer, table);
     291         572 :     if (!AssertWalkRibIn(prs))
     292           0 :         return;
     293         572 :     current_jobs_count_++;
     294         572 :     total_jobs_count_++;
     295         572 :     prs->set_action(RIBIN_WALK);
     296         572 :     prs->WalkRibIn();
     297        1588 :     BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
     298             :         table, "Walk table requested for action " << prs->action());
     299         572 : }
     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        5408 : bool BgpMembershipManager::GetRegistrationInfo(
     306             :     const IPeer *peer, const BgpTable *table,
     307             :     int *instance_id, uint64_t *subscription_gen_id) const {
     308        5408 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     309        5408 :     const PeerRibState *prs = FindPeerRibState(peer, table);
     310        5407 :     if (!prs)
     311        1824 :         return false;
     312        3583 :     if (instance_id)
     313        3583 :         *instance_id = prs->instance_id();
     314        3583 :     if (subscription_gen_id)
     315        3583 :         *subscription_gen_id = prs->subscription_gen_id();
     316        3583 :     return true;
     317        5407 : }
     318             : 
     319             : //
     320             : // Update the registration info of the IPeer for the BgpTable.
     321             : //
     322        3864 : void BgpMembershipManager::SetRegistrationInfo(
     323             :     const IPeer *peer, const BgpTable *table,
     324             :     int instance_id, uint64_t subscription_gen_id) {
     325        3864 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     326        3862 :     PeerRibState *prs = FindPeerRibState(peer, table);
     327        3859 :     if (!prs)
     328           0 :         return;
     329        3859 :     prs->set_instance_id(instance_id);
     330        3859 :     prs->set_subscription_gen_id(subscription_gen_id);
     331        3859 : }
     332             : 
     333             : //
     334             : // Return true if the IPeer is registered to the BgpTable.
     335             : //
     336        6772 : bool BgpMembershipManager::IsRegistered(const IPeer *peer,
     337             :     const BgpTable *table) const {
     338        6772 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     339        6772 :     const PeerRibState *prs = FindPeerRibState(peer, table);
     340       13544 :     return (prs && prs->ribin_registered() && prs->ribout_registered());
     341        6772 : }
     342             : 
     343             : //
     344             : // Return true if the IPeer is registered to the BgpTable for RibIn.
     345             : //
     346         854 : bool BgpMembershipManager::IsRibInRegistered(const IPeer *peer,
     347             :     const BgpTable *table) const {
     348         854 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     349         854 :     const PeerRibState *prs = FindPeerRibState(peer, table);
     350        1708 :     return (prs && prs->ribin_registered());
     351         854 : }
     352             : 
     353             : //
     354             : // Return true if the IPeer is registered to the BgpTable for RibOut.
     355             : //
     356        3861 : bool BgpMembershipManager::IsRibOutRegistered(const IPeer *peer,
     357             :     const BgpTable *table) const {
     358        3861 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     359        3863 :     const PeerRibState *prs = FindPeerRibState(peer, table);
     360        7725 :     return (prs && prs->ribout_registered());
     361        3861 : }
     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        2034 : void BgpMembershipManager::GetRegisteredRibs(const IPeer *peer,
     382             :     list<BgpTable *> *table_list) const {
     383        2034 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     384        2034 :     table_list->clear();
     385        2034 :     const PeerState *ps = FindPeerState(peer);
     386        2034 :     if (ps)
     387        1376 :         ps->GetRegisteredRibs(table_list);
     388        2034 : }
     389             : 
     390             : //
     391             : //
     392             : // Fill membership introspect information for a BgpTable.
     393             : //
     394           0 : void BgpMembershipManager::FillRoutingInstanceTableInfo(
     395             :     ShowRoutingInstanceTable *srit, const BgpTable *table) const {
     396           0 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     397           0 :     BgpTable *nc_table = const_cast<BgpTable *>(table);
     398           0 :     const RibState *rs = FindRibState(nc_table);
     399           0 :     if (rs)
     400           0 :         rs->FillRoutingInstanceTableInfo(srit);
     401           0 : }
     402             : 
     403             : //
     404             : // Fill membership introspect information for an IPeer.
     405             : //
     406           0 : void BgpMembershipManager::FillPeerMembershipInfo(const IPeer *peer,
     407             :         BgpNeighborResp *resp) const {
     408           0 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     409           0 :     assert(resp->get_routing_tables().empty());
     410           0 :     IPeer *nc_peer = const_cast<IPeer *>(peer);
     411             : 
     412           0 :     BgpUpdateSender *sender = server_->update_sender();
     413           0 :     if (sender->PeerIsRegistered(nc_peer)) {
     414           0 :         resp->set_send_state(
     415           0 :             sender->PeerInSync(nc_peer) ? "in sync" : "not in sync");
     416             :     } else {
     417           0 :         resp->set_send_state("not advertising");
     418             :     }
     419             : 
     420           0 :     const PeerState *ps = FindPeerState(nc_peer);
     421           0 :     if (ps)
     422           0 :         ps->FillPeerMembershipInfo(resp);
     423           0 : }
     424             : 
     425             : //
     426             : // Return true if no pending work in the BgpMembershipManager itself and
     427             : // in the Walker.
     428             : //
     429       24169 : bool BgpMembershipManager::IsQueueEmpty() const {
     430       24169 :     return (event_queue_->IsQueueEmpty() && walker_->IsQueueEmpty());
     431             : }
     432             : 
     433             : //
     434             : // Return number of PeerRibStates.
     435             : //
     436           0 : size_t BgpMembershipManager::GetMembershipCount() const {
     437           0 :     size_t count = 0;
     438           0 :     for (PeerStateMap::const_iterator loc = peer_state_map_.begin();
     439           0 :          loc != peer_state_map_.end(); ++loc) {
     440           0 :         const PeerState *ps = loc->second;
     441           0 :         count += ps->GetMembershipCount();
     442             :     }
     443           0 :     return count;
     444             : }
     445             : 
     446             : //
     447             : // Find or create the PeerState for given IPeer.
     448             : //
     449        6186 : BgpMembershipManager::PeerState *BgpMembershipManager::LocatePeerState(
     450             :     IPeer *peer) {
     451        6186 :     PeerStateMap::iterator loc = peer_state_map_.find(peer);
     452        6186 :     if (loc == peer_state_map_.end()) {
     453        1258 :         PeerState *ps = new PeerState(this, peer);
     454        1258 :         peer_state_map_.insert(make_pair(peer, ps));
     455        1258 :         return ps;
     456             :     } else {
     457        4928 :         return loc->second;
     458             :     }
     459             : }
     460             : 
     461             : //
     462             : // Find the PeerState for given IPeer.
     463             : //
     464       34644 : BgpMembershipManager::PeerState *BgpMembershipManager::FindPeerState(
     465             :     const IPeer *peer) {
     466       34644 :     PeerStateMap::iterator loc = peer_state_map_.find(peer);
     467       34642 :     return (loc != peer_state_map_.end() ? loc->second : NULL);
     468             : }
     469             : 
     470             : //
     471             : // Find the PeerState for given IPeer.
     472             : // Const version.
     473             : //
     474       18931 : const BgpMembershipManager::PeerState *BgpMembershipManager::FindPeerState(
     475             :     const IPeer *peer) const {
     476       18931 :     PeerStateMap::const_iterator loc = peer_state_map_.find(peer);
     477       18928 :     return (loc != peer_state_map_.end() ? loc->second : NULL);
     478             : }
     479             : 
     480             : //
     481             : // Destroy the given PeerState.
     482             : //
     483        1258 : void BgpMembershipManager::DestroyPeerState(PeerState *ps) {
     484        1258 :     peer_state_map_.erase(ps->peer());
     485        1258 :     delete ps;
     486        1258 : }
     487             : 
     488             : //
     489             : // Find or create the RibState for given BgpTable.
     490             : //
     491        6186 : BgpMembershipManager::RibState *BgpMembershipManager::LocateRibState(
     492             :     BgpTable *table) {
     493        6186 :     RibStateMap::iterator loc = rib_state_map_.find(table);
     494        6186 :     if (loc == rib_state_map_.end()) {
     495        1657 :         RibState *rs = new RibState(this, table);
     496        1657 :         rib_state_map_.insert(make_pair(table, rs));
     497        1657 :         return rs;
     498             :     } else {
     499        4529 :         return loc->second;
     500             :     }
     501             : }
     502             : 
     503             : //
     504             : // Find the RibState for given BgpTable.
     505             : //
     506       34642 : BgpMembershipManager::RibState *BgpMembershipManager::FindRibState(
     507             :     const BgpTable *table) {
     508       34642 :     RibStateMap::iterator loc = rib_state_map_.find(table);
     509       34642 :     return (loc != rib_state_map_.end() ? loc->second : NULL);
     510             : }
     511             : 
     512             : //
     513             : // Find the RibState for given BgpTable.
     514             : // Const version.
     515             : //
     516       16894 : const BgpMembershipManager::RibState *BgpMembershipManager::FindRibState(
     517             :     const BgpTable *table) const {
     518       16894 :     RibStateMap::const_iterator loc = rib_state_map_.find(table);
     519       16894 :     return (loc != rib_state_map_.end() ? loc->second : NULL);
     520             : }
     521             : 
     522             : //
     523             : // Destroy the given RibState.
     524             : //
     525        1657 : void BgpMembershipManager::DestroyRibState(RibState *rs) {
     526        1657 :     rib_state_map_.erase(rs->table());
     527        1657 :     delete rs;
     528        1657 : }
     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       12518 : void BgpMembershipManager::EnqueueRibState(RibState *rs) {
     535       12518 :     walker_->Enqueue(rs);
     536       12518 : }
     537             : 
     538             : //
     539             : // Find or create the PeerRibState for given (IPeer, BgpTable).
     540             : //
     541        6186 : BgpMembershipManager::PeerRibState *BgpMembershipManager::LocatePeerRibState(
     542             :     IPeer *peer, BgpTable *table) {
     543        6186 :     PeerState *ps = LocatePeerState(peer);
     544        6186 :     RibState *rs = LocateRibState(table);
     545        6186 :     PeerRibState *prs = ps->LocatePeerRibState(rs);
     546        6186 :     rs->InsertPeerRibState(prs);
     547        6184 :     return prs;
     548             : }
     549             : 
     550             : //
     551             : // Find the PeerRibState for given (IPeer, BgpTable).
     552             : //
     553       34644 : BgpMembershipManager::PeerRibState *BgpMembershipManager::FindPeerRibState(
     554             :     const IPeer *peer, const BgpTable *table) {
     555       34644 :     PeerState *ps = FindPeerState(peer);
     556       34642 :     RibState *rs = FindRibState(table);
     557       34642 :     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       16897 : BgpMembershipManager::FindPeerRibState(
     566             :     const IPeer *peer, const BgpTable *table) const {
     567       16897 :     const PeerState *ps = FindPeerState(peer);
     568       16894 :     const RibState *rs = FindRibState(table);
     569       16894 :     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        5286 : void BgpMembershipManager::DestroyPeerRibState(PeerRibState *prs) {
     577        5286 :     PeerState *ps = prs->peer_state();
     578        5286 :     RibState *rs = prs->rib_state();
     579        5286 :     if (ps->RemovePeerRibState(prs))
     580        1258 :         DestroyPeerState(ps);
     581        5286 :     if (rs->RemovePeerRibState(prs))
     582        1657 :         DestroyRibState(rs);
     583        5286 :     delete prs;
     584        5286 : }
     585             : 
     586             : //
     587             : // Trigger REGISTER_RIB_COMPLETE event.
     588             : //
     589        5746 : void BgpMembershipManager::TriggerRegisterRibCompleteEvent(IPeer *peer,
     590             :     BgpTable *table) {
     591        5746 :     Event *event = new Event(REGISTER_RIB_COMPLETE, peer, table);
     592        5746 :     EnqueueEvent(event);
     593        5746 : }
     594             : 
     595             : //
     596             : // Trigger UNREGISTER_RIB_COMPLETE event.
     597             : //
     598        5746 : void BgpMembershipManager::TriggerUnregisterRibCompleteEvent(IPeer *peer,
     599             :     BgpTable *table) {
     600        5746 :     Event *event = new Event(UNREGISTER_RIB_COMPLETE, peer, table);
     601        5746 :     EnqueueEvent(event);
     602        5746 : }
     603             : 
     604             : //
     605             : // Trigger WALK_RIB_COMPLETE event.
     606             : //
     607        1026 : void BgpMembershipManager::TriggerWalkRibCompleteEvent(IPeer *peer,
     608             :     BgpTable *table) {
     609        1026 :     Event *event = new Event(WALK_RIB_COMPLETE, peer, table);
     610        1026 :     EnqueueEvent(event);
     611        1026 : }
     612             : 
     613             : //
     614             : // Process REGISTER_RIB event.
     615             : //
     616        5746 : void BgpMembershipManager::ProcessRegisterRibEvent(Event *event) {
     617        5746 :     IPeer *peer = event->peer;
     618        5746 :     BgpTable *table = event->table;
     619        5746 :     PeerRibState *prs = FindPeerRibState(peer, table);
     620        5746 :     assert(prs && prs->action() == RIBOUT_ADD);
     621        5746 :     assert(prs->ribin_registered());
     622        5746 :     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        5746 :     if (table->IsDeleted()) {
     628           0 :         prs->set_ribout_registered(true);
     629           0 :         prs->clear_action();
     630           0 :         peer->MembershipRequestCallback(table);
     631           0 :         current_jobs_count_--;
     632           0 :         return;
     633             :     }
     634             : 
     635        5746 :     prs->RegisterRibOut(event->policy);
     636        8253 :     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        5746 : void BgpMembershipManager::ProcessRegisterRibCompleteEvent(Event *event) {
     645        5746 :     IPeer *peer = event->peer;
     646        5746 :     BgpTable *table = event->table;
     647        5746 :     PeerRibState *prs = FindPeerRibState(peer, table);
     648        5746 :     assert(prs && prs->action() == RIBOUT_ADD);
     649        5746 :     assert(prs->ribin_registered());
     650        5746 :     assert(prs->ribout_registered());
     651        8253 :     BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
     652             :         table, "Register table completed for action " << prs->action());
     653        5746 :     prs->clear_action();
     654        5746 :     peer->MembershipRequestCallback(table);
     655        5746 :     NotifyPeerRegistration(peer, table, false);
     656        5746 :     current_jobs_count_--;
     657        5746 : }
     658             : 
     659             : //
     660             : // Process UNREGISTER_RIB event.
     661             : //
     662        5746 : void BgpMembershipManager::ProcessUnregisterRibEvent(Event *event) {
     663        5746 :     IPeer *peer = event->peer;
     664        5746 :     BgpTable *table = event->table;
     665        5746 :     PeerRibState *prs = FindPeerRibState(peer, table);
     666        5746 :     assert(prs);
     667        5746 :     assert(prs->action() == RIBIN_DELETE_RIBOUT_DELETE ||
     668             :         prs->action() == RIBIN_WALK_RIBOUT_DELETE);
     669        5746 :     if (prs->action() == RIBIN_DELETE_RIBOUT_DELETE)
     670        4832 :         assert(!prs->ribin_registered());
     671        5746 :     if (prs->action() == RIBIN_WALK_RIBOUT_DELETE)
     672         914 :         assert(prs->ribin_registered());
     673        5746 :     assert(prs->ribout_registered());
     674             : 
     675        5746 :     prs->DeactivateRibOut();
     676        8253 :     BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
     677             :         table, "Unregister table requested for action " << prs->action());
     678        5746 : }
     679             : 
     680             : //
     681             : // Process UNREGISTER_RIB_COMPLETE event.
     682             : //
     683        5746 : void BgpMembershipManager::ProcessUnregisterRibCompleteEvent(Event *event) {
     684        5746 :     IPeer *peer = event->peer;
     685        5746 :     BgpTable *table = event->table;
     686        5746 :     PeerRibState *prs = FindPeerRibState(peer, table);
     687        5746 :     assert(prs);
     688        5746 :     assert(prs->action() == RIBIN_DELETE_RIBOUT_DELETE ||
     689             :         prs->action() == RIBIN_WALK_RIBOUT_DELETE);
     690        5746 :     if (prs->action() == RIBIN_DELETE_RIBOUT_DELETE)
     691        4832 :         assert(!prs->ribin_registered());
     692        5746 :     if (prs->action() == RIBIN_WALK_RIBOUT_DELETE)
     693         914 :         assert(prs->ribin_registered());
     694             : 
     695        5746 :     prs->UnregisterRibOut();
     696        8253 :     BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
     697             :         table, "Unregister table completed for action " << prs->action());
     698        5746 :     prs->clear_action();
     699        5746 :     if (!prs->ribin_registered() && !prs->ribout_registered())
     700        4832 :         DestroyPeerRibState(prs);
     701             : 
     702        5746 :     peer->MembershipRequestCallback(table);
     703        5746 :     NotifyPeerRegistration(peer, table, true);
     704        5746 :     current_jobs_count_--;
     705        5746 : }
     706             : 
     707             : //
     708             : // Process WALK_RIB_COMPLETE event.
     709             : //
     710        1026 : void BgpMembershipManager::ProcessWalkRibCompleteEvent(Event *event) {
     711        1026 :     IPeer *peer = event->peer;
     712        1026 :     BgpTable *table = event->table;
     713        1026 :     PeerRibState *prs = FindPeerRibState(peer, table);
     714        1026 :     assert(prs);
     715        1026 :     assert(prs->action() == RIBIN_WALK || prs->action() == RIBIN_DELETE);
     716        1026 :     if (prs->action() == RIBIN_WALK) {
     717         572 :         assert(prs->ribin_registered());
     718        1588 :         BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
     719             :             table, "Walk table completed for action " << prs->action());
     720             :     } else {
     721         454 :         assert(!prs->ribin_registered());
     722        1270 :         BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
     723             :             table, "Unregister table completed for action " << prs->action());
     724             :     }
     725        1026 :     prs->clear_action();
     726        1026 :     if (!prs->ribin_registered() && !prs->ribout_registered())
     727         454 :         DestroyPeerRibState(prs);
     728        1026 :     peer->MembershipRequestCallback(table);
     729        1026 :     current_jobs_count_--;
     730        1026 : }
     731             : 
     732             : //
     733             : // Internal handler for an Event.
     734             : // Exists so that test code can override it.
     735             : //
     736       24010 : bool BgpMembershipManager::EventCallbackInternal(Event *event) {
     737       24010 :     switch (event->event_type) {
     738        5746 :     case REGISTER_RIB:
     739        5746 :         ProcessRegisterRibEvent(event);
     740        5746 :         break;
     741        5746 :     case REGISTER_RIB_COMPLETE:
     742        5746 :         ProcessRegisterRibCompleteEvent(event);
     743        5746 :         break;
     744        5746 :     case UNREGISTER_RIB:
     745        5746 :         ProcessUnregisterRibEvent(event);
     746        5746 :         break;
     747        5746 :     case UNREGISTER_RIB_COMPLETE:
     748        5746 :         ProcessUnregisterRibCompleteEvent(event);
     749        5746 :         break;
     750        1026 :     case WALK_RIB_COMPLETE:
     751        1026 :         ProcessWalkRibCompleteEvent(event);
     752        1026 :         break;
     753           0 :     default:
     754           0 :         assert(false);
     755             :         break;
     756             :     }
     757             : 
     758       24010 :     delete event;
     759       24010 :     return true;
     760             : }
     761             : 
     762             : //
     763             : // Handler for an Event.
     764             : //
     765       24010 : bool BgpMembershipManager::EventCallback(Event *event) {
     766       24010 :     CHECK_CONCURRENCY("bgp::PeerMembership");
     767       24010 :     return EventCallbackInternal(event);
     768             : }
     769             : 
     770             : //
     771             : // Constructor.
     772             : //`
     773       18264 : BgpMembershipManager::Event::Event(EventType event_type, IPeer *peer,
     774       18264 :     BgpTable *table)
     775       18264 :     : event_type(event_type),
     776       18264 :       peer(peer),
     777       18264 :       table(table),
     778       18264 :       instance_id(-1) {
     779       18264 : }
     780             : 
     781             : //
     782             : // Constructor.
     783             : //`
     784        5746 : BgpMembershipManager::Event::Event(EventType event_type, IPeer *peer,
     785        5746 :     BgpTable *table, const RibExportPolicy &policy, int instance_id)
     786        5746 :     : event_type(event_type),
     787        5746 :       peer(peer),
     788        5746 :       table(table),
     789        5746 :       policy(policy),
     790        5745 :       instance_id(instance_id) {
     791        5745 : }
     792             : 
     793             : //
     794             : // Constructor.
     795             : //`
     796        1258 : BgpMembershipManager::PeerState::PeerState(BgpMembershipManager *manager,
     797        1258 :     IPeer *peer)
     798        1258 :     : manager_(manager),
     799        1258 :       peer_(peer) {
     800        1258 : }
     801             : 
     802             : //
     803             : // Destructor.
     804             : //`
     805        1258 : BgpMembershipManager::PeerState::~PeerState() {
     806        1258 :     assert(rib_map_.empty());
     807        1258 : }
     808             : 
     809             : //
     810             : // Find or create the PeerRibState for given RibState.
     811             : //
     812             : BgpMembershipManager::PeerRibState *
     813        6186 : BgpMembershipManager::PeerState::LocatePeerRibState(RibState *rs) {
     814        6186 :     PeerRibStateMap::iterator loc = rib_map_.find(rs);
     815        6186 :     if (loc == rib_map_.end()) {
     816        5286 :         PeerRibState *prs = new PeerRibState(manager_, this, rs);
     817        5285 :         rib_map_.insert(make_pair(rs, prs));
     818        5286 :         return prs;
     819             :     } else {
     820         900 :         return loc->second;
     821             :     }
     822             : }
     823             : 
     824             : //
     825             : // Find the PeerRibState for given RibState.
     826             : //
     827             : BgpMembershipManager::PeerRibState *
     828       34642 : BgpMembershipManager::PeerState::FindPeerRibState(const RibState *rs) {
     829       34642 :     PeerRibStateMap::iterator loc = rib_map_.find(rs);
     830       34641 :     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       16894 : BgpMembershipManager::PeerState::FindPeerRibState(const RibState *rs) const {
     839       16894 :     PeerRibStateMap::const_iterator loc = rib_map_.find(rs);
     840       16895 :     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        5286 : bool BgpMembershipManager::PeerState::RemovePeerRibState(PeerRibState *prs) {
     848        5286 :     PeerRibStateMap::iterator loc = rib_map_.find(prs->rib_state());
     849        5286 :     if (loc != rib_map_.end())
     850        5286 :         rib_map_.erase(loc);
     851       10572 :     return rib_map_.empty();
     852             : }
     853             : 
     854             : //
     855             : // Fill in the list of registered BgpTables.
     856             : //
     857        1376 : void BgpMembershipManager::PeerState::GetRegisteredRibs(
     858             :     list<BgpTable *> *table_list) const {
     859        1376 :     for (PeerRibStateMap::const_iterator loc = rib_map_.begin();
     860        8148 :          loc != rib_map_.end(); ++loc) {
     861        6772 :         const RibState *rs = loc->first;
     862        6772 :         table_list->push_back(rs->table());
     863             :     }
     864        1376 : }
     865             : 
     866             : //
     867             : // Fill introspect information.
     868             : //
     869           0 : void BgpMembershipManager::PeerState::FillPeerMembershipInfo(
     870             :     BgpNeighborResp *resp) const {
     871           0 :     vector<BgpNeighborRoutingTable> table_list;
     872           0 :     for (PeerRibStateMap::const_iterator loc = rib_map_.begin();
     873           0 :          loc != rib_map_.end(); ++loc) {
     874           0 :         const RibState *rs = loc->first;
     875           0 :         BgpNeighborRoutingTable table;
     876           0 :         table.set_name(rs->table()->name());
     877           0 :         table.set_current_state("subscribed");
     878           0 :         table_list.push_back(table);
     879           0 :     }
     880           0 :     resp->set_routing_tables(table_list);
     881           0 : }
     882             : 
     883             : //
     884             : // Constructor.
     885             : //
     886        1657 : BgpMembershipManager::RibState::RibState(BgpMembershipManager *manager,
     887        1657 :     BgpTable *table)
     888        1657 :     : manager_(manager),
     889        1657 :       table_(table),
     890        1657 :       request_count_(0),
     891        1657 :       walk_count_(0),
     892        1657 :       table_delete_ref_(this, table->deleter()) {
     893        1657 : }
     894             : 
     895             : //
     896             : // Destructor.
     897             : //
     898        1657 : BgpMembershipManager::RibState::~RibState() {
     899        1657 :     assert(peer_rib_list_.empty());
     900        1657 :     assert(pending_peer_rib_list_.empty());
     901        1657 : }
     902             : 
     903             : //
     904             : // Enqueue given PeerRibState into the pending PeerRibStateList.
     905             : //
     906       12518 : void BgpMembershipManager::RibState::EnqueuePeerRibState(PeerRibState *prs) {
     907       12518 :     request_count_++;
     908       12518 :     pending_peer_rib_list_.insert(prs);
     909       12518 :     manager_->EnqueueRibState(this);
     910       12518 : }
     911             : 
     912             : //
     913             : // Clear the pending PeerRibStateList.
     914             : //
     915        8346 : void BgpMembershipManager::RibState::ClearPeerRibStateList() {
     916        8346 :     pending_peer_rib_list_.clear();
     917        8346 : }
     918             : 
     919             : //
     920             : // Insert given PeerRibState into the regular PeerRibStateList.
     921             : //
     922        6186 : void BgpMembershipManager::RibState::InsertPeerRibState(PeerRibState *prs) {
     923        6186 :     peer_rib_list_.insert(prs);
     924        6184 : }
     925             : 
     926             : //
     927             : // Remove given PeerRibState from the regular PeerRibStateList.
     928             : //
     929        5286 : bool BgpMembershipManager::RibState::RemovePeerRibState(PeerRibState *prs) {
     930        5286 :     peer_rib_list_.erase(prs);
     931        5286 :     return peer_rib_list_.empty();
     932             : }
     933             : 
     934             : //
     935             : // Fill introspect information.
     936             : //
     937           0 : void BgpMembershipManager::RibState::FillRoutingInstanceTableInfo(
     938             :     ShowRoutingInstanceTable *srit) const {
     939           0 :     ShowTableMembershipInfo stmi;
     940           0 :     stmi.set_requests(request_count_);
     941           0 :     stmi.set_walks(walk_count_);
     942           0 :     vector<ShowMembershipPeerInfo> peers;
     943           0 :     for (PeerRibList::const_iterator it = peer_rib_list_.begin();
     944           0 :          it != peer_rib_list_.end(); ++it) {
     945           0 :         const PeerRibState *prs = *it;
     946           0 :         ShowMembershipPeerInfo smpi;
     947           0 :         prs->FillMembershipInfo(&smpi);
     948           0 :         peers.push_back(smpi);
     949           0 :     }
     950           0 :     stmi.set_peers(peers);
     951           0 :     srit->set_membership(stmi);
     952           0 : }
     953             : 
     954             : //
     955             : // Constructor.
     956             : //
     957        5285 : BgpMembershipManager::PeerRibState::PeerRibState(BgpMembershipManager *manager,
     958        5285 :     PeerState *ps, RibState *rs)
     959        5285 :     : manager_(manager),
     960        5285 :       ps_(ps),
     961        5285 :       rs_(rs),
     962        5285 :       ribout_(NULL),
     963        5285 :       ribout_index_(-1),
     964        5285 :       action_(BgpMembershipManager::NONE),
     965        5285 :       ribin_registered_(false),
     966        5285 :       ribout_registered_(false),
     967        5285 :       instance_id_(-1),
     968        5285 :       subscription_gen_id_(0) {
     969        5285 : }
     970             : 
     971             : //
     972             : // Destructor.
     973             : //
     974        5286 : BgpMembershipManager::PeerRibState::~PeerRibState() {
     975        5286 :     assert(!ribout_);
     976        5286 :     assert(ribout_index_ == -1);
     977        5286 :     assert(action_ == BgpMembershipManager::NONE);
     978        5286 :     assert(!ribin_registered_);
     979        5286 :     assert(!ribout_registered_);
     980        5286 :     assert(instance_id_ == -1);
     981        5286 :     assert(subscription_gen_id_ == 0);
     982        5286 : }
     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        5746 : void BgpMembershipManager::PeerRibState::RegisterRibOut(
     993             :     const RibExportPolicy &policy) {
     994        5746 :     CHECK_CONCURRENCY("bgp::PeerMembership");
     995             : 
     996        5746 :     BgpUpdateSender *sender = manager_->server()->update_sender();
     997        5746 :     ribout_ = rs_->table()->RibOutLocate(sender, policy);
     998        5746 :     ribout_->RegisterListener();
     999        5746 :     ribout_->Register(ps_->peer());
    1000        5746 :     ribout_index_ = ribout_->GetPeerIndex(ps_->peer());
    1001        5746 :     ribout_registered_ = true;
    1002        5746 :     rs_->EnqueuePeerRibState(this);
    1003        5746 : }
    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        5746 : void BgpMembershipManager::PeerRibState::DeactivateRibOut() {
    1016        5746 :     CHECK_CONCURRENCY("bgp::PeerMembership");
    1017        5746 :     if (ribout_) {
    1018        5746 :         ribout_->Deactivate(ps_->peer());
    1019        5746 :         rs_->EnqueuePeerRibState(this);
    1020             :     } else {
    1021           0 :         assert(ribout_index_ == -1);
    1022           0 :         ribout_registered_ = false;
    1023           0 :         manager_->TriggerUnregisterRibCompleteEvent(ps_->peer(), rs_->table());
    1024             :     }
    1025        5746 : }
    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        5746 : void BgpMembershipManager::PeerRibState::UnregisterRibOut() {
    1036        5746 :     CHECK_CONCURRENCY("bgp::PeerMembership");
    1037             : 
    1038        5746 :     if (!ribout_)
    1039           0 :         return;
    1040        5746 :     assert(ribout_index_ != -1);
    1041        5746 :     ribout_->Unregister(ps_->peer());
    1042        5746 :     ribout_ = NULL;
    1043        5746 :     ribout_index_ = -1;
    1044        5746 :     ribout_registered_ = false;
    1045             : }
    1046             : 
    1047             : //
    1048             : // Unregister the RibIn for the IPeer.
    1049             : //
    1050         454 : void BgpMembershipManager::PeerRibState::UnregisterRibIn() {
    1051         454 :     rs_->EnqueuePeerRibState(this);
    1052         454 : }
    1053             : 
    1054             : //
    1055             : // Walk the RibIn for the IPeer.
    1056             : //
    1057         572 : void BgpMembershipManager::PeerRibState::WalkRibIn() {
    1058         572 :     rs_->EnqueuePeerRibState(this);
    1059         572 : }
    1060             : 
    1061             : //
    1062             : // Fill introspect information.
    1063             : //
    1064           0 : void BgpMembershipManager::PeerRibState::FillMembershipInfo(
    1065             :     ShowMembershipPeerInfo *smpi) const {
    1066           0 :     smpi->set_peer(ps_->peer()->ToString());
    1067           0 :     smpi->set_ribin_registered(ribin_registered_);
    1068           0 :     smpi->set_ribout_registered(ribout_registered_);
    1069           0 :     smpi->set_instance_id(instance_id_);
    1070           0 :     smpi->set_generation_id(subscription_gen_id_);
    1071           0 : }
    1072             : 
    1073             : //
    1074             : // Constructor.
    1075             : //
    1076         418 : BgpMembershipManager::Walker::Walker(BgpMembershipManager *manager)
    1077         418 :     : manager_(manager),
    1078         836 :       trigger_(new TaskTrigger(
    1079             :           boost::bind(&BgpMembershipManager::Walker::WalkTrigger, this),
    1080         836 :           TaskScheduler::GetInstance()->GetTaskId("bgp::PeerMembership"), 0)),
    1081         418 :       postpone_walk_(false),
    1082         418 :       walk_started_(false),
    1083         418 :       walk_completed_(false),
    1084         418 :       rs_(NULL),
    1085         418 :       rib_state_list_size_(0),
    1086         836 :       ribout_state_list_size_(0) {
    1087         418 : }
    1088             : 
    1089             : //
    1090             : // Destructor.
    1091             : //
    1092         418 : BgpMembershipManager::Walker::~Walker() {
    1093         418 :     assert(rib_state_set_.empty());
    1094         418 :     assert(rib_state_list_.empty());
    1095         418 :     assert(!postpone_walk_);
    1096         418 :     assert(!rs_);
    1097         418 :     assert(walk_ref_ == NULL);
    1098         418 :     assert(peer_rib_list_.empty());
    1099         418 :     assert(peer_list_.empty());
    1100         418 :     assert(ribout_state_map_.empty());
    1101         418 :     assert(ribout_state_list_.empty());
    1102         418 : }
    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       12518 : void BgpMembershipManager::Walker::Enqueue(RibState *rs) {
    1109       12518 :     if (rib_state_set_.find(rs) != rib_state_set_.end())
    1110        4172 :         return;
    1111        8346 :     rib_state_set_.insert(rs);
    1112        8346 :     rib_state_list_.push_back(rs);
    1113        8346 :     rib_state_list_size_++;
    1114        8346 :     if (!walk_started_)
    1115        7539 :         trigger_->Set();
    1116             : }
    1117             : 
    1118             : //
    1119             : // Return true if the Walk does not have any pending items.
    1120             : //
    1121       23922 : bool BgpMembershipManager::Walker::IsQueueEmpty() const {
    1122       23922 :     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       11492 : BgpMembershipManager::Walker::LocateRibOutState(RibOut *ribout) {
    1130       11492 :     RibOutStateMap::iterator loc = ribout_state_map_.find(ribout);
    1131       11492 :     if (loc == ribout_state_map_.end()) {
    1132        7641 :         RibOutState *ros = new RibOutState(ribout);
    1133        7641 :         ribout_state_map_.insert(make_pair(ribout, ros));
    1134        7641 :         ribout_state_list_.push_back(ros);
    1135        7641 :         ribout_state_list_size_++;
    1136        7641 :         return ros;
    1137             :     } else {
    1138        3851 :         return loc->second;
    1139             :     }
    1140             : }
    1141             : 
    1142             : //
    1143             : // Process table walk callback from DB infrastructure.
    1144             : //
    1145      107136 : bool BgpMembershipManager::Walker::WalkCallback(DBTablePartBase *tpart,
    1146             :     DBEntryBase *db_entry) {
    1147      107136 :     CHECK_CONCURRENCY("db::DBTable");
    1148             : 
    1149             :     // Walk all RibOutStates and handle join/leave processing.
    1150      106882 :     for (RibOutStateList::iterator it = ribout_state_list_.begin();
    1151      181269 :          it != ribout_state_list_.end(); ++it) {
    1152       74157 :         RibOutState *ros = *it;
    1153       74150 :         RibOut *ribout = ros->ribout();
    1154       74147 :         ribout->bgp_export()->Join(tpart, ros->join_bitset(), db_entry);
    1155       74318 :         ribout->bgp_export()->Leave(tpart, ros->leave_bitset(), db_entry);
    1156             :     }
    1157             : 
    1158             :     // Bail if there's no peers that need RibIn processing.
    1159      107084 :     if (peer_list_.empty())
    1160       20515 :         return true;
    1161             : 
    1162             :     // Walk through all eligible paths and notify the source peer if needed.
    1163       86561 :     bool notify = false;
    1164       86561 :     BgpRoute *route = static_cast<BgpRoute *>(db_entry);
    1165      173126 :     for (Route::PathList::iterator it = route->GetPathList().begin(), next = it;
    1166      345748 :          it != route->GetPathList().end(); it = next) {
    1167       86322 :         next++;
    1168             : 
    1169       86322 :         BgpPath *path = static_cast<BgpPath *>(it.operator->());
    1170       86322 :         IPeer *peer = path->GetPeer();
    1171             : 
    1172             :         // Skip resolved paths - PathResolver is responsible for them.
    1173       86368 :         if (path->IsResolved())
    1174       68381 :             continue;
    1175             : 
    1176             :         // Skip aliased paths - EvpnManager is responsible for them.
    1177       86361 :         if (path->IsAliased())
    1178           0 :             continue;
    1179             : 
    1180             :         // Skip secondary paths.
    1181       86349 :         if (dynamic_cast<BgpSecondaryPath *>(path))
    1182       51844 :             continue;
    1183             : 
    1184             :         // Skip if there's no walk requested for this IPeer.
    1185       34505 :         if (!peer || peer_list_.find(peer) == peer_list_.end())
    1186       16537 :             continue;
    1187             : 
    1188       17947 :         notify |= peer->MembershipPathCallback(tpart, route, path);
    1189             :     }
    1190             : 
    1191       86470 :     rs_->table()->InputCommonPostProcess(tpart, route, notify);
    1192       86622 :     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        8346 : void BgpMembershipManager::Walker::WalkDoneCallback(DBTableBase *table_base) {
    1201        8346 :     CHECK_CONCURRENCY("db::Walker");
    1202        8346 :     assert(rs_->table() == table_base);
    1203        8346 :     walk_completed_ = true;
    1204        8346 :     trigger_->Set();
    1205        8346 : }
    1206             : 
    1207             : //
    1208             : // Start a walk for the BgpTable corresponding to the next RibState in the
    1209             : // RibStateList.
    1210             : //
    1211       10323 : void BgpMembershipManager::Walker::WalkStart() {
    1212       10323 :     CHECK_CONCURRENCY("bgp::PeerMembership");
    1213             : 
    1214       10323 :     assert(walk_ref_ == NULL);
    1215       10323 :     assert(!rs_);
    1216       10323 :     assert(peer_rib_list_.empty());
    1217       10323 :     assert(peer_list_.empty());
    1218       10323 :     assert(ribout_state_map_.empty());
    1219       10323 :     assert(ribout_state_list_.empty());
    1220       10323 :     assert(rib_state_list_size_ == rib_state_set_.size());
    1221             : 
    1222             :     // Bail if the list if empty.
    1223       10323 :     if (rib_state_list_.empty())
    1224        1977 :         return;
    1225             : 
    1226             :     // Get and remove the first RibState from the RibStateList.
    1227        8346 :     rs_ = rib_state_list_.front();
    1228        8346 :     rib_state_list_.pop_front();
    1229        8346 :     rib_state_list_size_--;
    1230        8346 :     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       20864 :     for (RibState::iterator it = rs_->begin(); it != rs_->end(); ++it) {
    1236       12518 :         PeerRibState *prs = *it;
    1237       12518 :         peer_rib_list_.insert(prs);
    1238             : 
    1239             :         // Update PeerList for RIBIN actions and RibOutStateMap for RIBOUT
    1240             :         // actions.
    1241       12518 :         switch (prs->action()) {
    1242        5746 :         case RIBOUT_ADD: {
    1243        5746 :             RibOutState *ros = LocateRibOutState(prs->ribout());
    1244        5746 :             ros->JoinPeer(prs->ribout_index());
    1245        5746 :             break;
    1246             :         }
    1247        1026 :         case RIBIN_DELETE:
    1248             :         case RIBIN_WALK: {
    1249        1026 :             IPeer *peer = prs->peer_state()->peer();
    1250        1026 :             peer_list_.insert(peer);
    1251        1026 :             break;
    1252             :         }
    1253        5746 :         case RIBIN_WALK_RIBOUT_DELETE:
    1254             :         case RIBIN_DELETE_RIBOUT_DELETE: {
    1255        5746 :             IPeer *peer = prs->peer_state()->peer();
    1256        5746 :             peer_list_.insert(peer);
    1257        5746 :             RibOutState *ros = LocateRibOutState(prs->ribout());
    1258        5746 :             ros->LeavePeer(prs->ribout_index());
    1259        5746 :             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        8346 :     rs_->ClearPeerRibStateList();
    1272             : 
    1273             :     // Start the walk.
    1274        8346 :     rs_->increment_walk_count();
    1275        8346 :     BgpTable *table = rs_->table();
    1276       16692 :     walk_ref_ = table->AllocWalker(
    1277             :         boost::bind(&BgpMembershipManager::Walker::WalkCallback, this, _1, _2),
    1278        8346 :         boost::bind(&BgpMembershipManager::Walker::WalkDoneCallback, this, _2));
    1279        8346 :     walk_started_ = true;
    1280        8346 :     if (!postpone_walk_)
    1281        8346 :         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        8346 : void BgpMembershipManager::Walker::WalkFinish() {
    1292        8346 :     CHECK_CONCURRENCY("bgp::PeerMembership");
    1293             : 
    1294        8346 :     assert(walk_ref_ != NULL);
    1295        8346 :     assert(rs_);
    1296        8346 :     assert(!peer_rib_list_.empty());
    1297        8346 :     assert(!peer_list_.empty() || !ribout_state_map_.empty());
    1298        8346 :     assert(rib_state_list_size_ == rib_state_set_.size());
    1299        8346 :     assert(ribout_state_list_size_ == ribout_state_map_.size());
    1300             : 
    1301        8346 :     BgpTable *table = rs_->table();
    1302        8346 :     for (PeerRibList::iterator it = peer_rib_list_.begin();
    1303       20864 :          it != peer_rib_list_.end(); ++it) {
    1304       12518 :         PeerRibState *prs = *it;
    1305       12518 :         IPeer *peer = prs->peer_state()->peer();
    1306             : 
    1307       12518 :         switch (prs->action()) {
    1308        5746 :         case RIBOUT_ADD:
    1309        5746 :             manager_->TriggerRegisterRibCompleteEvent(peer, table);
    1310        5746 :             break;
    1311        1026 :         case RIBIN_DELETE:
    1312             :         case RIBIN_WALK:
    1313        1026 :             manager_->TriggerWalkRibCompleteEvent(peer, table);
    1314        1026 :             break;
    1315        5746 :         case RIBIN_WALK_RIBOUT_DELETE:
    1316             :         case RIBIN_DELETE_RIBOUT_DELETE:
    1317        5746 :             manager_->TriggerUnregisterRibCompleteEvent(peer, table);
    1318        5746 :             break;
    1319           0 :         default:
    1320           0 :             assert(false);
    1321             :             break;
    1322             :         }
    1323             :     }
    1324             : 
    1325        8346 :     table->ReleaseWalker(walk_ref_);
    1326        8346 :     rs_ = NULL;
    1327        8346 :     peer_rib_list_.clear();
    1328        8346 :     peer_list_.clear();
    1329        8346 :     ribout_state_list_.clear();
    1330        8346 :     ribout_state_list_size_ = 0;
    1331        8346 :     STLDeleteElements(&ribout_state_map_);
    1332             : 
    1333        8346 :     walk_started_ = false;
    1334        8346 :     walk_completed_ = false;
    1335        8346 : }
    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       10323 : bool BgpMembershipManager::Walker::WalkTrigger() {
    1343       10323 :     CHECK_CONCURRENCY("bgp::PeerMembership");
    1344             : 
    1345       10323 :     if (!walk_started_) {
    1346        1977 :         assert(!walk_completed_);
    1347        1977 :         WalkStart();
    1348        8346 :     } else if (walk_completed_) {
    1349        8346 :         WalkFinish();
    1350        8346 :         WalkStart();
    1351             :     }
    1352       10323 :     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           0 : void BgpMembershipManager::Walker::SetQueueDisable(bool value) {
    1361           0 :     if (value) {
    1362           0 :         trigger_->set_disable();
    1363             :     } else {
    1364           0 :         trigger_->set_enable();
    1365             :     }
    1366           0 : }
    1367             : 
    1368             : //
    1369             : // Force the Walker to trigger walks that are postponed.
    1370             : // Testing only.
    1371             : //
    1372           0 : void BgpMembershipManager::Walker::PostponeWalk() {
    1373           0 :     assert(!walk_started_);
    1374           0 :     assert(walk_ref_ == NULL);
    1375           0 :     postpone_walk_ = true;
    1376           0 : }
    1377             : 
    1378             : //
    1379             : // Tell the DBTableWalkMgr to resume walk that was postponed previously.
    1380             : // Testing only.
    1381             : //
    1382           0 : void BgpMembershipManager::Walker::ResumeWalk() {
    1383           0 :     assert(walk_started_);
    1384           0 :     assert(!walk_completed_);
    1385           0 :     assert(walk_ref_ != NULL);
    1386           0 :     postpone_walk_ = false;
    1387           0 :     BgpTable *table = rs_->table();
    1388           0 :     table->WalkTable(walk_ref_);
    1389           0 : }

Generated by: LCOV version 1.14