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: 582 818 71.1 %
Date: 2026-09-07 02:14:47 Functions: 62 74 83.8 %
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          54 :     DeleteActor(AgentRouteTable *rt_table) :
      38             :         LifetimeActor(rt_table->agent()->lifetime_manager()),
      39          54 :         table_(rt_table) {
      40          54 :     }
      41         108 :     virtual ~DeleteActor() {
      42         108 :     }
      43          54 :     virtual bool MayDelete() const {
      44          54 :         return table_->MayDelete();
      45             :     }
      46          54 :     virtual void Shutdown() {
      47          54 :     }
      48          54 :     virtual void Destroy() {
      49          54 :         assert(table_->vrf_entry_.get() != NULL);
      50          54 :         table_->vrf_entry_->SetRouteTableDeleted(table_->GetTableType());
      51             :         //Release refernces
      52          54 :         table_->vrf_delete_ref_.Reset(NULL);
      53          54 :         table_->vrf_entry_ = NULL;
      54          54 :     }
      55             : 
      56             :   private:
      57             :     AgentRouteTable *table_;
      58             : };
      59             : 
      60         522 : bool RouteComparator::operator() (const AgentRoute *rt1, const AgentRoute *rt2) const {
      61         522 :     return rt1->IsLess(*rt2);
      62             : }
      63             : 
      64           0 : bool NHComparator::operator() (const NextHop *nh1, const NextHop *nh2) const {
      65           0 :     return nh1->IsLess(*nh2);
      66             : }
      67             : 
      68             : /////////////////////////////////////////////////////////////////////////////
      69             : // AgentRouteTable routines
      70             : /////////////////////////////////////////////////////////////////////////////
      71          54 : AgentRouteTable::AgentRouteTable(DB *db, const std::string &name):
      72          54 :     RouteTable(db, name), agent_(NULL), vrf_id_(0), vrf_entry_(NULL, this),
      73          54 :     deleter_(NULL), vrf_delete_ref_(this, NULL), unresolved_rt_tree_(),
      74         108 :     unresolved_nh_tree_() {
      75          54 :     OperDBTraceBuf = SandeshTraceBufferCreate("OperRoute", 5000);
      76          54 : }
      77             : 
      78          54 : AgentRouteTable::~AgentRouteTable() {
      79          54 : }
      80             : 
      81             : // Allocate a route entry
      82        1062 : unique_ptr<DBEntry> AgentRouteTable::AllocEntry(const DBRequestKey *k) const {
      83        1062 :     const AgentRouteKey *key = static_cast<const AgentRouteKey*>(k);
      84        1062 :     VrfKey vrf_key(key->vrf_name());
      85             :     AgentRoute *route =
      86        1062 :         static_cast<AgentRoute *>(key->AllocRouteEntry(vrf_entry_.get(),
      87             :                                                        false));
      88        2124 :     return unique_ptr<DBEntry>(static_cast<DBEntry *>(route));
      89        1062 : }
      90             : 
      91             : // Algorithm to select an active path from multiple potential paths.
      92             : // Uses comparator in path for selection
      93         512 : bool AgentRouteTable::PathSelection(const Path &path1, const Path &path2) {
      94         512 :     const AgentPath &l_path = dynamic_cast<const AgentPath &> (path1);
      95         512 :     const AgentPath &r_path = dynamic_cast<const AgentPath &> (path2);
      96         512 :     return l_path.IsLess(r_path);
      97             : }
      98             : 
      99          54 : const string &AgentRouteTable::GetSuffix(Agent::RouteTableType type) {
     100          54 :     static const string uc_suffix(".uc.route.0");
     101          54 :     static const string mpls_suffix(".uc.route.3");
     102          54 :     static const string mc_suffix(".mc.route.0");
     103          54 :     static const string evpn_suffix(".evpn.route.0");
     104          54 :     static const string l2_suffix(".l2.route.0");
     105          54 :     static const string uc_inet6_suffix(".uc.route6.0");
     106             : 
     107          54 :     switch (type) {
     108           9 :     case Agent::INET4_UNICAST:
     109           9 :         return uc_suffix;
     110           9 :     case Agent::INET4_MPLS:
     111           9 :         return mpls_suffix;
     112           9 :     case Agent::INET4_MULTICAST:
     113           9 :         return mc_suffix;
     114           9 :     case Agent::EVPN:
     115           9 :         return evpn_suffix;
     116           9 :     case Agent::BRIDGE:
     117           9 :         return l2_suffix;
     118           9 :     case Agent::INET6_UNICAST:
     119           9 :         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          54 : void AgentRouteTable::SetVrf(VrfEntry *vrf) {
     127          54 :     agent_ = (static_cast<VrfTable *>(vrf->get_table()))->agent();
     128          54 :     vrf_entry_ = vrf;
     129          54 :     vrf_id_ = vrf->vrf_id();
     130          54 :     vrf_delete_ref_.Reset(vrf->deleter());
     131          54 :     deleter_.reset(new DeleteActor(this));
     132          54 : }
     133             : 
     134             : //Delete all the routes
     135          54 : void AgentRouteTable::ManagedDelete() {
     136          54 :     RouteTableWalkerState *state = new RouteTableWalkerState(deleter());
     137             :     DBTable::DBTableWalkRef walk_ref = AllocWalker(
     138             :          boost::bind(&AgentRouteTable::DelExplicitRouteWalkerCb, this, _1, _2),
     139         108 :          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          54 :     WalkTable(walk_ref);
     144          54 :     deleter_->Delete();
     145          54 : }
     146             : 
     147          54 : void AgentRouteTable::DeleteRouteDone(DBTable::DBTableWalkRef walk_ref,
     148             :                                       DBTableBase *base,
     149             :                                       RouteTableWalkerState *state) {
     150          54 :     LOG(DEBUG, "Deleted all BGP injected routes for " << base->name());
     151          54 :     ReleaseWalker(walk_ref);
     152          54 :     delete state;
     153          54 : }
     154             : 
     155           2 : bool AgentRouteTable::DelExplicitRouteWalkerCb(DBTablePartBase *part,
     156             :                                   DBEntryBase *entry) {
     157           2 :     AgentRoute *route = static_cast<AgentRoute *>(entry);
     158           2 :     if (route == NULL)
     159           0 :         return true;
     160             : 
     161           2 :     return route->DeleteAllBgpPath(part, this);
     162             : }
     163             : 
     164         435 : void AgentRouteTable::RetryDelete() {
     165         435 :     if (!deleter()->IsDeleted()) {
     166         198 :         return;
     167             :     }
     168         237 :     if (empty()) {
     169         233 :         vrf_entry()->RetryDelete();
     170             :     }
     171         237 :     deleter()->RetryDelete();
     172             : }
     173             : 
     174           0 : void AgentRouteTable::NotifyEntry(AgentRoute *e) {
     175           0 :     agent()->ConcurrencyCheck();
     176             :     DBTablePartBase *tpart =
     177           0 :         static_cast<DBTablePartition *>(GetTablePartition(e));
     178           0 :     tpart->Notify(e);
     179           0 : }
     180             : 
     181             : /////////////////////////////////////////////////////////////////////////////
     182             : // Agent route input processing
     183             : /////////////////////////////////////////////////////////////////////////////
     184             : 
     185             : // Inline processing of Route request.
     186         505 : void AgentRouteTable::Process(DBRequest &req) {
     187         505 :     agent()->ConcurrencyCheck();
     188             :     DBTablePartition *tpart =
     189         505 :         static_cast<DBTablePartition *>(GetTablePartition(req.key.get()));
     190         505 :     tpart->Process(NULL, &req);
     191         505 : }
     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        1323 : void AgentRouteTable::Input(DBTablePartition *part, DBClient *client,
     200             :                             DBRequest *req) {
     201        1323 :     AgentRouteKey *key = static_cast<AgentRouteKey *>(req->key.get());
     202        1323 :     AgentRouteData *data = static_cast<AgentRouteData *>(req->data.get());
     203             : 
     204        1323 :     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        1323 :     if (vrf == NULL)
     208           1 :         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        1322 :     AgentRouteTable *req_table = vrf->GetRouteTable(key->GetRouteTableType());
     213        1322 :     if (req_table != this) {
     214         390 :         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         390 :             static_cast<DBTablePartition *>(req_table->GetTablePartition(key));
     223         390 :         req_table->Input(p, client, req);
     224         390 :         return;
     225             :     }
     226             : 
     227         932 :     AgentRoute *rt = static_cast<AgentRoute *>(part->Find(key));
     228         932 :     if (req->oper == DBRequest::DB_ENTRY_DELETE) {
     229         385 :         if (rt)
     230         251 :             rt->DeleteInput(part, this, key, data);
     231         385 :         return;
     232             :     }
     233             : 
     234         547 :     if (req->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
     235         547 :         AddChangeInput(part, vrf, rt, key, data);
     236         547 :         return;
     237             :     }
     238             : 
     239           0 :     assert(0);
     240             : }
     241             : 
     242             : // Handle RESYNC and ADD_CHANGE requests
     243         547 : void AgentRouteTable::AddChangeInput(DBTablePartition *part, VrfEntry *vrf,
     244             :                                      AgentRoute *rt, AgentRouteKey *key,
     245             :                                      AgentRouteData *data) {
     246         547 :     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         547 :     if (vrf->IsDeleted() && vrf->allow_route_add_on_deleted_vrf() == false)
     253           0 :         return;
     254             : 
     255         547 :     AgentPath *path = NULL;
     256         547 :     bool notify = false;
     257         547 :     const NextHop *nh = NULL;
     258         547 :     if (rt) {
     259         386 :         nh = rt->GetActiveNextHop();
     260             :     }
     261         547 :     if (key->sub_op_ == AgentKey::RESYNC) {
     262             :         // Process RESYNC only if route present and not-deleted
     263         167 :         if (rt && (rt->IsDeleted() == false))
     264         165 :             notify |= rt->SubOpResyncInput(vrf, this, &path, key, data);
     265         380 :     } else if (key->sub_op_ == AgentKey::ADD_DEL_CHANGE) {
     266         380 :         bool route_added = (rt == NULL);
     267         380 :         rt = LocateRoute(part, vrf, rt, key, data, &notify);
     268         380 :         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         547 :     if (rt && rt->HasUnresolvedPath() == true) {
     277         201 :         rt->AddUnresolvedRouteToTable(this);
     278             :     }
     279             :     // Route changed, trigger change on dependent routes
     280         547 :     if (notify) {
     281         476 :         bool active_path_changed = (path == rt->GetActivePath());
     282         476 :         const AgentPath *prev_active_path = rt->GetActivePath();
     283         476 :         CompositeNH *cnh = NULL;
     284         476 :         if (prev_active_path) {
     285         476 :             cnh = dynamic_cast<CompositeNH *>(prev_active_path->nexthop());
     286             :         }
     287         476 :         const Path *prev_front = rt->front();
     288         476 :         if (prev_front) {
     289         476 :             rt->Sort(&AgentRouteTable::PathSelection, prev_front);
     290             :         }
     291         476 :         if (rt->GetActiveNextHop() != nh) {
     292         196 :             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         721 :         if ( (path == rt->GetActivePath()) &&
     300         245 :             (path != prev_active_path)) {
     301             :             CompositeNH *new_cnh =
     302           0 :                 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           0 :                 (cnh->composite_nh_type() == Composite::ECMP) &&
     307           0 :                 (new_cnh->composite_nh_type() == Composite::ECMP)) {
     308           0 :                 path->ImportPrevActiveNH(agent_, cnh);
     309             :             }
     310             :         }
     311         476 :         part->Notify(rt);
     312         476 :         rt->UpdateDependantRoutes();
     313         476 :         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         476 :         active_path_changed |= (path == rt->GetActivePath());
     318         476 :         rt->UpdateDerivedRoutes(this, path, active_path_changed);
     319             :     }
     320             : }
     321             : 
     322         380 : 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         380 :     if (rt != NULL && rt->IsDeleted() == false)
     328         221 :         return rt;
     329             : 
     330             :     // Add route if not present already
     331         159 :     if (rt == NULL) {
     332             :         rt = static_cast<AgentRoute *>
     333         159 :             (key->AllocRouteEntry(vrf, data->is_multicast()));
     334         159 :         assert(rt->vrf() != NULL);
     335         159 :         part->Add(rt);
     336             :     }
     337             : 
     338             :     // Renew the route if its in deleted state
     339         159 :     if (rt->IsDeleted()) {
     340           0 :         assert(rt->IsDeleted());
     341           0 :         rt->ClearDelete();
     342           0 :         *notify = true;
     343             :     }
     344             : 
     345         159 :     ProcessAdd(rt);
     346         159 :     RouteInfo rt_info;
     347         159 :     rt->FillTrace(rt_info, AgentRoute::ADD, NULL);
     348         159 :     OPER_TRACE_ROUTE_ENTRY(Route, this, rt_info);
     349         159 :     return rt;
     350         159 : }
     351             : 
     352         201 : void AgentRoute::AddUnresolvedRouteToTable(AgentRouteTable *table) {
     353             : 
     354         201 :     if (dependent_route_table_ == NULL) {
     355          29 :         const AgentPath *path = GetActivePath();
     356          29 :         if (path->GetDependentTable()) {
     357           0 :             dependent_route_table_ = path->GetDependentTable();
     358             :         } else {
     359          29 :             dependent_route_table_ = table;
     360             :         }
     361             :     }
     362         201 :     dependent_route_table_->AddUnresolvedRoute(this);
     363         201 : }
     364         159 : void AgentRoute::RemoveUnresolvedRouteFromTable(AgentRouteTable *table) {
     365         159 :     if (dependent_route_table_) {
     366          29 :         dependent_route_table_->RemoveUnresolvedRoute(this);
     367             :     } else {
     368         130 :         table->RemoveUnresolvedRoute(this);
     369             :     }
     370         159 : }
     371             : 
     372             : 
     373             : // Re-evaluate all unresolved NH. Flush and enqueue RESYNC for all NH in the
     374             : // unresolved NH tree
     375         159 : void AgentRouteTable::EvaluateUnresolvedNH(void) {
     376         159 :     for (UnresolvedNHTree::iterator it = unresolved_nh_tree_.begin();
     377         159 :          it != unresolved_nh_tree_.end(); ++it) {
     378           0 :         (*it)->EnqueueResync();
     379             : 
     380           0 :         DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
     381           0 :         req.key = (*it)->GetDBRequestKey();
     382           0 :         (static_cast<NextHopKey *>(req.key.get()))->sub_op_ = AgentKey::RESYNC;
     383           0 :         agent_->nexthop_table()->Enqueue(&req);
     384           0 :     }
     385             : 
     386         159 :     unresolved_nh_tree_.clear();
     387         159 : }
     388             : 
     389           0 : void AgentRouteTable::AddUnresolvedNH(const NextHop *nh) {
     390           0 :     unresolved_nh_tree_.insert(nh);
     391           0 : }
     392             : 
     393          10 : void AgentRouteTable::RemoveUnresolvedNH(const NextHop *nh) {
     394          10 :     unresolved_nh_tree_.erase(nh);
     395          10 : }
     396             : 
     397             : // Re-evaluate all unresolved routes. Flush and enqueue RESYNC for all routes
     398             : // in the unresolved route tree
     399         159 : void AgentRouteTable::EvaluateUnresolvedRoutes(void) {
     400         159 :     for (UnresolvedRouteTree::iterator it = unresolved_rt_tree_.begin();
     401         202 :          it !=  unresolved_rt_tree_.end(); ++it) {
     402          43 :        (*it)->EnqueueRouteResync();
     403             :     }
     404             : 
     405         159 :     unresolved_rt_tree_.clear();
     406         159 : }
     407             : 
     408         201 : void AgentRouteTable::AddUnresolvedRoute(const AgentRoute *rt) {
     409         201 :     unresolved_rt_tree_.insert(rt);
     410         201 : }
     411             : 
     412         318 : void AgentRouteTable::RemoveUnresolvedRoute(const AgentRoute *rt) {
     413         318 :     unresolved_rt_tree_.erase(rt);
     414         318 : }
     415             : 
     416             : // Find entry not in deleted state
     417          18 : AgentRoute *AgentRouteTable::FindActiveEntry(const AgentRouteKey *key) {
     418          18 :     AgentRoute *entry = static_cast<AgentRoute *>(Find(key));
     419          18 :     if (entry && entry->IsDeleted()) {
     420           0 :         return NULL;
     421             :     }
     422          18 :     return entry;
     423             : }
     424             : 
     425           9 : AgentRoute *AgentRouteTable::FindActiveEntryNoLock(const AgentRouteKey *key) {
     426           9 :     DBTable *table = static_cast<DBTable *>(this);
     427           9 :     AgentRoute *entry = static_cast<AgentRoute *>(table->FindNoLock(key));
     428           9 :     if (entry && entry->IsDeleted()) {
     429           0 :         return NULL;
     430             :     }
     431           9 :     return entry;
     432             : }
     433             : 
     434          44 : AgentRoute *AgentRouteTable::FindActiveEntry(const AgentRoute *key) {
     435          44 :     AgentRoute *entry = static_cast<AgentRoute *>(Find(key));
     436          44 :     if (entry && entry->IsDeleted()) {
     437           0 :         return NULL;
     438             :     }
     439          44 :     return entry;
     440             : }
     441             : 
     442         105 : AgentRoute *AgentRouteTable::FindActiveEntryNoLock(const AgentRoute *key) {
     443         105 :     DBTable *table = static_cast<DBTable *>(this);
     444         105 :     AgentRoute *entry = static_cast<AgentRoute *>(table->FindNoLock(key));
     445         105 :     if (entry && entry->IsDeleted()) {
     446           6 :         return NULL;
     447             :     }
     448          99 :     return entry;
     449             : }
     450             : 
     451         903 : LifetimeActor *AgentRouteTable::deleter() {
     452         903 :     return deleter_.get();
     453             : }
     454             : 
     455          94 : const std::string &AgentRouteTable::vrf_name() const {
     456          94 :     return vrf_entry_->GetName();
     457             : }
     458             : 
     459        1144 : VrfEntry *AgentRouteTable::vrf_entry() const {
     460        1144 :     return vrf_entry_.get();
     461             : }
     462             : 
     463             : /////////////////////////////////////////////////////////////////////////////
     464             : // AgentRoute routines
     465             : /////////////////////////////////////////////////////////////////////////////
     466             : 
     467             : // Hnadle RESYNC operation for a route
     468         165 : 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         165 :     if (data == NULL || key->peer() == NULL) {
     473         152 :         Sync();
     474         152 :         return true;
     475             :     }
     476             : 
     477             :     // Get path to update
     478          13 :     AgentPath *path = FindPath(key->peer());
     479          13 :     if (path == NULL)
     480           0 :         return false;
     481             : 
     482          13 :     bool ret = false;
     483          13 :     *path_ptr = path;
     484          13 :     bool old_ecmp = path->path_preference().is_ecmp();
     485          13 :     if (data->AddChangePath(table->agent(), path, this))
     486          13 :         ret = true;
     487             : 
     488             :     // Transition from ECMP to non-ECMP should result in removal of member
     489             :     // from ECMP path
     490          13 :     if (old_ecmp && old_ecmp != path->path_preference().is_ecmp()) {
     491           0 :         ReComputePathDeletion(path);
     492           0 :         return ret;
     493             :     }
     494             : 
     495          13 :     if (ReComputePathAdd(path))
     496           1 :         ret = true;
     497             : 
     498          13 :     return ret;
     499             : }
     500             : 
     501         380 : bool AgentRoute::SubOpAddChangeInput(VrfEntry *vrf, AgentRouteTable *table,
     502             :                                      AgentPath **path_ptr, AgentRouteKey *key,
     503             :                                      AgentRouteData *data, bool route_added) {
     504         380 :     bool ret = false;
     505             :     // Update route level attributes first
     506         380 :     if (data && data->UpdateRoute(this))
     507          27 :         ret = true;
     508             : 
     509             :     AgentRoute::Trace event;
     510         380 :     AgentPath *path = FindPathUsingKeyData(key, data);
     511             :     // Allocate path if not yet present
     512         380 :     if (path == NULL) {
     513         209 :         path = data->CreateAgentPath(key->peer(), this);
     514         209 :         InsertPath(path);
     515         209 :         data->AddChangePath(table->agent(), path, this);
     516         209 :         set_origin_vn_name(path->dest_vn_list());
     517         209 :         ret = true;
     518         209 :         event = AgentRoute::ADD_PATH;
     519             :     } else {
     520         171 :         bool ecmp = path->path_preference().is_ecmp();
     521         171 :         if (data->AddChangePath(table->agent(), path, this))
     522         102 :             ret = true;
     523             : 
     524             :         // Transition from ECMP to non-ECMP should result in removal of member
     525             :         // from ECMP path
     526         171 :         if (ecmp && ecmp != path->path_preference().is_ecmp()) {
     527           0 :             ReComputePathDeletion(path);
     528             :         }
     529         171 :         event = AgentRoute::CHANGE_PATH;
     530             :     }
     531             : 
     532             :     // Trace log for path add/change
     533         380 :     RouteInfo rt_info;
     534         380 :     FillTrace(rt_info, event, path);
     535         380 :     OPER_TRACE_ROUTE_ENTRY(Route, table, rt_info);
     536             : 
     537         380 :     if (path->RouteNeedsSync())
     538          65 :         ret |= Sync();
     539             : 
     540         380 :     if (route_added) {
     541         159 :         table->EvaluateUnresolvedRoutes();
     542         159 :         table->EvaluateUnresolvedNH();
     543             :     }
     544             : 
     545             :     // Do necessary recompute on addition of path
     546         380 :     if (ReComputePathAdd(path))
     547          44 :         ret = true;
     548             : 
     549         380 :     *path_ptr = path;
     550         380 :     return ret;
     551         380 : }
     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         251 : void AgentRoute::DeleteInput(DBTablePartition *part, AgentRouteTable *table,
     557             :                              AgentRouteKey *key, AgentRouteData *data) {
     558         251 :     assert (key->sub_op_ == AgentKey::ADD_DEL_CHANGE);
     559         251 :     bool force_delete = false;
     560             :     // If peer in key is deleted, set force_delete to true.
     561         251 :     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         251 :     for (Route::PathList::iterator it = GetPathList().begin();
     567        1106 :          it != GetPathList().end(); ) {
     568         302 :         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         302 :         it++;
     572             : 
     573         302 :         if (key->peer() != path->peer())
     574          81 :             continue;
     575             : 
     576             :         bool check_can_delete =
     577         434 :             ((key->peer()->GetType() == Peer::BGP_PEER) ||
     578         426 :              (key->peer()->GetType() == Peer::EVPN_ROUTING_PEER) ||
     579         647 :              (key->peer()->GetType() == Peer::EVPN_PEER) ||
     580         168 :              (key->peer()->GetType() == Peer::INET_EVPN_PEER));
     581             : 
     582         221 :         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         288 :         if (check_can_delete && data &&
     593          67 :             data->CanDeletePath(table->agent(), path, this) == false) {
     594          14 :             continue;
     595             :         }
     596             : 
     597         207 :         DeletePathFromPeer(part, table, path);
     598             :     }
     599         251 : }
     600             : 
     601         216 : void AgentRoute::InsertPath(const AgentPath *path) {
     602         216 :     const Path *prev_front = front();
     603         216 :     insert(path);
     604         216 :     Sort(&AgentRouteTable::PathSelection, prev_front);
     605         216 : }
     606             : 
     607         216 : void AgentRoute::RemovePath(AgentPath *path) {
     608         216 :     const Path *prev_front = front();
     609         216 :     remove(path);
     610         216 :     Sort(&AgentRouteTable::PathSelection, prev_front);
     611         216 :     return;
     612             : }
     613             : 
     614             : // Delete all paths from BGP Peer. Delete route if no path left
     615           2 : bool AgentRoute::DeleteAllBgpPath(DBTablePartBase *part,
     616             :                                   AgentRouteTable *table) {
     617           2 :     for(Route::PathList::iterator it = GetPathList().begin();
     618           8 :         it != GetPathList().end();) {
     619           2 :         AgentPath *path = static_cast<AgentPath *>(it.operator->());
     620           2 :         it++;
     621             : 
     622           2 :         const Peer *peer = path->peer();
     623           2 :         if (peer == NULL)
     624           0 :             continue;
     625             : 
     626           2 :         if (peer->GetType() == Peer::BGP_PEER ||
     627           2 :             peer->GetType() == Peer::EVPN_ROUTING_PEER ||
     628           0 :             peer->GetType() == Peer::MULTICAST_FABRIC_TREE_BUILDER) {
     629           2 :             DeletePathFromPeer(part, table, path);
     630           0 :         } 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           2 :     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         209 : void AgentRoute::DeletePathFromPeer(DBTablePartBase *part,
     656             :                                     AgentRouteTable *table, AgentPath *path) {
     657             : 
     658         209 :     RouteInfo rt_info;
     659         209 :     FillTrace(rt_info, AgentRoute::DELETE_PATH, path);
     660         209 :     OPER_TRACE_ROUTE_ENTRY(Route, table, rt_info);
     661             : 
     662         209 :     if (path == NULL) {
     663           0 :         return;
     664             :     }
     665             : 
     666             :     // Assign path to auto-pointer to delete it on return
     667         209 :     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         209 :     ReComputePathDeletion(path);
     674             : 
     675             :     // Store if this was active path
     676         209 :     bool active_path = (GetActivePath() == path);
     677         209 :     const Peer *old_active_path_peer = path->peer();
     678             :     // Remove path from the route
     679         209 :     RemovePath(path);
     680             : 
     681             :     // TODO : Move this code to ECMP Hash management code.
     682         209 :     CompositeNH *cnh = dynamic_cast<CompositeNH *>(path->nexthop());
     683         209 :     if (cnh) {
     684          11 :         path->ResetEcmpHashFields();
     685          11 :         cnh->UpdateEcmpHashFieldsUponRouteDelete(table->agent(),
     686             :                                                  table->vrf_name());
     687             :     }
     688             : 
     689             :     // Delete route if no more paths
     690         209 :     if (GetActivePath() == NULL) {
     691         159 :         RouteInfo rt_info_del;
     692         159 :         FillTrace(rt_info_del, AgentRoute::DEL, NULL);
     693         159 :         OPER_TRACE_ROUTE_ENTRY(Route, table, rt_info_del);
     694         159 :         DeleteDerivedRoutes(table);
     695         159 :         table->RemoveUnresolvedRoute(this); // TODO: remove this call and make changes in gw route
     696         159 :         RemoveUnresolvedRouteFromTable(table);
     697         159 :         UpdateDependantRoutes();
     698         159 :         ResyncTunnelNextHop();
     699         159 :         table->ProcessDelete(this);
     700         159 :         part->Delete(this);
     701         159 :     } 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          50 :         const Peer *new_active_path_peer = GetActivePath()->peer();
     708          50 :         AgentPath *new_active_path = FindPath(new_active_path_peer);
     709          50 :         CompositeNH *new_cnh = NULL;
     710          50 :         if (new_active_path && new_active_path->nexthop()) {
     711          49 :             new_cnh =
     712          49 :                 dynamic_cast<CompositeNH *>(new_active_path->nexthop());
     713             :         }
     714          21 :         if (active_path &&
     715           6 :                 cnh && new_cnh &&
     716           3 :                 (old_active_path_peer->GetType() == Peer::BGP_PEER) &&
     717           0 :                 (new_active_path_peer->GetType() == Peer::BGP_PEER) &&
     718          71 :                 (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          50 :         part->Notify(this);
     724          50 :         UpdateDerivedRoutes(table, NULL, active_path);
     725             :     }
     726         209 : }
     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         600 : AgentPath *AgentRoute::FindLocalVmPortPath() const {
     744         778 :     for(Route::PathList::const_iterator it = GetPathList().begin();
     745        1556 :         it != GetPathList().end(); it++) {
     746         521 :         const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
     747         521 :         if (path->peer() == NULL) {
     748           0 :             continue;
     749             :         }
     750         521 :         if (path->peer()->export_to_controller()) {
     751         343 :             return const_cast<AgentPath *>(path);
     752             :         }
     753             : 
     754         356 :         if (path->peer()->GetType() == Peer::ECMP_PEER ||
     755         356 :             path->peer()->GetType() == Peer::VGW_PEER ||
     756         356 :             path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER ||
     757         534 :             path->peer()->GetType() == Peer::MULTICAST_TOR_PEER ||
     758         178 :             path->peer()->GetType() == Peer::OVS_PEER) {
     759           0 :             return const_cast<AgentPath *>(path);
     760             :         }
     761             :     }
     762         257 :     return NULL;
     763             : }
     764             : 
     765             : /// @brief returns true if the given path is not null and points
     766             : // to a local composite interface
     767           0 : bool RtPathHasInterfaceComposite (const AgentPath* a_path) {
     768           0 :     const NextHop *a_nh = NULL;
     769             : 
     770           0 :     if (!a_path) {
     771           0 :         return false;
     772             :     }
     773             : 
     774           0 :     a_nh = a_path->nexthop();
     775           0 :     if (!a_nh) {
     776           0 :         return false;
     777             :     }
     778             : 
     779           0 :     if (a_path->peer()->export_to_controller() &&
     780           0 :         a_nh->GetType() == NextHop::COMPOSITE) {
     781           0 :         return true;
     782             :     }
     783             : 
     784           0 :     if (a_path->peer()->GetType() == Peer::ECMP_PEER) {
     785           0 :         return true;
     786             :     }
     787             : 
     788           0 :     return false;
     789             : }
     790             : 
     791             : /// @brief returns true if the given path is not null and points
     792             : // to a local interface
     793           0 : bool RtPathHasLocalInterface(const AgentPath* a_path) {
     794           0 :     const NextHop *a_nh = NULL;
     795             : 
     796           0 :     if (!a_path) {
     797           0 :         return false;
     798             :     }
     799             : 
     800           0 :     a_nh = a_path->nexthop();
     801           0 :     if (!a_nh) {
     802           0 :         return false;
     803             :     }
     804             : 
     805           0 :     if (a_path->peer()->export_to_controller() &&
     806           0 :         a_nh->GetType() == NextHop::INTERFACE) {
     807           0 :         return true;
     808             :     }
     809             : 
     810           0 :     if (a_path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER) {
     811           0 :         return true;
     812             :     }
     813             : 
     814           0 :     return false;
     815             : }
     816             :  
     817          12 : const AgentPath *AgentRoute::FindIntfOrCompLocalVmPortPath() const {
     818          12 :     const AgentPath *intf_path = NULL;
     819          12 :     const AgentPath *icom_path = NULL;
     820          12 :     for (Route::PathList::const_iterator it =
     821          12 :         this->GetPathList().begin();
     822          24 :         it != this->GetPathList().end(); it++) {
     823             :         const AgentPath *path = static_cast<const AgentPath *>
     824           0 :             (it.operator->());
     825             : 
     826           0 :         if (intf_path == NULL &&
     827           0 :             RtPathHasLocalInterface(path)) {
     828           0 :             intf_path = path;
     829           0 :             continue;
     830             :         }
     831           0 :         if (RtPathHasInterfaceComposite(path)) {
     832           0 :             icom_path = path;
     833           0 :             continue;
     834             :         }
     835             :     }
     836          12 :     if (icom_path) {
     837           0 :         return icom_path;
     838             :     }
     839          12 :     if (intf_path) {
     840           0 :         return intf_path;
     841             :     }
     842          12 :     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          64 : AgentPath *AgentRoute::FindPathUsingKeyData(const AgentRouteKey *key,
     861             :                                             const AgentRouteData *data) const {
     862          64 :     return FindPath(key->peer());
     863             : }
     864             : 
     865         933 : AgentPath *AgentRoute::FindPath(const Peer *peer) const {
     866        1555 :     for(Route::PathList::const_iterator it = GetPathList().begin();
     867        3110 :         it != GetPathList().end(); it++) {
     868        1119 :         const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
     869        1119 :         if (path->peer() == peer) {
     870         497 :             return const_cast<AgentPath *>(path);
     871             :         }
     872             :     }
     873         436 :     return NULL;
     874             : }
     875             : 
     876             : // First path in list is always treated as active path.
     877        9071 : const AgentPath *AgentRoute::GetActivePath() const {
     878        9071 :     const AgentPath *path = static_cast<const AgentPath *>(front());
     879        9071 :     return (path ? path->UsablePath() : NULL);
     880             : }
     881             : 
     882        2468 : const NextHop *AgentRoute::GetActiveNextHop() const {
     883        2468 :     const AgentPath *path = GetActivePath();
     884        2468 :     if (path == NULL)
     885          44 :         return NULL;
     886             : 
     887        2424 :     return path->ComputeNextHop(static_cast<AgentRouteTable *>(get_table())->
     888        2424 :                             agent());
     889             : }
     890             : 
     891           0 : uint32_t AgentRoute::GetActiveLabel() const {
     892           0 :     return GetActivePath()->label();
     893             : };
     894             : 
     895             : // If a direct route has changed, invoke a change on tunnel NH dependent on it
     896         635 : void AgentRoute::ResyncTunnelNextHop(void) {
     897         635 :     for (AgentRoute::TunnelNhDependencyList::iterator iter =
     898        1270 :          tunnel_nh_list_.begin(); iter != tunnel_nh_list_.end(); iter++) {
     899             : 
     900           0 :         NextHop *nh = static_cast<NextHop *>(iter.operator->());
     901           0 :         DBEntryBase::KeyPtr key = nh->GetDBRequestKey();
     902           0 :         NextHopKey *nh_key = static_cast<NextHopKey *>(key.get());
     903           0 :         nh_key->sub_op_ = AgentKey::RESYNC;
     904             : 
     905           0 :         DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
     906           0 :         req.key = std::move(key);
     907           0 :         req.data.reset(NULL);
     908           0 :         Agent *agent = (static_cast<AgentRouteTable *>(get_table()))->agent();
     909           0 :         agent->nexthop_table()->Enqueue(&req);
     910           0 :     }
     911         635 : }
     912             : 
     913             : // Enqueue request to RESYNC a route
     914         153 : void AgentRoute::EnqueueRouteResync(void) const {
     915         153 :     DBRequest  req(DBRequest::DB_ENTRY_ADD_CHANGE);
     916         153 :     req.key = GetDBRequestKey();
     917         153 :     (static_cast<AgentKey *>(req.key.get()))->sub_op_ = AgentKey::RESYNC;
     918         153 :     Agent *agent = (static_cast<AgentRouteTable *>(get_table()))->agent();
     919             :     /* Setting req.data only for default route */
     920         153 :     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         153 :     agent->fabric_inet4_unicast_table()->Enqueue(&req);
     930         153 : }
     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         646 : void AgentRoute::UpdateDependantRoutes(void) {
     937         674 :     for (AgentRoute::RouteDependencyList::iterator iter =
     938        1320 :          dependant_routes_.begin(); iter != dependant_routes_.end(); iter++) {
     939          28 :         AgentRoute *rt = iter.operator->();
     940          28 :         rt->EnqueueRouteResync();
     941             :     }
     942         646 : }
     943             : 
     944         545 : bool AgentRoute::HasUnresolvedPath(void) {
     945        1806 :     for(Route::PathList::const_iterator it = GetPathList().begin();
     946        2522 :             it != GetPathList().end(); it++) {
     947             :         const AgentPath *path =
     948         917 :             static_cast<const AgentPath *>(it.operator->());
     949         917 :         if (path->unresolved() == true) {
     950         201 :             return true;
     951             :         }
     952             :     }
     953             : 
     954         344 :     return false;
     955             : }
     956             : 
     957             : // Invoke SYNC on all paths to re-evaluate NH/active state
     958         217 : bool AgentRoute::Sync(void) {
     959         217 :     bool ret = false;
     960         533 :     for(Route::PathList::iterator it = GetPathList().begin();
     961        1066 :         it != GetPathList().end(); it++) {
     962         316 :         AgentPath *path = static_cast<AgentPath *>(it.operator->());
     963         316 :         if (path->Sync(this) == true) {
     964          32 :             if (GetActivePath() == path) {
     965          22 :                 ret = true;
     966             :             }
     967             :         }
     968             :     }
     969         217 :     return ret;
     970             : }
     971             : 
     972         601 : bool AgentRoute::WaitForTraffic() const {
     973         708 :     for(Route::PathList::const_iterator it = GetPathList().begin();
     974        1416 :         it != GetPathList().end(); it++) {
     975         661 :         const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
     976         661 :         if (path->peer() && path->peer()->GetType() == Peer::INET_EVPN_PEER) {
     977          36 :             continue;
     978             :         }
     979         625 :         if (path->path_preference().wait_for_traffic() == true) {
     980         554 :             return true;
     981             :         }
     982             :     }
     983          47 :     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         138 : AgentPath *AgentRouteData::CreateAgentPath(const Peer *peer,
     996             :                                            AgentRoute *rt) const {
     997         138 :     return (new AgentPath(peer, rt));
     998             : }
     999             : 
    1000         393 : bool AgentRouteData::AddChangePath(Agent *agent, AgentPath *path,
    1001             :                                    const AgentRoute *rt) {
    1002         393 :     path->set_peer_sequence_number(sequence_number_);
    1003             : 
    1004         393 :     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         393 :     return AddChangePathExtended(agent, path, rt);
    1026             : }
    1027          24 : const string &AgentRoute::dest_vn_name() const {
    1028          24 :     assert(GetActivePath()->dest_vn_list().size() <= 1);
    1029          24 :     return *GetActivePath()->dest_vn_list().begin();
    1030             : };
    1031             : 
    1032           0 : string AgentRoute::ToString() const {
    1033           0 :     return "Route Entry";
    1034             : }
    1035             : 
    1036        5625 : bool AgentRoute::IsLess(const DBEntry &rhs) const {
    1037        5625 :     int cmp = CompareTo(static_cast<const Route &>(rhs));
    1038        5625 :     return (cmp < 0);
    1039             : };
    1040             : 
    1041         727 : uint32_t AgentRoute::vrf_id() const {
    1042         727 :     return vrf_->vrf_id();
    1043             : }
    1044             : 
    1045         152 : bool AgentRoute::IsRPFInvalid() const {
    1046         152 :     const AgentPath *path = GetActivePath();
    1047         152 :     if (path == NULL) {
    1048           0 :         return false;
    1049             :     }
    1050             : 
    1051         152 :     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          53 : 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          53 :     *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          53 :     switch (path->peer()->GetType()) {
    1075          44 :     case Peer::LOCAL_VM_PEER:
    1076             :         //Use local_peer path for label
    1077          44 :         if (local_peer_path) {
    1078          16 :             *evpn_label = local_peer_path->label();
    1079          16 :             assert(*evpn_label != MplsTable::kInvalidLabel);
    1080             :         }
    1081          44 :         break;
    1082           9 :     case Peer::LOCAL_PEER:
    1083             :         //Use local_peer path for label
    1084           9 :         if (local_vm_peer_path) {
    1085           0 :             *evpn_label = local_vm_peer_path->label();
    1086           0 :             assert(*evpn_label != MplsTable::kInvalidLabel);
    1087             :         }
    1088           9 :         break;
    1089           0 :     default:
    1090           0 :         if (local_vm_peer_path) {
    1091           0 :             *evpn_label = local_vm_peer_path->label();
    1092           0 :             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           0 :         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          53 :     if (del) {
    1103          10 :         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          10 :         if (path->peer()->GetType() == Peer::MULTICAST_FABRIC_TREE_BUILDER)
    1109           0 :             delete_label = true;
    1110          14 :         else if ((path->peer() == agent->local_vm_peer()) ||
    1111           4 :                  (path->peer() == agent->local_peer())) {
    1112          10 :             if (local_peer_path == NULL &&
    1113             :                 local_vm_peer_path == NULL) {
    1114           7 :                 delete_label = true;
    1115             :                 //Reset evpn label to invalid as it is freed
    1116           7 :                 if (*evpn_label == path->label()) {
    1117           0 :                     *evpn_label = MplsTable::kInvalidLabel;
    1118             :                 }
    1119             :             }
    1120             :         }
    1121          10 :         if (delete_label) {
    1122           7 :             agent->mpls_table()->FreeLabel(path->label(),
    1123             :                                            vrf()->GetName());
    1124             :             //Reset path label to invalid as it is freed
    1125           7 :             path->set_label(MplsTable::kInvalidLabel);
    1126             :         }
    1127          10 :         return;
    1128             :     }
    1129             : 
    1130             :     // Currently other than evpn label no other multicast path requires dynamic
    1131             :     // allocation so return.
    1132          43 :     if ((path != local_peer_path) && (path != local_vm_peer_path))
    1133           0 :         return;
    1134             : 
    1135             :     // Path already has label, return.
    1136          43 :     if (path->label() != MplsTable::kInvalidLabel) {
    1137          33 :         if (*evpn_label ==  MplsTable::kInvalidLabel) {
    1138          23 :             *evpn_label = path->label();
    1139             :         }
    1140          33 :         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          10 :     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           7 :         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           7 :         DiscardNHKey key;
    1153          14 :         *evpn_label = agent->mpls_table()->CreateRouteLabel(*evpn_label, &key,
    1154             :                                                             vrf()->GetName(),
    1155          14 :                                                             ToString());
    1156           7 :     }
    1157          10 :     assert(*evpn_label != MplsTable::kInvalidLabel);
    1158          10 :     path->set_label(*evpn_label);
    1159             : }
    1160             : 
    1161          53 : bool AgentRoute::ReComputeMulticastPaths(AgentPath *path, bool del) {
    1162          53 :     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          53 :     bool delete_all = false;
    1173          53 :     if (path->is_subnet_discard() && del) {
    1174           0 :         delete_all = true;
    1175             :     }
    1176             : 
    1177          53 :     Agent *agent = (static_cast<AgentRouteTable *> (get_table()))->agent();
    1178          53 :     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          53 :     AgentPath *multicast_peer_path = NULL;
    1186          53 :     AgentPath *local_vm_peer_path = NULL;
    1187          53 :     AgentPath *evpn_peer_path = NULL;
    1188          53 :     AgentPath *fabric_peer_path = NULL;
    1189          53 :     AgentPath *tor_peer_path = NULL;
    1190          53 :     AgentPath *local_peer_path = NULL;
    1191          53 :     bool tor_path = false;
    1192             : 
    1193             :     const CompositeNH *cnh =
    1194          53 :          static_cast<const CompositeNH *>(path->nexthop());
    1195          53 :     if (cnh && (cnh->composite_nh_type() == Composite::TOR)) {
    1196           0 :         tor_path = true;
    1197             :     }
    1198             : 
    1199         160 :     for (Route::PathList::iterator it = GetPathList().begin();
    1200         320 :         it != GetPathList().end(); it++) {
    1201             :         AgentPath *it_path =
    1202         107 :             static_cast<AgentPath *>(it.operator->());
    1203             : 
    1204         107 :         if (delete_all && (it_path->peer() != agent->multicast_peer()))
    1205           0 :             continue;
    1206             : 
    1207             :         //Handle deletions
    1208         107 :         if (del && (path->peer() == it_path->peer())) {
    1209          10 :             if (path->peer()->GetType() != Peer::BGP_PEER)
    1210          10 :                 continue;
    1211             : 
    1212             :             //Dive into comp NH type for BGP peer
    1213             :             const CompositeNH *it_path_comp_nh =
    1214           0 :                 static_cast<const CompositeNH *>(it_path->nexthop());
    1215             :             const CompositeNH *comp_nh =
    1216           0 :                 static_cast<const CompositeNH *>(path->nexthop());
    1217           0 :             if (it_path_comp_nh->composite_nh_type() ==
    1218           0 :                 comp_nh->composite_nh_type())
    1219           0 :                 continue;
    1220             :         }
    1221             : 
    1222             :         //Handle Add/Changes
    1223          97 :         if (it_path->inactive())
    1224           0 :             continue;
    1225          97 :         if (it_path->peer() == agent->local_vm_peer()) {
    1226          38 :             local_vm_peer_path = it_path;
    1227          59 :         } else if (it_path->peer()->GetType() == Peer::BGP_PEER) {
    1228             :             const CompositeNH *bgp_comp_nh =
    1229           0 :                 static_cast<const CompositeNH *>(it_path->nexthop());
    1230             :             //Its a TOR NH
    1231           0 :             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           0 :             if (bgp_comp_nh && (bgp_comp_nh->composite_nh_type() ==
    1238             :                                 Composite::EVPN)) {
    1239           0 :                 if (evpn_peer_path == NULL)
    1240           0 :                     evpn_peer_path = it_path;
    1241             :             }
    1242          59 :         } else if (it_path->peer()->GetType() ==
    1243             :                    Peer::MULTICAST_FABRIC_TREE_BUILDER) {
    1244           0 :             fabric_peer_path = it_path;
    1245          59 :         } else if (it_path->peer() == agent->multicast_peer()) {
    1246          38 :             multicast_peer_path = it_path;
    1247          21 :         } else if (it_path->peer() == agent->local_peer()) {
    1248          21 :             local_peer_path = it_path;
    1249             :         }
    1250             :     }
    1251             : 
    1252          53 :     if (tor_path) {
    1253           0 :         if ((del && (tor_peer_path == NULL)) || !del) {
    1254           0 :             HandleDeviceMastershipUpdate(path, del);
    1255             :         }
    1256             :     }
    1257             : 
    1258          53 :     uint32_t evpn_label = MplsTable::kInvalidLabel;
    1259          53 :     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          53 :     if ((local_vm_peer_path == NULL) &&
    1264          15 :         (tor_peer_path == NULL) &&
    1265          15 :         (evpn_peer_path == NULL) &&
    1266             :         (fabric_peer_path == NULL)) {
    1267          15 :         if (multicast_peer_path != NULL) {
    1268           6 :             if ((evpn_label != MplsTable::kInvalidLabel) && (local_peer_path)) {
    1269             :                 // Make evpn label point to discard-nh as composite-nh gets
    1270             :                 // deleted.
    1271           3 :                 DiscardNHKey key;
    1272           6 :                 agent->mpls_table()->CreateRouteLabel(evpn_label, &key,
    1273             :                                                       vrf()->GetName(),
    1274           6 :                                                       ToString());
    1275           3 :             }
    1276           6 :             std::unique_ptr<AgentPath> path_ref(multicast_peer_path);
    1277           6 :             RemovePath(multicast_peer_path);
    1278           6 :         }
    1279          15 :         return true;
    1280             :     }
    1281             : 
    1282          38 :     bool learning_enabled = false;
    1283          38 :     bool pbb_nh = false;
    1284          38 :     uint32_t old_fabric_mpls_label = 0;
    1285          38 :     if (multicast_peer_path == NULL) {
    1286           6 :         multicast_peer_path = new MulticastRoutePath(agent->multicast_peer());
    1287           6 :         InsertPath(multicast_peer_path);
    1288             :     } else {
    1289             :         //Multicast peer path can have evpn or fabric label.
    1290             :         //Identify using isfabricmulticastlabel.
    1291          32 :         if (agent->mpls_table()->
    1292          32 :              IsFabricMulticastLabel(multicast_peer_path->label()))
    1293             :         {
    1294           0 :             old_fabric_mpls_label = multicast_peer_path->label();
    1295             :         }
    1296             :     }
    1297             : 
    1298          38 :     ComponentNHKeyList component_nh_list;
    1299             : 
    1300          38 :     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          38 :     if (evpn_peer_path) {
    1310             :         NextHopKey *evpn_peer_key =
    1311             :             static_cast<NextHopKey *>((evpn_peer_path->
    1312           0 :                         ComputeNextHop(agent)->GetDBRequestKey()).release());
    1313           0 :         std::unique_ptr<const NextHopKey> key2(evpn_peer_key);
    1314           0 :         ComponentNHKeyPtr component_nh_data2(new ComponentNHKey(0, std::move(key2)));
    1315           0 :         component_nh_list.push_back(component_nh_data2);
    1316           0 :     }
    1317             : 
    1318          38 :     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          38 :     if (local_vm_peer_path) {
    1328             :         NextHopKey *local_vm_peer_key =
    1329             :             static_cast<NextHopKey *>((local_vm_peer_path->
    1330          38 :                                        ComputeNextHop(agent)->GetDBRequestKey()).release());
    1331          38 :         std::unique_ptr<const NextHopKey> key4(local_vm_peer_key);
    1332          38 :         ComponentNHKeyPtr component_nh_data4(new ComponentNHKey(0, std::move(key4)));
    1333          38 :         component_nh_list.push_back(component_nh_data4);
    1334             : 
    1335          38 :         const CompositeNH *cnh = dynamic_cast<const CompositeNH *>(
    1336          38 :                 local_vm_peer_path->ComputeNextHop(agent));
    1337          38 :         if (cnh && cnh->learning_enabled() == true) {
    1338           0 :             learning_enabled = true;
    1339             :         }
    1340          38 :         if (cnh && cnh->pbb_nh() == true) {
    1341           0 :             pbb_nh = true;
    1342             :         }
    1343          38 :     }
    1344             : 
    1345          38 :     DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
    1346          76 :     nh_req.key.reset(new CompositeNHKey(GetMulticastCompType(),
    1347          38 :                                         ValidateMcastSrc(), false,
    1348             :                                         component_nh_list,
    1349          38 :                                         vrf()->GetName()));
    1350          38 :     nh_req.data.reset(new CompositeNHData(pbb_nh, learning_enabled,
    1351          38 :                                           vrf()->layer2_control_word()));
    1352          38 :     agent->nexthop_table()->Process(nh_req);
    1353          76 :     NextHop *nh = static_cast<NextHop *>(agent->nexthop_table()->
    1354          38 :                                  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          38 :     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          38 :     NextHopRef nh_ref = nh;
    1366             : 
    1367          38 :     if (nh->GetType() == NextHop::COMPOSITE) {
    1368          38 :         CompositeNH *comp_nh = static_cast<CompositeNH *>(nh);
    1369          38 :         comp_nh->set_validate_mcast_src(ValidateMcastSrc());
    1370             :     }
    1371             : 
    1372          38 :     NextHopKey *key = static_cast<NextHopKey *>(nh_req.key.get());
    1373             :     //Bake all MPLS label
    1374          38 :     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          38 :     if (evpn_label != MplsTable::kInvalidLabel) {
    1387          76 :         evpn_label = agent->mpls_table()->CreateRouteLabel(evpn_label, key,
    1388          76 :                                               vrf()->GetName(), ToString());
    1389             :     }
    1390             : 
    1391          38 :     bool ret = false;
    1392             :     //Identify parameters to be passed to populate multicast_peer path and
    1393             :     //based on peer priorites for each attribute.
    1394          38 :     std::string dest_vn_name = "";
    1395          38 :     bool unresolved = false;
    1396          38 :     uint32_t vxlan_id = 0;
    1397          38 :     uint32_t tunnel_bmap = TunnelType::AllType();
    1398             : 
    1399             :     //Select based on priority of path peer.
    1400          38 :     if (local_vm_peer_path) {
    1401          38 :         dest_vn_name = local_vm_peer_path->dest_vn_name();
    1402          38 :         unresolved = local_vm_peer_path->unresolved();
    1403          38 :         vxlan_id = local_vm_peer_path->vxlan_id();
    1404          38 :         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          38 :     uint32_t label = evpn_label;
    1424             :     //Mpls label selection needs to be overridden by fabric label
    1425             :     //if fabric peer is present.
    1426          38 :     if (fabric_peer_path) {
    1427           0 :         label = fabric_peer_path->label();
    1428             :     }
    1429             : 
    1430          38 :     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          38 :         dynamic_cast<MulticastRoutePath *>(multicast_peer_path);
    1440          38 :     if (multicast_route_path) {
    1441          38 :         multicast_route_path->UpdateLabels(evpn_label, label);
    1442             :     }
    1443             : 
    1444          38 :     return ret;
    1445          38 : }

Generated by: LCOV version 1.14