LCOV - code coverage report
Current view: top level - vnsw/agent/oper - ecmp.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 0 307 0.0 %
Date: 2026-06-22 02:21:21 Functions: 0 15 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2017 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include <boost/foreach.hpp>
       6             : #include <boost/uuid/uuid_io.hpp>
       7             : 
       8             : #include <base/address_util.h>
       9             : #include <base/task_annotations.h>
      10             : #include <cmn/agent_cmn.h>
      11             : #include <route/route.h>
      12             : #include <oper/ecmp.h>
      13             : #include <oper/ecmp_load_balance.h>
      14             : #include <oper/route_common.h>
      15             : #include <oper/vrf.h>
      16             : #include <oper/tunnel_nh.h>
      17             : #include <oper/mpls.h>
      18             : #include <oper/vxlan.h>
      19             : #include <oper/mirror_table.h>
      20             : #include <oper/multicast.h>
      21             : #include <oper/agent_sandesh.h>
      22             : 
      23             : using namespace std;
      24             : using namespace boost::asio;
      25             : 
      26           0 : EcmpData::EcmpData(Agent *agent,
      27             :                    const string &vrf_name,
      28             :                    const string &route_str,
      29             :                    AgentPath *path,
      30           0 :                    bool del) :
      31           0 :     path_(path), ecmp_path_(NULL), delete_(del),
      32           0 :     alloc_label_(true), label_(MplsTable::kInvalidLabel),
      33           0 :     vrf_name_(vrf_name), route_str_(route_str),
      34           0 :     vn_list_(path->dest_vn_list()),
      35           0 :     sg_list_(path->sg_list()),
      36           0 :     tag_list_(path->tag_list()),
      37           0 :     community_list_(path->communities()),
      38           0 :     path_preference_(path->path_preference()),
      39           0 :     tunnel_bmap_(path->tunnel_bmap()),
      40           0 :     ecmp_load_balance_(path->ecmp_load_balance()),
      41           0 :     nh_req_(), agent_(agent) {
      42           0 : }
      43             : 
      44           0 : bool EcmpData::Update(AgentRoute *rt) {
      45           0 :     if (path_->peer() == NULL) {
      46           0 :         return false;
      47             :     }
      48             : 
      49           0 :     if (path_->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER) {
      50           0 :         return LocalVmPortPeerEcmp(rt);
      51             :     }
      52             : 
      53           0 :     if (path_->peer()->GetType() == Peer::BGP_PEER) {
      54           0 :         alloc_label_ = false;
      55           0 :         return BgpPeerEcmp();
      56             :     }
      57             : 
      58           0 :     return false;
      59             : }
      60             : 
      61           0 : bool EcmpData::UpdateWithParams(const SecurityGroupList &sg_list,
      62             :                                 const TagList &tag_list,
      63             :                                 const CommunityList &community_list,
      64             :                                 const PathPreference &path_preference,
      65             :                                 const TunnelType::TypeBmap bmap,
      66             :                                 const EcmpLoadBalance &ecmp_load_balance,
      67             :                                 const VnListType &vn_list,
      68             :                                 DBRequest &nh_req) {
      69           0 :     sg_list_ = sg_list;
      70           0 :     vn_list_ = vn_list;
      71           0 :     tag_list_ = tag_list;
      72           0 :     community_list_ = community_list;
      73           0 :     path_preference_ = path_preference;
      74           0 :     tunnel_bmap_ = bmap;
      75           0 :     ecmp_load_balance_ = ecmp_load_balance;
      76           0 :     nh_req_.Swap(&nh_req);
      77             : 
      78           0 :     return Update(NULL);
      79             : }
      80             : 
      81           0 : bool EcmpData::LocalVmPortPeerEcmp(AgentRoute *rt) {
      82           0 :     ecmp_path_ = rt->FindPath(agent_->ecmp_peer());
      83           0 :     if (delete_) {
      84           0 :         return EcmpDeletePath(rt);
      85             :     } else {
      86           0 :         if (path_->path_preference().is_ecmp() == false) {
      87           0 :             return false;
      88             :         }
      89           0 :         return EcmpAddPath(rt);
      90             :     }
      91             : }
      92             : 
      93           0 : bool EcmpData::BgpPeerEcmp() {
      94           0 :     ecmp_path_ = path_;
      95             :     //Bgp peer update for ecmp should always accompany nh_req.
      96             :     //Any other request like sync is to be ignored.
      97           0 :     NextHopKey *key = static_cast<NextHopKey *>(nh_req_.key.get());
      98           0 :     if (!key)
      99           0 :         return false;
     100           0 :     return ModifyEcmpPath();
     101             : }
     102             : 
     103             : // Handle add/update of a path in route.
     104             : // If there are more than one path of type LOCAL_VM_PORT_PEER, creates/updates
     105             : // Composite-NH for them
     106           0 : bool EcmpData::EcmpAddPath(AgentRoute *rt) {
     107           0 :     if (path_->tunnel_bmap() & TunnelType::NativeType()) {
     108           0 :         path_->set_tunnel_bmap(TunnelType::MplsType() |
     109           0 :                                TunnelType::NativeType());
     110             :     } else {
     111           0 :         path_->set_tunnel_bmap(TunnelType::MplsType());
     112             :     }
     113             : 
     114             :     // Count number of paths from LOCAL_VM_PORT_PEER already present
     115           0 :     const AgentPath *vm_port_path = NULL;
     116           0 :     int count = 0;
     117           0 :     for(Route::PathList::const_iterator it = rt->GetPathList().begin();
     118           0 :         it != rt->GetPathList().end(); it++) {
     119             :         const AgentPath *it_path =
     120           0 :             static_cast<const AgentPath *>(it.operator->());
     121             : 
     122           0 :         if (it_path->peer() == agent_->ecmp_peer())
     123           0 :             assert(ecmp_path_ == it_path);
     124             : 
     125           0 :         if (it_path->peer() &&
     126           0 :             it_path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER &&
     127           0 :             it_path->path_preference().is_ecmp() == true) {
     128           0 :             count++;
     129           0 :             if (it_path != path_)
     130           0 :                 vm_port_path = it_path;
     131             :         }
     132             :     }
     133             : 
     134           0 :     if (count == 0) {
     135           0 :         return false;
     136             :     }
     137             : 
     138             :     // Sanity check. When more than one LOCAL_VM_PORT_PEER, ECMP must be present
     139           0 :     if (count > 2) {
     140           0 :         assert(ecmp_path_ != NULL);
     141             :     }
     142             : 
     143           0 :     if (count == 1) {
     144           0 :         assert(ecmp_path_ == NULL);
     145           0 :         return false;
     146             :     }
     147             : 
     148           0 :     bool ret = false;
     149           0 :     if (count == 2 && ecmp_path_ == NULL) {
     150             :         // This is second path being added, make ECMP
     151           0 :         AllocateEcmpPath(rt, vm_port_path);
     152           0 :         ret = true;
     153           0 :     } else if (count > 2) {
     154             :         // ECMP already present, add/update Component-NH for the path
     155           0 :         AppendEcmpPath(rt, path_);
     156           0 :         ret = true;
     157           0 :     } else if (ecmp_path_) {
     158           0 :         bool updated = UpdateComponentNH(rt, path_);
     159             :         //No update happened for component NH, so verify if params are to be
     160             :         //synced. If update of component NH is done, then params would also have
     161             :         //been updated, so no need to do it again.
     162           0 :         if (!updated) {
     163           0 :             updated = SyncParams();
     164             :         }
     165           0 :         if (updated) {
     166           0 :             ret = true;
     167             :         }
     168             :     }
     169             : 
     170           0 :     return ret;
     171             : }
     172             : 
     173             : // Function to create a ECMP path from path and path2
     174             : // Creates Composite-NH with 2 Component-NH (one for each of path and path2)
     175             : // Creates a new MPLS Label for the ECMP path
     176           0 : void EcmpData::AllocateEcmpPath(AgentRoute *rt, const AgentPath *path2) {
     177             :     // Allocate and insert a path
     178           0 :     ecmp_path_ = new AgentPath(agent_->ecmp_peer(), rt);
     179           0 :     rt->InsertPath(ecmp_path_);
     180             : 
     181           0 :     const NextHop* path1_nh = path_->ComputeNextHop(agent_);
     182           0 :     bool composite_nh_policy = path1_nh->NexthopToInterfacePolicy();
     183             : 
     184             :     // Create Component NH to be added to ECMP path
     185           0 :     DBEntryBase::KeyPtr key1 = path1_nh->GetDBRequestKey();
     186           0 :     NextHopKey *nh_key1 = static_cast<NextHopKey *>(key1.release());
     187           0 :     std::unique_ptr<const NextHopKey> nh_akey1(nh_key1);
     188           0 :     nh_key1->SetPolicy(false);
     189           0 :     ComponentNHKeyPtr component_nh_data1(new ComponentNHKey(path_->label(),
     190           0 :                                                             std::move(nh_akey1)));
     191             : 
     192           0 :     const NextHop* path2_nh = path2->ComputeNextHop(agent_);
     193           0 :     if (!composite_nh_policy) {
     194           0 :         composite_nh_policy = path2_nh->NexthopToInterfacePolicy();
     195             :     }
     196           0 :     DBEntryBase::KeyPtr key2 = path2_nh->GetDBRequestKey();
     197           0 :     NextHopKey *nh_key2 = static_cast<NextHopKey *>(key2.release());
     198           0 :     std::unique_ptr<const NextHopKey> nh_akey2(nh_key2);
     199           0 :     nh_key2->SetPolicy(false);
     200           0 :     ComponentNHKeyPtr component_nh_data2(new ComponentNHKey(path2->label(),
     201           0 :                                                             std::move(nh_akey2)));
     202             : 
     203           0 :     ComponentNHKeyList component_nh_list;
     204           0 :     component_nh_list.push_back(component_nh_data2);
     205           0 :     component_nh_list.push_back(component_nh_data1);
     206             : 
     207             :     // Directly call AddChangePath to update NH in the ECMP path
     208             :     // It will also create CompositeNH if necessary
     209           0 :     DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
     210           0 :     nh_req.key.reset(new CompositeNHKey(Composite::LOCAL_ECMP,
     211             :                                         composite_nh_policy, component_nh_list,
     212           0 :                                         vrf_name_));
     213           0 :     nh_req.data.reset(new CompositeNHData());
     214           0 :     nh_req_.Swap(&nh_req);
     215             : 
     216           0 :     label_ = MplsTable::kInvalidLabel;
     217           0 :     ModifyEcmpPath();
     218             : 
     219           0 :     RouteInfo rt_info;
     220           0 :     rt->FillTrace(rt_info, AgentRoute::CHANGE_PATH, ecmp_path_);
     221           0 :     AgentRouteTable *table = static_cast<AgentRouteTable *>(rt->get_table());
     222           0 :     OPER_TRACE_ROUTE_ENTRY(Route, table, rt_info);
     223           0 :     AGENT_ROUTE_LOG(table, "Path Add", rt->ToString(), vrf_name_,
     224             :                     GETPEERNAME(agent_->ecmp_peer()));
     225           0 : }
     226             : 
     227           0 : void EcmpData::AppendEcmpPath(AgentRoute *rt, AgentPath *path) {
     228           0 :     assert(ecmp_path_);
     229           0 :     const NextHop* path_nh = path->ComputeNextHop(agent_);
     230           0 :     DBEntryBase::KeyPtr key = path_nh->GetDBRequestKey();
     231           0 :     NextHopKey *nh_key = static_cast<NextHopKey *>(key.release());
     232           0 :     std::unique_ptr<const NextHopKey> nh_akey(nh_key);
     233           0 :     nh_key->SetPolicy(false);
     234           0 :     ComponentNHKeyPtr comp_nh_key_ptr(new ComponentNHKey(path->label(), std::move(nh_akey)));
     235             : 
     236           0 :     ComponentNHKeyList component_nh_key_list;
     237             :     const CompositeNH *comp_nh =
     238           0 :         static_cast<const CompositeNH *>(ecmp_path_->ComputeNextHop(agent_));
     239           0 :     DBEntryBase::KeyPtr comp_nh_key = comp_nh->GetDBRequestKey();
     240           0 :     NextHopKey *cnh_key = static_cast<NextHopKey *>(comp_nh_key.get());
     241           0 :     bool composite_nh_policy = false;
     242           0 :     component_nh_key_list = comp_nh->AddComponentNHKey(comp_nh_key_ptr,
     243           0 :                                                        composite_nh_policy);
     244             :     // Form the request for Inet4UnicastEcmpRoute and invoke AddChangePath
     245             :     // Get the existing comp_nh key and do a resync
     246           0 :     DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
     247           0 :     cnh_key->sub_op_ = AgentKey::RESYNC;
     248             :     CompositeNHKey *composite_nh_key = new CompositeNHKey(Composite::LOCAL_ECMP,
     249             :                    composite_nh_policy,
     250             :                    component_nh_key_list,
     251           0 :                    vrf_name_);
     252           0 :     nh_req.key = std::move(comp_nh_key);
     253           0 :     nh_req.data.reset(new CompositeNHData(component_nh_key_list));
     254           0 :     nh_req_.Swap(&nh_req);
     255             : 
     256           0 :     label_ = ecmp_path_->label();
     257           0 :     ModifyEcmpPath(composite_nh_key);
     258           0 :     path->SyncRoute(true);
     259             : 
     260           0 :     RouteInfo rt_info;
     261           0 :     rt->FillTrace(rt_info, AgentRoute::CHANGE_PATH, path);
     262           0 :     AgentRouteTable *table = static_cast<AgentRouteTable *>(rt->get_table());
     263           0 :     OPER_TRACE_ROUTE_ENTRY(Route, table, rt_info);
     264           0 :     AGENT_ROUTE_LOG(table, "Path change", rt->ToString(), vrf_name_,
     265             :                     GETPEERNAME(agent_->ecmp_peer()));
     266           0 : }
     267             : 
     268             : // Handle deletion of a path in route. If the path being deleted is part of
     269             : // ECMP, then deletes the Component-NH for the path.
     270             : // Delete ECMP path if there is single Component-NH in Composite-NH
     271           0 : bool EcmpData::EcmpDeletePath(AgentRoute *rt) {
     272           0 :     if (path_->peer() == NULL) {
     273           0 :         return false;
     274             :     }
     275             : 
     276           0 :     if (path_->peer()->GetType() != Peer::LOCAL_VM_PORT_PEER) {
     277           0 :         return false;
     278             :     }
     279             : 
     280             :     // Composite-NH is made from LOCAL_VM_PORT_PEER, count number of paths
     281             :     // with LOCAL_VM_PORT_PEER
     282           0 :     int count = 0;
     283           0 :     for(Route::PathList::const_iterator it = rt->GetPathList().begin();
     284           0 :         it != rt->GetPathList().end(); it++) {
     285             :         const AgentPath *it_path =
     286           0 :             static_cast<const AgentPath *>(it.operator->());
     287             : 
     288           0 :         if (it_path->peer() &&
     289           0 :             it_path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER &&
     290           0 :             it_path->path_preference().is_ecmp() == true &&
     291           0 :             it_path != path_)
     292           0 :             count++;
     293             :     }
     294             : 
     295             :     // Sanity check. When more than one LOCAL_VM_PORT_PEER, ECMP must be present
     296           0 :     if (count >= 1) {
     297           0 :         if (ecmp_path_ == NULL) {
     298           0 :             return false;
     299             :         }
     300             :     }
     301             : 
     302           0 :     if (count == 1 && ecmp_path_) {
     303             :         // There is single path of type LOCAL_VM_PORT_PEER. Delete the ECMP path
     304           0 :         rt->RemovePath(ecmp_path_);
     305             :         //Enqueue MPLS label delete request
     306           0 :         agent_->mpls_table()->FreeLabel(ecmp_path_->label());
     307           0 :         delete ecmp_path_;
     308           0 :     } else if (count > 1) {
     309             :         // Remove Component-NH for the path being deleted
     310           0 :         DeleteComponentNH(rt, path_);
     311             :     }
     312             : 
     313           0 :     return true;
     314             : }
     315             : 
     316           0 : bool EcmpData::UpdateNh(CompositeNHKey *composite_nh_key) {
     317           0 :     NextHop *nh = NULL;
     318           0 :     bool ret = false;
     319             : 
     320           0 :     agent_->nexthop_table()->Process(nh_req_);
     321           0 :     NextHopKey *key = static_cast<NextHopKey *>(nh_req_.key.get());
     322             : 
     323             :     // Create MPLS label and point it to Composite NH
     324           0 :     if (alloc_label_) {
     325           0 :         label_ = agent_->mpls_table()->CreateRouteLabel(label_, key, vrf_name_,
     326           0 :                                                         route_str_);
     327             :     }
     328             : 
     329           0 :     if (composite_nh_key) {
     330           0 :         key = static_cast<NextHopKey *>(composite_nh_key);
     331             :     }
     332             : 
     333           0 :     nh = static_cast<NextHop *>(agent_->nexthop_table()->
     334           0 :                                 FindActiveEntry(key));
     335           0 :     if (nh == NULL) {
     336           0 :         VrfEntry *vrf = agent_->vrf_table()->FindVrfFromName(vrf_name_);
     337           0 :         if (vrf->IsDeleted())
     338           0 :             return ret;
     339           0 :         assert(0);
     340             :     }
     341             : 
     342           0 :     MplsLabel *mpls = agent_->mpls_table()->
     343           0 :              FindMplsLabel(label_);
     344           0 :     if (mpls && (ecmp_path_->local_ecmp_mpls_label() == NULL)) {
     345           0 :         ecmp_path_->set_local_ecmp_mpls_label(mpls);
     346             :     }
     347           0 :     if (ecmp_path_->ChangeNH(agent_, nh) == true)
     348           0 :         ret = true;
     349             : 
     350           0 :     return ret;
     351             : }
     352             : 
     353           0 : bool EcmpData::SyncParams() {
     354           0 :     bool ret = false;
     355             : 
     356           0 :     ecmp_path_->set_tunnel_bmap(tunnel_bmap_);
     357             :     TunnelType::Type new_tunnel_type =
     358           0 :         TunnelType::ComputeType(tunnel_bmap_);
     359           0 :     if (ecmp_path_->tunnel_type() != new_tunnel_type) {
     360           0 :         ecmp_path_->set_tunnel_type(new_tunnel_type);
     361           0 :         ret = true;
     362             :     }
     363             : 
     364           0 :     if (ecmp_path_->dest_vn_list() != vn_list_) {
     365           0 :         ecmp_path_->set_dest_vn_list(vn_list_);
     366           0 :         ret = true;
     367             :     }
     368             : 
     369           0 :     if (ecmp_path_->sg_list() != sg_list_) {
     370           0 :         ecmp_path_->set_sg_list(sg_list_);
     371           0 :         ret = true;
     372             :     }
     373             : 
     374           0 :     if (ecmp_path_->tag_list() != tag_list_) {
     375           0 :         ecmp_path_->set_tag_list(tag_list_);
     376           0 :         ret = true;
     377             :     }
     378             : 
     379           0 :     if (ecmp_path_->communities() != community_list_) {
     380           0 :         ecmp_path_->set_communities(community_list_);
     381           0 :         ret = true;
     382             :     }
     383             : 
     384           0 :     if (path_preference_ != ecmp_path_->path_preference()) {
     385           0 :         ecmp_path_->set_path_preference(path_preference_);
     386           0 :         ret = true;
     387             :     }
     388             : 
     389           0 :     if (ecmp_path_->ecmp_load_balance() != ecmp_load_balance_) {
     390           0 :         ecmp_path_->set_ecmp_load_balance(ecmp_load_balance_);
     391           0 :         ret = true;
     392             :     }
     393             : 
     394           0 :     return ret;
     395             : }
     396             : 
     397           0 : bool EcmpData::ModifyEcmpPath(CompositeNHKey *composite_nh_key) {
     398           0 :     bool ret = false;
     399             : 
     400           0 :     if (UpdateNh(composite_nh_key)) {
     401           0 :         ret = true;
     402             :     }
     403             : 
     404           0 :     if (ecmp_path_->label() != label_) {
     405           0 :         ecmp_path_->set_label(label_);
     406           0 :         ret = true;
     407             :     }
     408             : 
     409           0 :     if (SyncParams()) {
     410           0 :         ret = true;
     411             :     }
     412             : 
     413           0 :     ecmp_path_->set_unresolved(false);
     414           0 :     ret = true;
     415             : 
     416           0 :     return ret;
     417             : }
     418             : 
     419             : /* When label of VMI changes and if that VMI (ie VMI's InterfaceNH) is part of
     420             :  * ECMP, then update the CompositeNH for ECMP route to point to right label for
     421             :  * that VMI. Label of VMI can change when policy-status of VMI changes */
     422           0 : bool EcmpData::UpdateComponentNH(AgentRoute *rt, AgentPath *path) {
     423           0 :     if (!ecmp_path_) {
     424           0 :         return false;
     425             :     }
     426             :     //Build ComponentNHKey for new path
     427           0 :     const NextHop* path_nh = path->ComputeNextHop(agent_);
     428           0 :     DBEntryBase::KeyPtr key = path_nh->GetDBRequestKey();
     429           0 :     NextHopKey *nh_key = static_cast<NextHopKey *>(key.get());
     430           0 :     nh_key->SetPolicy(false);
     431             : 
     432           0 :     ComponentNHKeyList component_nh_key_list;
     433             :     const CompositeNH *comp_nh =
     434           0 :         static_cast<const CompositeNH *>(ecmp_path_->ComputeNextHop(agent_));
     435           0 :     bool composite_nh_policy = false;
     436           0 :     bool updated = comp_nh->UpdateComponentNHKey(path->label(), nh_key,
     437             :                                                  component_nh_key_list,
     438             :                                                  composite_nh_policy);
     439             : 
     440           0 :     if (!updated) {
     441           0 :         return false;
     442             :     }
     443             :     // Form the request for Inet4UnicastEcmpRoute and invoke AddChangePath
     444           0 :     DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
     445           0 :     nh_req.key.reset(new CompositeNHKey(Composite::LOCAL_ECMP,
     446             :                                         composite_nh_policy,
     447             :                                         component_nh_key_list,
     448           0 :                                         vrf_name_));
     449           0 :     nh_req.data.reset(new CompositeNHData());
     450           0 :     nh_req_.Swap(&nh_req);
     451           0 :     label_ = ecmp_path_->label();
     452           0 :     ModifyEcmpPath();
     453             : 
     454           0 :     RouteInfo rt_info;
     455           0 :     rt->FillTrace(rt_info, AgentRoute::CHANGE_PATH, path);
     456           0 :     AgentRouteTable *table = static_cast<AgentRouteTable *>(rt->get_table());
     457           0 :     OPER_TRACE_ROUTE_ENTRY(Route, table, rt_info);
     458           0 :     AGENT_ROUTE_LOG(table, "Path Update", rt->ToString(), vrf_name_,
     459             :                     GETPEERNAME(agent_->ecmp_peer()));
     460           0 :     return true;
     461           0 : }
     462             : 
     463           0 : void EcmpData::DeleteComponentNH(AgentRoute *rt, AgentPath *path) {
     464           0 :     assert(ecmp_path_);
     465           0 :     DBEntryBase::KeyPtr key = path->ComputeNextHop(agent_)->GetDBRequestKey();
     466           0 :     NextHopKey *nh_key = static_cast<NextHopKey *>(key.release());
     467           0 :     std::unique_ptr<const NextHopKey> nh_akey(nh_key);
     468           0 :     nh_key->SetPolicy(false);
     469           0 :     ComponentNHKeyPtr comp_nh_key_ptr(new ComponentNHKey(path->label(), std::move(nh_akey)));
     470             : 
     471           0 :     ComponentNHKeyList component_nh_key_list;
     472           0 :     bool comp_nh_policy = false;
     473             :     const CompositeNH *comp_nh =
     474           0 :         static_cast<const CompositeNH *>(ecmp_path_->ComputeNextHop(agent_));
     475           0 :     component_nh_key_list = comp_nh->DeleteComponentNHKey(comp_nh_key_ptr,
     476           0 :                                                           comp_nh_policy);
     477             : 
     478             :     // Form the request for Inet4UnicastEcmpRoute and invoke AddChangePath
     479           0 :     DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
     480           0 :     nh_req.key.reset(new CompositeNHKey(Composite::LOCAL_ECMP,
     481             :                                         comp_nh_policy, component_nh_key_list,
     482           0 :                                         vrf_name_));
     483           0 :     nh_req.data.reset(new CompositeNHData());
     484           0 :     nh_req_.Swap(&nh_req);
     485           0 :     label_ = ecmp_path_->label();
     486           0 :     UpdateNh();
     487             : 
     488           0 :     RouteInfo rt_info;
     489           0 :     rt->FillTrace(rt_info, AgentRoute::CHANGE_PATH, path);
     490           0 :     AgentRouteTable *table = static_cast<AgentRouteTable *>(rt->get_table());
     491           0 :     OPER_TRACE_ROUTE_ENTRY(Route, table, rt_info);
     492           0 :     AGENT_ROUTE_LOG(table, "Path change", rt->ToString(), vrf_name_,
     493             :                     GETPEERNAME(agent_->ecmp_peer()));
     494           0 : }
     495             : 
     496           0 : const NextHop* EcmpData::GetLocalNextHop(const AgentRoute *rt) {
     497             :     Agent *agent =
     498           0 :         (static_cast<InetUnicastAgentRouteTable *> (rt->get_table()))->agent();
     499             : 
     500           0 :     if (rt->FindPath(agent->ecmp_peer())) {
     501           0 :         return rt->FindPath(agent->ecmp_peer())->ComputeNextHop(agent);
     502             :     }
     503             : 
     504             :     //If a route is leaked, and it points to local composite nexthop
     505             :     //then choose that
     506           0 :     if (rt->GetActivePath()->local_ecmp_mpls_label()) {
     507           0 :         return rt->GetActivePath()->local_ecmp_mpls_label()->nexthop();
     508             :     }
     509             : 
     510             :     //Choose the first local vm peer path
     511           0 :     for (Route::PathList::const_iterator it = rt->GetPathList().begin();
     512           0 :             it != rt->GetPathList().end(); it++) {
     513           0 :         const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
     514           0 :         if (path) {
     515           0 :             if (path->peer() &&
     516           0 :                 path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER) {
     517           0 :                 return path->ComputeNextHop(agent);
     518             :             }
     519             :         }
     520             :     }
     521             : 
     522           0 :     const NextHop *nh = rt->GetActiveNextHop();
     523           0 :     if (nh && nh->GetType() == NextHop::COMPOSITE ) {
     524           0 :         const CompositeNH *comp_nh = static_cast<const CompositeNH *>(nh);
     525             :         //Get the local composite NH
     526           0 :         return comp_nh->GetLocalNextHop();
     527             :     }
     528           0 :     return NULL;
     529             : }

Generated by: LCOV version 1.14