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: 208 307 67.8 %
Date: 2026-06-04 02:06:09 Functions: 13 15 86.7 %
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         549 : EcmpData::EcmpData(Agent *agent,
      27             :                    const string &vrf_name,
      28             :                    const string &route_str,
      29             :                    AgentPath *path,
      30         549 :                    bool del) :
      31         549 :     path_(path), ecmp_path_(NULL), delete_(del),
      32         549 :     alloc_label_(true), label_(MplsTable::kInvalidLabel),
      33         549 :     vrf_name_(vrf_name), route_str_(route_str),
      34         549 :     vn_list_(path->dest_vn_list()),
      35         549 :     sg_list_(path->sg_list()),
      36         549 :     tag_list_(path->tag_list()),
      37         549 :     community_list_(path->communities()),
      38         549 :     path_preference_(path->path_preference()),
      39         549 :     tunnel_bmap_(path->tunnel_bmap()),
      40         549 :     ecmp_load_balance_(path->ecmp_load_balance()),
      41        1098 :     nh_req_(), agent_(agent) {
      42         549 : }
      43             : 
      44         549 : bool EcmpData::Update(AgentRoute *rt) {
      45         549 :     if (path_->peer() == NULL) {
      46           0 :         return false;
      47             :     }
      48             : 
      49         549 :     if (path_->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER) {
      50          77 :         return LocalVmPortPeerEcmp(rt);
      51             :     }
      52             : 
      53         472 :     if (path_->peer()->GetType() == Peer::BGP_PEER) {
      54           9 :         alloc_label_ = false;
      55           9 :         return BgpPeerEcmp();
      56             :     }
      57             : 
      58         463 :     return false;
      59             : }
      60             : 
      61           1 : 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           1 :     sg_list_ = sg_list;
      70           1 :     vn_list_ = vn_list;
      71           1 :     tag_list_ = tag_list;
      72           1 :     community_list_ = community_list;
      73           1 :     path_preference_ = path_preference;
      74           1 :     tunnel_bmap_ = bmap;
      75           1 :     ecmp_load_balance_ = ecmp_load_balance;
      76           1 :     nh_req_.Swap(&nh_req);
      77             : 
      78           1 :     return Update(NULL);
      79             : }
      80             : 
      81          77 : bool EcmpData::LocalVmPortPeerEcmp(AgentRoute *rt) {
      82          77 :     ecmp_path_ = rt->FindPath(agent_->ecmp_peer());
      83          77 :     if (delete_) {
      84          29 :         return EcmpDeletePath(rt);
      85             :     } else {
      86          48 :         if (path_->path_preference().is_ecmp() == false) {
      87          44 :             return false;
      88             :         }
      89           4 :         return EcmpAddPath(rt);
      90             :     }
      91             : }
      92             : 
      93           9 : bool EcmpData::BgpPeerEcmp() {
      94           9 :     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           9 :     NextHopKey *key = static_cast<NextHopKey *>(nh_req_.key.get());
      98           9 :     if (!key)
      99           8 :         return false;
     100           1 :     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           4 : bool EcmpData::EcmpAddPath(AgentRoute *rt) {
     107           4 :     if (path_->tunnel_bmap() & TunnelType::NativeType()) {
     108           0 :         path_->set_tunnel_bmap(TunnelType::MplsType() |
     109           0 :                                TunnelType::NativeType());
     110             :     } else {
     111           4 :         path_->set_tunnel_bmap(TunnelType::MplsType());
     112             :     }
     113             : 
     114             :     // Count number of paths from LOCAL_VM_PORT_PEER already present
     115           4 :     const AgentPath *vm_port_path = NULL;
     116           4 :     int count = 0;
     117          19 :     for(Route::PathList::const_iterator it = rt->GetPathList().begin();
     118          30 :         it != rt->GetPathList().end(); it++) {
     119             :         const AgentPath *it_path =
     120          11 :             static_cast<const AgentPath *>(it.operator->());
     121             : 
     122          11 :         if (it_path->peer() == agent_->ecmp_peer())
     123           1 :             assert(ecmp_path_ == it_path);
     124             : 
     125          22 :         if (it_path->peer() &&
     126          22 :             it_path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER &&
     127           6 :             it_path->path_preference().is_ecmp() == true) {
     128           6 :             count++;
     129           6 :             if (it_path != path_)
     130           2 :                 vm_port_path = it_path;
     131             :         }
     132             :     }
     133             : 
     134           4 :     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           4 :     if (count > 2) {
     140           0 :         assert(ecmp_path_ != NULL);
     141             :     }
     142             : 
     143           4 :     if (count == 1) {
     144           2 :         assert(ecmp_path_ == NULL);
     145           2 :         return false;
     146             :     }
     147             : 
     148           2 :     bool ret = false;
     149           2 :     if (count == 2 && ecmp_path_ == NULL) {
     150             :         // This is second path being added, make ECMP
     151           1 :         AllocateEcmpPath(rt, vm_port_path);
     152           1 :         ret = true;
     153           1 :     } 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           1 :     } else if (ecmp_path_) {
     158           1 :         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           1 :         if (!updated) {
     163           1 :             updated = SyncParams();
     164             :         }
     165           1 :         if (updated) {
     166           1 :             ret = true;
     167             :         }
     168             :     }
     169             : 
     170           2 :     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           1 : void EcmpData::AllocateEcmpPath(AgentRoute *rt, const AgentPath *path2) {
     177             :     // Allocate and insert a path
     178           1 :     ecmp_path_ = new AgentPath(agent_->ecmp_peer(), rt);
     179           1 :     rt->InsertPath(ecmp_path_);
     180             : 
     181           1 :     const NextHop* path1_nh = path_->ComputeNextHop(agent_);
     182           1 :     bool composite_nh_policy = path1_nh->NexthopToInterfacePolicy();
     183             : 
     184             :     // Create Component NH to be added to ECMP path
     185           1 :     DBEntryBase::KeyPtr key1 = path1_nh->GetDBRequestKey();
     186           1 :     NextHopKey *nh_key1 = static_cast<NextHopKey *>(key1.release());
     187           1 :     std::unique_ptr<const NextHopKey> nh_akey1(nh_key1);
     188           1 :     nh_key1->SetPolicy(false);
     189           1 :     ComponentNHKeyPtr component_nh_data1(new ComponentNHKey(path_->label(),
     190           1 :                                                             std::move(nh_akey1)));
     191             : 
     192           1 :     const NextHop* path2_nh = path2->ComputeNextHop(agent_);
     193           1 :     if (!composite_nh_policy) {
     194           0 :         composite_nh_policy = path2_nh->NexthopToInterfacePolicy();
     195             :     }
     196           1 :     DBEntryBase::KeyPtr key2 = path2_nh->GetDBRequestKey();
     197           1 :     NextHopKey *nh_key2 = static_cast<NextHopKey *>(key2.release());
     198           1 :     std::unique_ptr<const NextHopKey> nh_akey2(nh_key2);
     199           1 :     nh_key2->SetPolicy(false);
     200           1 :     ComponentNHKeyPtr component_nh_data2(new ComponentNHKey(path2->label(),
     201           1 :                                                             std::move(nh_akey2)));
     202             : 
     203           1 :     ComponentNHKeyList component_nh_list;
     204           1 :     component_nh_list.push_back(component_nh_data2);
     205           1 :     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           1 :     DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
     210           1 :     nh_req.key.reset(new CompositeNHKey(Composite::LOCAL_ECMP,
     211             :                                         composite_nh_policy, component_nh_list,
     212           1 :                                         vrf_name_));
     213           1 :     nh_req.data.reset(new CompositeNHData());
     214           1 :     nh_req_.Swap(&nh_req);
     215             : 
     216           1 :     label_ = MplsTable::kInvalidLabel;
     217           1 :     ModifyEcmpPath();
     218             : 
     219           1 :     RouteInfo rt_info;
     220           1 :     rt->FillTrace(rt_info, AgentRoute::CHANGE_PATH, ecmp_path_);
     221           1 :     AgentRouteTable *table = static_cast<AgentRouteTable *>(rt->get_table());
     222           1 :     OPER_TRACE_ROUTE_ENTRY(Route, table, rt_info);
     223           1 :     AGENT_ROUTE_LOG(table, "Path Add", rt->ToString(), vrf_name_,
     224             :                     GETPEERNAME(agent_->ecmp_peer()));
     225           1 : }
     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          29 : bool EcmpData::EcmpDeletePath(AgentRoute *rt) {
     272          29 :     if (path_->peer() == NULL) {
     273           0 :         return false;
     274             :     }
     275             : 
     276          29 :     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          29 :     int count = 0;
     283          93 :     for(Route::PathList::const_iterator it = rt->GetPathList().begin();
     284         128 :         it != rt->GetPathList().end(); it++) {
     285             :         const AgentPath *it_path =
     286          35 :             static_cast<const AgentPath *>(it.operator->());
     287             : 
     288          70 :         if (it_path->peer() &&
     289          35 :             it_path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER &&
     290          73 :             it_path->path_preference().is_ecmp() == true &&
     291           3 :             it_path != path_)
     292           1 :             count++;
     293             :     }
     294             : 
     295             :     // Sanity check. When more than one LOCAL_VM_PORT_PEER, ECMP must be present
     296          29 :     if (count >= 1) {
     297           1 :         if (ecmp_path_ == NULL) {
     298           0 :             return false;
     299             :         }
     300             :     }
     301             : 
     302          29 :     if (count == 1 && ecmp_path_) {
     303             :         // There is single path of type LOCAL_VM_PORT_PEER. Delete the ECMP path
     304           1 :         rt->RemovePath(ecmp_path_);
     305             :         //Enqueue MPLS label delete request
     306           1 :         agent_->mpls_table()->FreeLabel(ecmp_path_->label());
     307           1 :         delete ecmp_path_;
     308          28 :     } else if (count > 1) {
     309             :         // Remove Component-NH for the path being deleted
     310           0 :         DeleteComponentNH(rt, path_);
     311             :     }
     312             : 
     313          29 :     return true;
     314             : }
     315             : 
     316           2 : bool EcmpData::UpdateNh(CompositeNHKey *composite_nh_key) {
     317           2 :     NextHop *nh = NULL;
     318           2 :     bool ret = false;
     319             : 
     320           2 :     agent_->nexthop_table()->Process(nh_req_);
     321           2 :     NextHopKey *key = static_cast<NextHopKey *>(nh_req_.key.get());
     322             : 
     323             :     // Create MPLS label and point it to Composite NH
     324           2 :     if (alloc_label_) {
     325           2 :         label_ = agent_->mpls_table()->CreateRouteLabel(label_, key, vrf_name_,
     326           1 :                                                         route_str_);
     327             :     }
     328             : 
     329           2 :     if (composite_nh_key) {
     330           0 :         key = static_cast<NextHopKey *>(composite_nh_key);
     331             :     }
     332             : 
     333           4 :     nh = static_cast<NextHop *>(agent_->nexthop_table()->
     334           2 :                                 FindActiveEntry(key));
     335           2 :     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           2 :     MplsLabel *mpls = agent_->mpls_table()->
     343           2 :              FindMplsLabel(label_);
     344           2 :     if (mpls && (ecmp_path_->local_ecmp_mpls_label() == NULL)) {
     345           1 :         ecmp_path_->set_local_ecmp_mpls_label(mpls);
     346             :     }
     347           2 :     if (ecmp_path_->ChangeNH(agent_, nh) == true)
     348           2 :         ret = true;
     349             : 
     350           2 :     return ret;
     351             : }
     352             : 
     353           3 : bool EcmpData::SyncParams() {
     354           3 :     bool ret = false;
     355             : 
     356           3 :     ecmp_path_->set_tunnel_bmap(tunnel_bmap_);
     357             :     TunnelType::Type new_tunnel_type =
     358           3 :         TunnelType::ComputeType(tunnel_bmap_);
     359           3 :     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           3 :     if (ecmp_path_->dest_vn_list() != vn_list_) {
     365           2 :         ecmp_path_->set_dest_vn_list(vn_list_);
     366           2 :         ret = true;
     367             :     }
     368             : 
     369           3 :     if (ecmp_path_->sg_list() != sg_list_) {
     370           0 :         ecmp_path_->set_sg_list(sg_list_);
     371           0 :         ret = true;
     372             :     }
     373             : 
     374           3 :     if (ecmp_path_->tag_list() != tag_list_) {
     375           0 :         ecmp_path_->set_tag_list(tag_list_);
     376           0 :         ret = true;
     377             :     }
     378             : 
     379           3 :     if (ecmp_path_->communities() != community_list_) {
     380           0 :         ecmp_path_->set_communities(community_list_);
     381           0 :         ret = true;
     382             :     }
     383             : 
     384           3 :     if (path_preference_ != ecmp_path_->path_preference()) {
     385           2 :         ecmp_path_->set_path_preference(path_preference_);
     386           2 :         ret = true;
     387             :     }
     388             : 
     389           3 :     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           3 :     return ret;
     395             : }
     396             : 
     397           2 : bool EcmpData::ModifyEcmpPath(CompositeNHKey *composite_nh_key) {
     398           2 :     bool ret = false;
     399             : 
     400           2 :     if (UpdateNh(composite_nh_key)) {
     401           2 :         ret = true;
     402             :     }
     403             : 
     404           2 :     if (ecmp_path_->label() != label_) {
     405           1 :         ecmp_path_->set_label(label_);
     406           1 :         ret = true;
     407             :     }
     408             : 
     409           2 :     if (SyncParams()) {
     410           2 :         ret = true;
     411             :     }
     412             : 
     413           2 :     ecmp_path_->set_unresolved(false);
     414           2 :     ret = true;
     415             : 
     416           2 :     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           1 : bool EcmpData::UpdateComponentNH(AgentRoute *rt, AgentPath *path) {
     423           1 :     if (!ecmp_path_) {
     424           0 :         return false;
     425             :     }
     426             :     //Build ComponentNHKey for new path
     427           1 :     const NextHop* path_nh = path->ComputeNextHop(agent_);
     428           1 :     DBEntryBase::KeyPtr key = path_nh->GetDBRequestKey();
     429           1 :     NextHopKey *nh_key = static_cast<NextHopKey *>(key.get());
     430           1 :     nh_key->SetPolicy(false);
     431             : 
     432           1 :     ComponentNHKeyList component_nh_key_list;
     433             :     const CompositeNH *comp_nh =
     434           1 :         static_cast<const CompositeNH *>(ecmp_path_->ComputeNextHop(agent_));
     435           1 :     bool composite_nh_policy = false;
     436           1 :     bool updated = comp_nh->UpdateComponentNHKey(path->label(), nh_key,
     437             :                                                  component_nh_key_list,
     438             :                                                  composite_nh_policy);
     439             : 
     440           1 :     if (!updated) {
     441           1 :         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           1 : }
     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           9 : const NextHop* EcmpData::GetLocalNextHop(const AgentRoute *rt) {
     497             :     Agent *agent =
     498           9 :         (static_cast<InetUnicastAgentRouteTable *> (rt->get_table()))->agent();
     499             : 
     500           9 :     if (rt->FindPath(agent->ecmp_peer())) {
     501           4 :         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           5 :     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          12 :     for (Route::PathList::const_iterator it = rt->GetPathList().begin();
     512          24 :             it != rt->GetPathList().end(); it++) {
     513           7 :         const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
     514           7 :         if (path) {
     515          14 :             if (path->peer() &&
     516           7 :                 path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER) {
     517           0 :                 return path->ComputeNextHop(agent);
     518             :             }
     519             :         }
     520             :     }
     521             : 
     522           5 :     const NextHop *nh = rt->GetActiveNextHop();
     523           5 :     if (nh && nh->GetType() == NextHop::COMPOSITE ) {
     524           5 :         const CompositeNH *comp_nh = static_cast<const CompositeNH *>(nh);
     525             :         //Get the local composite NH
     526           5 :         return comp_nh->GetLocalNextHop();
     527             :     }
     528           0 :     return NULL;
     529             : }

Generated by: LCOV version 1.14