LCOV - code coverage report
Current view: top level - oper - peer.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 162 189 85.7 %
Date: 2026-09-22 08:13:23 Functions: 32 40 80.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include <cmn/agent_cmn.h>
       6             : #include <oper/vrf.h>
       7             : #include <oper/route_common.h>
       8             : #include <oper/peer.h>
       9             : #include <oper/agent_route_walker.h>
      10             : #include <oper/mirror_table.h>
      11             : 
      12             : #include <controller/controller_route_walker.h>
      13             : #include <controller/controller_peer.h>
      14             : #include <controller/controller_vrf_export.h>
      15             : #include <controller/controller_export.h>
      16             : #include <controller/controller_init.h>
      17             : 
      18         224 : Peer::Peer(Type type, const std::string &name, bool export_to_controller) :
      19         224 :     type_(type), name_(name), export_to_controller_(export_to_controller) {
      20         224 :     refcount_ = 0;
      21         224 :     sequence_number_ = 0;
      22         224 : }
      23             : 
      24         248 : Peer::~Peer() {
      25         248 : }
      26             : 
      27         405 : bool Peer::DeleteOnZeroRefcount() const {
      28         405 :     return false;
      29             : }
      30             : 
      31       26434 : void intrusive_ptr_add_ref(const Peer *p) {
      32       26434 :     p->refcount_++;
      33             :     // validate that reference is not taken while delete is in progress
      34       26434 :     assert(!p->IsDeleted());
      35       26434 : }
      36             : 
      37       26434 : void intrusive_ptr_release(const Peer *p) {
      38       52868 :     if (p->refcount_.fetch_sub(1) == 1 && p->DeleteOnZeroRefcount()) {
      39          20 :         delete p;
      40             :     }
      41       26434 : }
      42             : 
      43          20 : DynamicPeer::DynamicPeer(Agent *agent, Type type, const std::string &name,
      44          20 :                          bool export_to_controller) :
      45          20 :     Peer(type, name, export_to_controller) {
      46          40 :     delete_timeout_timer_ = TimerManager::CreateTimer(
      47          20 :                                 *(agent->event_manager())->io_service(),
      48             :                                 "Dynamic Peer Delete Timer",
      49             :                                 agent->task_scheduler()->\
      50             :                                 GetTaskId("db::DBTable"), 0);
      51          20 :     deleted_ = false;
      52          20 :     skip_add_change_ = false;
      53          20 : }
      54             : 
      55          20 : DynamicPeer::~DynamicPeer() {
      56             :     // Dynamic Peer should be marked deleted and will free
      57             :     // automatically once all the references go away
      58          20 :     assert(deleted_);
      59          20 :     assert(refcount() == 0);
      60          20 :     TimerManager::DeleteTimer(delete_timeout_timer_);
      61          20 : }
      62             : 
      63          20 : void DynamicPeer::ProcessDelete(DynamicPeer *p) {
      64          20 :     p->StopRouteExports();
      65             : 
      66          20 :     if (p->deleted_.exchange(true)) {
      67           0 :         return;
      68             :     }
      69             : 
      70          20 :     if (p->refcount() != 0) {
      71             :         // still pending references are there start delete timeout timer
      72          20 :         p->delete_timeout_timer_->Start(kDeleteTimeout,
      73             :                                      boost::bind(&DynamicPeer::DeleteTimeout,
      74             :                                      p));
      75          20 :         return;
      76             :     }
      77             : 
      78             :     // no pending references delete the peer inline and return
      79           0 :     delete p;
      80             : }
      81             : 
      82           0 : bool DynamicPeer::DeleteTimeout() {
      83           0 :     assert(0);
      84             :     return false;
      85             : }
      86             : 
      87          20 : bool DynamicPeer::DeleteOnZeroRefcount() const {
      88          20 :     if (!deleted_) {
      89           0 :         return false;
      90             :     }
      91             : 
      92             :     // last reference has gone, cancel the timer and delete peer
      93          20 :     delete_timeout_timer_->Cancel();
      94             : 
      95          20 :     return true;
      96             : }
      97             : 
      98          54 : const Ip4Address *Peer::NexthopIp(Agent *agent, const AgentPath *path) const {
      99          54 :     return agent->router_ip_ptr();
     100             : }
     101             : 
     102          20 : BgpPeer::BgpPeer(AgentXmppChannel *channel, const Ip4Address &server_ip,
     103             :                  const std::string &name, DBTableBase::ListenerId id,
     104          20 :                  Peer::Type bgp_peer_type) :
     105             :     DynamicPeer(channel->agent(), bgp_peer_type, name, false),
     106          40 :     channel_(channel), server_ip_(server_ip), id_(id),
     107          20 :     delete_stale_walker_(NULL), route_walker_cb_(NULL),
     108          40 :     delete_stale_walker_cb_(NULL) {
     109          20 :         AllocPeerNotifyWalker();
     110          20 :         AllocDeleteStaleWalker();
     111          20 :         AllocDeletePeerWalker();
     112          20 :         setup_time_ = UTCTimestampUsec();
     113          20 : }
     114             : 
     115          40 : BgpPeer::~BgpPeer() {
     116          20 :     const Agent *agent = route_walker()->agent();
     117             :     // TODO verify if this unregister can be done in walkdone callback
     118             :     // for delpeer
     119          20 :     if ((id_ != -1) && agent->vrf_table()) {
     120          20 :         agent->vrf_table()->Unregister(id_);
     121             :     }
     122          20 :     ReleaseDeleteStaleWalker();
     123          20 :     ReleaseDeletePeerWalker();
     124          20 :     ReleasePeerNotifyWalker();
     125          40 : }
     126             : 
     127             : // Route notify walker routines
     128          40 : void BgpPeer::AllocPeerNotifyWalker() {
     129          40 :     if (!route_walker()) {
     130          40 :         Agent *agent = channel_->agent();
     131          80 :         route_walker_ = new ControllerRouteWalker(server_ip_.to_string(),
     132          40 :                                                   this);
     133             :         agent->oper_db()->agent_route_walk_manager()->
     134          40 :             RegisterWalker(static_cast<AgentRouteWalker *>
     135             :                            (route_walker_.get()));
     136             :     }
     137          40 : }
     138             : 
     139          40 : void BgpPeer::ReleasePeerNotifyWalker() {
     140          40 :     if (!route_walker()) {
     141           0 :         return;
     142             :     }
     143             : 
     144          40 :     Agent *agent = Agent::GetInstance();
     145          40 :     agent->oper_db()->agent_route_walk_manager()->ReleaseWalker(route_walker());
     146          40 :     route_walker_.reset();
     147             : }
     148             : 
     149           0 : void BgpPeer::PeerNotifyRoutes(WalkDoneCb cb) {
     150           0 :     route_walker_cb_ = cb;
     151           0 :     route_walker()->Start(ControllerRouteWalker::NOTIFYALL, true,
     152           0 :                           route_walker_cb_);
     153           0 : }
     154             : 
     155          20 : void BgpPeer::StopPeerNotifyRoutes() {
     156             :     //No implementation of stop, to stop a walk release walker. Re-allocate for
     157             :     //further use.
     158          20 :     ReleasePeerNotifyWalker();
     159          20 :     AllocPeerNotifyWalker();
     160          20 : }
     161             : 
     162           0 : void BgpPeer::PeerNotifyMulticastRoutes(bool associate) {
     163           0 :     route_walker()->Start(ControllerRouteWalker::NOTIFYMULTICAST, associate,
     164             :                           NULL);
     165           0 : }
     166             : 
     167             : // Delete stale walker routines
     168          40 : void BgpPeer::AllocDeleteStaleWalker() {
     169          40 :     if (!delete_stale_walker()) {
     170          40 :         Agent *agent = channel_->agent();
     171          80 :         delete_stale_walker_ = new ControllerRouteWalker(server_ip_.to_string(),
     172          40 :                                                          this);
     173             :         agent->oper_db()->agent_route_walk_manager()->
     174          40 :             RegisterWalker(static_cast<AgentRouteWalker *>
     175             :                            (delete_stale_walker_.get()));
     176             :     }
     177          40 : }
     178             : 
     179          60 : void BgpPeer::ReleaseDeleteStaleWalker() {
     180          60 :     if (!delete_stale_walker()) {
     181          20 :         return;
     182             :     }
     183             : 
     184          40 :     Agent *agent = Agent::GetInstance();
     185             :     agent->oper_db()->agent_route_walk_manager()->
     186          40 :         ReleaseWalker(delete_stale_walker());
     187          40 :     delete_stale_walker_.reset();
     188             : }
     189             : 
     190             : // Delete stale walker routines
     191          20 : void BgpPeer::AllocDeletePeerWalker() {
     192          20 :     if (!delete_peer_walker()) {
     193          20 :         Agent *agent = channel_->agent();
     194          40 :         delete_peer_walker_ = new ControllerRouteWalker(server_ip_.to_string(),
     195          20 :                                                          this);
     196             :         agent->oper_db()->agent_route_walk_manager()->
     197          20 :             RegisterWalker(static_cast<AgentRouteWalker *>
     198             :                            (delete_peer_walker_.get()));
     199             :     }
     200          20 : }
     201             : 
     202          20 : void BgpPeer::ReleaseDeletePeerWalker() {
     203          20 :     if (!delete_peer_walker()) {
     204           0 :         return;
     205             :     }
     206             : 
     207          20 :     Agent *agent = Agent::GetInstance();
     208             :     agent->oper_db()->agent_route_walk_manager()->
     209          20 :         ReleaseWalker(delete_peer_walker());
     210          20 :     delete_peer_walker_.reset();
     211             : }
     212             : 
     213          20 : void BgpPeer::DelPeerRoutes(WalkDoneCb walk_done_cb,
     214             :                             uint64_t sequence_number) {
     215             :     //Since peer is getting deleted no need of seperate walk to delete stale or
     216             :     //non stale paths.
     217          20 :     ReleaseDeleteStaleWalker();
     218          20 :     delete_peer_walker_cb_ = walk_done_cb;
     219          20 :     delete_peer_walker()->set_sequence_number(sequence_number);
     220          40 :     delete_peer_walker()->Start(ControllerRouteWalker::DELPEER, false,
     221          20 :                           delete_peer_walker_cb_);
     222          20 : }
     223             : 
     224          38 : void BgpPeer::DeleteStale() {
     225             :     //If peer is marked for deletion skip. Deletion should take care of removing
     226             :     //routes.
     227          38 :     if (SkipAddChangeRequest())
     228          20 :         return;
     229             : 
     230          18 :     delete_stale_walker()->set_sequence_number(sequence_number());
     231          36 :     delete_stale_walker()->Start(ControllerRouteWalker::DELSTALE, false,
     232          18 :                                 delete_stale_walker_cb_);
     233             : }
     234             : 
     235          20 : void BgpPeer::StopDeleteStale() {
     236             :     //No implementation of stop, to stop a walk release walker. Re-allocate for
     237             :     //further use.
     238          20 :     ReleaseDeleteStaleWalker();
     239          20 :     AllocDeleteStaleWalker();
     240          20 : }
     241             : 
     242         149 : ControllerRouteWalker *BgpPeer::route_walker() const {
     243         149 :     return static_cast<ControllerRouteWalker *>(route_walker_.get());
     244             : }
     245             : 
     246         176 : ControllerRouteWalker *BgpPeer::delete_stale_walker() const {
     247         176 :     return static_cast<ControllerRouteWalker *>(delete_stale_walker_.get());
     248             : }
     249             : 
     250         100 : ControllerRouteWalker *BgpPeer::delete_peer_walker() const {
     251         100 :     return static_cast<ControllerRouteWalker *>(delete_peer_walker_.get());
     252             : }
     253             : /*
     254             :  * Get the VRF state and unregister from all route table using
     255             :  * rt_export listener id. This will be called for active and non active bgp
     256             :  * peers. In case of active bgp peers send unsubscribe to control node(request
     257             :  * came via vrf delete).
     258             :  */
     259        2180 : void BgpPeer::DeleteVrfState(DBTablePartBase *partition,
     260             :                              DBEntryBase *entry) {
     261        2180 :     VrfEntry *vrf = static_cast<VrfEntry *>(entry);
     262             : 
     263        2180 :     DBTableBase::ListenerId id = GetVrfExportListenerId();
     264             :     VrfExport::State *vrf_state = static_cast<VrfExport::State *>
     265        2180 :         (GetVrfExportState(partition, entry));
     266             : 
     267        2180 :     if (vrf_state == NULL)
     268        2171 :         return;
     269             : 
     270          63 :     for (uint8_t table_type = (Agent::INVALID + 1);
     271          63 :          table_type < Agent::ROUTE_TABLE_MAX; table_type++) {
     272          54 :         if (vrf_state->rt_export_[table_type])
     273          54 :             vrf_state->rt_export_[table_type]->Unregister();
     274             :     }
     275             : 
     276           9 :     if (vrf_state->exported_ == true) {
     277             :         // Check if the notification is for active bgp peer or not.
     278             :         // Send unsubscribe only for active bgp peer.
     279             :         // If skip_add_change is set for this dynamic peer, then dont export.
     280           9 :         if (SkipAddChangeRequest() == false) {
     281           9 :             AgentXmppChannel::ControllerSendSubscribe(GetAgentXmppChannel(),
     282             :                                                       vrf,
     283             :                                                       false);
     284             :         }
     285             :     }
     286             : 
     287           9 :     vrf->ClearState(partition->parent(), id);
     288           9 :     delete vrf_state;
     289             : 
     290           9 :     return;
     291             : }
     292             : 
     293             : // For given peer return the dbstate for given VRF and partition
     294        2326 : DBState *BgpPeer::GetVrfExportState(DBTablePartBase *partition,
     295             :                                     DBEntryBase *entry) {
     296        2326 :     DBTableBase::ListenerId id = GetVrfExportListenerId();
     297        2326 :     VrfEntry *vrf = static_cast<VrfEntry *>(entry);
     298        2326 :     return (static_cast<VrfExport::State *>(vrf->GetState(partition->parent(),
     299        2326 :                                                           id)));
     300             : }
     301             : 
     302             : // For given route return the dbstate for given partiton
     303          55 : DBState *BgpPeer::GetRouteExportState(DBTablePartBase *partition,
     304             :                                       DBEntryBase *entry) {
     305          55 :     AgentRoute *route = static_cast<AgentRoute *>(entry);
     306          55 :     VrfEntry *vrf = route->vrf();
     307             : 
     308          55 :     DBTablePartBase *vrf_partition = agent()->vrf_table()->
     309          55 :         GetTablePartition(vrf);
     310             : 
     311             :     VrfExport::State *vs = static_cast<VrfExport::State *>
     312          55 :         (GetVrfExportState(vrf_partition, vrf));
     313             : 
     314          55 :     if (vs == NULL)
     315           0 :         return NULL;
     316             : 
     317          55 :     Agent::RouteTableType table_type = route->GetTableType();
     318          55 :     RouteExport::State *state = NULL;
     319          55 :     if (vs->rt_export_[table_type]) {
     320          55 :         state = static_cast<RouteExport::State *>(route->GetState(partition->
     321             :                                                                   parent(),
     322          55 :                             vs->rt_export_[table_type]->GetListenerId()));
     323             :     }
     324          55 :     return state;
     325             : }
     326             : 
     327         165 : Agent *BgpPeer::agent() const {
     328         165 :     return channel_->agent();
     329             : }
     330             : 
     331         215 : AgentXmppChannel *BgpPeer::GetAgentXmppChannel() const {
     332         215 :     return channel_;
     333             : }
     334             : 
     335           0 : uint64_t BgpPeer::ChannelSequenceNumber() const {
     336           0 :     return GetAgentXmppChannel()->sequence_number();
     337             : }
     338             : 
     339           0 : void BgpPeer::set_route_walker_cb(WalkDoneCb cb) {
     340           0 :     route_walker_cb_ = cb;
     341           0 : }
     342             : 
     343           0 : void BgpPeer::set_delete_stale_walker_cb(WalkDoneCb cb) {
     344           0 :     delete_stale_walker_cb_ = cb;
     345           0 : }
     346           0 : void BgpPeer::set_delete_peer_walker_cb(WalkDoneCb cb) {
     347           0 :     delete_peer_walker_cb_ = cb;
     348           0 : }

Generated by: LCOV version 1.14