LCOV - code coverage report
Current view: top level - oper - ecmp.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 269 307 87.6 %
Date: 2026-08-04 16:13:09 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             :  */
       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        2510 : EcmpData::EcmpData(Agent *agent,
      27             :                    const string &vrf_name,
      28             :                    const string &route_str,
      29             :                    AgentPath *path,
      30        2510 :                    bool del) :
      31        2510 :     path_(path), ecmp_path_(NULL), delete_(del),
      32        2510 :     alloc_label_(true), label_(MplsTable::kInvalidLabel),
      33        2510 :     vrf_name_(vrf_name), route_str_(route_str),
      34        2510 :     vn_list_(path->dest_vn_list()),
      35        2510 :     sg_list_(path->sg_list()),
      36        2510 :     tag_list_(path->tag_list()),
      37        2510 :     community_list_(path->communities()),
      38        2510 :     path_preference_(path->path_preference()),
      39        2510 :     tunnel_bmap_(path->tunnel_bmap()),
      40        2510 :     ecmp_load_balance_(path->ecmp_load_balance()),
      41        5020 :     nh_req_(), agent_(agent) {
      42        2510 : }
      43             : 
      44        2510 : bool EcmpData::Update(AgentRoute *rt) {
      45        2510 :     if (path_->peer() == NULL) {
      46           0 :         return false;
      47             :     }
      48             : 
      49        2510 :     if (path_->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER) {
      50         793 :         return LocalVmPortPeerEcmp(rt);
      51             :     }
      52             : 
      53        1717 :     if (path_->peer()->GetType() == Peer::BGP_PEER) {
      54         160 :         alloc_label_ = false;
      55         160 :         return BgpPeerEcmp();
      56             :     }
      57             : 
      58        1557 :     return false;
      59             : }
      60             : 
      61          32 : 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          32 :     sg_list_ = sg_list;
      70          32 :     vn_list_ = vn_list;
      71          32 :     tag_list_ = tag_list;
      72          32 :     community_list_ = community_list;
      73          32 :     path_preference_ = path_preference;
      74          32 :     tunnel_bmap_ = bmap;
      75          32 :     ecmp_load_balance_ = ecmp_load_balance;
      76          32 :     nh_req_.Swap(&nh_req);
      77             : 
      78          32 :     return Update(NULL);
      79             : }
      80             : 
      81         793 : bool EcmpData::LocalVmPortPeerEcmp(AgentRoute *rt) {
      82         793 :     ecmp_path_ = rt->FindPath(agent_->ecmp_peer());
      83         793 :     if (delete_) {
      84         182 :         return EcmpDeletePath(rt);
      85             :     } else {
      86         611 :         if (path_->path_preference().is_ecmp() == false) {
      87         104 :             return false;
      88             :         }
      89         507 :         return EcmpAddPath(rt);
      90             :     }
      91             : }
      92             : 
      93         160 : bool EcmpData::BgpPeerEcmp() {
      94         160 :     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         160 :     NextHopKey *key = static_cast<NextHopKey *>(nh_req_.key.get());
      98         160 :     if (!key)
      99         128 :         return false;
     100          32 :     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         507 : bool EcmpData::EcmpAddPath(AgentRoute *rt) {
     107         507 :     if (path_->tunnel_bmap() & TunnelType::NativeType()) {
     108           0 :         path_->set_tunnel_bmap(TunnelType::MplsType() |
     109           0 :                                TunnelType::NativeType());
     110             :     } else {
     111         507 :         path_->set_tunnel_bmap(TunnelType::MplsType());
     112             :     }
     113             : 
     114             :     // Count number of paths from LOCAL_VM_PORT_PEER already present
     115         507 :     const AgentPath *vm_port_path = NULL;
     116         507 :     int count = 0;
     117        3966 :     for(Route::PathList::const_iterator it = rt->GetPathList().begin();
     118        6918 :         it != rt->GetPathList().end(); it++) {
     119             :         const AgentPath *it_path =
     120        2952 :             static_cast<const AgentPath *>(it.operator->());
     121             : 
     122        2952 :         if (it_path->peer() == agent_->ecmp_peer())
     123         393 :             assert(ecmp_path_ == it_path);
     124             : 
     125        5904 :         if (it_path->peer() &&
     126        5904 :             it_path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER &&
     127        1339 :             it_path->path_preference().is_ecmp() == true) {
     128        1334 :             count++;
     129        1334 :             if (it_path != path_)
     130         827 :                 vm_port_path = it_path;
     131             :         }
     132             :     }
     133             : 
     134         507 :     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         507 :     if (count > 2) {
     140         384 :         assert(ecmp_path_ != NULL);
     141             :     }
     142             : 
     143         507 :     if (count == 1) {
     144          66 :         assert(ecmp_path_ == NULL);
     145          66 :         return false;
     146             :     }
     147             : 
     148         441 :     bool ret = false;
     149         441 :     if (count == 2 && ecmp_path_ == NULL) {
     150             :         // This is second path being added, make ECMP
     151          48 :         AllocateEcmpPath(rt, vm_port_path);
     152          48 :         ret = true;
     153         393 :     } else if (count > 2) {
     154             :         // ECMP already present, add/update Component-NH for the path
     155         384 :         AppendEcmpPath(rt, path_);
     156         384 :         ret = true;
     157           9 :     } else if (ecmp_path_) {
     158           9 :         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           9 :         if (!updated) {
     163           9 :             updated = SyncParams();
     164             :         }
     165           9 :         if (updated) {
     166           6 :             ret = true;
     167             :         }
     168             :     }
     169             : 
     170         441 :     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          48 : void EcmpData::AllocateEcmpPath(AgentRoute *rt, const AgentPath *path2) {
     177             :     // Allocate and insert a path
     178          48 :     ecmp_path_ = new AgentPath(agent_->ecmp_peer(), rt);
     179          48 :     rt->InsertPath(ecmp_path_);
     180             : 
     181          48 :     const NextHop* path1_nh = path_->ComputeNextHop(agent_);
     182          48 :     bool composite_nh_policy = path1_nh->NexthopToInterfacePolicy();
     183             : 
     184             :     // Create Component NH to be added to ECMP path
     185          48 :     DBEntryBase::KeyPtr key1 = path1_nh->GetDBRequestKey();
     186          48 :     NextHopKey *nh_key1 = static_cast<NextHopKey *>(key1.release());
     187          48 :     std::unique_ptr<const NextHopKey> nh_akey1(nh_key1);
     188          48 :     nh_key1->SetPolicy(false);
     189          48 :     ComponentNHKeyPtr component_nh_data1(new ComponentNHKey(path_->label(),
     190          48 :                                                             std::move(nh_akey1)));
     191             : 
     192          48 :     const NextHop* path2_nh = path2->ComputeNextHop(agent_);
     193          48 :     if (!composite_nh_policy) {
     194           0 :         composite_nh_policy = path2_nh->NexthopToInterfacePolicy();
     195             :     }
     196          48 :     DBEntryBase::KeyPtr key2 = path2_nh->GetDBRequestKey();
     197          48 :     NextHopKey *nh_key2 = static_cast<NextHopKey *>(key2.release());
     198          48 :     std::unique_ptr<const NextHopKey> nh_akey2(nh_key2);
     199          48 :     nh_key2->SetPolicy(false);
     200          48 :     ComponentNHKeyPtr component_nh_data2(new ComponentNHKey(path2->label(),
     201          48 :                                                             std::move(nh_akey2)));
     202             : 
     203          48 :     ComponentNHKeyList component_nh_list;
     204          48 :     component_nh_list.push_back(component_nh_data2);
     205          48 :     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          48 :     DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
     210          48 :     nh_req.key.reset(new CompositeNHKey(Composite::LOCAL_ECMP,
     211             :                                         composite_nh_policy, component_nh_list,
     212          48 :                                         vrf_name_));
     213          48 :     nh_req.data.reset(new CompositeNHData());
     214          48 :     nh_req_.Swap(&nh_req);
     215             : 
     216          48 :     label_ = MplsTable::kInvalidLabel;
     217          48 :     ModifyEcmpPath();
     218             : 
     219          48 :     RouteInfo rt_info;
     220          48 :     rt->FillTrace(rt_info, AgentRoute::CHANGE_PATH, ecmp_path_);
     221          48 :     AgentRouteTable *table = static_cast<AgentRouteTable *>(rt->get_table());
     222          48 :     OPER_TRACE_ROUTE_ENTRY(Route, table, rt_info);
     223          48 :     AGENT_ROUTE_LOG(table, "Path Add", rt->ToString(), vrf_name_,
     224             :                     GETPEERNAME(agent_->ecmp_peer()));
     225          48 : }
     226             : 
     227         384 : void EcmpData::AppendEcmpPath(AgentRoute *rt, AgentPath *path) {
     228         384 :     assert(ecmp_path_);
     229         384 :     const NextHop* path_nh = path->ComputeNextHop(agent_);
     230         384 :     DBEntryBase::KeyPtr key = path_nh->GetDBRequestKey();
     231         384 :     NextHopKey *nh_key = static_cast<NextHopKey *>(key.release());
     232         384 :     std::unique_ptr<const NextHopKey> nh_akey(nh_key);
     233         384 :     nh_key->SetPolicy(false);
     234         384 :     ComponentNHKeyPtr comp_nh_key_ptr(new ComponentNHKey(path->label(), std::move(nh_akey)));
     235             : 
     236         384 :     ComponentNHKeyList component_nh_key_list;
     237             :     const CompositeNH *comp_nh =
     238         384 :         static_cast<const CompositeNH *>(ecmp_path_->ComputeNextHop(agent_));
     239         384 :     DBEntryBase::KeyPtr comp_nh_key = comp_nh->GetDBRequestKey();
     240         384 :     NextHopKey *cnh_key = static_cast<NextHopKey *>(comp_nh_key.get());
     241         384 :     bool composite_nh_policy = false;
     242         768 :     component_nh_key_list = comp_nh->AddComponentNHKey(comp_nh_key_ptr,
     243         384 :                                                        composite_nh_policy);
     244             :     // Form the request for Inet4UnicastEcmpRoute and invoke AddChangePath
     245             :     // Get the existing comp_nh key and do a resync
     246         384 :     DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
     247         384 :     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         384 :                    vrf_name_);
     252         384 :     nh_req.key = std::move(comp_nh_key);
     253         384 :     nh_req.data.reset(new CompositeNHData(component_nh_key_list));
     254         384 :     nh_req_.Swap(&nh_req);
     255             : 
     256         384 :     label_ = ecmp_path_->label();
     257         384 :     ModifyEcmpPath(composite_nh_key);
     258         384 :     path->SyncRoute(true);
     259             : 
     260         384 :     RouteInfo rt_info;
     261         384 :     rt->FillTrace(rt_info, AgentRoute::CHANGE_PATH, path);
     262         384 :     AgentRouteTable *table = static_cast<AgentRouteTable *>(rt->get_table());
     263         384 :     OPER_TRACE_ROUTE_ENTRY(Route, table, rt_info);
     264         384 :     AGENT_ROUTE_LOG(table, "Path change", rt->ToString(), vrf_name_,
     265             :                     GETPEERNAME(agent_->ecmp_peer()));
     266         384 : }
     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         182 : bool EcmpData::EcmpDeletePath(AgentRoute *rt) {
     272         182 :     if (path_->peer() == NULL) {
     273           0 :         return false;
     274             :     }
     275             : 
     276         182 :     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         182 :     int count = 0;
     283         939 :     for(Route::PathList::const_iterator it = rt->GetPathList().begin();
     284        1514 :         it != rt->GetPathList().end(); it++) {
     285             :         const AgentPath *it_path =
     286         575 :             static_cast<const AgentPath *>(it.operator->());
     287             : 
     288        1150 :         if (it_path->peer() &&
     289         575 :             it_path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER &&
     290        1440 :             it_path->path_preference().is_ecmp() == true &&
     291         290 :             it_path != path_)
     292         147 :             count++;
     293             :     }
     294             : 
     295             :     // Sanity check. When more than one LOCAL_VM_PORT_PEER, ECMP must be present
     296         182 :     if (count >= 1) {
     297          97 :         if (ecmp_path_ == NULL) {
     298           0 :             return false;
     299             :         }
     300             :     }
     301             : 
     302         182 :     if (count == 1 && ecmp_path_) {
     303             :         // There is single path of type LOCAL_VM_PORT_PEER. Delete the ECMP path
     304          48 :         rt->RemovePath(ecmp_path_);
     305             :         //Enqueue MPLS label delete request
     306          48 :         agent_->mpls_table()->FreeLabel(ecmp_path_->label());
     307          48 :         delete ecmp_path_;
     308         134 :     } else if (count > 1) {
     309             :         // Remove Component-NH for the path being deleted
     310          49 :         DeleteComponentNH(rt, path_);
     311             :     }
     312             : 
     313         182 :     return true;
     314             : }
     315             : 
     316         513 : bool EcmpData::UpdateNh(CompositeNHKey *composite_nh_key) {
     317         513 :     NextHop *nh = NULL;
     318         513 :     bool ret = false;
     319             : 
     320         513 :     agent_->nexthop_table()->Process(nh_req_);
     321         513 :     NextHopKey *key = static_cast<NextHopKey *>(nh_req_.key.get());
     322             : 
     323             :     // Create MPLS label and point it to Composite NH
     324         513 :     if (alloc_label_) {
     325         962 :         label_ = agent_->mpls_table()->CreateRouteLabel(label_, key, vrf_name_,
     326         481 :                                                         route_str_);
     327             :     }
     328             : 
     329         513 :     if (composite_nh_key) {
     330         384 :         key = static_cast<NextHopKey *>(composite_nh_key);
     331             :     }
     332             : 
     333        1026 :     nh = static_cast<NextHop *>(agent_->nexthop_table()->
     334         513 :                                 FindActiveEntry(key));
     335         513 :     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         513 :     MplsLabel *mpls = agent_->mpls_table()->
     343         513 :              FindMplsLabel(label_);
     344         513 :     if (mpls && (ecmp_path_->local_ecmp_mpls_label() == NULL)) {
     345          48 :         ecmp_path_->set_local_ecmp_mpls_label(mpls);
     346             :     }
     347         513 :     if (ecmp_path_->ChangeNH(agent_, nh) == true)
     348         176 :         ret = true;
     349             : 
     350         513 :     return ret;
     351             : }
     352             : 
     353         473 : bool EcmpData::SyncParams() {
     354         473 :     bool ret = false;
     355             : 
     356         473 :     ecmp_path_->set_tunnel_bmap(tunnel_bmap_);
     357             :     TunnelType::Type new_tunnel_type =
     358         473 :         TunnelType::ComputeType(tunnel_bmap_);
     359         473 :     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         473 :     if (ecmp_path_->dest_vn_list() != vn_list_) {
     365          80 :         ecmp_path_->set_dest_vn_list(vn_list_);
     366          80 :         ret = true;
     367             :     }
     368             : 
     369         473 :     if (ecmp_path_->sg_list() != sg_list_) {
     370           0 :         ecmp_path_->set_sg_list(sg_list_);
     371           0 :         ret = true;
     372             :     }
     373             : 
     374         473 :     if (ecmp_path_->tag_list() != tag_list_) {
     375           0 :         ecmp_path_->set_tag_list(tag_list_);
     376           0 :         ret = true;
     377             :     }
     378             : 
     379         473 :     if (ecmp_path_->communities() != community_list_) {
     380           0 :         ecmp_path_->set_communities(community_list_);
     381           0 :         ret = true;
     382             :     }
     383             : 
     384         473 :     if (path_preference_ != ecmp_path_->path_preference()) {
     385         130 :         ecmp_path_->set_path_preference(path_preference_);
     386         130 :         ret = true;
     387             :     }
     388             : 
     389         473 :     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         473 :     return ret;
     395             : }
     396             : 
     397         464 : bool EcmpData::ModifyEcmpPath(CompositeNHKey *composite_nh_key) {
     398         464 :     bool ret = false;
     399             : 
     400         464 :     if (UpdateNh(composite_nh_key)) {
     401         128 :         ret = true;
     402             :     }
     403             : 
     404         464 :     if (ecmp_path_->label() != label_) {
     405          48 :         ecmp_path_->set_label(label_);
     406          48 :         ret = true;
     407             :     }
     408             : 
     409         464 :     if (SyncParams()) {
     410         156 :         ret = true;
     411             :     }
     412             : 
     413         464 :     ecmp_path_->set_unresolved(false);
     414         464 :     ret = true;
     415             : 
     416         464 :     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           9 : bool EcmpData::UpdateComponentNH(AgentRoute *rt, AgentPath *path) {
     423           9 :     if (!ecmp_path_) {
     424           0 :         return false;
     425             :     }
     426             :     //Build ComponentNHKey for new path
     427           9 :     const NextHop* path_nh = path->ComputeNextHop(agent_);
     428           9 :     DBEntryBase::KeyPtr key = path_nh->GetDBRequestKey();
     429           9 :     NextHopKey *nh_key = static_cast<NextHopKey *>(key.get());
     430           9 :     nh_key->SetPolicy(false);
     431             : 
     432           9 :     ComponentNHKeyList component_nh_key_list;
     433             :     const CompositeNH *comp_nh =
     434           9 :         static_cast<const CompositeNH *>(ecmp_path_->ComputeNextHop(agent_));
     435           9 :     bool composite_nh_policy = false;
     436           9 :     bool updated = comp_nh->UpdateComponentNHKey(path->label(), nh_key,
     437             :                                                  component_nh_key_list,
     438             :                                                  composite_nh_policy);
     439             : 
     440           9 :     if (!updated) {
     441           9 :         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           9 : }
     462             : 
     463          49 : void EcmpData::DeleteComponentNH(AgentRoute *rt, AgentPath *path) {
     464          49 :     assert(ecmp_path_);
     465          49 :     DBEntryBase::KeyPtr key = path->ComputeNextHop(agent_)->GetDBRequestKey();
     466          49 :     NextHopKey *nh_key = static_cast<NextHopKey *>(key.release());
     467          49 :     std::unique_ptr<const NextHopKey> nh_akey(nh_key);
     468          49 :     nh_key->SetPolicy(false);
     469          49 :     ComponentNHKeyPtr comp_nh_key_ptr(new ComponentNHKey(path->label(), std::move(nh_akey)));
     470             : 
     471          49 :     ComponentNHKeyList component_nh_key_list;
     472          49 :     bool comp_nh_policy = false;
     473             :     const CompositeNH *comp_nh =
     474          49 :         static_cast<const CompositeNH *>(ecmp_path_->ComputeNextHop(agent_));
     475          98 :     component_nh_key_list = comp_nh->DeleteComponentNHKey(comp_nh_key_ptr,
     476          49 :                                                           comp_nh_policy);
     477             : 
     478             :     // Form the request for Inet4UnicastEcmpRoute and invoke AddChangePath
     479          49 :     DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
     480          49 :     nh_req.key.reset(new CompositeNHKey(Composite::LOCAL_ECMP,
     481             :                                         comp_nh_policy, component_nh_key_list,
     482          49 :                                         vrf_name_));
     483          49 :     nh_req.data.reset(new CompositeNHData());
     484          49 :     nh_req_.Swap(&nh_req);
     485          49 :     label_ = ecmp_path_->label();
     486          49 :     UpdateNh();
     487             : 
     488          49 :     RouteInfo rt_info;
     489          49 :     rt->FillTrace(rt_info, AgentRoute::CHANGE_PATH, path);
     490          49 :     AgentRouteTable *table = static_cast<AgentRouteTable *>(rt->get_table());
     491          49 :     OPER_TRACE_ROUTE_ENTRY(Route, table, rt_info);
     492          49 :     AGENT_ROUTE_LOG(table, "Path change", rt->ToString(), vrf_name_,
     493             :                     GETPEERNAME(agent_->ecmp_peer()));
     494          49 : }
     495             : 
     496         335 : const NextHop* EcmpData::GetLocalNextHop(const AgentRoute *rt) {
     497             :     Agent *agent =
     498         335 :         (static_cast<InetUnicastAgentRouteTable *> (rt->get_table()))->agent();
     499             : 
     500         335 :     if (rt->FindPath(agent->ecmp_peer())) {
     501         294 :         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          41 :     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          58 :     for (Route::PathList::const_iterator it = rt->GetPathList().begin();
     512         116 :             it != rt->GetPathList().end(); it++) {
     513          41 :         const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
     514          41 :         if (path) {
     515          82 :             if (path->peer() &&
     516          41 :                 path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER) {
     517          24 :                 return path->ComputeNextHop(agent);
     518             :             }
     519             :         }
     520             :     }
     521             : 
     522          17 :     const NextHop *nh = rt->GetActiveNextHop();
     523          17 :     if (nh && nh->GetType() == NextHop::COMPOSITE ) {
     524          17 :         const CompositeNH *comp_nh = static_cast<const CompositeNH *>(nh);
     525             :         //Get the local composite NH
     526          17 :         return comp_nh->GetLocalNextHop();
     527             :     }
     528           0 :     return NULL;
     529             : }

Generated by: LCOV version 1.14