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: 588 775 75.9 %
Date: 2026-09-28 02:13:17 Functions: 74 89 83.1 %
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         378 : BgpMembershipManager::BgpMembershipManager(BgpServer *server)
      28         378 :     : server_(server),
      29         378 :       walker_(new Walker(this)),
      30         756 :       event_queue_(new WorkQueue<Event *>(
      31         756 :           TaskScheduler::GetInstance()->GetTaskId("bgp::PeerMembership"), 0,
      32        1134 :           boost::bind(&BgpMembershipManager::EventCallback, this, _1))) {
      33         378 :     current_jobs_count_ = 0;
      34         378 :     total_jobs_count_ = 0;
      35         378 : }
      36             : 
      37             : //
      38             : // Destructor for BgpMembershipManager.
      39             : //
      40         756 : BgpMembershipManager::~BgpMembershipManager() {
      41         378 :     assert(current_jobs_count_ == 0);
      42         378 :     assert(rib_state_map_.empty());
      43         378 :     assert(peer_state_map_.empty());
      44         756 : }
      45             : 
      46        1512 : int BgpMembershipManager::RegisterPeerRegistrationCallback(
      47             :     PeerRegistrationCallback callback) {
      48        1512 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
      49             : 
      50        1512 :     size_t id = registration_bmap_.find_first();
      51        1512 :     if (id == registration_bmap_.npos) {
      52        1512 :         id = registration_callbacks_.size();
      53        1512 :         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        1512 :     return id;
      62        1512 : }
      63             : 
      64        1512 : void BgpMembershipManager::UnregisterPeerRegistrationCallback(int id) {
      65        1512 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
      66             : 
      67        1512 :     registration_callbacks_[id] = NULL;
      68        1512 :     if ((size_t) id == registration_callbacks_.size() - 1) {
      69        3402 :         while (!registration_callbacks_.empty() &&
      70        1512 :                registration_callbacks_.back() == NULL) {
      71        1512 :             registration_callbacks_.pop_back();
      72             :         }
      73         378 :         if (registration_bmap_.size() > registration_callbacks_.size()) {
      74         378 :             registration_bmap_.resize(registration_callbacks_.size());
      75             :         }
      76             :     } else {
      77        1134 :         if ((size_t) id >= registration_bmap_.size()) {
      78        1134 :             registration_bmap_.resize(id + 1);
      79             :         }
      80        1134 :         registration_bmap_.set(id);
      81             :     }
      82        1512 : }
      83             : 
      84        2272 : void BgpMembershipManager::NotifyPeerRegistration(IPeer *peer, BgpTable *table,
      85             :     bool unregister) {
      86        2272 :     CHECK_CONCURRENCY("bgp::PeerMembership");
      87             : 
      88        2272 :     if (!peer->IsXmppPeer())
      89        2272 :         return;
      90             : 
      91           0 :     for (PeerRegistrationListenerList::iterator iter =
      92           0 :          registration_callbacks_.begin();
      93           0 :          iter != registration_callbacks_.end(); ++iter) {
      94           0 :         if (*iter != NULL) {
      95           0 :             PeerRegistrationCallback callback = *iter;
      96           0 :             (callback)(peer, table, unregister);
      97           0 :         }
      98             :     }
      99             : }
     100             : 
     101        1132 : bool BgpMembershipManager::AssertRegister(PeerRibState *prs, bool do_assert) {
     102        1132 :     if (prs->action() != NONE) {
     103           0 :         if (do_assert)
     104           0 :             assert(prs->action() == NONE);
     105           0 :         return false;
     106             :     }
     107             : 
     108        1132 :     if (prs->ribout_registered()) {
     109           0 :         if (do_assert)
     110           0 :             assert(!prs->ribout_registered());
     111           0 :         return false;
     112             :     }
     113             : 
     114        1132 :     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        1134 : void BgpMembershipManager::Register(IPeer *peer, BgpTable *table,
     120             :     const RibExportPolicy &policy, int instance_id) {
     121        1134 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper",
     122             :         "bgp::StateMachine", "xmpp::StateMachine");
     123             : 
     124        1131 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
     125        1135 :     PeerRibState *prs = LocatePeerRibState(peer, table);
     126        1133 :     if (!AssertRegister(prs))
     127           0 :         return;
     128        1132 :     current_jobs_count_++;
     129        1136 :     total_jobs_count_++;
     130        1136 :     prs->set_ribin_registered(true);
     131        1136 :     prs->set_action(RIBOUT_ADD);
     132        1135 :     Event *event = new Event(REGISTER_RIB, peer, table, policy, instance_id);
     133        1134 :     EnqueueEvent(event);
     134        1135 : }
     135             : 
     136           0 : bool BgpMembershipManager::AssertRegisterRibIn(PeerRibState *prs, IPeer *peer,
     137             :                                                bool do_assert) {
     138           0 :     if (prs->action() != NONE) {
     139           0 :         if (do_assert)
     140           0 :             assert(prs->action() == NONE);
     141           0 :         return false;
     142             :     }
     143             : 
     144           0 :     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           0 :     if (prs->ribout_registered()) {
     151           0 :         if (do_assert)
     152           0 :             assert(!prs->ribout_registered());
     153           0 :         return false;
     154             :     }
     155             : 
     156           0 :     return true;
     157             : }
     158             : 
     159             : // Synchronously register the IPeer to the BgpTable for RIBIN.
     160           0 : void BgpMembershipManager::RegisterRibIn(IPeer *peer, BgpTable *table) {
     161           0 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper",
     162             :         "bgp::StateMachine", "xmpp::StateMachine");
     163             : 
     164           0 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
     165           0 :     PeerRibState *prs = LocatePeerRibState(peer, table);
     166           0 :     if (!AssertRegisterRibIn(prs, peer))
     167           0 :         return;
     168           0 :     prs->set_ribin_registered(true);
     169           0 : }
     170             : 
     171        1130 : bool BgpMembershipManager::AssertUnregister(PeerRibState *prs, bool do_assert) {
     172        1130 :     if (!prs || prs->action() != NONE) {
     173           0 :         if (do_assert)
     174           0 :             assert(prs && prs->action() == NONE);
     175           0 :         return false;
     176             :     }
     177             : 
     178        1130 :     if (!prs->ribin_registered()) {
     179           0 :         if (do_assert)
     180           0 :             assert(prs->ribin_registered());
     181           0 :         return false;
     182             :     }
     183             : 
     184        1130 :     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        1130 : void BgpMembershipManager::Unregister(IPeer *peer, BgpTable *table) {
     190        1130 :     CHECK_CONCURRENCY("bgp::Config", "bgp::StateMachine", "xmpp::StateMachine");
     191             : 
     192        1130 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
     193        1130 :     PeerRibState *prs = FindPeerRibState(peer, table);
     194        1130 :     if (!AssertUnregister(prs))
     195           0 :         return;
     196             : 
     197        1130 :     current_jobs_count_++;
     198        1130 :     total_jobs_count_++;
     199             : 
     200        1130 :     if (!prs->ribout_registered()) {
     201           0 :         UnregisterRibInUnlocked(prs);
     202           0 :         return;
     203             :     }
     204             : 
     205        1130 :     prs->set_action(RIBIN_DELETE_RIBOUT_DELETE);
     206        1130 :     prs->set_ribin_registered(false);
     207        1130 :     prs->set_instance_id(-1);
     208        1130 :     prs->set_subscription_gen_id(0);
     209        1130 :     Event *event = new Event(UNREGISTER_RIB, peer, table);
     210        1130 :     EnqueueEvent(event);
     211        1130 : }
     212             : 
     213             : //
     214             : // Unregister the IPeer from the BgpTable for RIBIN.
     215             : //
     216           6 : void BgpMembershipManager::UnregisterRibIn(IPeer *peer, BgpTable *table) {
     217           6 :     CHECK_CONCURRENCY("bgp::Config", "bgp::StateMachine", "xmpp::StateMachine");
     218             : 
     219           6 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
     220           6 :     current_jobs_count_++;
     221           6 :     total_jobs_count_++;
     222           6 :     PeerRibState *prs = FindPeerRibState(peer, table);
     223           6 :     assert(prs && prs->action() == NONE);
     224           6 :     assert(prs->ribin_registered() && !prs->ribout_registered());
     225           6 :     UnregisterRibInUnlocked(prs);
     226           6 : }
     227             : 
     228             : //
     229             : // Common routine to handle unregister of IPeer from Table for RIBIN.
     230             : //
     231           6 : void BgpMembershipManager::UnregisterRibInUnlocked(PeerRibState *prs) {
     232           6 :     prs->set_ribin_registered(false);
     233           6 :     prs->set_instance_id(-1);
     234           6 :     prs->set_subscription_gen_id(0);
     235           6 :     prs->set_action(RIBIN_DELETE);
     236           6 :     prs->UnregisterRibIn();
     237           6 :     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           6 : }
     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           6 : void BgpMembershipManager::UnregisterRibOut(IPeer *peer, BgpTable *table) {
     249           6 :     CHECK_CONCURRENCY("bgp::Config", "bgp::StateMachine", "xmpp::StateMachine");
     250             : 
     251           6 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
     252           6 :     current_jobs_count_++;
     253           6 :     total_jobs_count_++;
     254           6 :     PeerRibState *prs = FindPeerRibState(peer, table);
     255           6 :     assert(prs && prs->action() == NONE);
     256           6 :     assert(prs->ribin_registered());
     257           6 :     assert(prs->ribout_registered());
     258           6 :     prs->set_instance_id(-1);
     259           6 :     prs->set_subscription_gen_id(0);
     260           6 :     prs->set_action(RIBIN_WALK_RIBOUT_DELETE);
     261           6 :     Event *event = new Event(UNREGISTER_RIB, peer, table);
     262           6 :     EnqueueEvent(event);
     263           6 : }
     264             : 
     265           4 : bool BgpMembershipManager::AssertWalkRibIn(PeerRibState *prs, bool do_assert) {
     266           4 :     if (!prs || prs->action() != NONE) {
     267           0 :         if (do_assert)
     268           0 :             assert(prs && prs->action() == NONE);
     269           0 :         return false;
     270             :     }
     271             : 
     272           4 :     if (!prs->ribin_registered()) {
     273           0 :         if (do_assert)
     274           0 :             assert(prs->ribin_registered());
     275           0 :         return false;
     276             :     }
     277             : 
     278           4 :     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           4 : void BgpMembershipManager::WalkRibIn(IPeer *peer, BgpTable *table) {
     287           4 :     CHECK_CONCURRENCY("bgp::Config", "bgp::StateMachine", "xmpp::StateMachine");
     288             : 
     289           4 :     tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
     290           4 :     PeerRibState *prs = FindPeerRibState(peer, table);
     291           4 :     if (!AssertWalkRibIn(prs))
     292           0 :         return;
     293           4 :     current_jobs_count_++;
     294           4 :     total_jobs_count_++;
     295           4 :     prs->set_action(RIBIN_WALK);
     296           4 :     prs->WalkRibIn();
     297           4 :     BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
     298             :         table, "Walk table requested for action " << prs->action());
     299           4 : }
     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           0 : bool BgpMembershipManager::GetRegistrationInfo(
     306             :     const IPeer *peer, const BgpTable *table,
     307             :     int *instance_id, uint64_t *subscription_gen_id) const {
     308           0 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     309           0 :     const PeerRibState *prs = FindPeerRibState(peer, table);
     310           0 :     if (!prs)
     311           0 :         return false;
     312           0 :     if (instance_id)
     313           0 :         *instance_id = prs->instance_id();
     314           0 :     if (subscription_gen_id)
     315           0 :         *subscription_gen_id = prs->subscription_gen_id();
     316           0 :     return true;
     317           0 : }
     318             : 
     319             : //
     320             : // Update the registration info of the IPeer for the BgpTable.
     321             : //
     322           0 : void BgpMembershipManager::SetRegistrationInfo(
     323             :     const IPeer *peer, const BgpTable *table,
     324             :     int instance_id, uint64_t subscription_gen_id) {
     325           0 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     326           0 :     PeerRibState *prs = FindPeerRibState(peer, table);
     327           0 :     if (!prs)
     328           0 :         return;
     329           0 :     prs->set_instance_id(instance_id);
     330           0 :     prs->set_subscription_gen_id(subscription_gen_id);
     331           0 : }
     332             : 
     333             : //
     334             : // Return true if the IPeer is registered to the BgpTable.
     335             : //
     336        1146 : bool BgpMembershipManager::IsRegistered(const IPeer *peer,
     337             :     const BgpTable *table) const {
     338        1146 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     339        1146 :     const PeerRibState *prs = FindPeerRibState(peer, table);
     340        2292 :     return (prs && prs->ribin_registered() && prs->ribout_registered());
     341        1146 : }
     342             : 
     343             : //
     344             : // Return true if the IPeer is registered to the BgpTable for RibIn.
     345             : //
     346          10 : bool BgpMembershipManager::IsRibInRegistered(const IPeer *peer,
     347             :     const BgpTable *table) const {
     348          10 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     349          10 :     const PeerRibState *prs = FindPeerRibState(peer, table);
     350          20 :     return (prs && prs->ribin_registered());
     351          10 : }
     352             : 
     353             : //
     354             : // Return true if the IPeer is registered to the BgpTable for RibOut.
     355             : //
     356           0 : bool BgpMembershipManager::IsRibOutRegistered(const IPeer *peer,
     357             :     const BgpTable *table) const {
     358           0 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     359           0 :     const PeerRibState *prs = FindPeerRibState(peer, table);
     360           0 :     return (prs && prs->ribout_registered());
     361           0 : }
     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        1542 : void BgpMembershipManager::GetRegisteredRibs(const IPeer *peer,
     382             :     list<BgpTable *> *table_list) const {
     383        1542 :     tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     384        1542 :     table_list->clear();
     385        1542 :     const PeerState *ps = FindPeerState(peer);
     386        1542 :     if (ps)
     387        1014 :         ps->GetRegisteredRibs(table_list);
     388        1542 : }
     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       17103 : bool BgpMembershipManager::IsQueueEmpty() const {
     430       17103 :     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        1135 : BgpMembershipManager::PeerState *BgpMembershipManager::LocatePeerState(
     450             :     IPeer *peer) {
     451        1135 :     PeerStateMap::iterator loc = peer_state_map_.find(peer);
     452        1135 :     if (loc == peer_state_map_.end()) {
     453        1003 :         PeerState *ps = new PeerState(this, peer);
     454        1004 :         peer_state_map_.insert(make_pair(peer, ps));
     455        1004 :         return ps;
     456             :     } else {
     457         132 :         return loc->second;
     458             :     }
     459             : }
     460             : 
     461             : //
     462             : // Find the PeerState for given IPeer.
     463             : //
     464        5700 : BgpMembershipManager::PeerState *BgpMembershipManager::FindPeerState(
     465             :     const IPeer *peer) {
     466        5700 :     PeerStateMap::iterator loc = peer_state_map_.find(peer);
     467        5700 :     return (loc != peer_state_map_.end() ? loc->second : NULL);
     468             : }
     469             : 
     470             : //
     471             : // Find the PeerState for given IPeer.
     472             : // Const version.
     473             : //
     474        2698 : const BgpMembershipManager::PeerState *BgpMembershipManager::FindPeerState(
     475             :     const IPeer *peer) const {
     476        2698 :     PeerStateMap::const_iterator loc = peer_state_map_.find(peer);
     477        2698 :     return (loc != peer_state_map_.end() ? loc->second : NULL);
     478             : }
     479             : 
     480             : //
     481             : // Destroy the given PeerState.
     482             : //
     483        1004 : void BgpMembershipManager::DestroyPeerState(PeerState *ps) {
     484        1004 :     peer_state_map_.erase(ps->peer());
     485        1004 :     delete ps;
     486        1004 : }
     487             : 
     488             : //
     489             : // Find or create the RibState for given BgpTable.
     490             : //
     491        1135 : BgpMembershipManager::RibState *BgpMembershipManager::LocateRibState(
     492             :     BgpTable *table) {
     493        1135 :     RibStateMap::iterator loc = rib_state_map_.find(table);
     494        1135 :     if (loc == rib_state_map_.end()) {
     495         412 :         RibState *rs = new RibState(this, table);
     496         412 :         rib_state_map_.insert(make_pair(table, rs));
     497         412 :         return rs;
     498             :     } else {
     499         723 :         return loc->second;
     500             :     }
     501             : }
     502             : 
     503             : //
     504             : // Find the RibState for given BgpTable.
     505             : //
     506        5700 : BgpMembershipManager::RibState *BgpMembershipManager::FindRibState(
     507             :     const BgpTable *table) {
     508        5700 :     RibStateMap::iterator loc = rib_state_map_.find(table);
     509        5700 :     return (loc != rib_state_map_.end() ? loc->second : NULL);
     510             : }
     511             : 
     512             : //
     513             : // Find the RibState for given BgpTable.
     514             : // Const version.
     515             : //
     516        1156 : const BgpMembershipManager::RibState *BgpMembershipManager::FindRibState(
     517             :     const BgpTable *table) const {
     518        1156 :     RibStateMap::const_iterator loc = rib_state_map_.find(table);
     519        1156 :     return (loc != rib_state_map_.end() ? loc->second : NULL);
     520             : }
     521             : 
     522             : //
     523             : // Destroy the given RibState.
     524             : //
     525         412 : void BgpMembershipManager::DestroyRibState(RibState *rs) {
     526         412 :     rib_state_map_.erase(rs->table());
     527         412 :     delete rs;
     528         412 : }
     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        2282 : void BgpMembershipManager::EnqueueRibState(RibState *rs) {
     535        2282 :     walker_->Enqueue(rs);
     536        2282 : }
     537             : 
     538             : //
     539             : // Find or create the PeerRibState for given (IPeer, BgpTable).
     540             : //
     541        1135 : BgpMembershipManager::PeerRibState *BgpMembershipManager::LocatePeerRibState(
     542             :     IPeer *peer, BgpTable *table) {
     543        1135 :     PeerState *ps = LocatePeerState(peer);
     544        1135 :     RibState *rs = LocateRibState(table);
     545        1135 :     PeerRibState *prs = ps->LocatePeerRibState(rs);
     546        1135 :     rs->InsertPeerRibState(prs);
     547        1133 :     return prs;
     548             : }
     549             : 
     550             : //
     551             : // Find the PeerRibState for given (IPeer, BgpTable).
     552             : //
     553        5700 : BgpMembershipManager::PeerRibState *BgpMembershipManager::FindPeerRibState(
     554             :     const IPeer *peer, const BgpTable *table) {
     555        5700 :     PeerState *ps = FindPeerState(peer);
     556        5700 :     RibState *rs = FindRibState(table);
     557        5700 :     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        1156 : BgpMembershipManager::FindPeerRibState(
     566             :     const IPeer *peer, const BgpTable *table) const {
     567        1156 :     const PeerState *ps = FindPeerState(peer);
     568        1156 :     const RibState *rs = FindRibState(table);
     569        1156 :     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        1136 : void BgpMembershipManager::DestroyPeerRibState(PeerRibState *prs) {
     577        1136 :     PeerState *ps = prs->peer_state();
     578        1136 :     RibState *rs = prs->rib_state();
     579        1136 :     if (ps->RemovePeerRibState(prs))
     580        1004 :         DestroyPeerState(ps);
     581        1136 :     if (rs->RemovePeerRibState(prs))
     582         412 :         DestroyRibState(rs);
     583        1136 :     delete prs;
     584        1136 : }
     585             : 
     586             : //
     587             : // Trigger REGISTER_RIB_COMPLETE event.
     588             : //
     589        1136 : void BgpMembershipManager::TriggerRegisterRibCompleteEvent(IPeer *peer,
     590             :     BgpTable *table) {
     591        1136 :     Event *event = new Event(REGISTER_RIB_COMPLETE, peer, table);
     592        1136 :     EnqueueEvent(event);
     593        1136 : }
     594             : 
     595             : //
     596             : // Trigger UNREGISTER_RIB_COMPLETE event.
     597             : //
     598        1136 : void BgpMembershipManager::TriggerUnregisterRibCompleteEvent(IPeer *peer,
     599             :     BgpTable *table) {
     600        1136 :     Event *event = new Event(UNREGISTER_RIB_COMPLETE, peer, table);
     601        1136 :     EnqueueEvent(event);
     602        1136 : }
     603             : 
     604             : //
     605             : // Trigger WALK_RIB_COMPLETE event.
     606             : //
     607          10 : void BgpMembershipManager::TriggerWalkRibCompleteEvent(IPeer *peer,
     608             :     BgpTable *table) {
     609          10 :     Event *event = new Event(WALK_RIB_COMPLETE, peer, table);
     610          10 :     EnqueueEvent(event);
     611          10 : }
     612             : 
     613             : //
     614             : // Process REGISTER_RIB event.
     615             : //
     616        1136 : void BgpMembershipManager::ProcessRegisterRibEvent(Event *event) {
     617        1136 :     IPeer *peer = event->peer;
     618        1136 :     BgpTable *table = event->table;
     619        1136 :     PeerRibState *prs = FindPeerRibState(peer, table);
     620        1136 :     assert(prs && prs->action() == RIBOUT_ADD);
     621        1136 :     assert(prs->ribin_registered());
     622        1136 :     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        1136 :     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        1136 :     prs->RegisterRibOut(event->policy);
     636        1136 :     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        1136 : void BgpMembershipManager::ProcessRegisterRibCompleteEvent(Event *event) {
     645        1136 :     IPeer *peer = event->peer;
     646        1136 :     BgpTable *table = event->table;
     647        1136 :     PeerRibState *prs = FindPeerRibState(peer, table);
     648        1136 :     assert(prs && prs->action() == RIBOUT_ADD);
     649        1136 :     assert(prs->ribin_registered());
     650        1136 :     assert(prs->ribout_registered());
     651        1136 :     BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
     652             :         table, "Register table completed for action " << prs->action());
     653        1136 :     prs->clear_action();
     654        1136 :     peer->MembershipRequestCallback(table);
     655        1136 :     NotifyPeerRegistration(peer, table, false);
     656        1136 :     current_jobs_count_--;
     657        1136 : }
     658             : 
     659             : //
     660             : // Process UNREGISTER_RIB event.
     661             : //
     662        1136 : void BgpMembershipManager::ProcessUnregisterRibEvent(Event *event) {
     663        1136 :     IPeer *peer = event->peer;
     664        1136 :     BgpTable *table = event->table;
     665        1136 :     PeerRibState *prs = FindPeerRibState(peer, table);
     666        1136 :     assert(prs);
     667        1136 :     assert(prs->action() == RIBIN_DELETE_RIBOUT_DELETE ||
     668             :         prs->action() == RIBIN_WALK_RIBOUT_DELETE);
     669        1136 :     if (prs->action() == RIBIN_DELETE_RIBOUT_DELETE)
     670        1130 :         assert(!prs->ribin_registered());
     671        1136 :     if (prs->action() == RIBIN_WALK_RIBOUT_DELETE)
     672           6 :         assert(prs->ribin_registered());
     673        1136 :     assert(prs->ribout_registered());
     674             : 
     675        1136 :     prs->DeactivateRibOut();
     676        1136 :     BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
     677             :         table, "Unregister table requested for action " << prs->action());
     678        1136 : }
     679             : 
     680             : //
     681             : // Process UNREGISTER_RIB_COMPLETE event.
     682             : //
     683        1136 : void BgpMembershipManager::ProcessUnregisterRibCompleteEvent(Event *event) {
     684        1136 :     IPeer *peer = event->peer;
     685        1136 :     BgpTable *table = event->table;
     686        1136 :     PeerRibState *prs = FindPeerRibState(peer, table);
     687        1136 :     assert(prs);
     688        1136 :     assert(prs->action() == RIBIN_DELETE_RIBOUT_DELETE ||
     689             :         prs->action() == RIBIN_WALK_RIBOUT_DELETE);
     690        1136 :     if (prs->action() == RIBIN_DELETE_RIBOUT_DELETE)
     691        1130 :         assert(!prs->ribin_registered());
     692        1136 :     if (prs->action() == RIBIN_WALK_RIBOUT_DELETE)
     693           6 :         assert(prs->ribin_registered());
     694             : 
     695        1136 :     prs->UnregisterRibOut();
     696        1136 :     BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
     697             :         table, "Unregister table completed for action " << prs->action());
     698        1136 :     prs->clear_action();
     699        1136 :     if (!prs->ribin_registered() && !prs->ribout_registered())
     700        1130 :         DestroyPeerRibState(prs);
     701             : 
     702        1136 :     peer->MembershipRequestCallback(table);
     703        1136 :     NotifyPeerRegistration(peer, table, true);
     704        1136 :     current_jobs_count_--;
     705        1136 : }
     706             : 
     707             : //
     708             : // Process WALK_RIB_COMPLETE event.
     709             : //
     710          10 : void BgpMembershipManager::ProcessWalkRibCompleteEvent(Event *event) {
     711          10 :     IPeer *peer = event->peer;
     712          10 :     BgpTable *table = event->table;
     713          10 :     PeerRibState *prs = FindPeerRibState(peer, table);
     714          10 :     assert(prs);
     715          10 :     assert(prs->action() == RIBIN_WALK || prs->action() == RIBIN_DELETE);
     716          10 :     if (prs->action() == RIBIN_WALK) {
     717           4 :         assert(prs->ribin_registered());
     718           4 :         BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
     719             :             table, "Walk table completed for action " << prs->action());
     720             :     } else {
     721           6 :         assert(!prs->ribin_registered());
     722           6 :         BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
     723             :             table, "Unregister table completed for action " << prs->action());
     724             :     }
     725          10 :     prs->clear_action();
     726          10 :     if (!prs->ribin_registered() && !prs->ribout_registered())
     727           6 :         DestroyPeerRibState(prs);
     728          10 :     peer->MembershipRequestCallback(table);
     729          10 :     current_jobs_count_--;
     730          10 : }
     731             : 
     732             : //
     733             : // Internal handler for an Event.
     734             : // Exists so that test code can override it.
     735             : //
     736        4554 : bool BgpMembershipManager::EventCallbackInternal(Event *event) {
     737        4554 :     switch (event->event_type) {
     738        1136 :     case REGISTER_RIB:
     739        1136 :         ProcessRegisterRibEvent(event);
     740        1136 :         break;
     741        1136 :     case REGISTER_RIB_COMPLETE:
     742        1136 :         ProcessRegisterRibCompleteEvent(event);
     743        1136 :         break;
     744        1136 :     case UNREGISTER_RIB:
     745        1136 :         ProcessUnregisterRibEvent(event);
     746        1136 :         break;
     747        1136 :     case UNREGISTER_RIB_COMPLETE:
     748        1136 :         ProcessUnregisterRibCompleteEvent(event);
     749        1136 :         break;
     750          10 :     case WALK_RIB_COMPLETE:
     751          10 :         ProcessWalkRibCompleteEvent(event);
     752          10 :         break;
     753           0 :     default:
     754           0 :         assert(false);
     755             :         break;
     756             :     }
     757             : 
     758        4554 :     delete event;
     759        4554 :     return true;
     760             : }
     761             : 
     762             : //
     763             : // Handler for an Event.
     764             : //
     765        4554 : bool BgpMembershipManager::EventCallback(Event *event) {
     766        4554 :     CHECK_CONCURRENCY("bgp::PeerMembership");
     767        4554 :     return EventCallbackInternal(event);
     768             : }
     769             : 
     770             : //
     771             : // Constructor.
     772             : //`
     773        3418 : BgpMembershipManager::Event::Event(EventType event_type, IPeer *peer,
     774        3418 :     BgpTable *table)
     775        3418 :     : event_type(event_type),
     776        3418 :       peer(peer),
     777        3418 :       table(table),
     778        3418 :       instance_id(-1) {
     779        3418 : }
     780             : 
     781             : //
     782             : // Constructor.
     783             : //`
     784        1134 : BgpMembershipManager::Event::Event(EventType event_type, IPeer *peer,
     785        1134 :     BgpTable *table, const RibExportPolicy &policy, int instance_id)
     786        1134 :     : event_type(event_type),
     787        1134 :       peer(peer),
     788        1134 :       table(table),
     789        1134 :       policy(policy),
     790        1134 :       instance_id(instance_id) {
     791        1134 : }
     792             : 
     793             : //
     794             : // Constructor.
     795             : //`
     796        1002 : BgpMembershipManager::PeerState::PeerState(BgpMembershipManager *manager,
     797        1002 :     IPeer *peer)
     798        1002 :     : manager_(manager),
     799        1002 :       peer_(peer) {
     800        1004 : }
     801             : 
     802             : //
     803             : // Destructor.
     804             : //`
     805        1004 : BgpMembershipManager::PeerState::~PeerState() {
     806        1004 :     assert(rib_map_.empty());
     807        1004 : }
     808             : 
     809             : //
     810             : // Find or create the PeerRibState for given RibState.
     811             : //
     812             : BgpMembershipManager::PeerRibState *
     813        1135 : BgpMembershipManager::PeerState::LocatePeerRibState(RibState *rs) {
     814        1135 :     PeerRibStateMap::iterator loc = rib_map_.find(rs);
     815        1134 :     if (loc == rib_map_.end()) {
     816        1134 :         PeerRibState *prs = new PeerRibState(manager_, this, rs);
     817        1133 :         rib_map_.insert(make_pair(rs, prs));
     818        1135 :         return prs;
     819             :     } else {
     820           0 :         return loc->second;
     821             :     }
     822             : }
     823             : 
     824             : //
     825             : // Find the PeerRibState for given RibState.
     826             : //
     827             : BgpMembershipManager::PeerRibState *
     828        5700 : BgpMembershipManager::PeerState::FindPeerRibState(const RibState *rs) {
     829        5700 :     PeerRibStateMap::iterator loc = rib_map_.find(rs);
     830        5700 :     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        1156 : BgpMembershipManager::PeerState::FindPeerRibState(const RibState *rs) const {
     839        1156 :     PeerRibStateMap::const_iterator loc = rib_map_.find(rs);
     840        1156 :     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        1136 : bool BgpMembershipManager::PeerState::RemovePeerRibState(PeerRibState *prs) {
     848        1136 :     PeerRibStateMap::iterator loc = rib_map_.find(prs->rib_state());
     849        1136 :     if (loc != rib_map_.end())
     850        1136 :         rib_map_.erase(loc);
     851        2272 :     return rib_map_.empty();
     852             : }
     853             : 
     854             : //
     855             : // Fill in the list of registered BgpTables.
     856             : //
     857        1014 : void BgpMembershipManager::PeerState::GetRegisteredRibs(
     858             :     list<BgpTable *> *table_list) const {
     859        1014 :     for (PeerRibStateMap::const_iterator loc = rib_map_.begin();
     860        2160 :          loc != rib_map_.end(); ++loc) {
     861        1146 :         const RibState *rs = loc->first;
     862        1146 :         table_list->push_back(rs->table());
     863             :     }
     864        1014 : }
     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         412 : BgpMembershipManager::RibState::RibState(BgpMembershipManager *manager,
     887         412 :     BgpTable *table)
     888         412 :     : manager_(manager),
     889         412 :       table_(table),
     890         412 :       request_count_(0),
     891         412 :       walk_count_(0),
     892         412 :       table_delete_ref_(this, table->deleter()) {
     893         412 : }
     894             : 
     895             : //
     896             : // Destructor.
     897             : //
     898         412 : BgpMembershipManager::RibState::~RibState() {
     899         412 :     assert(peer_rib_list_.empty());
     900         412 :     assert(pending_peer_rib_list_.empty());
     901         412 : }
     902             : 
     903             : //
     904             : // Enqueue given PeerRibState into the pending PeerRibStateList.
     905             : //
     906        2282 : void BgpMembershipManager::RibState::EnqueuePeerRibState(PeerRibState *prs) {
     907        2282 :     request_count_++;
     908        2282 :     pending_peer_rib_list_.insert(prs);
     909        2282 :     manager_->EnqueueRibState(this);
     910        2282 : }
     911             : 
     912             : //
     913             : // Clear the pending PeerRibStateList.
     914             : //
     915        1096 : void BgpMembershipManager::RibState::ClearPeerRibStateList() {
     916        1096 :     pending_peer_rib_list_.clear();
     917        1096 : }
     918             : 
     919             : //
     920             : // Insert given PeerRibState into the regular PeerRibStateList.
     921             : //
     922        1135 : void BgpMembershipManager::RibState::InsertPeerRibState(PeerRibState *prs) {
     923        1135 :     peer_rib_list_.insert(prs);
     924        1133 : }
     925             : 
     926             : //
     927             : // Remove given PeerRibState from the regular PeerRibStateList.
     928             : //
     929        1136 : bool BgpMembershipManager::RibState::RemovePeerRibState(PeerRibState *prs) {
     930        1136 :     peer_rib_list_.erase(prs);
     931        1136 :     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        1133 : BgpMembershipManager::PeerRibState::PeerRibState(BgpMembershipManager *manager,
     958        1133 :     PeerState *ps, RibState *rs)
     959        1133 :     : manager_(manager),
     960        1133 :       ps_(ps),
     961        1133 :       rs_(rs),
     962        1133 :       ribout_(NULL),
     963        1133 :       ribout_index_(-1),
     964        1133 :       action_(BgpMembershipManager::NONE),
     965        1133 :       ribin_registered_(false),
     966        1133 :       ribout_registered_(false),
     967        1133 :       instance_id_(-1),
     968        1133 :       subscription_gen_id_(0) {
     969        1133 : }
     970             : 
     971             : //
     972             : // Destructor.
     973             : //
     974        1136 : BgpMembershipManager::PeerRibState::~PeerRibState() {
     975        1136 :     assert(!ribout_);
     976        1136 :     assert(ribout_index_ == -1);
     977        1136 :     assert(action_ == BgpMembershipManager::NONE);
     978        1136 :     assert(!ribin_registered_);
     979        1136 :     assert(!ribout_registered_);
     980        1136 :     assert(instance_id_ == -1);
     981        1136 :     assert(subscription_gen_id_ == 0);
     982        1136 : }
     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        1136 : void BgpMembershipManager::PeerRibState::RegisterRibOut(
     993             :     const RibExportPolicy &policy) {
     994        1136 :     CHECK_CONCURRENCY("bgp::PeerMembership");
     995             : 
     996        1136 :     BgpUpdateSender *sender = manager_->server()->update_sender();
     997        1136 :     ribout_ = rs_->table()->RibOutLocate(sender, policy);
     998        1136 :     ribout_->RegisterListener();
     999        1136 :     ribout_->Register(ps_->peer());
    1000        1136 :     ribout_index_ = ribout_->GetPeerIndex(ps_->peer());
    1001        1136 :     ribout_registered_ = true;
    1002        1136 :     rs_->EnqueuePeerRibState(this);
    1003        1136 : }
    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        1136 : void BgpMembershipManager::PeerRibState::DeactivateRibOut() {
    1016        1136 :     CHECK_CONCURRENCY("bgp::PeerMembership");
    1017        1136 :     if (ribout_) {
    1018        1136 :         ribout_->Deactivate(ps_->peer());
    1019        1136 :         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        1136 : }
    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        1136 : void BgpMembershipManager::PeerRibState::UnregisterRibOut() {
    1036        1136 :     CHECK_CONCURRENCY("bgp::PeerMembership");
    1037             : 
    1038        1136 :     if (!ribout_)
    1039           0 :         return;
    1040        1136 :     assert(ribout_index_ != -1);
    1041        1136 :     ribout_->Unregister(ps_->peer());
    1042        1136 :     ribout_ = NULL;
    1043        1136 :     ribout_index_ = -1;
    1044        1136 :     ribout_registered_ = false;
    1045             : }
    1046             : 
    1047             : //
    1048             : // Unregister the RibIn for the IPeer.
    1049             : //
    1050           6 : void BgpMembershipManager::PeerRibState::UnregisterRibIn() {
    1051           6 :     rs_->EnqueuePeerRibState(this);
    1052           6 : }
    1053             : 
    1054             : //
    1055             : // Walk the RibIn for the IPeer.
    1056             : //
    1057           4 : void BgpMembershipManager::PeerRibState::WalkRibIn() {
    1058           4 :     rs_->EnqueuePeerRibState(this);
    1059           4 : }
    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         378 : BgpMembershipManager::Walker::Walker(BgpMembershipManager *manager)
    1077         378 :     : manager_(manager),
    1078         756 :       trigger_(new TaskTrigger(
    1079             :           boost::bind(&BgpMembershipManager::Walker::WalkTrigger, this),
    1080         756 :           TaskScheduler::GetInstance()->GetTaskId("bgp::PeerMembership"), 0)),
    1081         378 :       postpone_walk_(false),
    1082         378 :       walk_started_(false),
    1083         378 :       walk_completed_(false),
    1084         378 :       rs_(NULL),
    1085         378 :       rib_state_list_size_(0),
    1086         756 :       ribout_state_list_size_(0) {
    1087         378 : }
    1088             : 
    1089             : //
    1090             : // Destructor.
    1091             : //
    1092         378 : BgpMembershipManager::Walker::~Walker() {
    1093         378 :     assert(rib_state_set_.empty());
    1094         378 :     assert(rib_state_list_.empty());
    1095         378 :     assert(!postpone_walk_);
    1096         378 :     assert(!rs_);
    1097         378 :     assert(walk_ref_ == NULL);
    1098         378 :     assert(peer_rib_list_.empty());
    1099         378 :     assert(peer_list_.empty());
    1100         378 :     assert(ribout_state_map_.empty());
    1101         378 :     assert(ribout_state_list_.empty());
    1102         378 : }
    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        2282 : void BgpMembershipManager::Walker::Enqueue(RibState *rs) {
    1109        2282 :     if (rib_state_set_.find(rs) != rib_state_set_.end())
    1110        1186 :         return;
    1111        1096 :     rib_state_set_.insert(rs);
    1112        1096 :     rib_state_list_.push_back(rs);
    1113        1096 :     rib_state_list_size_++;
    1114        1096 :     if (!walk_started_)
    1115         911 :         trigger_->Set();
    1116             : }
    1117             : 
    1118             : //
    1119             : // Return true if the Walk does not have any pending items.
    1120             : //
    1121       16904 : bool BgpMembershipManager::Walker::IsQueueEmpty() const {
    1122       16904 :     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        2272 : BgpMembershipManager::Walker::LocateRibOutState(RibOut *ribout) {
    1130        2272 :     RibOutStateMap::iterator loc = ribout_state_map_.find(ribout);
    1131        2272 :     if (loc == ribout_state_map_.end()) {
    1132        1086 :         RibOutState *ros = new RibOutState(ribout);
    1133        1086 :         ribout_state_map_.insert(make_pair(ribout, ros));
    1134        1086 :         ribout_state_list_.push_back(ros);
    1135        1086 :         ribout_state_list_size_++;
    1136        1086 :         return ros;
    1137             :     } else {
    1138        1186 :         return loc->second;
    1139             :     }
    1140             : }
    1141             : 
    1142             : //
    1143             : // Process table walk callback from DB infrastructure.
    1144             : //
    1145          50 : bool BgpMembershipManager::Walker::WalkCallback(DBTablePartBase *tpart,
    1146             :     DBEntryBase *db_entry) {
    1147          50 :     CHECK_CONCURRENCY("db::DBTable");
    1148             : 
    1149             :     // Walk all RibOutStates and handle join/leave processing.
    1150          50 :     for (RibOutStateList::iterator it = ribout_state_list_.begin();
    1151          90 :          it != ribout_state_list_.end(); ++it) {
    1152          40 :         RibOutState *ros = *it;
    1153          40 :         RibOut *ribout = ros->ribout();
    1154          40 :         ribout->bgp_export()->Join(tpart, ros->join_bitset(), db_entry);
    1155          40 :         ribout->bgp_export()->Leave(tpart, ros->leave_bitset(), db_entry);
    1156             :     }
    1157             : 
    1158             :     // Bail if there's no peers that need RibIn processing.
    1159          50 :     if (peer_list_.empty())
    1160           2 :         return true;
    1161             : 
    1162             :     // Walk through all eligible paths and notify the source peer if needed.
    1163          48 :     bool notify = false;
    1164          48 :     BgpRoute *route = static_cast<BgpRoute *>(db_entry);
    1165          96 :     for (Route::PathList::iterator it = route->GetPathList().begin(), next = it;
    1166         192 :          it != route->GetPathList().end(); it = next) {
    1167          48 :         next++;
    1168             : 
    1169          48 :         BgpPath *path = static_cast<BgpPath *>(it.operator->());
    1170          48 :         IPeer *peer = path->GetPeer();
    1171             : 
    1172             :         // Skip resolved paths - PathResolver is responsible for them.
    1173          48 :         if (path->IsResolved())
    1174          16 :             continue;
    1175             : 
    1176             :         // Skip aliased paths - EvpnManager is responsible for them.
    1177          48 :         if (path->IsAliased())
    1178           0 :             continue;
    1179             : 
    1180             :         // Skip secondary paths.
    1181          48 :         if (dynamic_cast<BgpSecondaryPath *>(path))
    1182           0 :             continue;
    1183             : 
    1184             :         // Skip if there's no walk requested for this IPeer.
    1185          48 :         if (!peer || peer_list_.find(peer) == peer_list_.end())
    1186          16 :             continue;
    1187             : 
    1188          32 :         notify |= peer->MembershipPathCallback(tpart, route, path);
    1189             :     }
    1190             : 
    1191          48 :     rs_->table()->InputCommonPostProcess(tpart, route, notify);
    1192          48 :     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        1096 : void BgpMembershipManager::Walker::WalkDoneCallback(DBTableBase *table_base) {
    1201        1096 :     CHECK_CONCURRENCY("db::Walker");
    1202        1096 :     assert(rs_->table() == table_base);
    1203        1096 :     walk_completed_ = true;
    1204        1096 :     trigger_->Set();
    1205        1096 : }
    1206             : 
    1207             : //
    1208             : // Start a walk for the BgpTable corresponding to the next RibState in the
    1209             : // RibStateList.
    1210             : //
    1211        1919 : void BgpMembershipManager::Walker::WalkStart() {
    1212        1919 :     CHECK_CONCURRENCY("bgp::PeerMembership");
    1213             : 
    1214        1919 :     assert(walk_ref_ == NULL);
    1215        1919 :     assert(!rs_);
    1216        1919 :     assert(peer_rib_list_.empty());
    1217        1919 :     assert(peer_list_.empty());
    1218        1919 :     assert(ribout_state_map_.empty());
    1219        1919 :     assert(ribout_state_list_.empty());
    1220        1919 :     assert(rib_state_list_size_ == rib_state_set_.size());
    1221             : 
    1222             :     // Bail if the list if empty.
    1223        1919 :     if (rib_state_list_.empty())
    1224         823 :         return;
    1225             : 
    1226             :     // Get and remove the first RibState from the RibStateList.
    1227        1096 :     rs_ = rib_state_list_.front();
    1228        1096 :     rib_state_list_.pop_front();
    1229        1096 :     rib_state_list_size_--;
    1230        1096 :     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        3378 :     for (RibState::iterator it = rs_->begin(); it != rs_->end(); ++it) {
    1236        2282 :         PeerRibState *prs = *it;
    1237        2282 :         peer_rib_list_.insert(prs);
    1238             : 
    1239             :         // Update PeerList for RIBIN actions and RibOutStateMap for RIBOUT
    1240             :         // actions.
    1241        2282 :         switch (prs->action()) {
    1242        1136 :         case RIBOUT_ADD: {
    1243        1136 :             RibOutState *ros = LocateRibOutState(prs->ribout());
    1244        1136 :             ros->JoinPeer(prs->ribout_index());
    1245        1136 :             break;
    1246             :         }
    1247          10 :         case RIBIN_DELETE:
    1248             :         case RIBIN_WALK: {
    1249          10 :             IPeer *peer = prs->peer_state()->peer();
    1250          10 :             peer_list_.insert(peer);
    1251          10 :             break;
    1252             :         }
    1253        1136 :         case RIBIN_WALK_RIBOUT_DELETE:
    1254             :         case RIBIN_DELETE_RIBOUT_DELETE: {
    1255        1136 :             IPeer *peer = prs->peer_state()->peer();
    1256        1136 :             peer_list_.insert(peer);
    1257        1136 :             RibOutState *ros = LocateRibOutState(prs->ribout());
    1258        1136 :             ros->LeavePeer(prs->ribout_index());
    1259        1136 :             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        1096 :     rs_->ClearPeerRibStateList();
    1272             : 
    1273             :     // Start the walk.
    1274        1096 :     rs_->increment_walk_count();
    1275        1096 :     BgpTable *table = rs_->table();
    1276        2192 :     walk_ref_ = table->AllocWalker(
    1277             :         boost::bind(&BgpMembershipManager::Walker::WalkCallback, this, _1, _2),
    1278        1096 :         boost::bind(&BgpMembershipManager::Walker::WalkDoneCallback, this, _2));
    1279        1096 :     walk_started_ = true;
    1280        1096 :     if (!postpone_walk_)
    1281        1096 :         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        1096 : void BgpMembershipManager::Walker::WalkFinish() {
    1292        1096 :     CHECK_CONCURRENCY("bgp::PeerMembership");
    1293             : 
    1294        1096 :     assert(walk_ref_ != NULL);
    1295        1096 :     assert(rs_);
    1296        1096 :     assert(!peer_rib_list_.empty());
    1297        1096 :     assert(!peer_list_.empty() || !ribout_state_map_.empty());
    1298        1096 :     assert(rib_state_list_size_ == rib_state_set_.size());
    1299        1096 :     assert(ribout_state_list_size_ == ribout_state_map_.size());
    1300             : 
    1301        1096 :     BgpTable *table = rs_->table();
    1302        1096 :     for (PeerRibList::iterator it = peer_rib_list_.begin();
    1303        3378 :          it != peer_rib_list_.end(); ++it) {
    1304        2282 :         PeerRibState *prs = *it;
    1305        2282 :         IPeer *peer = prs->peer_state()->peer();
    1306             : 
    1307        2282 :         switch (prs->action()) {
    1308        1136 :         case RIBOUT_ADD:
    1309        1136 :             manager_->TriggerRegisterRibCompleteEvent(peer, table);
    1310        1136 :             break;
    1311          10 :         case RIBIN_DELETE:
    1312             :         case RIBIN_WALK:
    1313          10 :             manager_->TriggerWalkRibCompleteEvent(peer, table);
    1314          10 :             break;
    1315        1136 :         case RIBIN_WALK_RIBOUT_DELETE:
    1316             :         case RIBIN_DELETE_RIBOUT_DELETE:
    1317        1136 :             manager_->TriggerUnregisterRibCompleteEvent(peer, table);
    1318        1136 :             break;
    1319           0 :         default:
    1320           0 :             assert(false);
    1321             :             break;
    1322             :         }
    1323             :     }
    1324             : 
    1325        1096 :     table->ReleaseWalker(walk_ref_);
    1326        1096 :     rs_ = NULL;
    1327        1096 :     peer_rib_list_.clear();
    1328        1096 :     peer_list_.clear();
    1329        1096 :     ribout_state_list_.clear();
    1330        1096 :     ribout_state_list_size_ = 0;
    1331        1096 :     STLDeleteElements(&ribout_state_map_);
    1332             : 
    1333        1096 :     walk_started_ = false;
    1334        1096 :     walk_completed_ = false;
    1335        1096 : }
    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        1919 : bool BgpMembershipManager::Walker::WalkTrigger() {
    1343        1919 :     CHECK_CONCURRENCY("bgp::PeerMembership");
    1344             : 
    1345        1919 :     if (!walk_started_) {
    1346         823 :         assert(!walk_completed_);
    1347         823 :         WalkStart();
    1348        1096 :     } else if (walk_completed_) {
    1349        1096 :         WalkFinish();
    1350        1096 :         WalkStart();
    1351             :     }
    1352        1919 :     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