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: 229 252 90.9 %
Date: 2026-11-09 02:10:49 Functions: 41 44 93.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14