LCOV - code coverage report
Current view: top level - vnsw/agent/oper - agent_route_walker.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 219 252 86.9 %
Date: 2026-08-03 02:19:58 Functions: 40 44 90.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : #include <assert.h>
       5             : #include <cmn/agent_cmn.h>
       6             : #include <route/route.h>
       7             : #include <vnc_cfg_types.h>
       8             : #include <agent_types.h>
       9             : #include <cmn/agent_db.h>
      10             : #include <oper/agent_route_walker.h>
      11             : #include <oper/vrf.h>
      12             : #include <oper/agent_route.h>
      13             : #include <sandesh/sandesh.h>
      14             : #include <sandesh/sandesh_types.h>
      15             : #include <sandesh/sandesh_trace.h>
      16             : #include <sandesh/common/vns_constants.h>
      17             : 
      18             : using namespace std;
      19             : 
      20             : SandeshTraceBufferPtr AgentDBwalkTraceBuf(SandeshTraceBufferCreate(
      21             :     AGENT_DBWALK_TRACE_BUF, 1000));
      22             : 
      23          16 : RouteWalkerDBState::RouteWalkerDBState() : walker_ref_map_() {
      24          16 : }
      25             : 
      26             : static void
      27          37 : RemoveWalkReferencesInRoutetable(RouteWalkerDBState::AgentRouteWalkerRefMapIter &it,
      28             :                                  RouteWalkerDBState *state) {
      29          37 :     for (uint8_t table_type = Agent::ROUTE_TABLE_START;
      30         259 :          table_type < Agent::ROUTE_TABLE_MAX; table_type++) {
      31         222 :         it->second[table_type] = DBTable::DBTableWalkRef();
      32             :     }
      33          37 : }
      34             : 
      35           3 : AgentRouteWalkerManager::AgentRouteWalkerManager(Agent *agent) : agent_(agent),
      36           3 :     walk_ref_list_(), marked_for_deletion_(false) {
      37           3 :     vrf_listener_id_ = agent->vrf_table()->Register(
      38             :                        boost::bind(&AgentRouteWalkerManager::VrfNotify, this,
      39             :                                    _1, _2));
      40           3 : }
      41             : 
      42           6 : AgentRouteWalkerManager::~AgentRouteWalkerManager() {
      43             :     //Since walker ref list is going off, mark all walkers to have NULL
      44             :     //managers.
      45             :     //TODO
      46           6 : }
      47             : 
      48          59 : void AgentRouteWalkerManager::ReleaseWalker(AgentRouteWalker *walker) {
      49          59 :     assert(std::find(walk_ref_list_.begin(), walk_ref_list_.end(), walker)
      50             :            != walk_ref_list_.end());
      51          59 :     walker->ReleaseVrfWalkReference();
      52          59 : }
      53             : 
      54             : void
      55           0 : AgentRouteWalkerManager::RemoveWalkReferencesInVrf(RouteWalkerDBState *state,
      56             :                                                    VrfEntry *vrf) {
      57           0 :     for (RouteWalkerDBState::AgentRouteWalkerRefMapIter it =
      58           0 :          state->walker_ref_map_.begin();
      59           0 :          it != state->walker_ref_map_.end(); it++) {
      60           0 :         RemoveWalkReferencesInRoutetable(it, state);
      61             :     }
      62           0 : }
      63             : 
      64             : //Handles VRF addition and deletion.
      65             : //Releases all vrf walker reference and route table walker references.
      66         106 : void AgentRouteWalkerManager::VrfNotify(DBTablePartBase *partition,
      67             :                                         DBEntryBase *e) {
      68         106 :     VrfEntry *vrf = static_cast<VrfEntry *>(e);
      69             :     RouteWalkerDBState *state =
      70         106 :         static_cast<RouteWalkerDBState *>(vrf->GetState(partition->parent(),
      71             :                                                         vrf_listener_id_));
      72         106 :     if (vrf->IsDeleted()) {
      73          88 :         if (!state)
      74          88 :             return;
      75           0 :         RemoveWalkReferencesInVrf(state, vrf);
      76           0 :         vrf->ClearState(partition->parent(), vrf_listener_id_);
      77           0 :         delete state;
      78           0 :         return;
      79             :     }
      80             : 
      81          18 :     if (!state) {
      82          12 :         CreateState(vrf);
      83             :     }
      84             : }
      85             : 
      86          16 : RouteWalkerDBState *AgentRouteWalkerManager::CreateState(VrfEntry *vrf) {
      87          16 :     RouteWalkerDBState *state = new RouteWalkerDBState();
      88          16 :     vrf->SetState(vrf->get_table(), vrf_listener_id_, state);
      89          16 :     return state;
      90             : }
      91             : 
      92          59 : void AgentRouteWalkerManager::RemoveWalker(AgentRouteWalkerPtr walker) {
      93          59 :     walk_ref_list_.erase(std::find(walk_ref_list_.begin(), walk_ref_list_.end(),
      94             :                                    walker));
      95          59 : }
      96             : 
      97           3 : void AgentRouteWalkerManager::Shutdown() {
      98           3 :     marked_for_deletion_ = true;
      99           3 :     TryUnregister();
     100           3 : }
     101             : 
     102          62 : void AgentRouteWalkerManager::TryUnregister() {
     103          62 :     if (walk_ref_list_.size() != 0)
     104          59 :         return;
     105           3 :     agent_->vrf_table()->Unregister(vrf_listener_id_);
     106             : }
     107             : 
     108          58 : void AgentRouteWalkerManager::ValidateAgentRouteWalker
     109             : (AgentRouteWalkerPtr walker) const {
     110          58 :    assert (std::find(walk_ref_list_.begin(), walk_ref_list_.end(), walker) !=
     111             :            walk_ref_list_.end());
     112          58 : }
     113             : 
     114          59 : void AgentRouteWalkerManager::RegisterWalker(AgentRouteWalker *walker) {
     115          59 :     if (marked_for_deletion_)
     116           0 :         return;
     117          59 :     walk_ref_list_.insert(walker);
     118          59 :     walker->set_mgr(this);
     119             : }
     120             : 
     121          59 : AgentRouteWalker::AgentRouteWalker(const std::string &name,
     122          59 :                                    Agent *agent) : agent_(agent), name_(name),
     123          59 :     route_walk_count_(), walk_done_cb_(), route_walk_done_for_vrf_cb_(),
     124         118 :     mgr_(NULL), deregister_done_(false) {
     125          59 :     walk_count_ = AgentRouteWalker::kInvalidWalkCount;
     126         118 :     vrf_walk_ref_ = agent_->vrf_table()->AllocWalker(
     127             :                             boost::bind(&AgentRouteWalker::VrfWalkNotify,
     128             :                                         this, _1, _2),
     129             :                             boost::bind(&AgentRouteWalker::VrfWalkDoneInternal,
     130          59 :                                         this, _2));
     131         118 :     delete_walk_ref_ = agent_->vrf_table()->AllocWalker(
     132             :                        boost::bind(&AgentRouteWalker::Deregister, this,
     133             :                                    _1, _2),
     134             :                        boost::bind(&AgentRouteWalker::DeregisterDone,
     135          59 :                                     this));
     136          59 :     refcount_ = 0;
     137          59 : }
     138             : 
     139          59 : AgentRouteWalker::~AgentRouteWalker() {
     140          59 :     assert(vrf_walk_ref_.get() == NULL);
     141          59 :     assert(delete_walk_ref_.get() == NULL);
     142          59 : }
     143             : 
     144             : RouteWalkerDBState *
     145         308 : AgentRouteWalker::LocateRouteWalkerDBState(VrfEntry *vrf) {
     146             :     RouteWalkerDBState *state =
     147         308 :         static_cast<RouteWalkerDBState *>(vrf->GetState(vrf->get_table(),
     148         308 :                                                         mgr_->vrf_listener_id()));
     149         308 :     if (vrf->IsDeleted())
     150           0 :         return state;
     151             : 
     152         308 :     if (!state)
     153           4 :         state = mgr_->CreateState(vrf);
     154             : 
     155         308 :     return state;
     156             : }
     157             : 
     158             : DBTable::DBTableWalkRef
     159         264 : AgentRouteWalker::LocateRouteTableWalkRef(const VrfEntry *vrf,
     160             :                                           RouteWalkerDBState *state,
     161             :                                           AgentRouteTable *table) {
     162         264 :     assert(state != NULL);
     163         264 :     Agent::RouteTableType table_type = table->GetTableType();
     164         264 :     AgentRouteWalkerPtr walker_ptr = AgentRouteWalkerPtr(this);
     165             : 
     166             :     // Search for walker and if found then check if table type has a reference
     167             :     // allocated or not. If allocated return the same.
     168             :     RouteWalkerDBState::AgentRouteWalkerRefMapIter it =
     169         264 :         state->walker_ref_map_.find(walker_ptr);
     170         264 :     DBTable::DBTableWalkRef route_table_walk_ref = DBTable::DBTableWalkRef();
     171             : 
     172             :     // Walker was not found in map, add it
     173         264 :     if (it == state->walker_ref_map_.end()) {
     174          37 :         RouteWalkerDBState::RouteWalkRef route_walk_ref;
     175          37 :         std::pair<RouteWalkerDBState::AgentRouteWalkerRefMapIter, bool> ret;
     176          37 :         ret = state->walker_ref_map_.insert(std::make_pair(walker_ptr, route_walk_ref));
     177          37 :         if (ret.second == false) {
     178           0 :             AGENT_DBWALK_TRACE(AgentRouteWalkerTrace, name_,
     179             :                                "LocateRouteTableWalkRef walker add failed.",
     180             :                                "", "");
     181           0 :             return DBTable::DBTableWalkRef();
     182             :         }
     183          37 :         it = ret.first;
     184          37 :     }
     185             : 
     186             :     // table type had no reference allocated, so allocate it.
     187         264 :     if (it->second[table_type] == DBTable::DBTableWalkRef()) {
     188         444 :         it->second[table_type] = table->AllocWalker(
     189             :                    boost::bind(&AgentRouteWalker::RouteWalkNotify,
     190             :                                this, _1, _2),
     191         444 :                    boost::bind(&AgentRouteWalker::RouteWalkDoneInternal,
     192         222 :                                this, _2, walker_ptr));
     193             :     }
     194         264 :     return it->second[table_type];
     195         264 : }
     196             : 
     197             : /*
     198             :  * Starts walk for all VRF.
     199             :  */
     200          14 : void AgentRouteWalker::StartVrfWalk() {
     201          14 :     mgr_->ValidateAgentRouteWalker(this);
     202          14 :     if (vrf_walk_ref_->in_progress() == false)
     203          14 :         IncrementWalkCount();
     204          14 :     agent_->vrf_table()->WalkAgain(vrf_walk_ref_);
     205             :     //TODO trace
     206          14 :     AGENT_DBWALK_TRACE(AgentRouteWalkerTrace, name_, "StartVrfWalk",
     207             :                        "", "");
     208          14 : }
     209             : 
     210             : DBTable::DBTableWalkRef
     211         264 : AgentRouteWalker::AllocateRouteTableReferences(AgentRouteTable *table) {
     212         264 :     VrfEntry *vrf = table->vrf_entry();
     213         264 :     RouteWalkerDBState *state = LocateRouteWalkerDBState(vrf);
     214         264 :     return LocateRouteTableWalkRef(vrf, state, table);
     215             : }
     216             : 
     217         264 : void AgentRouteWalker::WalkTable(AgentRouteTable *table,
     218             :                             DBTable::DBTableWalkRef &route_table_walk_ref) {
     219         264 :     if (route_table_walk_ref->in_progress() == false) {
     220         264 :         IncrementWalkCount();
     221         264 :         IncrementRouteWalkCount(table->vrf_entry());
     222             :     }
     223         264 :     table->WalkAgain(route_table_walk_ref);
     224         264 : }
     225             : 
     226             : /*
     227             :  * Starts route walk for given VRF.
     228             :  */
     229          44 : void AgentRouteWalker::StartRouteWalk(VrfEntry *vrf) {
     230          44 :     mgr_->ValidateAgentRouteWalker(this);
     231          44 :     AgentRouteTable *table = NULL;
     232             : 
     233             :     //Start the walk for every route table
     234         308 :     for (uint8_t table_type = (Agent::INVALID + 1);
     235         308 :          table_type < Agent::ROUTE_TABLE_MAX;
     236             :          table_type++) {
     237             :         table = static_cast<AgentRouteTable *>
     238         264 :             (vrf->GetRouteTable(table_type));
     239         264 :         if (!table) continue;
     240             :         DBTable::DBTableWalkRef route_table_walk_ref =
     241         264 :             AllocateRouteTableReferences(table);
     242         264 :         WalkTable(table, route_table_walk_ref);
     243         264 :     }
     244          44 : }
     245             : 
     246             : /*
     247             :  * VRF entry notification handler
     248             :  */
     249          18 : bool AgentRouteWalker::VrfWalkNotify(DBTablePartBase *partition,
     250             :                                      DBEntryBase *e) {
     251          18 :     VrfEntry *vrf = static_cast<VrfEntry *>(e);
     252             : 
     253             :     // TODO - VRF deletion need not be ignored, as it may be a way to
     254             :     // unsubscribe. Needs to be fixed with controller walks.
     255             :     //
     256             :     // In case of controller-peer going down. We want to send 'unsubscribe' of
     257             :     // VRF to BGP. Assume sequence where XMPP goes down and VRF is deleted. If
     258             :     // XMPP walk starts before VRF deletion, we unsubscribe to the VRF
     259             :     // notification at end of walk. If we skip deleted VRF in walk, we will not
     260             :     // send 'unsubscribe' to BGP
     261             :     //
     262          18 :     if (vrf->IsDeleted()) {
     263           0 :         AGENT_DBWALK_TRACE(AgentRouteWalkerTrace, name_,
     264             :                            "VrfWalkNotify: Vrf deleted, no route walk.",
     265             :                            (vrf != NULL) ? vrf->GetName() : "Unknown",
     266             :                            "NA");
     267           0 :         return true;
     268             :     }
     269             : 
     270          18 :     StartRouteWalk(vrf);
     271          18 :     return true;
     272             : }
     273             : 
     274          14 : void AgentRouteWalker::VrfWalkDoneInternal(DBTableBase *part) {
     275          14 :     VrfWalkDone(part);
     276          14 :     DecrementWalkCount();
     277          14 :     Callback(NULL);
     278          14 : }
     279             : 
     280          14 : void AgentRouteWalker::VrfWalkDone(DBTableBase *part) {
     281          14 : }
     282             : 
     283             : /*
     284             :  * Route entry notification handler
     285             :  */
     286           0 : bool AgentRouteWalker::RouteWalkNotify(DBTablePartBase *partition,
     287             :                                        DBEntryBase *e) {
     288           0 :     return true;
     289             : }
     290             : 
     291         264 : void AgentRouteWalker::RouteWalkDone(DBTableBase *part) {
     292         264 : }
     293             : 
     294         264 : void AgentRouteWalker::RouteWalkDoneInternal(DBTableBase *part,
     295             :                                              AgentRouteWalkerPtr ptr) {
     296         264 :     RouteWalkDone(part);
     297             : 
     298         264 :     AgentRouteTable *table = static_cast<AgentRouteTable *>(part);
     299         264 :     DecrementWalkCount();
     300         264 :     DecrementRouteWalkCount(table->vrf_entry());
     301         264 :     uint32_t vrf_id = table->vrf_id();
     302             : 
     303         264 :     VrfEntry *vrf = agent_->vrf_table()->
     304         264 :         FindVrfFromIdIncludingDeletedVrf(vrf_id);
     305             :     // If there is no vrf entry for table, that signifies that
     306             :     // routes have gone and table is empty. Since routes have gone
     307             :     // state from vncontroller on routes have been removed and so would
     308             :     // have happened on vrf entry as well.
     309         264 :     Callback(vrf);
     310         264 : }
     311             : 
     312         278 : void AgentRouteWalker::DecrementWalkCount() {
     313         278 :     assert(walk_count_ != AgentRouteWalker::kInvalidWalkCount);
     314         278 :     walk_count_--;
     315         278 : }
     316             : 
     317         264 : void AgentRouteWalker::DecrementRouteWalkCount(const VrfEntry *vrf) {
     318         264 :     VrfRouteWalkCountMap::iterator it = route_walk_count_.find(vrf);
     319         264 :     if (it != route_walk_count_.end()) {
     320         264 :         it->second--;
     321         264 :         if (it->second == AgentRouteWalker::kInvalidWalkCount)
     322          44 :             route_walk_count_.erase(vrf);
     323             :     }
     324         264 : }
     325             : 
     326         264 : void AgentRouteWalker::IncrementRouteWalkCount(const VrfEntry *vrf) {
     327         264 :     route_walk_count_[vrf]++;
     328         264 : }
     329             : 
     330         278 : void AgentRouteWalker::Callback(VrfEntry *vrf) {
     331         278 :     if (vrf && AreAllRouteWalksDone(vrf)) {
     332             :         //Deletes the state on VRF
     333          44 :         OnRouteTableWalkCompleteForVrf(vrf);
     334             :     }
     335         278 :     if (AreAllWalksDone()) {
     336             :         //To be executed in callback where surity is there
     337             :         //that all walks are done.
     338          38 :         AGENT_DBWALK_TRACE(AgentRouteWalkerTrace, name_,
     339             :                            "All Walks are done",
     340             :                            (vrf != NULL) ? vrf->GetName() : "Unknown",
     341             :                            "NA");
     342          38 :         if (walk_done_cb_.empty() == false) {
     343           7 :             walk_done_cb_();
     344             :         }
     345             :     }
     346         278 : }
     347             : 
     348           0 : bool AgentRouteWalker::IsRouteTableWalkCompleted(RouteWalkerDBState *state) {
     349             :     RouteWalkerDBState::AgentRouteWalkerRefMapConstIter it =
     350           0 :         state->walker_ref_map_.find(AgentRouteWalkerPtr(this));
     351           0 :     if (it == state->walker_ref_map_.end())
     352           0 :         return true;
     353             : 
     354           0 :     for (uint8_t table_type = Agent::ROUTE_TABLE_START;
     355           0 :          table_type < Agent::ROUTE_TABLE_MAX; table_type++) {
     356           0 :         if (it->second[table_type] != DBTable::DBTableWalkRef())
     357           0 :             return false;
     358             :     }
     359           0 :     return true;
     360             : }
     361             : 
     362             : /*
     363             :  * Check if all route table walk have been reset for this VRF
     364             :  */
     365          44 : void AgentRouteWalker::OnRouteTableWalkCompleteForVrf(VrfEntry *vrf) {
     366          44 :     RouteWalkerDBState *state = LocateRouteWalkerDBState(vrf);
     367          44 :     if (!state) {
     368           0 :         return;
     369             :     }
     370             : 
     371          44 :     AGENT_DBWALK_TRACE(AgentRouteWalkerTrace, name_,
     372             :                        "All route walks are done",
     373             :                        (vrf != NULL) ? vrf->GetName() : "Unknown",
     374             :                        "NA");
     375             : 
     376          44 :     if (route_walk_done_for_vrf_cb_.empty())
     377          42 :         return;
     378             : 
     379           2 :     route_walk_done_for_vrf_cb_(vrf);
     380             : }
     381             : 
     382         278 : bool AgentRouteWalker::AreAllWalksDone() const {
     383         278 :     return (walk_count_ == AgentRouteWalker::kInvalidWalkCount);
     384             : }
     385             : 
     386         264 : bool AgentRouteWalker::AreAllRouteWalksDone(const VrfEntry *vrf) const {
     387         264 :     VrfRouteWalkCountMap::const_iterator it = route_walk_count_.find(vrf);
     388         264 :     return (it == route_walk_count_.end());
     389             : }
     390             : 
     391             : /* Callback set, his is called when all walks are done i.e. VRF + route */
     392           8 : void AgentRouteWalker::WalkDoneCallback(WalkDone cb) {
     393           8 :     walk_done_cb_ = cb;
     394           8 : }
     395             : 
     396             : /*
     397             :  * Callback is registered to notify walk complete of all route tables for
     398             :  * a VRF.
     399             :  */
     400           2 : void AgentRouteWalker::RouteWalkDoneForVrfCallback(RouteWalkDoneCb cb) {
     401           2 :     route_walk_done_for_vrf_cb_ = cb;
     402           2 : }
     403             : 
     404          59 : void AgentRouteWalker::ReleaseVrfWalkReference() {
     405          59 :     agent_->vrf_table()->WalkAgain(delete_walk_ref_);
     406          59 :     if (vrf_walk_ref_ != NULL) {
     407          59 :         agent_->vrf_table()->ReleaseWalker(vrf_walk_ref());
     408             :     }
     409          59 :     vrf_walk_ref_.reset();
     410          59 : }
     411             : 
     412          88 : bool AgentRouteWalker::Deregister(DBTablePartBase *partition,
     413             :                                   DBEntryBase *e) {
     414          88 :     VrfEntry *vrf = static_cast<VrfEntry *>(e);
     415          88 :     DBTable::ListenerId vrf_listener_id = mgr_->vrf_listener_id();
     416             :     RouteWalkerDBState *state =
     417          88 :         static_cast<RouteWalkerDBState *>(vrf->GetState(vrf->get_table(),
     418             :                                                         vrf_listener_id));
     419          88 :     AgentRouteWalkerPtr walker_ptr = AgentRouteWalkerPtr(this);
     420             : 
     421          88 :     if (state == NULL)
     422          72 :         return true;
     423             : 
     424          16 :     if (vrf_walk_ref_.get() != NULL) {
     425             :         RouteWalkerDBState::AgentRouteWalkerRefMapIter it =
     426           0 :             state->walker_ref_map_.find(AgentRouteWalkerPtr(this));
     427           0 :         if (it != state->walker_ref_map_.end())
     428           0 :             RemoveWalkReferencesInRoutetable(it, state);
     429           0 :         return true;
     430             :     }
     431             : 
     432             :     //If walk reference is provided as NULL, its delete of walk manager and
     433             :     //agent shutdown. So delete all walk_refs.
     434          16 :     for (RouteWalkerDBState::AgentRouteWalkerRefMapIter it2 =
     435          16 :          state->walker_ref_map_.begin();
     436          53 :          it2 != state->walker_ref_map_.end(); it2++) {
     437          37 :         RemoveWalkReferencesInRoutetable(it2, state);
     438             :     }
     439          16 :     vrf->ClearState(partition->parent(), vrf_listener_id);
     440          16 :     delete state;
     441          16 :     return true;
     442          88 : }
     443             : 
     444             : void
     445          59 : AgentRouteWalker::DeregisterDone(AgentRouteWalkerPtr walker) {
     446          59 :     const Agent *agent = walker.get()->agent();
     447          59 :     if (walker.get()->vrf_walk_ref().get() != NULL) {
     448           0 :         walker.get()->agent()->vrf_table()->ReleaseWalker(walker.get()->
     449             :                                                           vrf_walk_ref());
     450             :     }
     451          59 :     if (walker.get()->delete_walk_ref().get() != NULL) {
     452          59 :         walker.get()->agent()->vrf_table()->ReleaseWalker(walker.get()->
     453             :                                                           delete_walk_ref());
     454             :     }
     455             : 
     456          59 :     if (agent->oper_db()->agent_route_walk_manager()) {
     457          59 :         walker.get()->mgr()->RemoveWalker(walker);
     458          59 :         walker.get()->mgr()->TryUnregister();
     459             :     }
     460          59 :     walker.get()->deregister_done_ = true;
     461          59 : }
     462             : 
     463        4583 : void intrusive_ptr_add_ref(AgentRouteWalker *w) {
     464        4583 :     w->refcount_++;
     465        4583 : }
     466             : 
     467        4583 : void intrusive_ptr_release(AgentRouteWalker *w) {
     468        9166 :     if (w->refcount_.fetch_sub(1) == 1) {
     469          59 :         delete w;
     470             :     }
     471        4583 : }

Generated by: LCOV version 1.14