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

Generated by: LCOV version 1.14