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: 269 307 87.6 %
Date: 2026-11-09 02:10:49 Functions: 15 15 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14