LCOV - code coverage report
Current view: top level - vnsw/agent/controller - controller_route_walker.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 83 174 47.7 %
Date: 2026-08-03 02:19:58 Functions: 12 18 66.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include <boost/shared_ptr.hpp>
       6             : 
       7             : #include <sandesh/sandesh_trace.h>
       8             : 
       9             : #include <cmn/agent_cmn.h>
      10             : #include <oper/route_common.h>
      11             : #include <oper/agent_route_walker.h>
      12             : #include <oper/peer.h>
      13             : #include <oper/vrf.h>
      14             : #include <oper/mirror_table.h>
      15             : #include <oper/agent_sandesh.h>
      16             : 
      17             : #include "controller/controller_route_walker.h"
      18             : #include "controller/controller_init.h"
      19             : #include "controller/controller_types.h"
      20             : #include "controller/controller_vrf_export.h"
      21             : #include "controller/controller_export.h"
      22             : #include "controller/controller_route_path.h"
      23             : 
      24          20 : ControllerRouteWalker::ControllerRouteWalker(const std::string &name,
      25          20 :                                              Peer *peer) :
      26          20 :     AgentRouteWalker(name, dynamic_cast<BgpPeer *>(peer)->agent()),
      27          40 :     peer_(peer), associate_(false), type_(NOTIFYALL), sequence_number_(0) {
      28          20 : }
      29             : 
      30             : // Takes action based on context of walk. These walks are not parallel.
      31             : // At a time peer can be only in one state.
      32           4 : bool ControllerRouteWalker::VrfWalkNotify(DBTablePartBase *partition,
      33             :                                           DBEntryBase *entry) {
      34           4 :     VrfEntry *vrf = static_cast<VrfEntry *>(entry);
      35             :     // Notification from deleted VRF should have taken care of all operations
      36             :     // w.r.t. peer, see VrfExport::Notify
      37             :     // Exception is DelPeer walk. Reason being that this walk will start when
      38             :     // peer goes down in agent xmpp channel. When it happens bgp peer in channel
      39             :     // is reset. Any add/delete notification on said VRF checks if xmpp channel
      40             :     // is active which internally checks for bgp peer. In current case it will
      41             :     // be NULL and will in-turn ignore notification for delete. State will
      42             :     // not be deleted for that peer in vrf. To delete state, delpeer walk will
      43             :     // have to traverse deleted VRF as well.
      44           4 :     if (vrf->IsDeleted() && (type_ != DELPEER))
      45           0 :         return true;
      46             : 
      47           4 :     switch (type_) {
      48           0 :     case NOTIFYALL:
      49           0 :         return VrfNotifyAll(partition, entry);
      50           0 :     case NOTIFYMULTICAST:
      51           0 :         return VrfNotifyMulticast(partition, entry);
      52           2 :     case DELPEER:
      53           2 :         return VrfDelPeer(partition, entry);
      54           2 :     case DELSTALE:
      55           2 :         return VrfDelStale(partition, entry);
      56           0 :     default:
      57           0 :         return false;
      58             :     }
      59             :     return false;
      60             : }
      61             : 
      62             : /*
      63             :  * Notification for vrf entry - Creates states (VRF and route) and
      64             :  * send subscription to control node
      65             :  * This will be called for active bgp peer only.
      66             :  */
      67           0 : bool ControllerRouteWalker::VrfNotifyAll(DBTablePartBase *partition,
      68             :                                          DBEntryBase *entry) {
      69           0 :     VrfEntry *vrf = static_cast<VrfEntry *>(entry);
      70           0 :     if (peer_->GetType() == Peer::BGP_PEER) {
      71           0 :         BgpPeer *bgp_peer = static_cast<BgpPeer *>(peer_);
      72             : 
      73           0 :         DBTableBase::ListenerId id = bgp_peer->GetVrfExportListenerId();
      74             :         VrfExport::State *state =
      75           0 :             static_cast<VrfExport::State *>(vrf->GetState(partition->parent(),
      76             :                                                           id));
      77           0 :         if (state) {
      78             :             /* state for __default__ instance will not be created if the
      79             :              * xmpp channel is up the first time as export code registers to
      80             :              * vrf-table after entry for __default__ instance is created */
      81           0 :             state->force_chg_ = true;
      82             :         }
      83             : 
      84             :         //Pass this object pointer so that VrfExport::Notify can start the route
      85             :         //walk if required on this VRF. Also it adds state if none is found.
      86           0 :         VrfExport::Notify(agent(), bgp_peer->GetAgentXmppChannel(),
      87             :                           partition, entry);
      88           0 :         CONTROLLER_ROUTE_WALKER_TRACE(Walker, "Vrf Notify all", vrf->GetName(),
      89             :                          bgp_peer->GetName());
      90           0 :         return true;
      91             :     }
      92           0 :     return false;
      93             : }
      94             : 
      95             : /*
      96             :  * Delete peer notifications for VRF.
      97             :  */
      98           2 : bool ControllerRouteWalker::VrfDelPeer(DBTablePartBase *partition,
      99             :                                        DBEntryBase *entry) {
     100           2 :     VrfEntry *vrf = static_cast<VrfEntry *>(entry);
     101           2 :     if (peer_->GetType() == Peer::BGP_PEER) {
     102           2 :         BgpPeer *bgp_peer = static_cast<BgpPeer *>(peer_);
     103             :         VrfExport::State *state = static_cast<VrfExport::State *>
     104           2 :             (bgp_peer->GetVrfExportState(partition, vrf));
     105             :         // State can be NULL, when vrf delete has happened before peer goes down
     106             :         // and VRF is not deleted before delpeer walker reaches the entry.
     107             :         // Controller Notify would have deleted state before delpeer was invoked.
     108           2 :         if (!state)
     109           2 :             return true;
     110             :         // skip starting walk on route tables if all the the route tables
     111             :         // are already delete, this also safe-gaurds that StartRouteWalk
     112             :         // will not be the first reference on the deleted VRF which will
     113             :         // end up taking reference and setting refcount state on deleted
     114             :         // VRF which can cause Bug - 1495824
     115           0 :         if (vrf->AllRouteTableDeleted()) return true;
     116             :         // Register Callback for deletion of VRF state on completion of route
     117             :         // walks
     118           0 :         if (type_ == ControllerRouteWalker::DELPEER) {
     119           0 :             RouteWalkDoneForVrfCallback(boost::bind(
     120             :                                &ControllerRouteWalker::RouteWalkDoneForVrf,
     121             :                                this, _1));
     122             :         }
     123           0 :         StartRouteWalk(vrf, associate_, type_);
     124           0 :         return true;
     125             :     }
     126           0 :     return false;
     127             : }
     128             : 
     129             : /*
     130             :  * Delete stale notifications for VRF.
     131             :  */
     132           2 : bool ControllerRouteWalker::VrfDelStale(DBTablePartBase *partition,
     133             :                                         DBEntryBase *entry) {
     134           2 :     VrfEntry *vrf = static_cast<VrfEntry *>(entry);
     135           2 :     if (peer_->GetType() == Peer::BGP_PEER) {
     136             :         // skip starting walk on route tables if all the the route tables
     137             :         // are already delete, this also safe-gaurds that StartRouteWalk
     138             :         // will not be the first reference on the deleted VRF which will
     139             :         // end up taking reference and setting refcount state on deleted
     140             :         // VRF which can cause Bug - 1495824
     141           2 :         if (vrf->AllRouteTableDeleted()) return true;
     142             :         // Register Callback for deletion of VRF state on completion of route
     143             :         // walks
     144           2 :         if (type_ == ControllerRouteWalker::DELSTALE) {
     145           2 :             RouteWalkDoneForVrfCallback(boost::bind(
     146             :                                &ControllerRouteWalker::RouteWalkDoneForVrf,
     147             :                                this, _1));
     148             :         }
     149           2 :         StartRouteWalk(vrf, associate_, type_);
     150           2 :         return true;
     151             :     }
     152           0 :     return false;
     153             : }
     154             : 
     155           0 : bool ControllerRouteWalker::VrfNotifyMulticast(DBTablePartBase *partition,
     156             :                                                DBEntryBase *entry) {
     157           0 :     VrfEntry *vrf = static_cast<VrfEntry *>(entry);
     158           0 :     CONTROLLER_ROUTE_WALKER_TRACE(Walker, "Vrf Multicast", vrf->GetName(),
     159             :                                   peer_->GetName());
     160           0 :     return VrfNotifyInternal(partition, entry);
     161             : }
     162             : 
     163             : //Common routeine if basic vrf and peer check is required for the walk
     164           0 : bool ControllerRouteWalker::VrfNotifyInternal(DBTablePartBase *partition,
     165             :                                               DBEntryBase *entry) {
     166           0 :     VrfEntry *vrf = static_cast<VrfEntry *>(entry);
     167           0 :     if (peer_->GetType() == Peer::BGP_PEER) {
     168           0 :         BgpPeer *bgp_peer = static_cast<BgpPeer *>(peer_);
     169           0 :         if (IgnoreNotify()) {
     170           0 :             return false;
     171             :         }
     172             : 
     173           0 :         DBTableBase::ListenerId id = bgp_peer->GetVrfExportListenerId();
     174             :         VrfExport::State *state =
     175           0 :             static_cast<VrfExport::State *>(vrf->GetState(partition->parent(),
     176             :                                                           id));
     177           0 :         if (state) {
     178           0 :             StartRouteWalk(vrf, associate_, type_);
     179             : 
     180           0 :             if (Agent::GetInstance()->mulitcast_builder() ==
     181           0 :                 bgp_peer->GetAgentXmppChannel()) {
     182           0 :                 state->mcast_exported_ = associate_;
     183             :             }
     184             :         }
     185             : 
     186           0 :         return true;
     187             :     }
     188           0 :     return false;
     189             : }
     190             : 
     191             : // Takes action based on context of walk. These walks are not parallel.
     192             : // At a time peer can be only in one state.
     193          38 : bool ControllerRouteWalker::RouteWalkNotify(DBTablePartBase *partition,
     194             :                                       DBEntryBase *entry) {
     195          38 :     switch (type_) {
     196          24 :     case NOTIFYALL:
     197          24 :         return RouteNotifyAll(partition, entry);
     198           0 :     case NOTIFYMULTICAST:
     199           0 :         return RouteNotifyMulticast(partition, entry);
     200           0 :     case DELPEER:
     201           0 :         return RouteDelPeer(partition, entry);
     202          14 :     case DELSTALE:
     203          14 :         return RouteDelStale(partition, entry);
     204           0 :     default:
     205           0 :         return false;
     206             :     }
     207             :     return false;
     208             : }
     209             : 
     210          24 : bool ControllerRouteWalker::RouteNotifyInternal(DBTablePartBase *partition,
     211             :                                                 DBEntryBase *entry) {
     212          24 :     AgentRoute *route = static_cast<AgentRoute *>(entry);
     213             : 
     214          24 :     if ((type_ == NOTIFYMULTICAST) && !route->is_multicast())
     215           0 :         return true;
     216             : 
     217          24 :     BgpPeer *bgp_peer = static_cast<BgpPeer *>(peer_);
     218          24 :     if (IgnoreNotify()) {
     219           0 :         return false;
     220             :     }
     221             : 
     222          24 :     Agent::RouteTableType table_type = route->GetTableType();
     223             : 
     224             :     //Get the route state
     225             :     RouteExport::State *route_state = static_cast<RouteExport::State *>
     226          24 :         (bgp_peer->GetRouteExportState(partition, entry));
     227          24 :     if (route_state) {
     228             :         // Forcibly send the notification to peer.
     229           0 :         route_state->force_chg_ = true;
     230             :     }
     231             : 
     232          24 :     VrfEntry *vrf = route->vrf();
     233          24 :     DBTablePartBase *vrf_partition = agent()->vrf_table()->
     234          24 :         GetTablePartition(vrf);
     235             :     VrfExport::State *vs = static_cast<VrfExport::State *>
     236          24 :         (bgp_peer->GetVrfExportState(vrf_partition, vrf));
     237             : 
     238          24 :     if (vs) {
     239          24 :         vs->rt_export_[table_type]->
     240          24 :             Notify(agent(), bgp_peer->GetAgentXmppChannel(), associate_,
     241             :                    table_type, partition, entry);
     242             :     }
     243          24 :     return true;
     244             : }
     245             : 
     246          24 : bool ControllerRouteWalker::RouteNotifyAll(DBTablePartBase *partition,
     247             :                                            DBEntryBase *entry) {
     248          24 :     AgentRoute *route = static_cast<AgentRoute *>(entry);
     249          24 :     CONTROLLER_ROUTE_WALKER_TRACE(Walker, "Route NotifyAll", route->ToString(),
     250             :                      peer_->GetName());
     251          24 :     return RouteNotifyInternal(partition, entry);
     252             : }
     253             : 
     254           0 : bool ControllerRouteWalker::RouteNotifyMulticast(DBTablePartBase *partition,
     255             :                                                  DBEntryBase *entry) {
     256           0 :     AgentRoute *route = static_cast<AgentRoute *>(entry);
     257           0 :     CONTROLLER_ROUTE_WALKER_TRACE(Walker, "Route Multicast Notify", route->ToString(),
     258             :                      peer_->GetName());
     259           0 :     return RouteNotifyInternal(partition, entry);
     260             : }
     261             : 
     262          14 : bool ControllerRouteWalker::RouteDelStale(DBTablePartBase *partition,
     263             :                                               DBEntryBase *entry) {
     264          14 :     AgentRoute *route = static_cast<AgentRoute *>(entry);
     265          14 :     if (!route)
     266           0 :         return true;
     267             : 
     268             :     //Enqueue path delete.
     269             :     AgentRouteKey *key = (static_cast<AgentRouteKey *>(route->
     270          14 :                                       GetDBRequestKey().get()))->Clone();
     271          14 :     key->set_peer(peer_);
     272          14 :     DBRequest req(DBRequest::DB_ENTRY_DELETE);
     273          14 :     req.key.reset(key);
     274          14 :     req.data.reset(new StalePathData(sequence_number_));
     275          14 :     AgentRouteTable *table = static_cast<AgentRouteTable *>(route->get_table());
     276          14 :     table->Process(req);
     277          14 :     return true;
     278          14 : }
     279             : 
     280             : // Deletes the peer and corresponding state in route
     281           0 : bool ControllerRouteWalker::RouteDelPeer(DBTablePartBase *partition,
     282             :                                          DBEntryBase *entry) {
     283           0 :     AgentRoute *route = static_cast<AgentRoute *>(entry);
     284           0 :     BgpPeer *bgp_peer = static_cast<BgpPeer *>(peer_);
     285             : 
     286           0 :     if (!route)
     287           0 :         return true;
     288             : 
     289           0 :     CONTROLLER_ROUTE_WALKER_TRACE(Walker, "Route Delpeer", route->ToString(),
     290             :                      peer_->GetName());
     291             : 
     292           0 :     VrfEntry *vrf = route->vrf();
     293           0 :     DBTablePartBase *vrf_partition = agent()->vrf_table()->
     294           0 :         GetTablePartition(vrf);
     295             :     VrfExport::State *vrf_state = static_cast<VrfExport::State *>
     296           0 :         (bgp_peer->GetVrfExportState(vrf_partition, vrf));
     297             :     RouteExport::State *state = static_cast<RouteExport::State *>
     298           0 :         (bgp_peer->GetRouteExportState(partition, entry));
     299           0 :     if (vrf_state && state && vrf_state->rt_export_[route->GetTableType()]) {
     300           0 :         route->ClearState(partition->parent(), vrf_state->rt_export_[route->
     301           0 :                           GetTableType()]->GetListenerId());
     302           0 :         delete state;
     303           0 :         CONTROLLER_ROUTE_WALKER_TRACE(Walker, "DelPeer route walk, delete state",
     304             :                          route->ToString(), peer_->GetName());
     305             :     }
     306             : 
     307             :     //Enqueue path delete.
     308             :     AgentRouteKey *key = (static_cast<AgentRouteKey *>(route->
     309           0 :                                       GetDBRequestKey().get()))->Clone();
     310           0 :     key->set_peer(peer_);
     311           0 :     DBRequest req(DBRequest::DB_ENTRY_DELETE);
     312           0 :     req.key.reset(key);
     313           0 :     req.data.reset();
     314           0 :     AgentRouteTable *table = static_cast<AgentRouteTable *>(route->get_table());
     315           0 :     table->Process(req);
     316           0 :     return true;
     317           0 : }
     318             : 
     319             : // Called when for a VRF all route table walks are complete.
     320             : // Deletes the VRF state of that peer.
     321           2 : void ControllerRouteWalker::RouteWalkDoneForVrf(VrfEntry *vrf) {
     322             :     // Currently used only for delete peer handling
     323             :     // Deletes the state and release the listener id
     324           2 :     if (type_ != DELPEER)
     325           2 :         return;
     326             : 
     327           0 :     CONTROLLER_ROUTE_WALKER_TRACE(Walker, "Route Walk done", vrf->GetName(),
     328             :                      peer_->GetName());
     329           0 :     BgpPeer *bgp_peer = static_cast<BgpPeer *>(peer_);
     330           0 :     DBEntryBase *entry = static_cast<DBEntryBase *>(vrf);
     331           0 :     DBTablePartBase *partition = agent()->vrf_table()->GetTablePartition(vrf);
     332           0 :     bgp_peer->DeleteVrfState(partition, entry);
     333             : }
     334             : 
     335             : // walk_done_cb - Called back when all walk i.e. VRF and route are done.
     336           5 : void ControllerRouteWalker::Start(Type type, bool associate,
     337             :                             AgentRouteWalker::WalkDone walk_done_cb) {
     338           5 :     associate_ = associate;
     339           5 :     type_ = type;
     340           5 :     WalkDoneCallback(walk_done_cb);
     341             : 
     342           5 :     StartVrfWalk();
     343           5 : }
     344             : 
     345           8 : void ControllerRouteWalker::StartRouteWalk(VrfEntry *vrf, bool associate,
     346             :                                            Type type) {
     347           8 :     associate_ = associate;
     348           8 :     type_ = type;
     349           8 :     AgentRouteWalker::StartRouteWalk(vrf);
     350           8 : }
     351             : 
     352           0 : bool ControllerRouteWalker::IsDeleteWalk() const {
     353           0 :     return ((type_ == DELSTALE) || (type_ == DELPEER));
     354             : }
     355             : 
     356          24 : bool ControllerRouteWalker::IgnoreNotify() {
     357          24 :     BgpPeer *bgp_peer = static_cast<BgpPeer *>(peer_);
     358          24 :     return bgp_peer->SkipAddChangeRequest();
     359             : }

Generated by: LCOV version 1.14