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

Generated by: LCOV version 1.14