LCOV - code coverage report
Current view: top level - vnsw/agent/oper - agent_route.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 672 818 82.2 %
Date: 2026-08-17 02:09:53 Functions: 68 74 91.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : #include <boost/uuid/uuid_io.hpp>
       5             : #include <boost/lexical_cast.hpp>
       6             : 
       7             : #include <cmn/agent_cmn.h>
       8             : #include <route/route.h>
       9             : 
      10             : #include <vnc_cfg_types.h>
      11             : #include <agent_types.h>
      12             : 
      13             : #include <init/agent_param.h>
      14             : #include <oper/peer.h>
      15             : #include <oper/vrf.h>
      16             : #include <oper/interface_common.h>
      17             : #include <oper/nexthop.h>
      18             : #include <oper/tunnel_nh.h>
      19             : #include <oper/vn.h>
      20             : #include <oper/mirror_table.h>
      21             : #include <oper/vxlan.h>
      22             : #include <oper/mpls.h>
      23             : #include <oper/route_common.h>
      24             : #include <oper/multicast.h>
      25             : #include <sandesh/sandesh_trace.h>
      26             : #include <sandesh/common/vns_constants.h>
      27             : #include <resource_manager/resource_manager.h>
      28             : #include <resource_manager/resource_table.h>
      29             : #include <resource_manager/mpls_index.h>
      30             : 
      31             : #include <oper/physical_device.h>
      32             : using namespace std;
      33             : using namespace boost::asio;
      34             : 
      35             : class AgentRouteTable::DeleteActor : public LifetimeActor {
      36             :   public:
      37        1056 :     DeleteActor(AgentRouteTable *rt_table) :
      38             :         LifetimeActor(rt_table->agent()->lifetime_manager()),
      39        1056 :         table_(rt_table) {
      40        1056 :     }
      41        2112 :     virtual ~DeleteActor() {
      42        2112 :     }
      43        1056 :     virtual bool MayDelete() const {
      44        1056 :         return table_->MayDelete();
      45             :     }
      46        1056 :     virtual void Shutdown() {
      47        1056 :     }
      48        1056 :     virtual void Destroy() {
      49        1056 :         assert(table_->vrf_entry_.get() != NULL);
      50        1056 :         table_->vrf_entry_->SetRouteTableDeleted(table_->GetTableType());
      51             :         //Release refernces
      52        1056 :         table_->vrf_delete_ref_.Reset(NULL);
      53        1056 :         table_->vrf_entry_ = NULL;
      54        1056 :     }
      55             : 
      56             :   private:
      57             :     AgentRouteTable *table_;
      58             : };
      59             : 
      60       21520 : bool RouteComparator::operator() (const AgentRoute *rt1, const AgentRoute *rt2) const {
      61       21520 :     return rt1->IsLess(*rt2);
      62             : }
      63             : 
      64           3 : bool NHComparator::operator() (const NextHop *nh1, const NextHop *nh2) const {
      65           3 :     return nh1->IsLess(*nh2);
      66             : }
      67             : 
      68             : /////////////////////////////////////////////////////////////////////////////
      69             : // AgentRouteTable routines
      70             : /////////////////////////////////////////////////////////////////////////////
      71        1056 : AgentRouteTable::AgentRouteTable(DB *db, const std::string &name):
      72        1056 :     RouteTable(db, name), agent_(NULL), vrf_id_(0), vrf_entry_(NULL, this),
      73        1056 :     deleter_(NULL), vrf_delete_ref_(this, NULL), unresolved_rt_tree_(),
      74        2112 :     unresolved_nh_tree_() {
      75        1056 :     OperDBTraceBuf = SandeshTraceBufferCreate("OperRoute", 5000);
      76        1056 : }
      77             : 
      78        1056 : AgentRouteTable::~AgentRouteTable() {
      79        1056 : }
      80             : 
      81             : // Allocate a route entry
      82       43003 : unique_ptr<DBEntry> AgentRouteTable::AllocEntry(const DBRequestKey *k) const {
      83       43003 :     const AgentRouteKey *key = static_cast<const AgentRouteKey*>(k);
      84       43003 :     VrfKey vrf_key(key->vrf_name());
      85             :     AgentRoute *route =
      86       43003 :         static_cast<AgentRoute *>(key->AllocRouteEntry(vrf_entry_.get(),
      87             :                                                        false));
      88       86006 :     return unique_ptr<DBEntry>(static_cast<DBEntry *>(route));
      89       43003 : }
      90             : 
      91             : // Algorithm to select an active path from multiple potential paths.
      92             : // Uses comparator in path for selection
      93       27857 : bool AgentRouteTable::PathSelection(const Path &path1, const Path &path2) {
      94       27857 :     const AgentPath &l_path = dynamic_cast<const AgentPath &> (path1);
      95       27857 :     const AgentPath &r_path = dynamic_cast<const AgentPath &> (path2);
      96       27857 :     return l_path.IsLess(r_path);
      97             : }
      98             : 
      99        1056 : const string &AgentRouteTable::GetSuffix(Agent::RouteTableType type) {
     100        1056 :     static const string uc_suffix(".uc.route.0");
     101        1056 :     static const string mpls_suffix(".uc.route.3");
     102        1056 :     static const string mc_suffix(".mc.route.0");
     103        1056 :     static const string evpn_suffix(".evpn.route.0");
     104        1056 :     static const string l2_suffix(".l2.route.0");
     105        1056 :     static const string uc_inet6_suffix(".uc.route6.0");
     106             : 
     107        1056 :     switch (type) {
     108         176 :     case Agent::INET4_UNICAST:
     109         176 :         return uc_suffix;
     110         176 :     case Agent::INET4_MPLS:
     111         176 :         return mpls_suffix;
     112         176 :     case Agent::INET4_MULTICAST:
     113         176 :         return mc_suffix;
     114         176 :     case Agent::EVPN:
     115         176 :         return evpn_suffix;
     116         176 :     case Agent::BRIDGE:
     117         176 :         return l2_suffix;
     118         176 :     case Agent::INET6_UNICAST:
     119         176 :         return uc_inet6_suffix;
     120           0 :     default:
     121           0 :         return Agent::NullString();
     122             :     }
     123             : }
     124             : 
     125             : // Set VRF and delete life-time actor reference to VRF
     126        1056 : void AgentRouteTable::SetVrf(VrfEntry *vrf) {
     127        1056 :     agent_ = (static_cast<VrfTable *>(vrf->get_table()))->agent();
     128        1056 :     vrf_entry_ = vrf;
     129        1056 :     vrf_id_ = vrf->vrf_id();
     130        1056 :     vrf_delete_ref_.Reset(vrf->deleter());
     131        1056 :     deleter_.reset(new DeleteActor(this));
     132        1056 : }
     133             : 
     134             : //Delete all the routes
     135        1056 : void AgentRouteTable::ManagedDelete() {
     136        1056 :     RouteTableWalkerState *state = new RouteTableWalkerState(deleter());
     137             :     DBTable::DBTableWalkRef walk_ref = AllocWalker(
     138             :          boost::bind(&AgentRouteTable::DelExplicitRouteWalkerCb, this, _1, _2),
     139        2112 :          boost::bind(&AgentRouteTable::DeleteRouteDone, this, _1, _2, state));
     140             :     //On managed delete, walk to delete paths need to be done once as no route
     141             :     //should be added in deleted vrf.
     142             :     //Once the walk is over walkdone will reset walk_ref.
     143        1056 :     WalkTable(walk_ref);
     144        1056 :     deleter_->Delete();
     145        1056 : }
     146             : 
     147        1056 : void AgentRouteTable::DeleteRouteDone(DBTable::DBTableWalkRef walk_ref,
     148             :                                       DBTableBase *base,
     149             :                                       RouteTableWalkerState *state) {
     150        1056 :     LOG(DEBUG, "Deleted all BGP injected routes for " << base->name());
     151        1056 :     ReleaseWalker(walk_ref);
     152        1056 :     delete state;
     153        1056 : }
     154             : 
     155          30 : bool AgentRouteTable::DelExplicitRouteWalkerCb(DBTablePartBase *part,
     156             :                                   DBEntryBase *entry) {
     157          30 :     AgentRoute *route = static_cast<AgentRoute *>(entry);
     158          30 :     if (route == NULL)
     159           0 :         return true;
     160             : 
     161          30 :     return route->DeleteAllBgpPath(part, this);
     162             : }
     163             : 
     164       11521 : void AgentRouteTable::RetryDelete() {
     165       11521 :     if (!deleter()->IsDeleted()) {
     166        7204 :         return;
     167             :     }
     168        4317 :     if (empty()) {
     169        4241 :         vrf_entry()->RetryDelete();
     170             :     }
     171        4316 :     deleter()->RetryDelete();
     172             : }
     173             : 
     174          10 : void AgentRouteTable::NotifyEntry(AgentRoute *e) {
     175          10 :     agent()->ConcurrencyCheck();
     176             :     DBTablePartBase *tpart =
     177          10 :         static_cast<DBTablePartition *>(GetTablePartition(e));
     178          10 :     tpart->Notify(e);
     179          10 : }
     180             : 
     181             : /////////////////////////////////////////////////////////////////////////////
     182             : // Agent route input processing
     183             : /////////////////////////////////////////////////////////////////////////////
     184             : 
     185             : // Inline processing of Route request.
     186       14853 : void AgentRouteTable::Process(DBRequest &req) {
     187       14853 :     agent()->ConcurrencyCheck();
     188             :     DBTablePartition *tpart =
     189       14853 :         static_cast<DBTablePartition *>(GetTablePartition(req.key.get()));
     190       14853 :     tpart->Process(NULL, &req);
     191       14853 : }
     192             : 
     193             : //  Input handler for Route Table.
     194             : //  Adds a route entry if not present.
     195             : //      Adds path to route entry
     196             : //      Paths are sorted in order of their precedence
     197             : //  A DELETE request always removes path from the peer
     198             : //      Route entry with no paths is automatically deleted
     199       45748 : void AgentRouteTable::Input(DBTablePartition *part, DBClient *client,
     200             :                             DBRequest *req) {
     201       45748 :     AgentRouteKey *key = static_cast<AgentRouteKey *>(req->key.get());
     202       45748 :     AgentRouteData *data = static_cast<AgentRouteData *>(req->data.get());
     203             : 
     204       45748 :     VrfEntry *vrf = agent_->vrf_table()->FindVrfFromName(key->vrf_name());
     205             :     // Ignore request if VRF not found.
     206             :     // VRF in deleted state is handled below based on operation
     207       45748 :     if (vrf == NULL)
     208           9 :         return;
     209             : 
     210             :     // We dont force DBRequest to be enqueued to the right DB Table.
     211             :     // Find the right DBTable from VRF and invoke Input from right table
     212       45739 :     AgentRouteTable *req_table = vrf->GetRouteTable(key->GetRouteTableType());
     213       45739 :     if (req_table != this) {
     214       15030 :         if (req_table == NULL) {
     215             :             // If route table is already deleted from VRF, it means VRF should
     216             :             // also be in deleted state
     217           0 :             assert(vrf->IsDeleted());
     218           0 :             return;
     219             :         }
     220             : 
     221             :         DBTablePartition *p =
     222       15030 :             static_cast<DBTablePartition *>(req_table->GetTablePartition(key));
     223       15030 :         req_table->Input(p, client, req);
     224       15030 :         return;
     225             :     }
     226             : 
     227       30709 :     AgentRoute *rt = static_cast<AgentRoute *>(part->Find(key));
     228       30709 :     if (req->oper == DBRequest::DB_ENTRY_DELETE) {
     229       11606 :         if (rt)
     230       11022 :             rt->DeleteInput(part, this, key, data);
     231       11606 :         return;
     232             :     }
     233             : 
     234       19103 :     if (req->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
     235       19103 :         AddChangeInput(part, vrf, rt, key, data);
     236       19103 :         return;
     237             :     }
     238             : 
     239           0 :     assert(0);
     240             : }
     241             : 
     242             : // Handle RESYNC and ADD_CHANGE requests
     243       19103 : void AgentRouteTable::AddChangeInput(DBTablePartition *part, VrfEntry *vrf,
     244             :                                      AgentRoute *rt, AgentRouteKey *key,
     245             :                                      AgentRouteData *data) {
     246       19103 :     if (key->peer()->SkipAddChangeRequest()) {
     247           0 :         AGENT_ROUTE_LOG(this, "Route operation ignored. Deleted Peer ",
     248             :                         key->ToString(), vrf_name(), key->peer()->GetName());
     249           0 :         return;
     250             :     }
     251             : 
     252       19103 :     if (vrf->IsDeleted() && vrf->allow_route_add_on_deleted_vrf() == false)
     253           0 :         return;
     254             : 
     255       19103 :     AgentPath *path = NULL;
     256       19103 :     bool notify = false;
     257       19103 :     const NextHop *nh = NULL;
     258       19103 :     if (rt) {
     259       14326 :         nh = rt->GetActiveNextHop();
     260             :     }
     261       19103 :     if (key->sub_op_ == AgentKey::RESYNC) {
     262             :         // Process RESYNC only if route present and not-deleted
     263        3289 :         if (rt && (rt->IsDeleted() == false))
     264        3257 :             notify |= rt->SubOpResyncInput(vrf, this, &path, key, data);
     265       15814 :     } else if (key->sub_op_ == AgentKey::ADD_DEL_CHANGE) {
     266       15814 :         bool route_added = (rt == NULL);
     267       15814 :         rt = LocateRoute(part, vrf, rt, key, data, &notify);
     268       15814 :         notify |= rt->SubOpAddChangeInput(vrf, this, &path, key, data,
     269             :                                           route_added);
     270             :     } else {
     271           0 :         assert(0);
     272             :     }
     273             : 
     274             :     // If this route has a unresolved path, insert to unresolved list
     275             :     // this is a hack , TODO: fix unresolved route handling correctly
     276       19103 :     if (rt && rt->HasUnresolvedPath() == true) {
     277        5636 :         rt->AddUnresolvedRouteToTable(this);
     278             :     }
     279             :     // Route changed, trigger change on dependent routes
     280       19103 :     if (notify) {
     281       14434 :         bool active_path_changed = (path == rt->GetActivePath());
     282       14434 :         const AgentPath *prev_active_path = rt->GetActivePath();
     283       14434 :         CompositeNH *cnh = NULL;
     284       14434 :         if (prev_active_path) {
     285       14434 :             cnh = dynamic_cast<CompositeNH *>(prev_active_path->nexthop());
     286             :         }
     287       14434 :         const Path *prev_front = rt->front();
     288       14434 :         if (prev_front) {
     289       14434 :             rt->Sort(&AgentRouteTable::PathSelection, prev_front);
     290             :         }
     291       14434 :         if (rt->GetActiveNextHop() != nh) {
     292        6569 :             active_path_changed = true;
     293             :         }
     294             :         // for flow stickiness , maintain same component NH grid
     295             :         // if the newly insterted path becomes active,
     296             :         // if peer type is same, and it is composite NH
     297             :         // then import previous active NH to current active path
     298             :         // Note: Change is limited to BGP peer paths
     299       22493 :         if ( (path == rt->GetActivePath()) &&
     300        8059 :             (path != prev_active_path)) {
     301             :             CompositeNH *new_cnh =
     302           5 :                 dynamic_cast<CompositeNH *>(path->nexthop());
     303           0 :             if (cnh && new_cnh &&
     304           0 :                 (path->peer()->GetType() == Peer::BGP_PEER) &&
     305           0 :                 (prev_active_path->peer()->GetType() == Peer::BGP_PEER) &&
     306           5 :                 (cnh->composite_nh_type() == Composite::ECMP) &&
     307           0 :                 (new_cnh->composite_nh_type() == Composite::ECMP)) {
     308           0 :                 path->ImportPrevActiveNH(agent_, cnh);
     309             :             }
     310             :         }
     311       14434 :         part->Notify(rt);
     312       14434 :         rt->UpdateDependantRoutes();
     313       14434 :         rt->ResyncTunnelNextHop();
     314             : 
     315             :         // Since newly added path became active path, send path with
     316             :         // path_changed flag as true. Path can be NULL for resync requests
     317       14434 :         active_path_changed |= (path == rt->GetActivePath());
     318       14434 :         rt->UpdateDerivedRoutes(this, path, active_path_changed);
     319             :     }
     320             : }
     321             : 
     322       15814 : AgentRoute *AgentRouteTable::LocateRoute(DBTablePartition *part,
     323             :                                          VrfEntry *vrf, AgentRoute *rt,
     324             :                                          AgentRouteKey *key,
     325             :                                          AgentRouteData *data, bool *notify) {
     326             :     // Return if route already present and not deleted
     327       15814 :     if (rt != NULL && rt->IsDeleted() == false)
     328       10067 :         return rt;
     329             : 
     330             :     // Add route if not present already
     331        5747 :     if (rt == NULL) {
     332             :         rt = static_cast<AgentRoute *>
     333        4745 :             (key->AllocRouteEntry(vrf, data->is_multicast()));
     334        4745 :         assert(rt->vrf() != NULL);
     335        4745 :         part->Add(rt);
     336             :     }
     337             : 
     338             :     // Renew the route if its in deleted state
     339        5747 :     if (rt->IsDeleted()) {
     340        1002 :         assert(rt->IsDeleted());
     341        1002 :         rt->ClearDelete();
     342        1002 :         *notify = true;
     343             :     }
     344             : 
     345        5747 :     ProcessAdd(rt);
     346        5747 :     RouteInfo rt_info;
     347        5747 :     rt->FillTrace(rt_info, AgentRoute::ADD, NULL);
     348        5747 :     OPER_TRACE_ROUTE_ENTRY(Route, this, rt_info);
     349        5747 :     return rt;
     350        5747 : }
     351             : 
     352        5636 : void AgentRoute::AddUnresolvedRouteToTable(AgentRouteTable *table) {
     353             : 
     354        5636 :     if (dependent_route_table_ == NULL) {
     355         460 :         const AgentPath *path = GetActivePath();
     356         460 :         if (path->GetDependentTable()) {
     357           6 :             dependent_route_table_ = path->GetDependentTable();
     358             :         } else {
     359         454 :             dependent_route_table_ = table;
     360             :         }
     361             :     }
     362        5636 :     dependent_route_table_->AddUnresolvedRoute(this);
     363        5636 : }
     364        5747 : void AgentRoute::RemoveUnresolvedRouteFromTable(AgentRouteTable *table) {
     365        5747 :     if (dependent_route_table_) {
     366         460 :         dependent_route_table_->RemoveUnresolvedRoute(this);
     367             :     } else {
     368        5287 :         table->RemoveUnresolvedRoute(this);
     369             :     }
     370        5747 : }
     371             : 
     372             : 
     373             : // Re-evaluate all unresolved NH. Flush and enqueue RESYNC for all NH in the
     374             : // unresolved NH tree
     375        4745 : void AgentRouteTable::EvaluateUnresolvedNH(void) {
     376        4745 :     for (UnresolvedNHTree::iterator it = unresolved_nh_tree_.begin();
     377        4768 :          it != unresolved_nh_tree_.end(); ++it) {
     378          23 :         (*it)->EnqueueResync();
     379             : 
     380          23 :         DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
     381          23 :         req.key = (*it)->GetDBRequestKey();
     382          23 :         (static_cast<NextHopKey *>(req.key.get()))->sub_op_ = AgentKey::RESYNC;
     383          23 :         agent_->nexthop_table()->Enqueue(&req);
     384          23 :     }
     385             : 
     386        4745 :     unresolved_nh_tree_.clear();
     387        4745 : }
     388             : 
     389          23 : void AgentRouteTable::AddUnresolvedNH(const NextHop *nh) {
     390          23 :     unresolved_nh_tree_.insert(nh);
     391          23 : }
     392             : 
     393        7147 : void AgentRouteTable::RemoveUnresolvedNH(const NextHop *nh) {
     394        7147 :     unresolved_nh_tree_.erase(nh);
     395        7147 : }
     396             : 
     397             : // Re-evaluate all unresolved routes. Flush and enqueue RESYNC for all routes
     398             : // in the unresolved route tree
     399        4745 : void AgentRouteTable::EvaluateUnresolvedRoutes(void) {
     400        4745 :     for (UnresolvedRouteTree::iterator it = unresolved_rt_tree_.begin();
     401        5979 :          it !=  unresolved_rt_tree_.end(); ++it) {
     402        1234 :        (*it)->EnqueueRouteResync();
     403             :     }
     404             : 
     405        4745 :     unresolved_rt_tree_.clear();
     406        4745 : }
     407             : 
     408        5636 : void AgentRouteTable::AddUnresolvedRoute(const AgentRoute *rt) {
     409        5636 :     unresolved_rt_tree_.insert(rt);
     410        5636 : }
     411             : 
     412       11512 : void AgentRouteTable::RemoveUnresolvedRoute(const AgentRoute *rt) {
     413       11512 :     unresolved_rt_tree_.erase(rt);
     414       11512 : }
     415             : 
     416             : // Find entry not in deleted state
     417        9124 : AgentRoute *AgentRouteTable::FindActiveEntry(const AgentRouteKey *key) {
     418        9124 :     AgentRoute *entry = static_cast<AgentRoute *>(Find(key));
     419        9124 :     if (entry && entry->IsDeleted()) {
     420           6 :         return NULL;
     421             :     }
     422        9118 :     return entry;
     423             : }
     424             : 
     425          85 : AgentRoute *AgentRouteTable::FindActiveEntryNoLock(const AgentRouteKey *key) {
     426          85 :     DBTable *table = static_cast<DBTable *>(this);
     427          85 :     AgentRoute *entry = static_cast<AgentRoute *>(table->FindNoLock(key));
     428          85 :     if (entry && entry->IsDeleted()) {
     429           0 :         return NULL;
     430             :     }
     431          85 :     return entry;
     432             : }
     433             : 
     434        1642 : AgentRoute *AgentRouteTable::FindActiveEntry(const AgentRoute *key) {
     435        1642 :     AgentRoute *entry = static_cast<AgentRoute *>(Find(key));
     436        1642 :     if (entry && entry->IsDeleted()) {
     437           0 :         return NULL;
     438             :     }
     439        1642 :     return entry;
     440             : }
     441             : 
     442         144 : AgentRoute *AgentRouteTable::FindActiveEntryNoLock(const AgentRoute *key) {
     443         144 :     DBTable *table = static_cast<DBTable *>(this);
     444         144 :     AgentRoute *entry = static_cast<AgentRoute *>(table->FindNoLock(key));
     445         144 :     if (entry && entry->IsDeleted()) {
     446           4 :         return NULL;
     447             :     }
     448         140 :     return entry;
     449             : }
     450             : 
     451       19938 : LifetimeActor *AgentRouteTable::deleter() {
     452       19938 :     return deleter_.get();
     453             : }
     454             : 
     455        4665 : const std::string &AgentRouteTable::vrf_name() const {
     456        4665 :     return vrf_entry_->GetName();
     457             : }
     458             : 
     459       26787 : VrfEntry *AgentRouteTable::vrf_entry() const {
     460       26787 :     return vrf_entry_.get();
     461             : }
     462             : 
     463             : /////////////////////////////////////////////////////////////////////////////
     464             : // AgentRoute routines
     465             : /////////////////////////////////////////////////////////////////////////////
     466             : 
     467             : // Hnadle RESYNC operation for a route
     468        3257 : bool AgentRoute::SubOpResyncInput(VrfEntry *vrf, AgentRouteTable *table,
     469             :                                   AgentPath **path_ptr, AgentRouteKey *key,
     470             :                                   AgentRouteData *data) {
     471             :     // Handle change to route itself and not to a particular path
     472        3257 :     if (data == NULL || key->peer() == NULL) {
     473        3058 :         Sync();
     474        3058 :         return true;
     475             :     }
     476             : 
     477             :     // Get path to update
     478         199 :     AgentPath *path = FindPath(key->peer());
     479         199 :     if (path == NULL)
     480           4 :         return false;
     481             : 
     482         195 :     bool ret = false;
     483         195 :     *path_ptr = path;
     484         195 :     bool old_ecmp = path->path_preference().is_ecmp();
     485         195 :     if (data->AddChangePath(table->agent(), path, this))
     486         185 :         ret = true;
     487             : 
     488             :     // Transition from ECMP to non-ECMP should result in removal of member
     489             :     // from ECMP path
     490         195 :     if (old_ecmp && old_ecmp != path->path_preference().is_ecmp()) {
     491           0 :         ReComputePathDeletion(path);
     492           0 :         return ret;
     493             :     }
     494             : 
     495         195 :     if (ReComputePathAdd(path))
     496         148 :         ret = true;
     497             : 
     498         195 :     return ret;
     499             : }
     500             : 
     501       15814 : bool AgentRoute::SubOpAddChangeInput(VrfEntry *vrf, AgentRouteTable *table,
     502             :                                      AgentPath **path_ptr, AgentRouteKey *key,
     503             :                                      AgentRouteData *data, bool route_added) {
     504       15814 :     bool ret = false;
     505             :     // Update route level attributes first
     506       15814 :     if (data && data->UpdateRoute(this))
     507         365 :         ret = true;
     508             : 
     509             :     AgentRoute::Trace event;
     510       15814 :     AgentPath *path = FindPathUsingKeyData(key, data);
     511             :     // Allocate path if not yet present
     512       15814 :     if (path == NULL) {
     513        6751 :         path = data->CreateAgentPath(key->peer(), this);
     514        6751 :         InsertPath(path);
     515        6751 :         data->AddChangePath(table->agent(), path, this);
     516        6751 :         set_origin_vn_name(path->dest_vn_list());
     517        6751 :         ret = true;
     518        6751 :         event = AgentRoute::ADD_PATH;
     519             :     } else {
     520        9063 :         bool ecmp = path->path_preference().is_ecmp();
     521        9063 :         if (data->AddChangePath(table->agent(), path, this))
     522        4440 :             ret = true;
     523             : 
     524             :         // Transition from ECMP to non-ECMP should result in removal of member
     525             :         // from ECMP path
     526        9063 :         if (ecmp && ecmp != path->path_preference().is_ecmp()) {
     527          10 :             ReComputePathDeletion(path);
     528             :         }
     529        9063 :         event = AgentRoute::CHANGE_PATH;
     530             :     }
     531             : 
     532             :     // Trace log for path add/change
     533       15814 :     RouteInfo rt_info;
     534       15814 :     FillTrace(rt_info, event, path);
     535       15814 :     OPER_TRACE_ROUTE_ENTRY(Route, table, rt_info);
     536             : 
     537       15814 :     if (path->RouteNeedsSync())
     538        1278 :         ret |= Sync();
     539             : 
     540       15814 :     if (route_added) {
     541        4745 :         table->EvaluateUnresolvedRoutes();
     542        4745 :         table->EvaluateUnresolvedNH();
     543             :     }
     544             : 
     545             :     // Do necessary recompute on addition of path
     546       15814 :     if (ReComputePathAdd(path))
     547        2305 :         ret = true;
     548             : 
     549       15814 :     *path_ptr = path;
     550       15814 :     return ret;
     551       15814 : }
     552             : 
     553             : // Handle DELETE operation for a route. Deletes path created by peer in key.
     554             : // Ideally only peer match is required in path however for few cases
     555             : // more than peer comparision be required.
     556       11022 : void AgentRoute::DeleteInput(DBTablePartition *part, AgentRouteTable *table,
     557             :                              AgentRouteKey *key, AgentRouteData *data) {
     558       11022 :     assert (key->sub_op_ == AgentKey::ADD_DEL_CHANGE);
     559       11022 :     bool force_delete = false;
     560             :     // If peer in key is deleted, set force_delete to true.
     561       11022 :     if (key->peer()->IsDeleted() || key->peer()->SkipAddChangeRequest())
     562           0 :         force_delete = true;
     563             : 
     564             :     // In case of multicast routes, BGP can give multiple paths.
     565             :     // So, iterate thru all paths and identify paths that can be deleted
     566       11022 :     for (Route::PathList::iterator it = GetPathList().begin();
     567       48088 :          it != GetPathList().end(); ) {
     568       13022 :         AgentPath *path = static_cast<AgentPath *>(it.operator->());
     569             :         // Current path can be deleted below. Incremnt the iterator and dont
     570             :         // use it again below
     571       13022 :         it++;
     572             : 
     573       13022 :         if (key->peer() != path->peer())
     574        5882 :             continue;
     575             : 
     576             :         bool check_can_delete =
     577       11112 :             ((key->peer()->GetType() == Peer::BGP_PEER) ||
     578        7944 :              (key->peer()->GetType() == Peer::EVPN_ROUTING_PEER) ||
     579       15084 :              (key->peer()->GetType() == Peer::EVPN_PEER) ||
     580        3214 :              (key->peer()->GetType() == Peer::INET_EVPN_PEER));
     581             : 
     582        7140 :         if (force_delete)
     583           0 :             check_can_delete = false;
     584             : 
     585             :         // There are two ways to receive delete of BGP peer path in l2 route.
     586             :         // First is via withdraw meesage from control node in which
     587             :         // force_delete will be false and vxlan_id will be matched to
     588             :         // decide.
     589             :         // Second can be via route walkers where on peer going down or vrf
     590             :         // delete, paths from BGP peer should be deleted irrespective of
     591             :         // vxlan_id.
     592        8382 :         if (check_can_delete && data &&
     593        1242 :             data->CanDeletePath(table->agent(), path, this) == false) {
     594         402 :             continue;
     595             :         }
     596             : 
     597        6738 :         DeletePathFromPeer(part, table, path);
     598             :     }
     599       11022 : }
     600             : 
     601        6885 : void AgentRoute::InsertPath(const AgentPath *path) {
     602        6885 :     const Path *prev_front = front();
     603        6885 :     insert(path);
     604        6885 :     Sort(&AgentRouteTable::PathSelection, prev_front);
     605        6885 : }
     606             : 
     607        6885 : void AgentRoute::RemovePath(AgentPath *path) {
     608        6885 :     const Path *prev_front = front();
     609        6885 :     remove(path);
     610        6885 :     Sort(&AgentRouteTable::PathSelection, prev_front);
     611        6885 :     return;
     612             : }
     613             : 
     614             : // Delete all paths from BGP Peer. Delete route if no path left
     615          30 : bool AgentRoute::DeleteAllBgpPath(DBTablePartBase *part,
     616             :                                   AgentRouteTable *table) {
     617          30 :     for(Route::PathList::iterator it = GetPathList().begin();
     618          98 :         it != GetPathList().end();) {
     619          19 :         AgentPath *path = static_cast<AgentPath *>(it.operator->());
     620          19 :         it++;
     621             : 
     622          19 :         const Peer *peer = path->peer();
     623          19 :         if (peer == NULL)
     624           0 :             continue;
     625             : 
     626          27 :         if (peer->GetType() == Peer::BGP_PEER ||
     627          27 :             peer->GetType() == Peer::EVPN_ROUTING_PEER ||
     628           6 :             peer->GetType() == Peer::MULTICAST_FABRIC_TREE_BUILDER) {
     629          13 :             DeletePathFromPeer(part, table, path);
     630           6 :         } else if (peer->GetType() == Peer::LOCAL_VM_PEER) {
     631             :             // Delete LOCAL_VM_PEER paths only from routes belonging to
     632             :             // routing VRFs
     633           0 :             VrfEntry *vrf = vrf_;
     634           0 :             if (vrf && vrf->routing_vrf() && (table->GetTableType() == Agent::EVPN)) {
     635           0 :                 DeletePathFromPeer(part, table, path);
     636             :             }
     637             :         }
     638             :     }
     639             : 
     640          30 :     return true;
     641             : }
     642             : 
     643             : // Delete path from the given peer.
     644             : // If all paths are deleted,
     645             : //     delete the route and notify
     646             : // Else
     647             : //     Notify the DBEntry if any path is deleted
     648             : //
     649             : // Ideally, route must be notified only when active-path is deleted,
     650             : // But, notification of deleting non-active path is needed in one case.
     651             : //
     652             : // For VM spawned locally, we path BGP_PEER path with higher priority than
     653             : // LOCAL_VM peer path. But, controller-peer needs to know deletion of
     654             : // LOCAL_VM path to retract the route.  So, force notify deletion of any path.
     655        6751 : void AgentRoute::DeletePathFromPeer(DBTablePartBase *part,
     656             :                                     AgentRouteTable *table, AgentPath *path) {
     657             : 
     658        6751 :     RouteInfo rt_info;
     659        6751 :     FillTrace(rt_info, AgentRoute::DELETE_PATH, path);
     660        6751 :     OPER_TRACE_ROUTE_ENTRY(Route, table, rt_info);
     661             : 
     662        6751 :     if (path == NULL) {
     663           0 :         return;
     664             :     }
     665             : 
     666             :     // Assign path to auto-pointer to delete it on return
     667        6751 :     std::unique_ptr<AgentPath> path_ref(path);
     668             : 
     669             :     // TODO : Move this to end of delete processing?
     670             :     // Path deletion can result in changes such as ECMP-NH, Mulitcast NH etc
     671             :     // The algirthms expect path to be present in route still. So, do the
     672             :     // necessary recompute before path is deleted from route
     673        6751 :     ReComputePathDeletion(path);
     674             : 
     675             :     // Store if this was active path
     676        6751 :     bool active_path = (GetActivePath() == path);
     677        6751 :     const Peer *old_active_path_peer = path->peer();
     678             :     // Remove path from the route
     679        6751 :     RemovePath(path);
     680             : 
     681             :     // TODO : Move this code to ECMP Hash management code.
     682        6751 :     CompositeNH *cnh = dynamic_cast<CompositeNH *>(path->nexthop());
     683        6751 :     if (cnh) {
     684        2227 :         path->ResetEcmpHashFields();
     685        2227 :         cnh->UpdateEcmpHashFieldsUponRouteDelete(table->agent(),
     686             :                                                  table->vrf_name());
     687             :     }
     688             : 
     689             :     // Delete route if no more paths
     690        6751 :     if (GetActivePath() == NULL) {
     691        5747 :         RouteInfo rt_info_del;
     692        5747 :         FillTrace(rt_info_del, AgentRoute::DEL, NULL);
     693        5747 :         OPER_TRACE_ROUTE_ENTRY(Route, table, rt_info_del);
     694        5747 :         DeleteDerivedRoutes(table);
     695        5747 :         table->RemoveUnresolvedRoute(this); // TODO: remove this call and make changes in gw route
     696        5747 :         RemoveUnresolvedRouteFromTable(table);
     697        5747 :         UpdateDependantRoutes();
     698        5747 :         ResyncTunnelNextHop();
     699        5747 :         table->ProcessDelete(this);
     700        5747 :         part->Delete(this);
     701        5747 :     } else {
     702             :         // change to support flow stickiness for ecmp paths
     703             :         // find new active path peer
     704             :         // if peer type is same, and it is composite NH
     705             :         // then import previous active NH to current active path
     706             :         // Note: Change is limited to paths of same type
     707        1004 :         const Peer *new_active_path_peer = GetActivePath()->peer();
     708        1004 :         AgentPath *new_active_path = FindPath(new_active_path_peer);
     709        1004 :         CompositeNH *new_cnh = NULL;
     710        1004 :         if (new_active_path && new_active_path->nexthop()) {
     711         998 :             new_cnh =
     712         998 :                 dynamic_cast<CompositeNH *>(new_active_path->nexthop());
     713             :         }
     714         407 :         if (active_path &&
     715         166 :                 cnh && new_cnh &&
     716          98 :                 (old_active_path_peer->GetType() == Peer::BGP_PEER) &&
     717          15 :                 (new_active_path_peer->GetType() == Peer::BGP_PEER) &&
     718        1411 :                 (cnh->composite_nh_type() == Composite::ECMP) &&
     719           0 :                 (new_cnh->composite_nh_type() == Composite::ECMP)) {
     720           0 :             new_active_path->ImportPrevActiveNH(table->agent(), cnh);
     721             :         }
     722             :         // Notify deletion of path.
     723        1004 :         part->Notify(this);
     724        1004 :         UpdateDerivedRoutes(table, NULL, active_path);
     725             :     }
     726        6751 : }
     727             : 
     728           0 : AgentPath *AgentRoute::FindLocalPath() const {
     729           0 :     for(Route::PathList::const_iterator it = GetPathList().begin();
     730           0 :         it != GetPathList().end(); it++) {
     731           0 :         const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
     732           0 :         if (path->peer() == NULL) {
     733           0 :             continue;
     734             :         }
     735           0 :         if (path->peer()->GetType() == Peer::LOCAL_PEER ||
     736           0 :             path->peer()->GetType() == Peer::LINKLOCAL_PEER) {
     737           0 :             return const_cast<AgentPath *>(path);
     738             :         }
     739             :     }
     740           0 :     return NULL;
     741             : }
     742             : 
     743       20696 : AgentPath *AgentRoute::FindLocalVmPortPath() const {
     744       31408 :     for(Route::PathList::const_iterator it = GetPathList().begin();
     745       62816 :         it != GetPathList().end(); it++) {
     746       17246 :         const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
     747       17246 :         if (path->peer() == NULL) {
     748           0 :             continue;
     749             :         }
     750       17246 :         if (path->peer()->export_to_controller()) {
     751        6534 :             return const_cast<AgentPath *>(path);
     752             :         }
     753             : 
     754       21424 :         if (path->peer()->GetType() == Peer::ECMP_PEER ||
     755       21424 :             path->peer()->GetType() == Peer::VGW_PEER ||
     756       21424 :             path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER ||
     757       32136 :             path->peer()->GetType() == Peer::MULTICAST_TOR_PEER ||
     758       10712 :             path->peer()->GetType() == Peer::OVS_PEER) {
     759           0 :             return const_cast<AgentPath *>(path);
     760             :         }
     761             :     }
     762       14162 :     return NULL;
     763             : }
     764             : 
     765             : /// @brief returns true if the given path is not null and points
     766             : // to a local composite interface
     767          40 : bool RtPathHasInterfaceComposite (const AgentPath* a_path) {
     768          40 :     const NextHop *a_nh = NULL;
     769             : 
     770          40 :     if (!a_path) {
     771           0 :         return false;
     772             :     }
     773             : 
     774          40 :     a_nh = a_path->nexthop();
     775          40 :     if (!a_nh) {
     776          16 :         return false;
     777             :     }
     778             : 
     779          24 :     if (a_path->peer()->export_to_controller() &&
     780           0 :         a_nh->GetType() == NextHop::COMPOSITE) {
     781           0 :         return true;
     782             :     }
     783             : 
     784          24 :     if (a_path->peer()->GetType() == Peer::ECMP_PEER) {
     785           0 :         return true;
     786             :     }
     787             : 
     788          24 :     return false;
     789             : }
     790             : 
     791             : /// @brief returns true if the given path is not null and points
     792             : // to a local interface
     793          40 : bool RtPathHasLocalInterface(const AgentPath* a_path) {
     794          40 :     const NextHop *a_nh = NULL;
     795             : 
     796          40 :     if (!a_path) {
     797           0 :         return false;
     798             :     }
     799             : 
     800          40 :     a_nh = a_path->nexthop();
     801          40 :     if (!a_nh) {
     802           8 :         return false;
     803             :     }
     804             : 
     805          40 :     if (a_path->peer()->export_to_controller() &&
     806           8 :         a_nh->GetType() == NextHop::INTERFACE) {
     807           8 :         return true;
     808             :     }
     809             : 
     810          24 :     if (a_path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER) {
     811           0 :         return true;
     812             :     }
     813             : 
     814          24 :     return false;
     815             : }
     816             :  
     817         196 : const AgentPath *AgentRoute::FindIntfOrCompLocalVmPortPath() const {
     818         196 :     const AgentPath *intf_path = NULL;
     819         196 :     const AgentPath *icom_path = NULL;
     820         244 :     for (Route::PathList::const_iterator it =
     821         196 :         this->GetPathList().begin();
     822         488 :         it != this->GetPathList().end(); it++) {
     823             :         const AgentPath *path = static_cast<const AgentPath *>
     824          48 :             (it.operator->());
     825             : 
     826          88 :         if (intf_path == NULL &&
     827          40 :             RtPathHasLocalInterface(path)) {
     828           8 :             intf_path = path;
     829           8 :             continue;
     830             :         }
     831          40 :         if (RtPathHasInterfaceComposite(path)) {
     832           0 :             icom_path = path;
     833           0 :             continue;
     834             :         }
     835             :     }
     836         196 :     if (icom_path) {
     837           0 :         return icom_path;
     838             :     }
     839         196 :     if (intf_path) {
     840           8 :         return intf_path;
     841             :     }
     842         188 :     return NULL;
     843             : }
     844             : 
     845           0 : AgentPath *AgentRoute::GetLocalVmPortPath() const {
     846           0 :     for(Route::PathList::const_iterator it = GetPathList().begin();
     847           0 :         it != GetPathList().end(); it++) {
     848           0 :         const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
     849           0 :         if (path->peer() == NULL) {
     850           0 :             continue;
     851             :         }
     852             : 
     853           0 :         if (path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER) {
     854           0 :             return const_cast<AgentPath *>(path);
     855             :         }
     856             :     }
     857           0 :     return NULL;
     858             : }
     859             : 
     860        2365 : AgentPath *AgentRoute::FindPathUsingKeyData(const AgentRouteKey *key,
     861             :                                             const AgentRouteData *data) const {
     862        2365 :     return FindPath(key->peer());
     863             : }
     864             : 
     865       28262 : AgentPath *AgentRoute::FindPath(const Peer *peer) const {
     866       46566 :     for(Route::PathList::const_iterator it = GetPathList().begin();
     867       93132 :         it != GetPathList().end(); it++) {
     868       34220 :         const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
     869       34220 :         if (path->peer() == peer) {
     870       15916 :             return const_cast<AgentPath *>(path);
     871             :         }
     872             :     }
     873       12346 :     return NULL;
     874             : }
     875             : 
     876             : // First path in list is always treated as active path.
     877      238202 : const AgentPath *AgentRoute::GetActivePath() const {
     878      238202 :     const AgentPath *path = static_cast<const AgentPath *>(front());
     879      238202 :     return (path ? path->UsablePath() : NULL);
     880             : }
     881             : 
     882       68904 : const NextHop *AgentRoute::GetActiveNextHop() const {
     883       68904 :     const AgentPath *path = GetActivePath();
     884       68904 :     if (path == NULL)
     885        1383 :         return NULL;
     886             : 
     887       67521 :     return path->ComputeNextHop(static_cast<AgentRouteTable *>(get_table())->
     888       67521 :                             agent());
     889             : }
     890             : 
     891           6 : uint32_t AgentRoute::GetActiveLabel() const {
     892           6 :     return GetActivePath()->label();
     893             : };
     894             : 
     895             : // If a direct route has changed, invoke a change on tunnel NH dependent on it
     896       20181 : void AgentRoute::ResyncTunnelNextHop(void) {
     897       20243 :     for (AgentRoute::TunnelNhDependencyList::iterator iter =
     898       40424 :          tunnel_nh_list_.begin(); iter != tunnel_nh_list_.end(); iter++) {
     899             : 
     900          62 :         NextHop *nh = static_cast<NextHop *>(iter.operator->());
     901          62 :         DBEntryBase::KeyPtr key = nh->GetDBRequestKey();
     902          62 :         NextHopKey *nh_key = static_cast<NextHopKey *>(key.get());
     903          62 :         nh_key->sub_op_ = AgentKey::RESYNC;
     904             : 
     905          62 :         DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
     906          62 :         req.key = std::move(key);
     907          62 :         req.data.reset(NULL);
     908          62 :         Agent *agent = (static_cast<AgentRouteTable *>(get_table()))->agent();
     909          62 :         agent->nexthop_table()->Enqueue(&req);
     910          62 :     }
     911       20181 : }
     912             : 
     913             : // Enqueue request to RESYNC a route
     914        3047 : void AgentRoute::EnqueueRouteResync(void) const {
     915        3047 :     DBRequest  req(DBRequest::DB_ENTRY_ADD_CHANGE);
     916        3047 :     req.key = GetDBRequestKey();
     917        3047 :     (static_cast<AgentKey *>(req.key.get()))->sub_op_ = AgentKey::RESYNC;
     918        3047 :     Agent *agent = (static_cast<AgentRouteTable *>(get_table()))->agent();
     919             :     /* Setting req.data only for default route */
     920        3047 :     if (agent->is_l3mh() && this->ToString().compare("0.0.0.0/0") == 0) {
     921           0 :         VnListType vn_list;
     922           0 :         vn_list.insert(agent->fabric_vn_name());
     923           0 :         req.data.reset(new Inet4UnicastGatewayRoute(
     924           0 :                     agent->params()->gateway_list(), agent->fabric_vrf_name(),
     925           0 :                     vn_list, MplsTable::kInvalidLabel, SecurityGroupList(),
     926           0 :                     TagList(), CommunityList(),
     927           0 :                     true));
     928           0 :     }
     929        3047 :     agent->fabric_inet4_unicast_table()->Enqueue(&req);
     930        3047 : }
     931             : 
     932             : //If a direct route get modified invariably trigger change
     933             : //on all dependent indirect routes, coz if a nexthop has
     934             : //changed we need to update the same in datapath for indirect
     935             : //routes
     936       20341 : void AgentRoute::UpdateDependantRoutes(void) {
     937       21082 :     for (AgentRoute::RouteDependencyList::iterator iter =
     938       41423 :          dependant_routes_.begin(); iter != dependant_routes_.end(); iter++) {
     939         741 :         AgentRoute *rt = iter.operator->();
     940         741 :         rt->EnqueueRouteResync();
     941             :     }
     942       20341 : }
     943             : 
     944       19071 : bool AgentRoute::HasUnresolvedPath(void) {
     945       70803 :     for(Route::PathList::const_iterator it = GetPathList().begin();
     946      103464 :             it != GetPathList().end(); it++) {
     947             :         const AgentPath *path =
     948       38297 :             static_cast<const AgentPath *>(it.operator->());
     949       38297 :         if (path->unresolved() == true) {
     950        5636 :             return true;
     951             :         }
     952             :     }
     953             : 
     954       13435 :     return false;
     955             : }
     956             : 
     957             : // Invoke SYNC on all paths to re-evaluate NH/active state
     958        4336 : bool AgentRoute::Sync(void) {
     959        4336 :     bool ret = false;
     960       13993 :     for(Route::PathList::iterator it = GetPathList().begin();
     961       27986 :         it != GetPathList().end(); it++) {
     962        9657 :         AgentPath *path = static_cast<AgentPath *>(it.operator->());
     963        9657 :         if (path->Sync(this) == true) {
     964        1096 :             if (GetActivePath() == path) {
     965         995 :                 ret = true;
     966             :             }
     967             :         }
     968             :     }
     969        4336 :     return ret;
     970             : }
     971             : 
     972       16583 : bool AgentRoute::WaitForTraffic() const {
     973       20943 :     for(Route::PathList::const_iterator it = GetPathList().begin();
     974       41886 :         it != GetPathList().end(); it++) {
     975       20079 :         const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
     976       20079 :         if (path->peer() && path->peer()->GetType() == Peer::INET_EVPN_PEER) {
     977        1772 :             continue;
     978             :         }
     979       18307 :         if (path->path_preference().wait_for_traffic() == true) {
     980       15719 :             return true;
     981             :         }
     982             :     }
     983         864 :     return false;
     984             : }
     985             : 
     986           0 : bool AgentRoute::ProcessPath(Agent *agent, DBTablePartition *part,
     987             :                              AgentPath *path, AgentRouteData *data) {
     988           0 :     bool ret = data->AddChangePath(agent, path, this);
     989           0 :     if (RecomputeRoutePath(agent, part, path, data)) {
     990           0 :         ret = true;
     991             :     }
     992           0 :     return ret;
     993             : }
     994             : 
     995        5511 : AgentPath *AgentRouteData::CreateAgentPath(const Peer *peer,
     996             :                                            AgentRoute *rt) const {
     997        5511 :     return (new AgentPath(peer, rt));
     998             : }
     999             : 
    1000       16009 : bool AgentRouteData::AddChangePath(Agent *agent, AgentPath *path,
    1001             :                                    const AgentRoute *rt) {
    1002       16009 :     path->set_peer_sequence_number(sequence_number_);
    1003             : 
    1004       16009 :     if (agent->tsn_enabled() && !agent->forwarding_enabled()) {
    1005           0 :         bool is_inet_rt = false;
    1006           0 :         bool service_address = false;
    1007           0 :         if ((rt->GetTableType() == Agent::INET4_UNICAST) ||
    1008           0 :             (rt->GetTableType() == Agent::INET6_UNICAST)) {
    1009           0 :             is_inet_rt = true;
    1010             :             service_address = agent->params()->
    1011           0 :                 IsConfiguredTsnHostRoute(rt->GetAddressString());
    1012             :         }
    1013           0 :         Peer::Type type = path->peer()->GetType();
    1014           0 :         bool local_route = false;
    1015           0 :         if ((type == Peer::LINKLOCAL_PEER) ||
    1016             :             (type == Peer::LOCAL_PEER))
    1017           0 :             local_route = true;
    1018           0 :         if (rt->FindLocalPath())
    1019           0 :             local_route = true;
    1020           0 :         if (is_inet_rt && (!service_address && !local_route) &&
    1021           0 :             (rt->vrf()->GetName().compare(agent->fabric_vrf_name()) != 0))
    1022           0 :             path->set_inactive(true);
    1023             :     }
    1024             : 
    1025       16009 :     return AddChangePathExtended(agent, path, rt);
    1026             : }
    1027         484 : const string &AgentRoute::dest_vn_name() const {
    1028         484 :     assert(GetActivePath()->dest_vn_list().size() <= 1);
    1029         484 :     return *GetActivePath()->dest_vn_list().begin();
    1030             : };
    1031             : 
    1032           0 : string AgentRoute::ToString() const {
    1033           0 :     return "Route Entry";
    1034             : }
    1035             : 
    1036      183622 : bool AgentRoute::IsLess(const DBEntry &rhs) const {
    1037      183622 :     int cmp = CompareTo(static_cast<const Route &>(rhs));
    1038      183622 :     return (cmp < 0);
    1039             : };
    1040             : 
    1041       18646 : uint32_t AgentRoute::vrf_id() const {
    1042       18646 :     return vrf_->vrf_id();
    1043             : }
    1044             : 
    1045         347 : bool AgentRoute::IsRPFInvalid() const {
    1046         347 :     const AgentPath *path = GetActivePath();
    1047         347 :     if (path == NULL) {
    1048           0 :         return false;
    1049             :     }
    1050             : 
    1051         347 :     return path->is_subnet_discard();
    1052             : }
    1053             : 
    1054           0 : void AgentRoute::HandleDeviceMastershipUpdate(AgentPath *path, bool del) {
    1055           0 :     Agent *agent = Agent::GetInstance();
    1056           0 :     PhysicalDeviceTable *table = agent->physical_device_table();
    1057           0 :     CompositeNH *nh = static_cast<CompositeNH *>(path->nexthop());
    1058           0 :     ComponentNHList clist = nh->component_nh_list();
    1059           0 :     table->UpdateDeviceMastership(vrf()->GetName(), clist, del);
    1060           0 : }
    1061             : 
    1062        2159 : void AgentRoute::HandleMulticastLabel(const Agent *agent,
    1063             :                                             AgentPath *path,
    1064             :                                             const AgentPath *local_peer_path,
    1065             :                                             const AgentPath *local_vm_peer_path,
    1066             :                                             bool del, uint32_t *evpn_label) {
    1067        2159 :     *evpn_label = MplsTable::kInvalidLabel;
    1068             : 
    1069             :     //EVPN label is present in two paths:
    1070             :     // local_vm_peer(courtesy: vmi) or local_peer(courtesy: vn)
    1071             :     // Irrespective of delete/add operation if one of them is present and is not
    1072             :     // the affected path, then extract the label from same.
    1073             :     // By default pick it from available path (local or local_vm).
    1074        2159 :     switch (path->peer()->GetType()) {
    1075        1906 :     case Peer::LOCAL_VM_PEER:
    1076             :         //Use local_peer path for label
    1077        1906 :         if (local_peer_path) {
    1078        1862 :             *evpn_label = local_peer_path->label();
    1079        1862 :             assert(*evpn_label != MplsTable::kInvalidLabel);
    1080             :         }
    1081        1906 :         break;
    1082         237 :     case Peer::LOCAL_PEER:
    1083             :         //Use local_peer path for label
    1084         237 :         if (local_vm_peer_path) {
    1085          75 :             *evpn_label = local_vm_peer_path->label();
    1086          75 :             assert(*evpn_label != MplsTable::kInvalidLabel);
    1087             :         }
    1088         237 :         break;
    1089          16 :     default:
    1090          16 :         if (local_vm_peer_path) {
    1091          16 :             *evpn_label = local_vm_peer_path->label();
    1092          16 :             assert(*evpn_label != MplsTable::kInvalidLabel);
    1093           0 :         } else if (local_peer_path) {
    1094           0 :             *evpn_label = local_peer_path->label();
    1095           0 :             assert(*evpn_label != MplsTable::kInvalidLabel);
    1096             :         }
    1097          16 :         break;
    1098             :     }
    1099             : 
    1100             :     //Delete path evpn label if path is local_peer or local_vm_peer.
    1101             :     //Delete fabric label if path is multicast_fabric_tree
    1102        2159 :     if (del) {
    1103         170 :         bool delete_label = false;
    1104             :         // On deletion of fabric path delete fabric label.
    1105             :         // Other type of label is evpn mcast label.
    1106             :         // EVPN label is deleted when both local peer and local_vm_peer path are
    1107             :         // gone.
    1108         170 :         if (path->peer()->GetType() == Peer::MULTICAST_FABRIC_TREE_BUILDER)
    1109           0 :             delete_label = true;
    1110         261 :         else if ((path->peer() == agent->local_vm_peer()) ||
    1111          91 :                  (path->peer() == agent->local_peer())) {
    1112         162 :             if (local_peer_path == NULL &&
    1113             :                 local_vm_peer_path == NULL) {
    1114          86 :                 delete_label = true;
    1115             :                 //Reset evpn label to invalid as it is freed
    1116          86 :                 if (*evpn_label == path->label()) {
    1117           0 :                     *evpn_label = MplsTable::kInvalidLabel;
    1118             :                 }
    1119             :             }
    1120             :         }
    1121         170 :         if (delete_label) {
    1122          86 :             agent->mpls_table()->FreeLabel(path->label(),
    1123             :                                            vrf()->GetName());
    1124             :             //Reset path label to invalid as it is freed
    1125          86 :             path->set_label(MplsTable::kInvalidLabel);
    1126             :         }
    1127         170 :         return;
    1128             :     }
    1129             : 
    1130             :     // Currently other than evpn label no other multicast path requires dynamic
    1131             :     // allocation so return.
    1132        1989 :     if ((path != local_peer_path) && (path != local_vm_peer_path))
    1133           8 :         return;
    1134             : 
    1135             :     // Path already has label, return.
    1136        1981 :     if (path->label() != MplsTable::kInvalidLabel) {
    1137        1819 :         if (*evpn_label ==  MplsTable::kInvalidLabel) {
    1138          34 :             *evpn_label = path->label();
    1139             :         }
    1140        1819 :         return;
    1141             :     }
    1142             : 
    1143             :     // If this is the first time i.e. local_peer has come with no local_vm_peer
    1144             :     // and vice versa then allocate label.
    1145             :     // If its not then we should have valid evpn label calculated above.
    1146         162 :     if (*evpn_label == MplsTable::kInvalidLabel) {
    1147             :         // XOR use - we shud never reach here when both are NULL or set.
    1148             :         // Only one should be present.
    1149          86 :         assert((local_vm_peer_path != NULL) ^ (local_peer_path != NULL));
    1150             :         // Allocate route label with discard nh, nh in label gets updated
    1151             :         // after composite-nh is created.
    1152          86 :         DiscardNHKey key;
    1153         172 :         *evpn_label = agent->mpls_table()->CreateRouteLabel(*evpn_label, &key,
    1154             :                                                             vrf()->GetName(),
    1155         172 :                                                             ToString());
    1156          86 :     }
    1157         162 :     assert(*evpn_label != MplsTable::kInvalidLabel);
    1158         162 :     path->set_label(*evpn_label);
    1159             : }
    1160             : 
    1161        2159 : bool AgentRoute::ReComputeMulticastPaths(AgentPath *path, bool del) {
    1162        2159 :     if (path->peer() == NULL) {
    1163           0 :         return false;
    1164             :     }
    1165             : 
    1166             :     //HACK: subnet route uses multicast NH. During IPAM delete
    1167             :     //subnet discard is deleted. Consider this as delete of all
    1168             :     //paths. Though this can be handled via multicast module
    1169             :     //which can also issue delete of all peers, however
    1170             :     //this is a temporary code as subnet route will not use
    1171             :     //multicast NH.
    1172        2159 :     bool delete_all = false;
    1173        2159 :     if (path->is_subnet_discard() && del) {
    1174           0 :         delete_all = true;
    1175             :     }
    1176             : 
    1177        2159 :     Agent *agent = (static_cast<AgentRouteTable *> (get_table()))->agent();
    1178        2159 :     if (del && (path->peer() == agent->multicast_peer()))
    1179           0 :         return false;
    1180             : 
    1181             :     //Possible paths:
    1182             :     //EVPN path - can be from multiple peers.
    1183             :     //Fabric path - from multicast builder
    1184             :     //Multicast peer
    1185        2159 :     AgentPath *multicast_peer_path = NULL;
    1186        2159 :     AgentPath *local_vm_peer_path = NULL;
    1187        2159 :     AgentPath *evpn_peer_path = NULL;
    1188        2159 :     AgentPath *fabric_peer_path = NULL;
    1189        2159 :     AgentPath *tor_peer_path = NULL;
    1190        2159 :     AgentPath *local_peer_path = NULL;
    1191        2159 :     bool tor_path = false;
    1192             : 
    1193             :     const CompositeNH *cnh =
    1194        2159 :          static_cast<const CompositeNH *>(path->nexthop());
    1195        2159 :     if (cnh && (cnh->composite_nh_type() == Composite::TOR)) {
    1196           0 :         tor_path = true;
    1197             :     }
    1198             : 
    1199        8221 :     for (Route::PathList::iterator it = GetPathList().begin();
    1200       16442 :         it != GetPathList().end(); it++) {
    1201             :         AgentPath *it_path =
    1202        6062 :             static_cast<AgentPath *>(it.operator->());
    1203             : 
    1204        6062 :         if (delete_all && (it_path->peer() != agent->multicast_peer()))
    1205           0 :             continue;
    1206             : 
    1207             :         //Handle deletions
    1208        6062 :         if (del && (path->peer() == it_path->peer())) {
    1209         170 :             if (path->peer()->GetType() != Peer::BGP_PEER)
    1210         162 :                 continue;
    1211             : 
    1212             :             //Dive into comp NH type for BGP peer
    1213             :             const CompositeNH *it_path_comp_nh =
    1214           8 :                 static_cast<const CompositeNH *>(it_path->nexthop());
    1215             :             const CompositeNH *comp_nh =
    1216           8 :                 static_cast<const CompositeNH *>(path->nexthop());
    1217           8 :             if (it_path_comp_nh->composite_nh_type() ==
    1218           8 :                 comp_nh->composite_nh_type())
    1219           8 :                 continue;
    1220             :         }
    1221             : 
    1222             :         //Handle Add/Changes
    1223        5892 :         if (it_path->inactive())
    1224           0 :             continue;
    1225        5892 :         if (it_path->peer() == agent->local_vm_peer()) {
    1226        1918 :             local_vm_peer_path = it_path;
    1227        3974 :         } else if (it_path->peer()->GetType() == Peer::BGP_PEER) {
    1228             :             const CompositeNH *bgp_comp_nh =
    1229          24 :                 static_cast<const CompositeNH *>(it_path->nexthop());
    1230             :             //Its a TOR NH
    1231          24 :             if (bgp_comp_nh && (bgp_comp_nh->composite_nh_type() ==
    1232             :                                 Composite::TOR)) {
    1233           0 :                 if (tor_peer_path == NULL)
    1234           0 :                     tor_peer_path = it_path;
    1235             :             }
    1236             :             //Pick up the first peer.
    1237          24 :             if (bgp_comp_nh && (bgp_comp_nh->composite_nh_type() ==
    1238             :                                 Composite::EVPN)) {
    1239          24 :                 if (evpn_peer_path == NULL)
    1240          24 :                     evpn_peer_path = it_path;
    1241             :             }
    1242        3950 :         } else if (it_path->peer()->GetType() ==
    1243             :                    Peer::MULTICAST_FABRIC_TREE_BUILDER) {
    1244           0 :             fabric_peer_path = it_path;
    1245        3950 :         } else if (it_path->peer() == agent->multicast_peer()) {
    1246        1918 :             multicast_peer_path = it_path;
    1247        2032 :         } else if (it_path->peer() == agent->local_peer()) {
    1248        2032 :             local_peer_path = it_path;
    1249             :         }
    1250             :     }
    1251             : 
    1252        2159 :     if (tor_path) {
    1253           0 :         if ((del && (tor_peer_path == NULL)) || !del) {
    1254           0 :             HandleDeviceMastershipUpdate(path, del);
    1255             :         }
    1256             :     }
    1257             : 
    1258        2159 :     uint32_t evpn_label = MplsTable::kInvalidLabel;
    1259        2159 :     HandleMulticastLabel(agent, path, local_peer_path, local_vm_peer_path, del,
    1260             :                          &evpn_label);
    1261             : 
    1262             :     //all paths are gone so delete multicast_peer path as well
    1263        2159 :     if ((local_vm_peer_path == NULL) &&
    1264         241 :         (tor_peer_path == NULL) &&
    1265         241 :         (evpn_peer_path == NULL) &&
    1266             :         (fabric_peer_path == NULL)) {
    1267         241 :         if (multicast_peer_path != NULL) {
    1268          79 :             if ((evpn_label != MplsTable::kInvalidLabel) && (local_peer_path)) {
    1269             :                 // Make evpn label point to discard-nh as composite-nh gets
    1270             :                 // deleted.
    1271          68 :                 DiscardNHKey key;
    1272         136 :                 agent->mpls_table()->CreateRouteLabel(evpn_label, &key,
    1273             :                                                       vrf()->GetName(),
    1274         136 :                                                       ToString());
    1275          68 :             }
    1276          79 :             std::unique_ptr<AgentPath> path_ref(multicast_peer_path);
    1277          79 :             RemovePath(multicast_peer_path);
    1278          79 :         }
    1279         241 :         return true;
    1280             :     }
    1281             : 
    1282        1918 :     bool learning_enabled = false;
    1283        1918 :     bool pbb_nh = false;
    1284        1918 :     uint32_t old_fabric_mpls_label = 0;
    1285        1918 :     if (multicast_peer_path == NULL) {
    1286          79 :         multicast_peer_path = new MulticastRoutePath(agent->multicast_peer());
    1287          79 :         InsertPath(multicast_peer_path);
    1288             :     } else {
    1289             :         //Multicast peer path can have evpn or fabric label.
    1290             :         //Identify using isfabricmulticastlabel.
    1291        1839 :         if (agent->mpls_table()->
    1292        1839 :              IsFabricMulticastLabel(multicast_peer_path->label()))
    1293             :         {
    1294           0 :             old_fabric_mpls_label = multicast_peer_path->label();
    1295             :         }
    1296             :     }
    1297             : 
    1298        1918 :     ComponentNHKeyList component_nh_list;
    1299             : 
    1300        1918 :     if (tor_peer_path) {
    1301             :         NextHopKey *tor_peer_key =
    1302             :             static_cast<NextHopKey *>((tor_peer_path->
    1303           0 :                         ComputeNextHop(agent)->GetDBRequestKey()).release());
    1304           0 :         std::unique_ptr<const NextHopKey> key4(tor_peer_key);
    1305           0 :         ComponentNHKeyPtr component_nh_data4(new ComponentNHKey(0, std::move(key4)));
    1306           0 :         component_nh_list.push_back(component_nh_data4);
    1307           0 :     }
    1308             : 
    1309        1918 :     if (evpn_peer_path) {
    1310             :         NextHopKey *evpn_peer_key =
    1311             :             static_cast<NextHopKey *>((evpn_peer_path->
    1312          24 :                         ComputeNextHop(agent)->GetDBRequestKey()).release());
    1313          24 :         std::unique_ptr<const NextHopKey> key2(evpn_peer_key);
    1314          24 :         ComponentNHKeyPtr component_nh_data2(new ComponentNHKey(0, std::move(key2)));
    1315          24 :         component_nh_list.push_back(component_nh_data2);
    1316          24 :     }
    1317             : 
    1318        1918 :     if (fabric_peer_path) {
    1319             :         NextHopKey *fabric_peer_key =
    1320             :             static_cast<NextHopKey *>((fabric_peer_path->
    1321           0 :                         ComputeNextHop(agent)->GetDBRequestKey()).release());
    1322           0 :         std::unique_ptr<const NextHopKey> key3(fabric_peer_key);
    1323           0 :         ComponentNHKeyPtr component_nh_data3(new ComponentNHKey(0, std::move(key3)));
    1324           0 :         component_nh_list.push_back(component_nh_data3);
    1325           0 :     }
    1326             : 
    1327        1918 :     if (local_vm_peer_path) {
    1328             :         NextHopKey *local_vm_peer_key =
    1329             :             static_cast<NextHopKey *>((local_vm_peer_path->
    1330        1918 :                                        ComputeNextHop(agent)->GetDBRequestKey()).release());
    1331        1918 :         std::unique_ptr<const NextHopKey> key4(local_vm_peer_key);
    1332        1918 :         ComponentNHKeyPtr component_nh_data4(new ComponentNHKey(0, std::move(key4)));
    1333        1918 :         component_nh_list.push_back(component_nh_data4);
    1334             : 
    1335        1918 :         const CompositeNH *cnh = dynamic_cast<const CompositeNH *>(
    1336        1918 :                 local_vm_peer_path->ComputeNextHop(agent));
    1337        1918 :         if (cnh && cnh->learning_enabled() == true) {
    1338           0 :             learning_enabled = true;
    1339             :         }
    1340        1918 :         if (cnh && cnh->pbb_nh() == true) {
    1341           0 :             pbb_nh = true;
    1342             :         }
    1343        1918 :     }
    1344             : 
    1345        1918 :     DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
    1346        3836 :     nh_req.key.reset(new CompositeNHKey(GetMulticastCompType(),
    1347        1918 :                                         ValidateMcastSrc(), false,
    1348             :                                         component_nh_list,
    1349        1918 :                                         vrf()->GetName()));
    1350        1918 :     nh_req.data.reset(new CompositeNHData(pbb_nh, learning_enabled,
    1351        1918 :                                           vrf()->layer2_control_word()));
    1352        1918 :     agent->nexthop_table()->Process(nh_req);
    1353        3836 :     NextHop *nh = static_cast<NextHop *>(agent->nexthop_table()->
    1354        1918 :                                  FindActiveEntry(nh_req.key.get()));
    1355             :     //NH may not get added if VRF is marked for delete. Route may be in
    1356             :     //transition of getting deleted, skip NH modification.
    1357        1918 :     if (!nh) {
    1358           0 :         return false;
    1359             :     }
    1360             : 
    1361             :     // Since we holding a ref to composite NHs from FMG labels now,
    1362             :     // it is possible for nh's ref to drop to zerp becuase of freelabel
    1363             :     // call below. Hold a ref until the nh is updated in labels i.e.,
    1364             :     // till the end of this function
    1365        1918 :     NextHopRef nh_ref = nh;
    1366             : 
    1367        1918 :     if (nh->GetType() == NextHop::COMPOSITE) {
    1368        1918 :         CompositeNH *comp_nh = static_cast<CompositeNH *>(nh);
    1369        1918 :         comp_nh->set_validate_mcast_src(ValidateMcastSrc());
    1370             :     }
    1371             : 
    1372        1918 :     NextHopKey *key = static_cast<NextHopKey *>(nh_req.key.get());
    1373             :     //Bake all MPLS label
    1374        1918 :     if (fabric_peer_path) {
    1375             :         //Add new label
    1376           0 :         agent->mpls_table()->CreateRouteLabel(fabric_peer_path->label(), key,
    1377           0 :                                               vrf()->GetName(), ToString());
    1378             :         //Delete Old label, in case label has changed for same peer.
    1379           0 :         if (old_fabric_mpls_label != fabric_peer_path->label()) {
    1380           0 :             agent->mpls_table()->FreeLabel(old_fabric_mpls_label,
    1381             :                                            vrf()->GetName());
    1382             :         }
    1383             :     }
    1384             : 
    1385             :     // Rebake label with whatever comp NH has been calculated.
    1386        1918 :     if (evpn_label != MplsTable::kInvalidLabel) {
    1387        3836 :         evpn_label = agent->mpls_table()->CreateRouteLabel(evpn_label, key,
    1388        3836 :                                               vrf()->GetName(), ToString());
    1389             :     }
    1390             : 
    1391        1918 :     bool ret = false;
    1392             :     //Identify parameters to be passed to populate multicast_peer path and
    1393             :     //based on peer priorites for each attribute.
    1394        1918 :     std::string dest_vn_name = "";
    1395        1918 :     bool unresolved = false;
    1396        1918 :     uint32_t vxlan_id = 0;
    1397        1918 :     uint32_t tunnel_bmap = TunnelType::AllType();
    1398             : 
    1399             :     //Select based on priority of path peer.
    1400        1918 :     if (local_vm_peer_path) {
    1401        1918 :         dest_vn_name = local_vm_peer_path->dest_vn_name();
    1402        1918 :         unresolved = local_vm_peer_path->unresolved();
    1403        1918 :         vxlan_id = local_vm_peer_path->vxlan_id();
    1404        1918 :         tunnel_bmap = TunnelType::AllType();
    1405           0 :     } else if (tor_peer_path) {
    1406           0 :         dest_vn_name = tor_peer_path->dest_vn_name();
    1407           0 :         unresolved = tor_peer_path->unresolved();
    1408           0 :         vxlan_id = tor_peer_path->vxlan_id();
    1409           0 :         tunnel_bmap = TunnelType::VxlanType();
    1410           0 :     } else if (fabric_peer_path) {
    1411           0 :         dest_vn_name = fabric_peer_path->dest_vn_name();
    1412           0 :         unresolved = fabric_peer_path->unresolved();
    1413           0 :         vxlan_id = fabric_peer_path->vxlan_id();
    1414           0 :         tunnel_bmap = TunnelType::MplsType();
    1415           0 :     } else if (evpn_peer_path) {
    1416           0 :         dest_vn_name = evpn_peer_path->dest_vn_name();
    1417           0 :         unresolved = evpn_peer_path->unresolved();
    1418           0 :         vxlan_id = evpn_peer_path->vxlan_id();
    1419           0 :         tunnel_bmap = TunnelType::VxlanType();
    1420             :     }
    1421             : 
    1422             :     //By default mark label stored in multicast_peer path to be evpn label.
    1423        1918 :     uint32_t label = evpn_label;
    1424             :     //Mpls label selection needs to be overridden by fabric label
    1425             :     //if fabric peer is present.
    1426        1918 :     if (fabric_peer_path) {
    1427           0 :         label = fabric_peer_path->label();
    1428             :     }
    1429             : 
    1430        1918 :     ret = MulticastRoute::CopyPathParameters(agent,
    1431             :                                              multicast_peer_path,
    1432             :                                              dest_vn_name,
    1433             :                                              unresolved,
    1434             :                                              vxlan_id,
    1435             :                                              label,
    1436             :                                              tunnel_bmap,
    1437             :                                              nh, this);
    1438             :     MulticastRoutePath *multicast_route_path =
    1439        1918 :         dynamic_cast<MulticastRoutePath *>(multicast_peer_path);
    1440        1918 :     if (multicast_route_path) {
    1441        1918 :         multicast_route_path->UpdateLabels(evpn_label, label);
    1442             :     }
    1443             : 
    1444        1918 :     return ret;
    1445        1918 : }

Generated by: LCOV version 1.14