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

Generated by: LCOV version 1.14