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: 597 818 73.0 %
Date: 2026-11-09 02:10:49 Functions: 64 74 86.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14