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

Generated by: LCOV version 1.14