From 3bcbc7784a6a247da7911e5ff7d219ec5c44261b Mon Sep 17 00:00:00 2001 From: ashoksingh Date: Fri, 3 Jun 2016 22:57:49 +0530 Subject: [PATCH] Disable policy on ECMP nexthops To support requirement of ECMP without policy, disable policy on ECMP nexthops. Also separate out ECMP NH test-cases and make them non-flaky. Also update these UT to verify that policy is disabled for ECMP Nexthop Change-Id: Ida1b7cf65ba6145031530effa4f442de11a41ff1 Closes-Bug: #1566650 --- src/vnsw/agent/controller/controller_peer.cc | 2 +- src/vnsw/agent/oper/inet_unicast_route.cc | 6 +- src/vnsw/agent/oper/mpls.cc | 2 +- src/vnsw/agent/test/SConscript | 1 + src/vnsw/agent/test/test_ecmp_nh.cc | 1570 ++++++++++++++++++ src/vnsw/agent/test/test_nh.cc | 1479 ----------------- src/vnsw/agent/test/test_util.cc | 5 +- 7 files changed, 1578 insertions(+), 1487 deletions(-) create mode 100644 src/vnsw/agent/test/test_ecmp_nh.cc diff --git a/src/vnsw/agent/controller/controller_peer.cc b/src/vnsw/agent/controller/controller_peer.cc index d09437f3a6f..b0a5e22fe4d 100644 --- a/src/vnsw/agent/controller/controller_peer.cc +++ b/src/vnsw/agent/controller/controller_peer.cc @@ -718,7 +718,7 @@ void AgentXmppChannel::AddEcmpRoute(string vrf_name, IpAddress prefix_addr, // Build the NH request and then create route data to be passed DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE); - nh_req.key.reset(new CompositeNHKey(Composite::ECMP, true, + nh_req.key.reset(new CompositeNHKey(Composite::ECMP, false, comp_nh_list, vrf_name)); nh_req.data.reset(new CompositeNHData()); ControllerEcmpRoute *data = diff --git a/src/vnsw/agent/oper/inet_unicast_route.cc b/src/vnsw/agent/oper/inet_unicast_route.cc index 42551ab4f7d..1dbc7a4dade 100644 --- a/src/vnsw/agent/oper/inet_unicast_route.cc +++ b/src/vnsw/agent/oper/inet_unicast_route.cc @@ -406,7 +406,7 @@ AgentPath *InetUnicastRouteEntry::AllocateEcmpPath(Agent *agent, // It will also create CompositeNH if necessary DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE); nh_req.key.reset(new CompositeNHKey(Composite::LOCAL_ECMP, - true, component_nh_list, + false, component_nh_list, vrf()->GetName())); nh_req.data.reset(new CompositeNHData()); @@ -687,7 +687,7 @@ void InetUnicastRouteEntry::AppendEcmpPath(Agent *agent, // Form the request for Inet4UnicastEcmpRoute and invoke AddChangePath DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE); nh_req.key.reset(new CompositeNHKey(Composite::LOCAL_ECMP, - true, component_nh_key_list, + false, component_nh_key_list, vrf()->GetName())); nh_req.data.reset(new CompositeNHData()); @@ -729,7 +729,7 @@ void InetUnicastRouteEntry::DeleteComponentNH(Agent *agent, AgentPath *path) { // Form the request for Inet4UnicastEcmpRoute and invoke AddChangePath DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE); nh_req.key.reset(new CompositeNHKey(Composite::LOCAL_ECMP, - true, component_nh_key_list, + false, component_nh_key_list, vrf()->GetName())); nh_req.data.reset(new CompositeNHData()); diff --git a/src/vnsw/agent/oper/mpls.cc b/src/vnsw/agent/oper/mpls.cc index bcd03030d62..2d7154af79e 100644 --- a/src/vnsw/agent/oper/mpls.cc +++ b/src/vnsw/agent/oper/mpls.cc @@ -209,7 +209,7 @@ void MplsLabel::CreateEcmpLabel(const Agent *agent, MplsLabelKey *key = new MplsLabelKey(MplsLabel::VPORT_NH, label); req.key.reset(key); - MplsLabelData *data = new MplsLabelData(type, true, component_nh_key_list, + MplsLabelData *data = new MplsLabelData(type, false, component_nh_key_list, vrf_name); req.data.reset(data); diff --git a/src/vnsw/agent/test/SConscript b/src/vnsw/agent/test/SConscript index 213fa26a6ab..e925a8bf138 100644 --- a/src/vnsw/agent/test/SConscript +++ b/src/vnsw/agent/test/SConscript @@ -105,6 +105,7 @@ test_vhost_ip_change = AgentEnv.MakeTestCmd(env, 'test_vhost_ip_change', flaky_agent_suite) test_mirror = AgentEnv.MakeTestCmd(env, 'test_mirror', flaky_agent_suite) test_nh = AgentEnv.MakeTestCmd(env, 'test_nh', flaky_agent_suite) +test_ecmp_nh = AgentEnv.MakeTestCmd(env, 'test_ecmp_nh', agent_suite) test_dummy = AgentEnv.MakeTestCmd(env, 'test_dummy', flaky_agent_suite) test_multicast = AgentEnv.MakeTestCmd(env, 'test_multicast', flaky_agent_suite) test_xmpp_bcast_hv = AgentEnv.MakeTestCmd(env, 'test_xmpp_bcast_hv', diff --git a/src/vnsw/agent/test/test_ecmp_nh.cc b/src/vnsw/agent/test/test_ecmp_nh.cc new file mode 100644 index 00000000000..de398c2d605 --- /dev/null +++ b/src/vnsw/agent/test/test_ecmp_nh.cc @@ -0,0 +1,1570 @@ +/* + * Copyright (c) 2016 Juniper Networks, Inc. All rights reserved. + */ + +#include "base/os.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "testing/gunit.h" +#include "test_cmn_util.h" +#include "vr_types.h" + +using namespace std; +using namespace boost::assign; + +void RouterIdDepInit(Agent *agent) { +} + +class EcmpNhTest : public ::testing::Test { +public: + void SetUp() { + boost::system::error_code ec; + bgp_peer = CreateBgpPeer(Ip4Address::from_string("0.0.0.1", ec), + "xmpp channel"); + agent_ = Agent::GetInstance(); + } + void TearDown() { + WAIT_FOR(1000, 1000, agent_->vrf_table()->Size() == 1); + DeleteBgpPeer(bgp_peer); + } + + Agent *agent_; + BgpPeer *bgp_peer; +}; + +TEST_F(EcmpNhTest, DISABLED_EcmpNH_controller) { + client->WaitForIdle(); + struct PortInfo input1[] = { + {"vnet10", 10, "1.1.1.1", "00:00:00:01:01:01", 10, 10} + }; + + client->Reset(); + AddEncapList("MPLSoGRE", "MPLSoUDP", "VXLAN"); + client->WaitForIdle(); + CreateVmportEnv(input1, 1); + client->WaitForIdle(); + + //Now add remote route with ECMP comp NH + Ip4Address ip1 = Ip4Address::from_string("9.9.9.1"); + Ip4Address ip2 = Ip4Address::from_string("9.9.9.2"); + TunnelNHKey *nh_key = new TunnelNHKey(agent_->fabric_vrf_name(), + agent_->router_id(), + ip1, false, + TunnelType::MPLS_GRE); + std::auto_ptr nh_key_ptr(nh_key); + TunnelNHKey *nh_key_2 = new TunnelNHKey(agent_->fabric_vrf_name(), + agent_->router_id(), + ip2, false, + TunnelType::MPLS_GRE); + std::auto_ptr nh_key_ptr_2(nh_key_2); + + ComponentNHKeyPtr component_nh_key(new ComponentNHKey(1000, + nh_key_ptr)); + ComponentNHKeyPtr component_nh_key_2(new ComponentNHKey(1001, + nh_key_ptr_2)); + ComponentNHKeyList comp_nh_list; + comp_nh_list.push_back(component_nh_key); + comp_nh_list.push_back(component_nh_key_2); + + DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE); + nh_req.key.reset(new CompositeNHKey(Composite::ECMP, true, + comp_nh_list, "vrf10")); + nh_req.data.reset(new CompositeNHData()); + Ip4Address prefix = Ip4Address::from_string("18.18.18.0"); + PathPreference rp(100, PathPreference::LOW, false, false); + SecurityGroupList sg; + BgpPeer *peer_; + peer_ = CreateBgpPeer(Ip4Address::from_string("0.0.0.1"), + "xmpp channel"); + VnListType vn_list; + vn_list.insert("vn10"); + ControllerEcmpRoute *data = + new ControllerEcmpRoute(peer_, prefix, 24, vn_list, -1, + false, "vrf10", sg, rp, + (1 << TunnelType::MPLS_GRE), + EcmpLoadBalance(), + nh_req); + + //ECMP create component NH + InetUnicastAgentRouteTable::AddRemoteVmRouteReq(peer_, "vrf10", + prefix, 24, data); + client->WaitForIdle(); + InetUnicastRouteEntry *rt = RouteGet("vrf10", prefix, 24); + EXPECT_TRUE(rt != NULL); + const CompositeNH *cnh = static_cast(rt->GetActiveNextHop()); + const TunnelNH *tnh = static_cast(cnh->GetNH(0)); + EXPECT_TRUE(tnh->GetTunnelType().GetType() == TunnelType::MPLS_GRE); + tnh = static_cast(cnh->GetNH(1)); + EXPECT_TRUE(tnh->GetTunnelType().GetType() == TunnelType::MPLS_GRE); + + AddEncapList("MPLSoUDP", "MPLSoGRE", "VXLAN"); + client->WaitForIdle(); + rt = RouteGet("vrf10", prefix, 24); + EXPECT_TRUE(rt != NULL); + cnh = static_cast(rt->GetActiveNextHop()); + tnh = static_cast(cnh->GetNH(0)); + EXPECT_TRUE(tnh->GetTunnelType().GetType() == TunnelType::MPLS_GRE); + tnh = static_cast(cnh->GetNH(1)); + EXPECT_TRUE(tnh->GetTunnelType().GetType() == TunnelType::MPLS_GRE); + + //cleanup + DeleteRoute("vrf10", "18.18.18.0", 24, peer_); + client->WaitForIdle(); + DeleteVmportEnv(input1, 1, true); + client->WaitForIdle(); + DeleteBgpPeer(peer_); + client->WaitForIdle(); +} + +TEST_F(EcmpNhTest, EcmpNH_1) { + //Create mutliple VM interface with same IP + struct PortInfo input1[] = { + {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1}, + {"vnet2", 2, "1.1.1.1", "00:00:00:02:02:01", 1, 2}, + {"vnet3", 3, "1.1.1.1", "00:00:00:02:02:03", 1, 3}, + {"vnet4", 4, "1.1.1.1", "00:00:00:02:02:04", 1, 4}, + {"vnet5", 5, "1.1.1.1", "00:00:00:02:02:05", 1, 5}, + }; + + CreateVmportWithEcmp(input1, 5); + client->WaitForIdle(); + + //Check that route points to composite NH, + //with 5 members + Ip4Address ip = Ip4Address::from_string("1.1.1.1"); + InetUnicastRouteEntry *rt = RouteGet("vrf1", ip, 32); + EXPECT_TRUE(rt != NULL); + const NextHop *nh = rt->GetActiveNextHop(); + EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); + const CompositeNH *comp_nh = static_cast(nh); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 5); + + //Get the MPLS label corresponding to this path and verify + //that mpls label also has 5 component NH + uint32_t mpls_label = rt->GetActiveLabel(); + EXPECT_TRUE(FindMplsLabel(MplsLabel::VPORT_NH, mpls_label)); + EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); + comp_nh = static_cast(nh); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 5); + EXPECT_TRUE(comp_nh->PolicyEnabled() == false); + + DeleteVmportEnv(input1, 5, true); + client->WaitForIdle(); + WAIT_FOR(100, 1000, (VrfFind("vrf1") == false)); + EXPECT_FALSE(RouteFind("vrf1", ip, 32)); + + //Expect MPLS label to be not present + EXPECT_FALSE(FindMplsLabel(MplsLabel::VPORT_NH, mpls_label)); +} + +//Create multiple VM with same virtual IP and verify +//ecmp NH gets created and also verify that it gets deleted +//upon VM deletion. +TEST_F(EcmpNhTest, EcmpNH_2) { + //Create mutliple VM interface with same IP + struct PortInfo input1[] = { + {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1} + }; + + struct PortInfo input2[] = { + {"vnet2", 2, "1.1.1.1", "00:00:00:02:02:01", 1, 2} + }; + + struct PortInfo input3[] = { + {"vnet3", 3, "1.1.1.1", "00:00:00:02:02:03", 1, 3} + }; + + struct PortInfo input4[] = { + {"vnet4", 4, "1.1.1.1", "00:00:00:02:02:04", 1, 4} + }; + + struct PortInfo input5[] = { + {"vnet5", 5, "1.1.1.1", "00:00:00:02:02:05", 1, 5} + }; + + CreateVmportWithEcmp(input1, 1, 1); + client->WaitForIdle(); + //First VM added, route points to composite NH + Ip4Address ip = Ip4Address::from_string("1.1.1.1"); + InetUnicastRouteEntry *rt = RouteGet("vrf1", ip, 32); + EXPECT_TRUE(rt != NULL); + const NextHop *nh = rt->GetActiveNextHop(); + EXPECT_TRUE(nh->GetType() == NextHop::INTERFACE); + EXPECT_TRUE(nh->PolicyEnabled() == true); + + //Second VM added, route should point to composite NH + CreateVmportWithEcmp(input2, 1); + client->WaitForIdle(); + nh = rt->GetActiveNextHop(); + EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); + const CompositeNH *comp_nh = static_cast(nh); + EXPECT_TRUE(comp_nh->PolicyEnabled() == false); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 2); + const InterfaceNH *intf_nh = static_cast(comp_nh->Get(0)->nh()); + EXPECT_TRUE(intf_nh->PolicyEnabled() == false); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); + + CreateVmportWithEcmp(input3, 1); + client->WaitForIdle(); + comp_nh = static_cast(rt->GetActiveNextHop()); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 3); + + CreateVmportWithEcmp(input4, 1); + client->WaitForIdle(); + comp_nh = static_cast(rt->GetActiveNextHop()); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 4); + + CreateVmportWithEcmp(input5, 1); + client->WaitForIdle(); + comp_nh = static_cast(rt->GetActiveNextHop()); + EXPECT_TRUE(comp_nh->GetType() == NextHop::COMPOSITE); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 5); + EXPECT_TRUE(comp_nh->PolicyEnabled() == false); + + //Verify all the component NH have right label and nexthop + ComponentNHList::const_iterator component_nh_it = + comp_nh->begin(); + intf_nh = static_cast + ((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); + MplsLabel *mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); + + component_nh_it++; + intf_nh = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet2"); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet2"); + + component_nh_it++; + intf_nh = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); + + component_nh_it++; + intf_nh = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet4"); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet4"); + + component_nh_it++; + intf_nh = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet5"); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet5"); + + //Verify that mpls label allocated for ECMP route, points + //to the same composite NH + uint32_t composite_nh_mpls_label = rt->GetActiveLabel(); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, composite_nh_mpls_label); + EXPECT_TRUE(mpls->nexthop() == comp_nh); + + + //Delete couple of interface and verify composite NH also get + //deleted + DeleteVmportEnv(input2, 1, false); + DeleteVmportEnv(input4, 1, false); + client->WaitForIdle(); + + //Verify all the component NH have right label and nexthop + comp_nh = static_cast(rt->GetActiveNextHop()); + EXPECT_TRUE(comp_nh->PolicyEnabled() == false); + component_nh_it = comp_nh->begin(); + intf_nh = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); + + //Interface 2 and 4 have been deleted, expected the component NH to + //be NULL + component_nh_it++; + EXPECT_TRUE(*component_nh_it == NULL); + + component_nh_it++; + intf_nh = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); + + //Interface vnet4 has been deleted, expect the component NH to be NULL + component_nh_it++; + EXPECT_TRUE(*component_nh_it == NULL); + + component_nh_it++; + intf_nh = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet5"); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet5"); + + DeleteVmportEnv(input3, 1, false); + DeleteVmportEnv(input5, 1, false); + DeleteVmportEnv(input1, 1, true); + client->WaitForIdle(); + EXPECT_FALSE(RouteFind("vrf1", ip, 32)); + + //Expect MPLS label to be not present + EXPECT_FALSE(FindMplsLabel(MplsLabel::VPORT_NH, composite_nh_mpls_label)); + + WAIT_FOR(100, 1000, (VrfFind("vrf1") == false)); +} + +//Create multiple VM with same floating IP and verify +//ecmp NH gets created and also verify that it gets deleted +//upon floating IP disassociation +TEST_F(EcmpNhTest, EcmpNH_3) { + //Create mutliple VM interface with same IP + struct PortInfo input1[] = { + {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1}, + {"vnet2", 2, "1.1.1.2", "00:00:00:02:02:01", 1, 2}, + {"vnet3", 3, "1.1.1.3", "00:00:00:02:02:03", 1, 3}, + {"vnet4", 4, "1.1.1.4", "00:00:00:02:02:04", 1, 4}, + {"vnet5", 5, "1.1.1.5", "00:00:00:02:02:05", 1, 5} + }; + + CreateVmportFIpEnv(input1, 5); + client->WaitForIdle(); + EXPECT_TRUE(VmPortActive(1)); + EXPECT_TRUE(VmPortActive(2)); + EXPECT_TRUE(VmPortActive(3)); + EXPECT_TRUE(VmPortActive(4)); + EXPECT_TRUE(VmPortActive(5)); + + //Create one dummy interface vrf2 for floating IP + struct PortInfo input2[] = { + {"vnet6", 6, "1.1.1.1", "00:00:00:01:01:01", 2, 6}, + }; + CreateVmportFIpEnv(input2, 1); + client->WaitForIdle(); + EXPECT_TRUE(VmPortActive(6)); + + //Create floating IP pool + AddFloatingIpPool("fip-pool1", 1); + AddFloatingIp("fip1", 1, "2.2.2.2"); + AddLink("floating-ip", "fip1", "floating-ip-pool", "fip-pool1"); + AddLink("floating-ip-pool", "fip-pool1", "virtual-network", + "default-project:vn2"); + + //Associate vnet1 with floating IP + AddLink("virtual-machine-interface", "vnet1", "floating-ip", "fip1"); + client->WaitForIdle(); + //First VM added, route points to composite NH + Ip4Address ip = Ip4Address::from_string("2.2.2.2"); + InetUnicastRouteEntry *rt = RouteGet("default-project:vn2:vn2", ip, 32); + EXPECT_TRUE(rt != NULL); + const NextHop *nh = rt->GetActiveNextHop(); + EXPECT_TRUE(nh->GetType() == NextHop::INTERFACE); + + //Second VM added with same floating IP, route should point to composite NH + AddLink("virtual-machine-interface", "vnet2", "floating-ip", "fip1"); + client->WaitForIdle(); + nh = rt->GetActiveNextHop(); + EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); + const CompositeNH *comp_nh = static_cast(nh); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 2); + + AddLink("virtual-machine-interface", "vnet3", "floating-ip", "fip1"); + client->WaitForIdle(); + comp_nh = static_cast(rt->GetActiveNextHop()); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 3); + + AddLink("virtual-machine-interface", "vnet4", "floating-ip", "fip1"); + client->WaitForIdle(); + comp_nh = static_cast(rt->GetActiveNextHop()); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 4); + + AddLink("virtual-machine-interface", "vnet5", "floating-ip", "fip1"); + client->WaitForIdle(); + comp_nh = static_cast(rt->GetActiveNextHop()); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 5); + + //Verify all the component NH have right label and nexthop + ComponentNHList::const_iterator component_nh_it = + comp_nh->begin(); + const InterfaceNH *intf_nh = static_cast + ((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); + MplsLabel *mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); + + component_nh_it++; + intf_nh = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet2"); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet2"); + + component_nh_it++; + intf_nh = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); + + component_nh_it++; + intf_nh = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet4"); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet4"); + + component_nh_it++; + intf_nh = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet5"); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet5"); + + //Verify that mpls label allocated for ECMP route, points + //to the same composite NH + uint32_t composite_mpls_label = rt->GetActiveLabel(); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, composite_mpls_label); + EXPECT_TRUE(mpls->nexthop() == comp_nh); + + //Delete couple of interface and verify composite NH also get + //deleted + DelLink("virtual-machine-interface", "vnet1", "floating-ip", "fip1"); + client->WaitForIdle(); + comp_nh = static_cast(rt->GetActiveNextHop()); + + //Interface 1 has been deleted, expected the component NH to + //be NULL + component_nh_it = comp_nh->begin(); + EXPECT_TRUE(*component_nh_it == NULL); + + DelLink("virtual-machine-interface", "vnet2", "floating-ip", "fip1"); + client->WaitForIdle(); + comp_nh = static_cast(rt->GetActiveNextHop()); + //Interface 2 has been deleted, expected the component NH to + //be NULL + component_nh_it = comp_nh->begin(); + component_nh_it++; + EXPECT_TRUE(*component_nh_it == NULL); + + DelLink("virtual-machine-interface", "vnet3", "floating-ip", "fip1"); + client->WaitForIdle(); + comp_nh = static_cast(rt->GetActiveNextHop()); + //be NULL + component_nh_it = comp_nh->begin(); + component_nh_it++; + component_nh_it++; + EXPECT_TRUE(*component_nh_it == NULL); + + component_nh_it++; + intf_nh = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet4"); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet4"); + + component_nh_it++; + intf_nh = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet5"); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet5"); + + //Delete the vnet4 floating ip. Since only vent5 has floating IP + //route should point to interface NH + DelLink("virtual-machine-interface", "vnet4", "floating-ip", "fip1"); + client->WaitForIdle(); + EXPECT_TRUE(rt->GetActiveNextHop() == intf_nh); + + //Expect MPLS label to be not present + EXPECT_FALSE(FindMplsLabel(MplsLabel::VPORT_NH, composite_mpls_label)); + + DelLink("virtual-machine-interface", "vnet5", "floating-ip", "fip1"); + DelLink("floating-ip-pool", "fip-pool1", "virtual-network", "default-project:vn2"); + client->WaitForIdle(); + EXPECT_FALSE(RouteFind("default-project:vn2:vn2", ip, 32)); + + DeleteVmportFIpEnv(input1, 5, true); + DeleteVmportFIpEnv(input2, 1, true); + WAIT_FOR(100, 1000, (VrfFind("vrf1") == false)); + WAIT_FOR(100, 1000, (VrfFind("vrf2") == false)); + client->WaitForIdle(); +} + +//Create a ECMP NH on a delete marked VRF, +//and make sure NH is not created +TEST_F(EcmpNhTest, EcmpNH_4) { + AddVrf("vrf2"); + client->WaitForIdle(); + + VrfEntryRef vrf1 = VrfGet("vrf2"); + client->WaitForIdle(); + + DelVrf("vrf2"); + WAIT_FOR(100, 1000, (VrfFind("vrf2") == false)); + client->WaitForIdle(); + + //Enqueue a request to add composite NH + //since the entry is marked delete, composite NH will not get + //created + ComponentNHKeyList comp_nh_list; + DBRequest req; + req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; + req.key.reset(new CompositeNHKey(Composite::ECMP, true, comp_nh_list, "vrf2")); + req.data.reset(new CompositeNHData()); + agent_->nexthop_table()->Enqueue(&req); + + client->WaitForIdle(); + + CompositeNHKey key(Composite::ECMP, true, comp_nh_list, "vrf2"); + EXPECT_FALSE(FindNH(&key)); + vrf1.reset(); +} + +//Create a remote route first pointing to tunnel NH +//Change the route to point to composite NH with old tunnel NH +//and a new tunnel NH, and make sure +//preexiting NH gets slot 0 in composite NH +TEST_F(EcmpNhTest, EcmpNH_5) { + AddVrf("vrf2"); + client->WaitForIdle(); + + Ip4Address remote_vm_ip = Ip4Address::from_string("1.1.1.1"); + Ip4Address remote_server_ip1 = Ip4Address::from_string("10.10.10.100"); + Ip4Address remote_server_ip2 = Ip4Address::from_string("10.10.10.101"); + //Add a remote VM route + Inet4TunnelRouteAdd(bgp_peer, "vrf2", remote_vm_ip, 32, remote_server_ip1, + TunnelType::DefaultType(), 30, "vn2", + SecurityGroupList(), PathPreference()); + client->WaitForIdle(); + //Create component NH list + //Transition remote VM route to ECMP route + ComponentNHKeyPtr nh_data1(new ComponentNHKey(30, agent_->fabric_vrf_name(), + agent_->router_id(), + remote_server_ip1, + false, + TunnelType::DefaultType())); + ComponentNHKeyPtr nh_data2(new ComponentNHKey(20, + agent_->fabric_vrf_name(), + agent_->router_id(), + remote_server_ip2, + false, + TunnelType::DefaultType())); + ComponentNHKeyList comp_nh_list; + //Insert new NH first and then existing route NH + comp_nh_list.push_back(nh_data2); + comp_nh_list.push_back(nh_data1); + + SecurityGroupList sg_id_list; + EcmpTunnelRouteAdd(bgp_peer, "vrf2", remote_vm_ip, 32, + comp_nh_list, -1, "vn2", sg_id_list, PathPreference()); + client->WaitForIdle(); + InetUnicastRouteEntry *rt = RouteGet("vrf2", remote_vm_ip, 32); + EXPECT_TRUE(rt != NULL); + const NextHop *nh = rt->GetActiveNextHop(); + EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); + + const CompositeNH *comp_nh = static_cast(nh); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 2); + EXPECT_TRUE(comp_nh->PolicyEnabled() == false); + + //Verify all the component NH have right label and nexthop + ComponentNHList::const_iterator component_nh_it = + comp_nh->begin(); + const TunnelNH *tun_nh1 = static_cast + ((*component_nh_it)->nh()); + EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip1); + EXPECT_TRUE((*component_nh_it)->label() == 30); + + component_nh_it++; + tun_nh1 = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip2); + EXPECT_TRUE((*component_nh_it)->label() == 20); + + DeleteRoute("vrf2", "1.1.1.1", 32, bgp_peer); + client->WaitForIdle(); + DelVrf("vrf2"); + WAIT_FOR(100, 1000, (VrfFind("vrf2") == false)); + client->WaitForIdle(); + EXPECT_FALSE(VrfFind("vrf2")); +} + +//Create a remote route first pointing to tunnel NH +//Change the route to point to composite NH with all new tunnel NH +//make sure preexiting NH doesnt exist in the new component NH list +TEST_F(EcmpNhTest, EcmpNH_6) { + AddVrf("vrf2"); + client->WaitForIdle(); + + Ip4Address remote_vm_ip = Ip4Address::from_string("1.1.1.1"); + Ip4Address remote_server_ip1 = Ip4Address::from_string("10.10.10.100"); + Ip4Address remote_server_ip2 = Ip4Address::from_string("10.10.10.101"); + Ip4Address remote_server_ip3 = Ip4Address::from_string("10.10.10.102"); + //Add a remote VM route + Inet4TunnelRouteAdd(bgp_peer, "vrf2", + remote_vm_ip, + 32, remote_server_ip1, + TunnelType::AllType(), + 30, "vn2", + SecurityGroupList(), PathPreference()); + client->WaitForIdle(); + //Create component NH list + //Transition remote VM route to ECMP route + ComponentNHKeyPtr nh_data1(new ComponentNHKey(30, agent_->fabric_vrf_name(), + agent_->router_id(), + remote_server_ip2, + false, + TunnelType::DefaultType())); + ComponentNHKeyPtr nh_data2(new ComponentNHKey(20, + agent_->fabric_vrf_name(), + agent_->router_id(), + remote_server_ip3, + false, + TunnelType::DefaultType())); + ComponentNHKeyList comp_nh_list; + //Insert new NH first and then existing route NH + comp_nh_list.push_back(nh_data1); + comp_nh_list.push_back(nh_data2); + + SecurityGroupList sg_list; + EcmpTunnelRouteAdd(bgp_peer, "vrf2", remote_vm_ip, 32, + comp_nh_list, -1, "vn2", sg_list, PathPreference()); + client->WaitForIdle(); + InetUnicastRouteEntry *rt = RouteGet("vrf2", remote_vm_ip, 32); + EXPECT_TRUE(rt != NULL); + const NextHop *nh = rt->GetActiveNextHop(); + EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); + + const CompositeNH *comp_nh = static_cast(nh); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 2); + EXPECT_TRUE(comp_nh->PolicyEnabled() == false); + + //Verify all the component NH have right label and nexthop + ComponentNHList::const_iterator component_nh_it = + comp_nh->begin(); + const TunnelNH *tun_nh1 = static_cast + ((*component_nh_it)->nh()); + EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip2); + EXPECT_TRUE((*component_nh_it)->label() == 30); + + component_nh_it++; + tun_nh1 = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip3); + EXPECT_TRUE((*component_nh_it)->label() == 20); + + DeleteRoute("vrf2", "1.1.1.1", 32, bgp_peer); + client->WaitForIdle(); + DelVrf("vrf2"); + WAIT_FOR(100, 1000, (VrfFind("vrf2") == false)); + client->WaitForIdle(); + EXPECT_FALSE(VrfFind("vrf2")); +} + +TEST_F(EcmpNhTest, DISABLED_EcmpNH_7) { + //Create mutliple VM interface with same IP + struct PortInfo input1[] = { + {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1} + }; + + struct PortInfo input2[] = { + {"vnet2", 2, "1.1.1.1", "00:00:00:02:02:01", 1, 2} + }; + + struct PortInfo input3[] = { + {"vnet3", 3, "1.1.1.1", "00:00:00:02:02:03", 1, 3} + }; + + CreateVmportWithEcmp(input1, 1); + client->WaitForIdle(); + //First VM added, route points to composite NH + Ip4Address ip = Ip4Address::from_string("1.1.1.1"); + InetUnicastRouteEntry *rt = RouteGet("vrf1", ip, 32); + EXPECT_TRUE(rt != NULL); + const NextHop *nh = rt->GetActiveNextHop(); + EXPECT_TRUE(nh->GetType() == NextHop::INTERFACE); + + //Second VM added, route should point to composite NH + CreateVmportWithEcmp(input2, 1); + client->WaitForIdle(); + nh = rt->GetActiveNextHop(); + EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); + const CompositeNH *comp_nh = static_cast(nh); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 2); + EXPECT_TRUE(comp_nh->PolicyEnabled() == false); + + DBEntryBase::KeyPtr comp_key = comp_nh->GetDBRequestKey(); + NextHopKey *nh_key = static_cast(comp_key.release()); + std::auto_ptr nh_key_ptr(nh_key); + ComponentNHKeyPtr nh_data1(new ComponentNHKey(rt->GetActiveLabel(), + nh_key_ptr)); + Ip4Address remote_server_ip1 = Ip4Address::from_string("11.1.1.1"); + //Leak the route via BGP peer + ComponentNHKeyPtr nh_data2(new ComponentNHKey(30, agent_->fabric_vrf_name(), + agent_->router_id(), + remote_server_ip1, + false, + TunnelType::DefaultType())); + ComponentNHKeyList comp_nh_list; + comp_nh_list.push_back(nh_data1); + comp_nh_list.push_back(nh_data2); + + SecurityGroupList sg_id_list; + EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip, 32, + comp_nh_list, false, "vn1", sg_id_list, PathPreference()); + client->WaitForIdle(); + + CreateVmportWithEcmp(input3, 1); + client->WaitForIdle(); + comp_nh = static_cast(rt->GetActiveNextHop()); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 4); + + //Verify all the component NH have right label and nexthop + ComponentNHList::const_iterator component_nh_it = + comp_nh->begin(); + const InterfaceNH *intf_nh = static_cast + ((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); + MplsLabel *mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); + + component_nh_it++; + component_nh_it++; + intf_nh = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet2"); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet2"); + + component_nh_it++; + intf_nh = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); + + //Delete couple of interface and verify composite NH also get + //deleted + DeleteVmportEnv(input1, 1, false); + client->WaitForIdle(); + + //Verify all the component NH have right label and nexthop + comp_nh = static_cast(rt->GetActiveNextHop()); + component_nh_it = comp_nh->begin(); + EXPECT_TRUE(*component_nh_it == NULL); + + component_nh_it++; + component_nh_it++; + intf_nh = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet2"); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet2"); + + //Interface vnet3 has been deleted, expect the component NH to be NULL + component_nh_it++; + intf_nh = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); + + //Create Vmport again + CreateVmportWithEcmp(input1, 1); + client->WaitForIdle(); + comp_nh = static_cast(rt->GetActiveNextHop()); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 4); + + //Verify all the component NH have right label and nexthop + component_nh_it = comp_nh->begin(); + intf_nh = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); + + component_nh_it++; + component_nh_it++; + intf_nh = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet2"); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet2"); + + component_nh_it++; + intf_nh = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); + mpls = GetActiveLabel(MplsLabel::VPORT_NH, + (*component_nh_it)->label()); + intf_nh = static_cast(mpls->nexthop()); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); + + //cleanup + DeleteVmportEnv(input1, 1, false); + DeleteVmportEnv(input2, 1, false); + DeleteVmportEnv(input3, 1, true); + client->WaitForIdle(); + DeleteRoute("vrf1", "1.1.1.1", 32, bgp_peer); + client->WaitForIdle(); + + EXPECT_FALSE(RouteFind("vrf1", ip, 32)); + + WAIT_FOR(100, 1000, (VrfFind("vrf1") == false)); +} + +//Add multiple remote routes with same set of composite NH +//make sure they share the composite NH +TEST_F(EcmpNhTest, EcmpNH_8) { + AddVrf("vrf1"); + client->WaitForIdle(); + + Ip4Address remote_server_ip1 = Ip4Address::from_string("10.10.10.100"); + Ip4Address remote_server_ip2 = Ip4Address::from_string("10.10.10.101"); + + ComponentNHKeyPtr nh_data1(new ComponentNHKey(30, agent_->fabric_vrf_name(), + agent_->router_id(), + remote_server_ip1, + false, + TunnelType::DefaultType())); + ComponentNHKeyPtr nh_data2(new ComponentNHKey(20, agent_->fabric_vrf_name(), + agent_->router_id(), + remote_server_ip2, + false, + TunnelType::DefaultType())); + + ComponentNHKeyList comp_nh_list; + comp_nh_list.push_back(nh_data1); + comp_nh_list.push_back(nh_data2); + + Ip4Address ip1 = Ip4Address::from_string("100.1.1.1"); + SecurityGroupList sg_id_list; + EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip1, 32, + comp_nh_list, false, "vn1", sg_id_list, PathPreference()); + client->WaitForIdle(); + + Ip4Address ip2 = Ip4Address::from_string("100.1.1.2"); + EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip2, 32, + comp_nh_list, false, "vn1", sg_id_list, PathPreference()); + client->WaitForIdle(); + + InetUnicastRouteEntry *rt1 = RouteGet("vrf1", ip1, 32); + InetUnicastRouteEntry *rt2 = RouteGet("vrf1", ip2, 32); + EXPECT_TRUE(rt1->GetActiveNextHop()->GetType() == NextHop::COMPOSITE); + EXPECT_TRUE(rt1->GetActiveNextHop()->PolicyEnabled() == false); + EXPECT_TRUE(rt1->GetActiveNextHop() == rt2->GetActiveNextHop()); + + const NextHop *nh = rt1->GetActiveNextHop(); + //Change ip1 route nexthop to be unicast nexthop + //and ensure ip2 route still points to old composite nexthop + Inet4TunnelRouteAdd(bgp_peer, "vrf1", ip1, 32, remote_server_ip1, + TunnelType::AllType(), 8, "vn1", + SecurityGroupList(), PathPreference()); + client->WaitForIdle(); + + EXPECT_TRUE(rt1->GetActiveNextHop()->GetType() == NextHop::TUNNEL); + EXPECT_TRUE(rt2->GetActiveNextHop() == nh); + client->WaitForIdle(); + + //Delete all the routes and make sure nexthop is also deleted + DeleteRoute("vrf1", "100.1.1.1", 32, bgp_peer); + client->WaitForIdle(); + DeleteRoute("vrf1", "100.1.1.2", 32, bgp_peer); + client->WaitForIdle(); + + CompositeNHKey composite_nh_key(Composite::ECMP, true, comp_nh_list, "vrf1"); + EXPECT_FALSE(FindNH(&composite_nh_key)); + DelVrf("vrf1"); +} + +//Add ECMP composite NH with no member +TEST_F(EcmpNhTest, EcmpNH_9) { + AddVrf("vrf1"); + client->WaitForIdle(); + ComponentNHKeyList comp_nh_list; + Ip4Address ip1 = Ip4Address::from_string("100.1.1.1"); + Ip4Address remote_server_ip1 = Ip4Address::from_string("10.1.1.10"); + SecurityGroupList sg_id_list; + EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip1, 32, + comp_nh_list, false, "vn1", sg_id_list, PathPreference()); + client->WaitForIdle(); + + InetUnicastRouteEntry *rt1 = RouteGet("vrf1", ip1, 32); + EXPECT_TRUE(rt1->GetActiveNextHop()->GetType() == NextHop::COMPOSITE); + EXPECT_TRUE(rt1->GetActiveNextHop()->PolicyEnabled() == false); + + //Change ip1 route nexthop to be unicast nexthop + Inet4TunnelRouteAdd(bgp_peer, "vrf1", ip1, 32, remote_server_ip1, + TunnelType::AllType(), 8, "vn1", + SecurityGroupList(), PathPreference()); + client->WaitForIdle(); + + EXPECT_TRUE(rt1->GetActiveNextHop()->GetType() == NextHop::TUNNEL); + client->WaitForIdle(); + + //Delete all the routes and make sure nexthop is also deleted + DeleteRoute("vrf1", "100.1.1.1", 32, bgp_peer); + client->WaitForIdle(); + + CompositeNHKey composite_nh_key(Composite::ECMP, true, comp_nh_list, "vrf1"); + EXPECT_FALSE(FindNH(&composite_nh_key)); + DelVrf("vrf1"); +} + +//Add 2 routes with different composite NH +//Modify the routes, to point to same composite NH +//and ensure both routes would share same nexthop +TEST_F(EcmpNhTest, EcmpNH_10) { + AddVrf("vrf1"); + client->WaitForIdle(); + + Ip4Address remote_server_ip1 = Ip4Address::from_string("10.10.10.100"); + Ip4Address remote_server_ip2 = Ip4Address::from_string("10.10.10.101"); + Ip4Address remote_server_ip3 = Ip4Address::from_string("10.10.10.102"); + + ComponentNHKeyPtr nh_data1(new ComponentNHKey(30, agent_->fabric_vrf_name(), + agent_->router_id(), + remote_server_ip1, + false, + TunnelType::DefaultType())); + ComponentNHKeyPtr nh_data2(new ComponentNHKey(20, agent_->fabric_vrf_name(), + agent_->router_id(), + remote_server_ip2, + false, + TunnelType::DefaultType())); + ComponentNHKeyPtr nh_data3(new ComponentNHKey(20, agent_->fabric_vrf_name(), + agent_->router_id(), + remote_server_ip3, + false, + TunnelType::DefaultType())); + ComponentNHKeyList comp_nh_list1; + comp_nh_list1.push_back(nh_data1); + comp_nh_list1.push_back(nh_data2); + + Ip4Address ip1 = Ip4Address::from_string("100.1.1.1"); + SecurityGroupList sg_id_list; + EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip1, 32, + comp_nh_list1, false, "vn1", sg_id_list, PathPreference()); + client->WaitForIdle(); + + ComponentNHKeyList comp_nh_list2; + comp_nh_list2.push_back(nh_data3); + comp_nh_list2.push_back(nh_data2); + + Ip4Address ip2 = Ip4Address::from_string("100.1.1.2"); + EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip2, 32, + comp_nh_list2, false, "vn1", sg_id_list, PathPreference()); + client->WaitForIdle(); + + InetUnicastRouteEntry *rt1 = RouteGet("vrf1", ip1, 32); + InetUnicastRouteEntry *rt2 = RouteGet("vrf1", ip2, 32); + EXPECT_TRUE(rt1->GetActiveNextHop()->GetType() == NextHop::COMPOSITE); + EXPECT_TRUE(rt1->GetActiveNextHop()->PolicyEnabled() == false); + EXPECT_TRUE(rt1->GetActiveNextHop() != rt2->GetActiveNextHop()); + + const NextHop *nh = rt1->GetActiveNextHop(); + //Change ip2 route, such that ip1 route and ip2 route + //should share same nexthop + EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip2, 32, + comp_nh_list1, false, "vn1", sg_id_list, + PathPreference()); + client->WaitForIdle(); + + EXPECT_TRUE(rt1->GetActiveNextHop() == rt2->GetActiveNextHop()); + EXPECT_TRUE(rt2->GetActiveNextHop() == nh); + EXPECT_TRUE(rt2->GetActiveNextHop()->GetType() == NextHop::COMPOSITE); + //Make sure old nexthop is deleted + CompositeNHKey composite_nh_key2(Composite::ECMP, true, comp_nh_list2, "vrf1"); + EXPECT_FALSE(FindNH(&composite_nh_key2)); + CompositeNHKey composite_nh_key1(Composite::ECMP, true, comp_nh_list1, "vrf1"); + EXPECT_TRUE(GetNH(&composite_nh_key1)->GetRefCount() == 2); + + //Delete all the routes and make sure nexthop is also deleted + DeleteRoute("vrf1", "100.1.1.1", 32, bgp_peer); + client->WaitForIdle(); + DeleteRoute("vrf1", "100.1.1.2", 32, bgp_peer); + client->WaitForIdle(); + + EXPECT_FALSE(FindNH(&composite_nh_key1)); + DelVrf("vrf1"); +} + +//Add 2 routes with different composite NH +//Modify the routes, to point to same composite NH +//and ensure both routes would share same nexthop +TEST_F(EcmpNhTest, EcmpNH_11) { + AddVrf("vrf1"); + client->WaitForIdle(); + + Ip4Address remote_server_ip1 = Ip4Address::from_string("10.10.10.100"); + Ip4Address remote_server_ip2 = Ip4Address::from_string("10.10.10.101"); + Ip4Address remote_server_ip3 = Ip4Address::from_string("10.10.10.102"); + + ComponentNHKeyPtr nh_data1(new ComponentNHKey(30, agent_->fabric_vrf_name(), + agent_->router_id(), + remote_server_ip1, + false, + TunnelType::DefaultType())); + ComponentNHKeyPtr nh_data2(new ComponentNHKey(20, agent_->fabric_vrf_name(), + agent_->router_id(), + remote_server_ip2, + false, + TunnelType::DefaultType())); + ComponentNHKeyPtr nh_data3(new ComponentNHKey(20, agent_->fabric_vrf_name(), + agent_->router_id(), + remote_server_ip3, + false, + TunnelType::DefaultType())); + ComponentNHKeyList comp_nh_list1; + comp_nh_list1.push_back(nh_data1); + comp_nh_list1.push_back(nh_data2); + + Ip4Address ip1 = Ip4Address::from_string("100.1.1.1"); + SecurityGroupList sg_id_list; + EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip1, 32, + comp_nh_list1, false, "vn1", sg_id_list, PathPreference()); + client->WaitForIdle(); + + ComponentNHKeyList comp_nh_list2; + comp_nh_list2.push_back(nh_data1); + comp_nh_list2.push_back(nh_data2); + comp_nh_list2.push_back(nh_data3); + + Ip4Address ip2 = Ip4Address::from_string("100.1.1.2"); + EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip2, 32, + comp_nh_list2, false, "vn1", sg_id_list, PathPreference()); + client->WaitForIdle(); + + InetUnicastRouteEntry *rt1 = RouteGet("vrf1", ip1, 32); + InetUnicastRouteEntry *rt2 = RouteGet("vrf1", ip2, 32); + EXPECT_TRUE(rt1->GetActiveNextHop()->GetType() == NextHop::COMPOSITE); + EXPECT_TRUE(rt1->GetActiveNextHop()->PolicyEnabled() == false); + EXPECT_TRUE(rt1->GetActiveNextHop() != rt2->GetActiveNextHop()); + CompositeNHKey composite_nh_key1(Composite::ECMP, true, comp_nh_list1, "vrf1"); + CompositeNHKey composite_nh_key2(Composite::ECMP, true, comp_nh_list2, "vrf1"); + CompositeNH *composite_nh1 = + static_cast(GetNH(&composite_nh_key1)); + EXPECT_TRUE(composite_nh1->GetRefCount() == 1); + EXPECT_TRUE(composite_nh1->ComponentNHCount() == 2); + + CompositeNH *composite_nh2 = + static_cast(GetNH(&composite_nh_key2)); + EXPECT_TRUE(composite_nh2->GetRefCount() == 1); + EXPECT_TRUE(composite_nh2->ComponentNHCount() == 3); + + //Change ip1 route, such that ip1 route and ip2 route + //should share same nexthop + EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip1, 32, + comp_nh_list2, false, "vn1", sg_id_list, + PathPreference()); + client->WaitForIdle(); + + EXPECT_TRUE(rt1->GetActiveNextHop() == rt2->GetActiveNextHop()); + EXPECT_TRUE(rt2->GetActiveNextHop() == composite_nh2); + EXPECT_TRUE(rt2->GetActiveNextHop()->GetType() == NextHop::COMPOSITE); + EXPECT_TRUE(rt2->GetActiveNextHop()->PolicyEnabled() == false); + //Make sure old nexthop is deleted + EXPECT_TRUE(composite_nh2->GetRefCount() == 2); + EXPECT_TRUE(composite_nh2->ComponentNHCount() == 3); + + //Delete all the routes and make sure nexthop is also deleted + DeleteRoute("vrf1", "100.1.1.1", 32, bgp_peer); + client->WaitForIdle(); + DeleteRoute("vrf1", "100.1.1.2", 32, bgp_peer); + client->WaitForIdle(); + + EXPECT_FALSE(FindNH(&composite_nh_key1)); + DelVrf("vrf1"); +} + +//Add a route pointing to tunnel NH +//Change the route to point to ECMP composite NH with no member +TEST_F(EcmpNhTest, EcmpNH_12) { + AddVrf("vrf1"); + client->WaitForIdle(); + + Ip4Address ip1 = Ip4Address::from_string("100.1.1.1"); + Ip4Address remote_server_ip1 = Ip4Address::from_string("10.1.1.10"); + SecurityGroupList sg_id_list; + + //Change ip1 route nexthop to be unicast nexthop + Inet4TunnelRouteAdd(bgp_peer, "vrf1", ip1, 32, remote_server_ip1, + TunnelType::AllType(), 8, "vn1", + SecurityGroupList(), PathPreference()); + client->WaitForIdle(); + + InetUnicastRouteEntry *rt1 = RouteGet("vrf1", ip1, 32); + EXPECT_TRUE(rt1->GetActiveNextHop()->GetType() == NextHop::TUNNEL); + client->WaitForIdle(); + + ComponentNHKeyList comp_nh_list; + EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip1, 32, + comp_nh_list, false, "vn1", sg_id_list, PathPreference()); + client->WaitForIdle(); + + rt1 = RouteGet("vrf1", ip1, 32); + EXPECT_TRUE(rt1->GetActiveNextHop()->GetType() == NextHop::COMPOSITE); + EXPECT_TRUE(rt1->GetActiveNextHop()->PolicyEnabled() == false); + + //Delete all the routes and make sure nexthop is also deleted + DeleteRoute("vrf1", "100.1.1.1", 32, bgp_peer); + client->WaitForIdle(); + + CompositeNHKey composite_nh_key(Composite::ECMP, true, comp_nh_list, "vrf1"); + EXPECT_FALSE(FindNH(&composite_nh_key)); + DelVrf("vrf1"); +} + +//Verify renewal of composite NH +TEST_F(EcmpNhTest, EcmpNH_13) { + AddVrf("vrf1"); + client->WaitForIdle(); + Ip4Address remote_server_ip1 = Ip4Address::from_string("10.10.10.100"); + Ip4Address remote_server_ip2 = Ip4Address::from_string("10.10.10.101"); + + ComponentNHKeyPtr nh_data1(new ComponentNHKey(30, agent_->fabric_vrf_name(), + agent_->router_id(), + remote_server_ip1, + false, + TunnelType::DefaultType())); + ComponentNHKeyPtr nh_data2(new ComponentNHKey(20, agent_->fabric_vrf_name(), + agent_->router_id(), + remote_server_ip2, + false, + TunnelType::DefaultType())); + ComponentNHKeyList comp_nh_list; + comp_nh_list.push_back(nh_data1); + comp_nh_list.push_back(nh_data2); + + Ip4Address ip1 = Ip4Address::from_string("100.1.1.1"); + SecurityGroupList sg_id_list; + EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip1, 32, + comp_nh_list, false, "vn1", sg_id_list, PathPreference()); + client->WaitForIdle(); + + //Delete composite NH + CompositeNHKey composite_nh_key(Composite::ECMP, true, comp_nh_list, "vrf1"); + const CompositeNH *comp_nh = static_cast( + GetNH(&composite_nh_key)); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 2); + EXPECT_TRUE(comp_nh->PolicyEnabled() == false); + + DBRequest req; + req.oper = DBRequest::DB_ENTRY_DELETE; + NextHopKey *key = new CompositeNHKey(Composite::ECMP, true, + comp_nh_list, "vrf1"); + req.key.reset(key); + req.data.reset(NULL); + NextHopTable::GetInstance()->Enqueue(&req); + client->WaitForIdle(); + EXPECT_TRUE(comp_nh->ActiveComponentNHCount() == 0); + client->NextHopReset(); + + req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; + key = new CompositeNHKey(Composite::ECMP, true, + comp_nh_list, "vrf1"); + ((CompositeNHKey *)key)->CreateTunnelNHReq(agent_); + req.key.reset(key); + req.data.reset(NULL); + NextHopTable::GetInstance()->Enqueue(&req); + client->WaitForIdle(); + client->CompositeNHWait(1); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 2); + + //Delete all the routes and make sure nexthop is also deleted + DeleteRoute("vrf1", "100.1.1.1", 32, bgp_peer); + client->WaitForIdle(); + + EXPECT_FALSE(FindNH(&composite_nh_key)); + DelVrf("vrf1"); +} + +TEST_F(EcmpNhTest, EcmpNH_14) { + //Create mutliple VM interface with same IP + struct PortInfo input1[] = { + {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1}, + {"vnet2", 2, "1.1.1.1", "00:00:00:01:01:01", 1, 2} + }; + + CreateVmportWithEcmp(input1, 1); + client->WaitForIdle(); + //First VM added, route points to composite NH + Ip4Address ip = Ip4Address::from_string("1.1.1.1"); + InetUnicastRouteEntry *rt = RouteGet("vrf1", ip, 32); + EXPECT_TRUE(rt != NULL); + const NextHop *nh = rt->GetActiveNextHop(); + EXPECT_TRUE(nh->GetType() == NextHop::INTERFACE); + + DBEntryBase::KeyPtr db_nh_key = nh->GetDBRequestKey(); + NextHopKey *nh_key = static_cast(db_nh_key.release()); + std::auto_ptr nh_key_ptr(nh_key); + ComponentNHKeyPtr nh_data1(new ComponentNHKey(rt->GetActiveLabel(), + nh_key_ptr)); + Ip4Address remote_server_ip1 = Ip4Address::from_string("11.1.1.1"); + //Leak the route via BGP peer + ComponentNHKeyPtr nh_data2(new ComponentNHKey(30, agent_->fabric_vrf_name(), + agent_->router_id(), + remote_server_ip1, + false, + TunnelType::DefaultType())); + ComponentNHKeyList comp_nh_list; + comp_nh_list.push_back(nh_data1); + comp_nh_list.push_back(nh_data2); + + SecurityGroupList sg_id_list; + EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip, 32, + comp_nh_list, false, "vn1", sg_id_list, + PathPreference()); + client->WaitForIdle(); + + //Deactivate vm interface + DelLink("virtual-network", "vn1", "virtual-machine-interface", "vnet1"); + //Transition ecmp to tunnel NH + Inet4TunnelRouteAdd(bgp_peer, "vrf1", ip, 32, remote_server_ip1, + TunnelType::DefaultType(), 30, "vn2", + SecurityGroupList(), PathPreference()); + client->WaitForIdle(); + + //Resync the route + rt->EnqueueRouteResync(); + client->WaitForIdle(); + + DeleteVmportEnv(input1, 2, true); + client->WaitForIdle(); + EXPECT_FALSE(VrfFind("vrf1", true)); +} + +//Create a remote route with ECMP component NH in order A,B and C +//Enqueue change for the same route in different order of composite NH +//verify that nexthop doesnt change +TEST_F(EcmpNhTest, EcmpNH_15) { + AddVrf("vrf2"); + client->WaitForIdle(); + + Ip4Address remote_vm_ip = Ip4Address::from_string("1.1.1.1"); + Ip4Address remote_server_ip1 = Ip4Address::from_string("10.10.10.100"); + Ip4Address remote_server_ip2 = Ip4Address::from_string("10.10.10.101"); + Ip4Address remote_server_ip3 = Ip4Address::from_string("10.10.10.102"); + //Create component NH list + //Transition remote VM route to ECMP route + ComponentNHKeyPtr nh_data1(new ComponentNHKey(15, agent_->fabric_vrf_name(), + agent_->router_id(), + remote_server_ip1, + false, + TunnelType::DefaultType())); + ComponentNHKeyPtr nh_data2(new ComponentNHKey(20, + agent_->fabric_vrf_name(), + agent_->router_id(), + remote_server_ip2, + false, + TunnelType::DefaultType())); + ComponentNHKeyPtr nh_data3(new ComponentNHKey(25, + agent_->fabric_vrf_name(), + agent_->router_id(), + remote_server_ip3, + false, + TunnelType::DefaultType())); + + ComponentNHKeyList comp_nh_list; + //Insert new NH first and then existing route NH + comp_nh_list.push_back(nh_data1); + comp_nh_list.push_back(nh_data2); + comp_nh_list.push_back(nh_data3); + + SecurityGroupList sg_list; + EcmpTunnelRouteAdd(bgp_peer, "vrf2", remote_vm_ip, 32, + comp_nh_list, -1, "vn2", sg_list, PathPreference()); + client->WaitForIdle(); + InetUnicastRouteEntry *rt = RouteGet("vrf2", remote_vm_ip, 32); + EXPECT_TRUE(rt != NULL); + const NextHop *nh = rt->GetActiveNextHop(); + EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); + + const CompositeNH *comp_nh = static_cast(nh); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 3); + + //Verify all the component NH have right label and nexthop + ComponentNHList::const_iterator component_nh_it = + comp_nh->begin(); + const TunnelNH *tun_nh1 = static_cast + ((*component_nh_it)->nh()); + EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip1); + EXPECT_TRUE((*component_nh_it)->label() == 15); + + component_nh_it++; + tun_nh1 = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip2); + EXPECT_TRUE((*component_nh_it)->label() == 20); + + component_nh_it++; + tun_nh1 = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip3); + EXPECT_TRUE((*component_nh_it)->label() == 25); + + //Enqueue route change in different order + comp_nh_list.clear(); + comp_nh_list.push_back(nh_data2); + comp_nh_list.push_back(nh_data3); + comp_nh_list.push_back(nh_data1); + + EcmpTunnelRouteAdd(bgp_peer, "vrf2", remote_vm_ip, 32, + comp_nh_list, -1, "vn2", sg_list, PathPreference()); + client->WaitForIdle(); + rt = RouteGet("vrf2", remote_vm_ip, 32); + EXPECT_TRUE(rt != NULL); + nh = rt->GetActiveNextHop(); + EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); + + comp_nh = static_cast(nh); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 3); + EXPECT_TRUE(comp_nh->PolicyEnabled() == false); + + //Verify all the component NH have right label and nexthop + component_nh_it = comp_nh->begin(); + tun_nh1 = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip1); + EXPECT_TRUE((*component_nh_it)->label() == 15); + + component_nh_it++; + tun_nh1 = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip2); + EXPECT_TRUE((*component_nh_it)->label() == 20); + + component_nh_it++; + tun_nh1 = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip3); + EXPECT_TRUE((*component_nh_it)->label() == 25); + + comp_nh_list.clear(); + comp_nh_list.push_back(nh_data3); + comp_nh_list.push_back(nh_data2); + comp_nh_list.push_back(nh_data1); + + EcmpTunnelRouteAdd(bgp_peer, "vrf2", remote_vm_ip, 32, + comp_nh_list, -1, "vn2", sg_list, PathPreference()); + client->WaitForIdle(); + rt = RouteGet("vrf2", remote_vm_ip, 32); + EXPECT_TRUE(rt != NULL); + nh = rt->GetActiveNextHop(); + EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); + + comp_nh = static_cast(nh); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 3); + EXPECT_TRUE(comp_nh->PolicyEnabled() == false); + + //Verify all the component NH have right label and nexthop + component_nh_it = comp_nh->begin(); + tun_nh1 = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip1); + EXPECT_TRUE((*component_nh_it)->label() == 15); + + component_nh_it++; + tun_nh1 = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip2); + EXPECT_TRUE((*component_nh_it)->label() == 20); + + component_nh_it++; + tun_nh1 = static_cast((*component_nh_it)->nh()); + EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip3); + EXPECT_TRUE((*component_nh_it)->label() == 25); + + //cleanup + DeleteRoute("vrf2", "1.1.1.1", 32, bgp_peer); + client->WaitForIdle(); + //agent_->fabric_inet4_unicast_table()->DeleteReq(NULL, "vrf2", + // remote_vm_ip, 32, NULL); + DelVrf("vrf2"); + WAIT_FOR(100, 1000, (VrfFind("vrf2") == false)); + client->WaitForIdle(); + EXPECT_FALSE(VrfFind("vrf2")); +} + +//Create a composite NH with one interface NH which is not present +//Add the interface, trigger route change and verify that component NH +//list get populated +TEST_F(EcmpNhTest, EcmpNH_16) { + AddVrf("vrf2"); + client->WaitForIdle(); + Ip4Address remote_vm_ip = Ip4Address::from_string("1.1.1.1"); + //Transition remote VM route to ECMP route + ComponentNHKeyPtr nh_data1(new ComponentNHKey(15, MakeUuid(1), + InterfaceNHFlags::INET4)); + ComponentNHKeyList comp_nh_list; + //Insert new NH first and then existing route NH + comp_nh_list.push_back(nh_data1); + SecurityGroupList sg_list; + EcmpTunnelRouteAdd(bgp_peer, "vrf2", remote_vm_ip, 32, + comp_nh_list, -1, "vn2", sg_list, PathPreference()); + client->WaitForIdle(); + + //Nexthop is not found, hence component NH count is 0 + InetUnicastRouteEntry *rt = RouteGet("vrf2", remote_vm_ip, 32); + EXPECT_TRUE(rt != NULL); + const NextHop *nh = rt->GetActiveNextHop(); + EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); + + const CompositeNH *comp_nh = static_cast(nh); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 1); + //Verify all the component NH have right label and nexthop + ComponentNHList::const_iterator component_nh_it = + comp_nh->begin(); + EXPECT_TRUE(*component_nh_it == NULL); + + //Add interface + struct PortInfo input[] = { + {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1}, + }; + CreateVmportEnv(input, 1); + client->WaitForIdle(); + + client->NextHopReset(); + EcmpTunnelRouteAdd(bgp_peer, "vrf2", remote_vm_ip, 32, + comp_nh_list, -1, "vn2", sg_list, PathPreference()); + client->WaitForIdle(); + + EXPECT_TRUE(client->CompositeNHWait(1)); + //Nexthop is not found, hence component NH count is 0 + rt = RouteGet("vrf2", remote_vm_ip, 32); + EXPECT_TRUE(rt != NULL); + nh = rt->GetActiveNextHop(); + EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); + comp_nh = static_cast(nh); + EXPECT_TRUE(comp_nh->ComponentNHCount() == 1); + component_nh_it = comp_nh->begin(); + EXPECT_TRUE(*component_nh_it != NULL); + EXPECT_TRUE((*component_nh_it)->nh()->GetType() == NextHop::INTERFACE); + + DeleteVmportEnv(input, 1, true); + DeleteRoute("vrf2", "1.1.1.1", 32, bgp_peer); + client->WaitForIdle(); + DelVrf("vrf2"); + WAIT_FOR(100, 1000, (VrfFind("vrf2") == false)); + WAIT_FOR(100, 1000, (VrfFind("vrf1") == false)); + client->WaitForIdle(); + EXPECT_FALSE(VrfFind("vrf2")); +} + +//Add a interface NH with policy +//Add a BGP peer route with one interface NH and one tunnel NH +//make sure interface NH gets added without policy +TEST_F(EcmpNhTest, EcmpNH_17) { + //Add interface + struct PortInfo input[] = { + {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1}, + }; + CreateVmportEnv(input, 1, 1); + client->WaitForIdle(); + + VnListType vn_list; + vn_list.insert("vn1"); + const VmInterface *intf = static_cast(VmPortGet(1)); + Ip4Address ip = Ip4Address::from_string("1.1.1.1"); + agent_->fabric_inet4_unicast_table()-> + AddLocalVmRouteReq(agent_->local_peer(), "vrf1", ip, 32, + MakeUuid(1), vn_list, intf->label(), + SecurityGroupList(), CommunityList(), false, PathPreference(), + Ip4Address(0), EcmpLoadBalance()); + client->WaitForIdle(); + + InetUnicastRouteEntry *rt = RouteGet("vrf1", ip, 32); + EXPECT_TRUE(rt != NULL); + const NextHop *nh = rt->GetActiveNextHop(); + + Ip4Address remote_server_ip1 = Ip4Address::from_string("10.10.10.100"); + //Create component NH list + //Transition remote VM route to ECMP route + ComponentNHKeyPtr nh_data1(new ComponentNHKey(15, agent_->fabric_vrf_name(), + agent_->router_id(), + remote_server_ip1, + false, + TunnelType::DefaultType())); + DBEntryBase::KeyPtr key = nh->GetDBRequestKey(); + NextHopKey *nh_key = static_cast(key.release()); + std::auto_ptr nh_akey(nh_key); + nh_key->SetPolicy(false); + ComponentNHKeyPtr nh_data2(new ComponentNHKey(intf->label(), nh_akey)); + + ComponentNHKeyList comp_nh_list; + //Insert new NH first and then existing route NH + comp_nh_list.push_back(nh_data1); + comp_nh_list.push_back(nh_data2); + + SecurityGroupList sg_list; + EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip, 32, + comp_nh_list, false, "vn1", sg_list, PathPreference()); + client->WaitForIdle(); + + rt = RouteGet("vrf1", ip, 32); + EXPECT_TRUE(rt != NULL); + nh = rt->GetActiveNextHop(); + EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); + const CompositeNH *comp_nh = static_cast(nh); + EXPECT_TRUE(comp_nh->PolicyEnabled() == false); + const InterfaceNH *intf_nh = static_cast(comp_nh->Get(1)->nh()); + EXPECT_TRUE(intf_nh->PolicyEnabled() == false); + EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); + + //cleanup + agent_->fabric_inet4_unicast_table()->DeleteReq(agent_->local_peer(), "vrf1", + ip, 32, NULL); + client->WaitForIdle(); + DeleteVmportEnv(input, 1, true); + client->WaitForIdle(); + DeleteRoute("vrf1", "1.1.1.1", 32, bgp_peer); + client->WaitForIdle(); + WAIT_FOR(100, 1000, (VrfFind("vrf1") == false)); + EXPECT_FALSE(RouteFind("vrf1", ip, 32)); +} + +int main(int argc, char **argv) { + GETUSERARGS(); + client = TestInit(init_file, ksync_init); + + int ret = RUN_ALL_TESTS(); + client->WaitForIdle(); + TestShutdown(); + delete client; + return ret; +} diff --git a/src/vnsw/agent/test/test_nh.cc b/src/vnsw/agent/test/test_nh.cc index a5af32269b8..cbc3e642466 100644 --- a/src/vnsw/agent/test/test_nh.cc +++ b/src/vnsw/agent/test/test_nh.cc @@ -367,1485 +367,6 @@ TEST_F(CfgTest, CreateVrfNh_1) { VrfDelReq("test_vrf"); } -TEST_F(CfgTest, EcmpNH_controller) { - client->WaitForIdle(); - struct PortInfo input1[] = { - {"vnet10", 10, "1.1.1.1", "00:00:00:01:01:01", 10, 10} - }; - - client->Reset(); - AddEncapList("MPLSoGRE", "MPLSoUDP", "VXLAN"); - client->WaitForIdle(); - CreateVmportEnv(input1, 1); - client->WaitForIdle(); - - //Now add remote route with ECMP comp NH - Ip4Address ip1 = Ip4Address::from_string("9.9.9.1"); - Ip4Address ip2 = Ip4Address::from_string("9.9.9.2"); - TunnelNHKey *nh_key = new TunnelNHKey(agent_->fabric_vrf_name(), - agent_->router_id(), - ip1, false, - TunnelType::MPLS_GRE); - std::auto_ptr nh_key_ptr(nh_key); - TunnelNHKey *nh_key_2 = new TunnelNHKey(agent_->fabric_vrf_name(), - agent_->router_id(), - ip2, false, - TunnelType::MPLS_GRE); - std::auto_ptr nh_key_ptr_2(nh_key_2); - - ComponentNHKeyPtr component_nh_key(new ComponentNHKey(1000, - nh_key_ptr)); - ComponentNHKeyPtr component_nh_key_2(new ComponentNHKey(1001, - nh_key_ptr_2)); - ComponentNHKeyList comp_nh_list; - comp_nh_list.push_back(component_nh_key); - comp_nh_list.push_back(component_nh_key_2); - - DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE); - nh_req.key.reset(new CompositeNHKey(Composite::ECMP, true, - comp_nh_list, "vrf10")); - nh_req.data.reset(new CompositeNHData()); - Ip4Address prefix = Ip4Address::from_string("18.18.18.0"); - PathPreference rp(100, PathPreference::LOW, false, false); - SecurityGroupList sg; - BgpPeer *peer_; - peer_ = CreateBgpPeer(Ip4Address::from_string("0.0.0.1"), - "xmpp channel"); - VnListType vn_list; - vn_list.insert("vn10"); - ControllerEcmpRoute *data = - new ControllerEcmpRoute(peer_, prefix, 24, vn_list, -1, - false, "vrf10", sg, rp, - (1 << TunnelType::MPLS_GRE), - EcmpLoadBalance(), - nh_req); - - //ECMP create component NH - InetUnicastAgentRouteTable::AddRemoteVmRouteReq(peer_, "vrf10", - prefix, 24, data); - client->WaitForIdle(); - InetUnicastRouteEntry *rt = RouteGet("vrf10", prefix, 24); - EXPECT_TRUE(rt != NULL); - const CompositeNH *cnh = static_cast(rt->GetActiveNextHop()); - const TunnelNH *tnh = static_cast(cnh->GetNH(0)); - EXPECT_TRUE(tnh->GetTunnelType().GetType() == TunnelType::MPLS_GRE); - tnh = static_cast(cnh->GetNH(1)); - EXPECT_TRUE(tnh->GetTunnelType().GetType() == TunnelType::MPLS_GRE); - - AddEncapList("MPLSoUDP", "MPLSoGRE", "VXLAN"); - client->WaitForIdle(); - rt = RouteGet("vrf10", prefix, 24); - EXPECT_TRUE(rt != NULL); - cnh = static_cast(rt->GetActiveNextHop()); - tnh = static_cast(cnh->GetNH(0)); - EXPECT_TRUE(tnh->GetTunnelType().GetType() == TunnelType::MPLS_GRE); - tnh = static_cast(cnh->GetNH(1)); - EXPECT_TRUE(tnh->GetTunnelType().GetType() == TunnelType::MPLS_GRE); - - DeleteBgpPeer(peer_); -} - -TEST_F(CfgTest, EcmpNH_1) { - //Create mutliple VM interface with same IP - struct PortInfo input1[] = { - {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1}, - {"vnet2", 2, "1.1.1.1", "00:00:00:02:02:01", 1, 2}, - {"vnet3", 3, "1.1.1.1", "00:00:00:02:02:03", 1, 3}, - {"vnet4", 4, "1.1.1.1", "00:00:00:02:02:04", 1, 4}, - {"vnet5", 5, "1.1.1.1", "00:00:00:02:02:05", 1, 5}, - }; - - CreateVmportWithEcmp(input1, 5); - client->WaitForIdle(); - - //Check that route points to composite NH, - //with 5 members - Ip4Address ip = Ip4Address::from_string("1.1.1.1"); - InetUnicastRouteEntry *rt = RouteGet("vrf1", ip, 32); - EXPECT_TRUE(rt != NULL); - const NextHop *nh = rt->GetActiveNextHop(); - EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); - const CompositeNH *comp_nh = static_cast(nh); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 5); - - //Get the MPLS label corresponding to this path and verify - //that mpls label also has 5 component NH - uint32_t mpls_label = rt->GetActiveLabel(); - EXPECT_TRUE(FindMplsLabel(MplsLabel::VPORT_NH, mpls_label)); - EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); - comp_nh = static_cast(nh); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 5); - - DeleteVmportEnv(input1, 5, true); - WAIT_FOR(100, 1000, (VrfFind("vrf1") == false)); - client->WaitForIdle(); - EXPECT_FALSE(RouteFind("vrf1", ip, 32)); - - //Expect MPLS label to be not present - EXPECT_FALSE(FindMplsLabel(MplsLabel::VPORT_NH, mpls_label)); -} - -//Create multiple VM with same virtual IP and verify -//ecmp NH gets created and also verify that it gets deleted -//upon VM deletion. -TEST_F(CfgTest, EcmpNH_2) { - //Create mutliple VM interface with same IP - struct PortInfo input1[] = { - {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1} - }; - - struct PortInfo input2[] = { - {"vnet2", 2, "1.1.1.1", "00:00:00:02:02:01", 1, 2} - }; - - struct PortInfo input3[] = { - {"vnet3", 3, "1.1.1.1", "00:00:00:02:02:03", 1, 3} - }; - - struct PortInfo input4[] = { - {"vnet4", 4, "1.1.1.1", "00:00:00:02:02:04", 1, 4} - }; - - struct PortInfo input5[] = { - {"vnet5", 5, "1.1.1.1", "00:00:00:02:02:05", 1, 5} - }; - - CreateVmportWithEcmp(input1, 1, 1); - client->WaitForIdle(); - //First VM added, route points to composite NH - Ip4Address ip = Ip4Address::from_string("1.1.1.1"); - InetUnicastRouteEntry *rt = RouteGet("vrf1", ip, 32); - EXPECT_TRUE(rt != NULL); - const NextHop *nh = rt->GetActiveNextHop(); - EXPECT_TRUE(nh->GetType() == NextHop::INTERFACE); - EXPECT_TRUE(nh->PolicyEnabled() == true); - - //Second VM added, route should point to composite NH - CreateVmportWithEcmp(input2, 1); - client->WaitForIdle(); - nh = rt->GetActiveNextHop(); - EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); - const CompositeNH *comp_nh = static_cast(nh); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 2); - const InterfaceNH *intf_nh = static_cast(comp_nh->Get(0)->nh()); - EXPECT_TRUE(intf_nh->PolicyEnabled() == false); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); - - CreateVmportWithEcmp(input3, 1); - client->WaitForIdle(); - comp_nh = static_cast(rt->GetActiveNextHop()); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 3); - - CreateVmportWithEcmp(input4, 1); - client->WaitForIdle(); - comp_nh = static_cast(rt->GetActiveNextHop()); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 4); - - CreateVmportWithEcmp(input5, 1); - client->WaitForIdle(); - comp_nh = static_cast(rt->GetActiveNextHop()); - EXPECT_TRUE(comp_nh->GetType() == NextHop::COMPOSITE); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 5); - - //Verify all the component NH have right label and nexthop - ComponentNHList::const_iterator component_nh_it = - comp_nh->begin(); - intf_nh = static_cast - ((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); - MplsLabel *mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); - - component_nh_it++; - intf_nh = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet2"); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet2"); - - component_nh_it++; - intf_nh = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); - - component_nh_it++; - intf_nh = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet4"); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet4"); - - component_nh_it++; - intf_nh = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet5"); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet5"); - - //Verify that mpls label allocated for ECMP route, points - //to the same composite NH - uint32_t composite_nh_mpls_label = rt->GetActiveLabel(); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, composite_nh_mpls_label); - EXPECT_TRUE(mpls->nexthop() == comp_nh); - - - //Delete couple of interface and verify composite NH also get - //deleted - DeleteVmportEnv(input2, 1, false); - DeleteVmportEnv(input4, 1, false); - client->WaitForIdle(); - - //Verify all the component NH have right label and nexthop - comp_nh = static_cast(rt->GetActiveNextHop()); - component_nh_it = comp_nh->begin(); - intf_nh = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); - - //Interface 2 and 4 have been deleted, expected the component NH to - //be NULL - component_nh_it++; - EXPECT_TRUE(*component_nh_it == NULL); - - component_nh_it++; - intf_nh = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); - - //Interface vnet4 has been deleted, expect the component NH to be NULL - component_nh_it++; - EXPECT_TRUE(*component_nh_it == NULL); - - component_nh_it++; - intf_nh = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet5"); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet5"); - - DeleteVmportEnv(input3, 1, false); - DeleteVmportEnv(input5, 1, false); - DeleteVmportEnv(input1, 1, true); - client->WaitForIdle(); - EXPECT_FALSE(RouteFind("vrf1", ip, 32)); - - //Expect MPLS label to be not present - EXPECT_FALSE(FindMplsLabel(MplsLabel::VPORT_NH, composite_nh_mpls_label)); - - WAIT_FOR(100, 1000, (VrfFind("vrf1") == false)); -} - -//Create multiple VM with same floating IP and verify -//ecmp NH gets created and also verify that it gets deleted -//upon floating IP disassociation -TEST_F(CfgTest, EcmpNH_3) { - //Create mutliple VM interface with same IP - struct PortInfo input1[] = { - {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1}, - {"vnet2", 2, "1.1.1.2", "00:00:00:02:02:01", 1, 2}, - {"vnet3", 3, "1.1.1.3", "00:00:00:02:02:03", 1, 3}, - {"vnet4", 4, "1.1.1.4", "00:00:00:02:02:04", 1, 4}, - {"vnet5", 5, "1.1.1.5", "00:00:00:02:02:05", 1, 5} - }; - - CreateVmportFIpEnv(input1, 5); - client->WaitForIdle(); - EXPECT_TRUE(VmPortActive(1)); - EXPECT_TRUE(VmPortActive(2)); - EXPECT_TRUE(VmPortActive(3)); - EXPECT_TRUE(VmPortActive(4)); - EXPECT_TRUE(VmPortActive(5)); - - //Create one dummy interface vrf2 for floating IP - struct PortInfo input2[] = { - {"vnet6", 6, "1.1.1.1", "00:00:00:01:01:01", 2, 6}, - }; - CreateVmportFIpEnv(input2, 1); - client->WaitForIdle(); - EXPECT_TRUE(VmPortActive(6)); - - //Create floating IP pool - AddFloatingIpPool("fip-pool1", 1); - AddFloatingIp("fip1", 1, "2.2.2.2"); - AddLink("floating-ip", "fip1", "floating-ip-pool", "fip-pool1"); - AddLink("floating-ip-pool", "fip-pool1", "virtual-network", - "default-project:vn2"); - - //Associate vnet1 with floating IP - AddLink("virtual-machine-interface", "vnet1", "floating-ip", "fip1"); - client->WaitForIdle(); - //First VM added, route points to composite NH - Ip4Address ip = Ip4Address::from_string("2.2.2.2"); - InetUnicastRouteEntry *rt = RouteGet("default-project:vn2:vn2", ip, 32); - EXPECT_TRUE(rt != NULL); - const NextHop *nh = rt->GetActiveNextHop(); - EXPECT_TRUE(nh->GetType() == NextHop::INTERFACE); - - //Second VM added with same floating IP, route should point to composite NH - AddLink("virtual-machine-interface", "vnet2", "floating-ip", "fip1"); - client->WaitForIdle(); - nh = rt->GetActiveNextHop(); - EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); - const CompositeNH *comp_nh = static_cast(nh); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 2); - - AddLink("virtual-machine-interface", "vnet3", "floating-ip", "fip1"); - client->WaitForIdle(); - comp_nh = static_cast(rt->GetActiveNextHop()); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 3); - - AddLink("virtual-machine-interface", "vnet4", "floating-ip", "fip1"); - client->WaitForIdle(); - comp_nh = static_cast(rt->GetActiveNextHop()); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 4); - - AddLink("virtual-machine-interface", "vnet5", "floating-ip", "fip1"); - client->WaitForIdle(); - comp_nh = static_cast(rt->GetActiveNextHop()); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 5); - - //Verify all the component NH have right label and nexthop - ComponentNHList::const_iterator component_nh_it = - comp_nh->begin(); - const InterfaceNH *intf_nh = static_cast - ((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); - MplsLabel *mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); - - component_nh_it++; - intf_nh = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet2"); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet2"); - - component_nh_it++; - intf_nh = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); - - component_nh_it++; - intf_nh = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet4"); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet4"); - - component_nh_it++; - intf_nh = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet5"); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet5"); - - //Verify that mpls label allocated for ECMP route, points - //to the same composite NH - uint32_t composite_mpls_label = rt->GetActiveLabel(); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, composite_mpls_label); - EXPECT_TRUE(mpls->nexthop() == comp_nh); - - //Delete couple of interface and verify composite NH also get - //deleted - DelLink("virtual-machine-interface", "vnet1", "floating-ip", "fip1"); - client->WaitForIdle(); - comp_nh = static_cast(rt->GetActiveNextHop()); - - //Interface 1 has been deleted, expected the component NH to - //be NULL - component_nh_it = comp_nh->begin(); - EXPECT_TRUE(*component_nh_it == NULL); - - DelLink("virtual-machine-interface", "vnet2", "floating-ip", "fip1"); - client->WaitForIdle(); - comp_nh = static_cast(rt->GetActiveNextHop()); - //Interface 2 has been deleted, expected the component NH to - //be NULL - component_nh_it = comp_nh->begin(); - component_nh_it++; - EXPECT_TRUE(*component_nh_it == NULL); - - DelLink("virtual-machine-interface", "vnet3", "floating-ip", "fip1"); - client->WaitForIdle(); - comp_nh = static_cast(rt->GetActiveNextHop()); - //be NULL - component_nh_it = comp_nh->begin(); - component_nh_it++; - component_nh_it++; - EXPECT_TRUE(*component_nh_it == NULL); - - component_nh_it++; - intf_nh = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet4"); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet4"); - - component_nh_it++; - intf_nh = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet5"); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet5"); - - //Delete the vnet4 floating ip. Since only vent5 has floating IP - //route should point to interface NH - DelLink("virtual-machine-interface", "vnet4", "floating-ip", "fip1"); - client->WaitForIdle(); - EXPECT_TRUE(rt->GetActiveNextHop() == intf_nh); - - //Expect MPLS label to be not present - EXPECT_FALSE(FindMplsLabel(MplsLabel::VPORT_NH, composite_mpls_label)); - - DelLink("virtual-machine-interface", "vnet5", "floating-ip", "fip1"); - DelLink("floating-ip-pool", "fip-pool1", "virtual-network", "default-project:vn2"); - client->WaitForIdle(); - EXPECT_FALSE(RouteFind("default-project:vn2:vn2", ip, 32)); - - DeleteVmportFIpEnv(input1, 5, true); - DeleteVmportFIpEnv(input2, 1, true); - WAIT_FOR(100, 1000, (VrfFind("vrf1") == false)); - WAIT_FOR(100, 1000, (VrfFind("vrf2") == false)); - client->WaitForIdle(); -} - -//Create a ECMP NH on a delete marked VRF, -//and make sure NH is not created -TEST_F(CfgTest, EcmpNH_4) { - AddVrf("vrf2"); - client->WaitForIdle(); - - VrfEntryRef vrf1 = VrfGet("vrf2"); - client->WaitForIdle(); - - DelVrf("vrf2"); - WAIT_FOR(100, 1000, (VrfFind("vrf2") == false)); - client->WaitForIdle(); - - //Enqueue a request to add composite NH - //since the entry is marked delete, composite NH will not get - //created - ComponentNHKeyList comp_nh_list; - DBRequest req; - req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; - req.key.reset(new CompositeNHKey(Composite::ECMP, true, comp_nh_list, "vrf2")); - req.data.reset(new CompositeNHData()); - agent_->nexthop_table()->Enqueue(&req); - - client->WaitForIdle(); - - CompositeNHKey key(Composite::ECMP, true, comp_nh_list, "vrf2"); - EXPECT_FALSE(FindNH(&key)); - vrf1.reset(); -} - -//Create a remote route first pointing to tunnel NH -//Change the route to point to composite NH with old tunnel NH -//and a new tunnel NH, and make sure -//preexiting NH gets slot 0 in composite NH -TEST_F(CfgTest, EcmpNH_5) { - AddVrf("vrf2"); - client->WaitForIdle(); - - Ip4Address remote_vm_ip = Ip4Address::from_string("1.1.1.1"); - Ip4Address remote_server_ip1 = Ip4Address::from_string("10.10.10.100"); - Ip4Address remote_server_ip2 = Ip4Address::from_string("10.10.10.101"); - //Add a remote VM route - Inet4TunnelRouteAdd(NULL, "vrf2", remote_vm_ip, 32, remote_server_ip1, - TunnelType::DefaultType(), 30, "vn2", - SecurityGroupList(), PathPreference()); - client->WaitForIdle(); - //Create component NH list - //Transition remote VM route to ECMP route - ComponentNHKeyPtr nh_data1(new ComponentNHKey(30, agent_->fabric_vrf_name(), - agent_->router_id(), - remote_server_ip1, - false, - TunnelType::DefaultType())); - ComponentNHKeyPtr nh_data2(new ComponentNHKey(20, - agent_->fabric_vrf_name(), - agent_->router_id(), - remote_server_ip2, - false, - TunnelType::DefaultType())); - ComponentNHKeyList comp_nh_list; - //Insert new NH first and then existing route NH - comp_nh_list.push_back(nh_data2); - comp_nh_list.push_back(nh_data1); - - SecurityGroupList sg_id_list; - EcmpTunnelRouteAdd(NULL, "vrf2", remote_vm_ip, 32, - comp_nh_list, -1, "vn2", sg_id_list, PathPreference()); - client->WaitForIdle(); - InetUnicastRouteEntry *rt = RouteGet("vrf2", remote_vm_ip, 32); - EXPECT_TRUE(rt != NULL); - const NextHop *nh = rt->GetActiveNextHop(); - EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); - - const CompositeNH *comp_nh = static_cast(nh); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 2); - - //Verify all the component NH have right label and nexthop - ComponentNHList::const_iterator component_nh_it = - comp_nh->begin(); - const TunnelNH *tun_nh1 = static_cast - ((*component_nh_it)->nh()); - EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip1); - EXPECT_TRUE((*component_nh_it)->label() == 30); - - component_nh_it++; - tun_nh1 = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip2); - EXPECT_TRUE((*component_nh_it)->label() == 20); - - agent_->fabric_inet4_unicast_table()->DeleteReq(NULL, "vrf2", - remote_vm_ip, 32, NULL); - DelVrf("vrf2"); - WAIT_FOR(100, 1000, (VrfFind("vrf2") == false)); - client->WaitForIdle(); - EXPECT_FALSE(VrfFind("vrf2")); -} - -//Create a remote route first pointing to tunnel NH -//Change the route to point to composite NH with all new tunnel NH -//make sure preexiting NH doesnt exist in the new component NH list -TEST_F(CfgTest, EcmpNH_6) { - AddVrf("vrf2"); - client->WaitForIdle(); - - Ip4Address remote_vm_ip = Ip4Address::from_string("1.1.1.1"); - Ip4Address remote_server_ip1 = Ip4Address::from_string("10.10.10.100"); - Ip4Address remote_server_ip2 = Ip4Address::from_string("10.10.10.101"); - Ip4Address remote_server_ip3 = Ip4Address::from_string("10.10.10.102"); - //Add a remote VM route - Inet4TunnelRouteAdd(NULL, "vrf2", - remote_vm_ip, - 32, remote_server_ip1, - TunnelType::AllType(), - 30, "vn2", - SecurityGroupList(), PathPreference()); - client->WaitForIdle(); - //Create component NH list - //Transition remote VM route to ECMP route - ComponentNHKeyPtr nh_data1(new ComponentNHKey(30, agent_->fabric_vrf_name(), - agent_->router_id(), - remote_server_ip2, - false, - TunnelType::DefaultType())); - ComponentNHKeyPtr nh_data2(new ComponentNHKey(20, - agent_->fabric_vrf_name(), - agent_->router_id(), - remote_server_ip3, - false, - TunnelType::DefaultType())); - ComponentNHKeyList comp_nh_list; - //Insert new NH first and then existing route NH - comp_nh_list.push_back(nh_data1); - comp_nh_list.push_back(nh_data2); - - SecurityGroupList sg_list; - EcmpTunnelRouteAdd(NULL, "vrf2", remote_vm_ip, 32, - comp_nh_list, -1, "vn2", sg_list, PathPreference()); - client->WaitForIdle(); - InetUnicastRouteEntry *rt = RouteGet("vrf2", remote_vm_ip, 32); - EXPECT_TRUE(rt != NULL); - const NextHop *nh = rt->GetActiveNextHop(); - EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); - - const CompositeNH *comp_nh = static_cast(nh); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 2); - - //Verify all the component NH have right label and nexthop - ComponentNHList::const_iterator component_nh_it = - comp_nh->begin(); - const TunnelNH *tun_nh1 = static_cast - ((*component_nh_it)->nh()); - EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip2); - EXPECT_TRUE((*component_nh_it)->label() == 30); - - component_nh_it++; - tun_nh1 = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip3); - EXPECT_TRUE((*component_nh_it)->label() == 20); - - agent_->fabric_inet4_unicast_table()->DeleteReq(NULL, "vrf2", - remote_vm_ip, 32, NULL); - DelVrf("vrf2"); - WAIT_FOR(100, 1000, (VrfFind("vrf2") == false)); - client->WaitForIdle(); - EXPECT_FALSE(VrfFind("vrf2")); -} - -TEST_F(CfgTest, EcmpNH_7) { - //Create mutliple VM interface with same IP - struct PortInfo input1[] = { - {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1} - }; - - struct PortInfo input2[] = { - {"vnet2", 2, "1.1.1.1", "00:00:00:02:02:01", 1, 2} - }; - - struct PortInfo input3[] = { - {"vnet3", 3, "1.1.1.1", "00:00:00:02:02:03", 1, 3} - }; - - CreateVmportWithEcmp(input1, 1); - client->WaitForIdle(); - //First VM added, route points to composite NH - Ip4Address ip = Ip4Address::from_string("1.1.1.1"); - InetUnicastRouteEntry *rt = RouteGet("vrf1", ip, 32); - EXPECT_TRUE(rt != NULL); - const NextHop *nh = rt->GetActiveNextHop(); - EXPECT_TRUE(nh->GetType() == NextHop::INTERFACE); - - //Second VM added, route should point to composite NH - CreateVmportWithEcmp(input2, 1); - client->WaitForIdle(); - nh = rt->GetActiveNextHop(); - EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); - const CompositeNH *comp_nh = static_cast(nh); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 2); - - DBEntryBase::KeyPtr comp_key = comp_nh->GetDBRequestKey(); - NextHopKey *nh_key = static_cast(comp_key.release()); - std::auto_ptr nh_key_ptr(nh_key); - ComponentNHKeyPtr nh_data1(new ComponentNHKey(rt->GetActiveLabel(), - nh_key_ptr)); - Ip4Address remote_server_ip1 = Ip4Address::from_string("11.1.1.1"); - //Leak the route via BGP peer - ComponentNHKeyPtr nh_data2(new ComponentNHKey(30, agent_->fabric_vrf_name(), - agent_->router_id(), - remote_server_ip1, - false, - TunnelType::DefaultType())); - ComponentNHKeyList comp_nh_list; - comp_nh_list.push_back(nh_data1); - comp_nh_list.push_back(nh_data2); - - SecurityGroupList sg_id_list; - EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip, 32, - comp_nh_list, false, "vn1", sg_id_list, PathPreference()); - client->WaitForIdle(); - - CreateVmportWithEcmp(input3, 1); - client->WaitForIdle(); - comp_nh = static_cast(rt->GetActiveNextHop()); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 4); - - //Verify all the component NH have right label and nexthop - ComponentNHList::const_iterator component_nh_it = - comp_nh->begin(); - const InterfaceNH *intf_nh = static_cast - ((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); - MplsLabel *mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); - - component_nh_it++; - component_nh_it++; - intf_nh = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet2"); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet2"); - - component_nh_it++; - intf_nh = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); - - //Delete couple of interface and verify composite NH also get - //deleted - DeleteVmportEnv(input1, 1, false); - client->WaitForIdle(); - - //Verify all the component NH have right label and nexthop - comp_nh = static_cast(rt->GetActiveNextHop()); - component_nh_it = comp_nh->begin(); - EXPECT_TRUE(*component_nh_it == NULL); - - component_nh_it++; - component_nh_it++; - intf_nh = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet2"); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet2"); - - //Interface vnet3 has been deleted, expect the component NH to be NULL - component_nh_it++; - intf_nh = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); - - //Create Vmport again - CreateVmportWithEcmp(input1, 1); - client->WaitForIdle(); - comp_nh = static_cast(rt->GetActiveNextHop()); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 4); - - //Verify all the component NH have right label and nexthop - component_nh_it = comp_nh->begin(); - intf_nh = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); - - component_nh_it++; - component_nh_it++; - intf_nh = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet2"); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet2"); - - component_nh_it++; - intf_nh = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); - mpls = GetActiveLabel(MplsLabel::VPORT_NH, - (*component_nh_it)->label()); - intf_nh = static_cast(mpls->nexthop()); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet3"); - - - DeleteVmportEnv(input1, 1, false); - DeleteVmportEnv(input2, 1, false); - DeleteVmportEnv(input3, 1, true); - client->WaitForIdle(); - EXPECT_FALSE(RouteFind("vrf1", ip, 32)); - - WAIT_FOR(100, 1000, (VrfFind("vrf1") == false)); -} - -//Add multiple remote routes with same set of composite NH -//make sure they share the composite NH -TEST_F(CfgTest, EcmpNH_8) { - AddVrf("vrf1"); - client->WaitForIdle(); - - Ip4Address remote_server_ip1 = Ip4Address::from_string("10.10.10.100"); - Ip4Address remote_server_ip2 = Ip4Address::from_string("10.10.10.101"); - - ComponentNHKeyPtr nh_data1(new ComponentNHKey(30, agent_->fabric_vrf_name(), - agent_->router_id(), - remote_server_ip1, - false, - TunnelType::DefaultType())); - ComponentNHKeyPtr nh_data2(new ComponentNHKey(20, agent_->fabric_vrf_name(), - agent_->router_id(), - remote_server_ip2, - false, - TunnelType::DefaultType())); - - ComponentNHKeyList comp_nh_list; - comp_nh_list.push_back(nh_data1); - comp_nh_list.push_back(nh_data2); - - Ip4Address ip1 = Ip4Address::from_string("100.1.1.1"); - SecurityGroupList sg_id_list; - EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip1, 32, - comp_nh_list, false, "vn1", sg_id_list, PathPreference()); - client->WaitForIdle(); - - Ip4Address ip2 = Ip4Address::from_string("100.1.1.2"); - EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip2, 32, - comp_nh_list, false, "vn1", sg_id_list, PathPreference()); - client->WaitForIdle(); - - InetUnicastRouteEntry *rt1 = RouteGet("vrf1", ip1, 32); - InetUnicastRouteEntry *rt2 = RouteGet("vrf1", ip2, 32); - EXPECT_TRUE(rt1->GetActiveNextHop()->GetType() == NextHop::COMPOSITE); - EXPECT_TRUE(rt1->GetActiveNextHop() == rt2->GetActiveNextHop()); - - const NextHop *nh = rt1->GetActiveNextHop(); - //Change ip1 route nexthop to be unicast nexthop - //and ensure ip2 route still points to old composite nexthop - Inet4TunnelRouteAdd(bgp_peer, "vrf1", ip1, 32, remote_server_ip1, - TunnelType::AllType(), 8, "vn1", - SecurityGroupList(), PathPreference()); - client->WaitForIdle(); - - EXPECT_TRUE(rt1->GetActiveNextHop()->GetType() == NextHop::TUNNEL); - EXPECT_TRUE(rt2->GetActiveNextHop() == nh); - client->WaitForIdle(); - - //Delete all the routes and make sure nexthop is also deleted - agent_->fabric_inet4_unicast_table()-> - DeleteReq(bgp_peer, "vrf1", ip1, 32, NULL); - agent_->fabric_inet4_unicast_table()-> - DeleteReq(bgp_peer, "vrf1", ip2, 32, NULL); - client->WaitForIdle(); - - CompositeNHKey composite_nh_key(Composite::ECMP, true, comp_nh_list, "vrf1"); - EXPECT_FALSE(FindNH(&composite_nh_key)); - DelVrf("vrf1"); -} - -//Add ECMP composite NH with no member -TEST_F(CfgTest, EcmpNH_9) { - AddVrf("vrf1"); - client->WaitForIdle(); - ComponentNHKeyList comp_nh_list; - Ip4Address ip1 = Ip4Address::from_string("100.1.1.1"); - Ip4Address remote_server_ip1 = Ip4Address::from_string("10.1.1.10"); - SecurityGroupList sg_id_list; - EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip1, 32, - comp_nh_list, false, "vn1", sg_id_list, PathPreference()); - client->WaitForIdle(); - - InetUnicastRouteEntry *rt1 = RouteGet("vrf1", ip1, 32); - EXPECT_TRUE(rt1->GetActiveNextHop()->GetType() == NextHop::COMPOSITE); - - //Change ip1 route nexthop to be unicast nexthop - Inet4TunnelRouteAdd(bgp_peer, "vrf1", ip1, 32, remote_server_ip1, - TunnelType::AllType(), 8, "vn1", - SecurityGroupList(), PathPreference()); - client->WaitForIdle(); - - EXPECT_TRUE(rt1->GetActiveNextHop()->GetType() == NextHop::TUNNEL); - client->WaitForIdle(); - - //Delete all the routes and make sure nexthop is also deleted - agent_->fabric_inet4_unicast_table()-> - DeleteReq(bgp_peer, "vrf1", ip1, 32, NULL); - client->WaitForIdle(); - - CompositeNHKey composite_nh_key(Composite::ECMP, true, comp_nh_list, "vrf1"); - EXPECT_FALSE(FindNH(&composite_nh_key)); - DelVrf("vrf1"); -} - -//Add 2 routes with different composite NH -//Modify the routes, to point to same composite NH -//and ensure both routes would share same nexthop -TEST_F(CfgTest, EcmpNH_10) { - AddVrf("vrf1"); - client->WaitForIdle(); - - Ip4Address remote_server_ip1 = Ip4Address::from_string("10.10.10.100"); - Ip4Address remote_server_ip2 = Ip4Address::from_string("10.10.10.101"); - Ip4Address remote_server_ip3 = Ip4Address::from_string("10.10.10.102"); - - ComponentNHKeyPtr nh_data1(new ComponentNHKey(30, agent_->fabric_vrf_name(), - agent_->router_id(), - remote_server_ip1, - false, - TunnelType::DefaultType())); - ComponentNHKeyPtr nh_data2(new ComponentNHKey(20, agent_->fabric_vrf_name(), - agent_->router_id(), - remote_server_ip2, - false, - TunnelType::DefaultType())); - ComponentNHKeyPtr nh_data3(new ComponentNHKey(20, agent_->fabric_vrf_name(), - agent_->router_id(), - remote_server_ip3, - false, - TunnelType::DefaultType())); - ComponentNHKeyList comp_nh_list1; - comp_nh_list1.push_back(nh_data1); - comp_nh_list1.push_back(nh_data2); - - Ip4Address ip1 = Ip4Address::from_string("100.1.1.1"); - SecurityGroupList sg_id_list; - EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip1, 32, - comp_nh_list1, false, "vn1", sg_id_list, PathPreference()); - client->WaitForIdle(); - - ComponentNHKeyList comp_nh_list2; - comp_nh_list2.push_back(nh_data3); - comp_nh_list2.push_back(nh_data2); - - Ip4Address ip2 = Ip4Address::from_string("100.1.1.2"); - EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip2, 32, - comp_nh_list2, false, "vn1", sg_id_list, PathPreference()); - client->WaitForIdle(); - - InetUnicastRouteEntry *rt1 = RouteGet("vrf1", ip1, 32); - InetUnicastRouteEntry *rt2 = RouteGet("vrf1", ip2, 32); - EXPECT_TRUE(rt1->GetActiveNextHop()->GetType() == NextHop::COMPOSITE); - EXPECT_TRUE(rt1->GetActiveNextHop() != rt2->GetActiveNextHop()); - - const NextHop *nh = rt1->GetActiveNextHop(); - //Change ip2 route, such that ip1 route and ip2 route - //should share same nexthop - EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip2, 32, - comp_nh_list1, false, "vn1", sg_id_list, - PathPreference()); - client->WaitForIdle(); - - EXPECT_TRUE(rt1->GetActiveNextHop() == rt2->GetActiveNextHop()); - EXPECT_TRUE(rt2->GetActiveNextHop() == nh); - EXPECT_TRUE(rt2->GetActiveNextHop()->GetType() == NextHop::COMPOSITE); - //Make sure old nexthop is deleted - CompositeNHKey composite_nh_key2(Composite::ECMP, true, comp_nh_list2, "vrf1"); - EXPECT_FALSE(FindNH(&composite_nh_key2)); - CompositeNHKey composite_nh_key1(Composite::ECMP, true, comp_nh_list1, "vrf1"); - EXPECT_TRUE(GetNH(&composite_nh_key1)->GetRefCount() == 2); - - //Delete all the routes and make sure nexthop is also deleted - agent_->fabric_inet4_unicast_table()-> - DeleteReq(bgp_peer, "vrf1", ip1, 32, NULL); - agent_->fabric_inet4_unicast_table()-> - DeleteReq(bgp_peer, "vrf1", ip2, 32, NULL); - client->WaitForIdle(); - - EXPECT_FALSE(FindNH(&composite_nh_key1)); - DelVrf("vrf1"); -} - -//Add 2 routes with different composite NH -//Modify the routes, to point to same composite NH -//and ensure both routes would share same nexthop -TEST_F(CfgTest, EcmpNH_11) { - AddVrf("vrf1"); - client->WaitForIdle(); - - Ip4Address remote_server_ip1 = Ip4Address::from_string("10.10.10.100"); - Ip4Address remote_server_ip2 = Ip4Address::from_string("10.10.10.101"); - Ip4Address remote_server_ip3 = Ip4Address::from_string("10.10.10.102"); - - ComponentNHKeyPtr nh_data1(new ComponentNHKey(30, agent_->fabric_vrf_name(), - agent_->router_id(), - remote_server_ip1, - false, - TunnelType::DefaultType())); - ComponentNHKeyPtr nh_data2(new ComponentNHKey(20, agent_->fabric_vrf_name(), - agent_->router_id(), - remote_server_ip2, - false, - TunnelType::DefaultType())); - ComponentNHKeyPtr nh_data3(new ComponentNHKey(20, agent_->fabric_vrf_name(), - agent_->router_id(), - remote_server_ip3, - false, - TunnelType::DefaultType())); - ComponentNHKeyList comp_nh_list1; - comp_nh_list1.push_back(nh_data1); - comp_nh_list1.push_back(nh_data2); - - Ip4Address ip1 = Ip4Address::from_string("100.1.1.1"); - SecurityGroupList sg_id_list; - EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip1, 32, - comp_nh_list1, false, "vn1", sg_id_list, PathPreference()); - client->WaitForIdle(); - - ComponentNHKeyList comp_nh_list2; - comp_nh_list2.push_back(nh_data1); - comp_nh_list2.push_back(nh_data2); - comp_nh_list2.push_back(nh_data3); - - Ip4Address ip2 = Ip4Address::from_string("100.1.1.2"); - EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip2, 32, - comp_nh_list2, false, "vn1", sg_id_list, PathPreference()); - client->WaitForIdle(); - - InetUnicastRouteEntry *rt1 = RouteGet("vrf1", ip1, 32); - InetUnicastRouteEntry *rt2 = RouteGet("vrf1", ip2, 32); - EXPECT_TRUE(rt1->GetActiveNextHop()->GetType() == NextHop::COMPOSITE); - EXPECT_TRUE(rt1->GetActiveNextHop() != rt2->GetActiveNextHop()); - CompositeNHKey composite_nh_key1(Composite::ECMP, true, comp_nh_list1, "vrf1"); - CompositeNHKey composite_nh_key2(Composite::ECMP, true, comp_nh_list2, "vrf1"); - CompositeNH *composite_nh1 = - static_cast(GetNH(&composite_nh_key1)); - EXPECT_TRUE(composite_nh1->GetRefCount() == 1); - EXPECT_TRUE(composite_nh1->ComponentNHCount() == 2); - - CompositeNH *composite_nh2 = - static_cast(GetNH(&composite_nh_key2)); - EXPECT_TRUE(composite_nh2->GetRefCount() == 1); - EXPECT_TRUE(composite_nh2->ComponentNHCount() == 3); - - //Change ip1 route, such that ip1 route and ip2 route - //should share same nexthop - EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip1, 32, - comp_nh_list2, false, "vn1", sg_id_list, - PathPreference()); - client->WaitForIdle(); - - EXPECT_TRUE(rt1->GetActiveNextHop() == rt2->GetActiveNextHop()); - EXPECT_TRUE(rt2->GetActiveNextHop() == composite_nh2); - EXPECT_TRUE(rt2->GetActiveNextHop()->GetType() == NextHop::COMPOSITE); - //Make sure old nexthop is deleted - EXPECT_TRUE(composite_nh2->GetRefCount() == 2); - EXPECT_TRUE(composite_nh2->ComponentNHCount() == 3); - - //Delete all the routes and make sure nexthop is also deleted - agent_->fabric_inet4_unicast_table()-> - DeleteReq(bgp_peer, "vrf1", ip1, 32, NULL); - agent_->fabric_inet4_unicast_table()-> - DeleteReq(bgp_peer, "vrf1", ip2, 32, NULL); - client->WaitForIdle(); - - EXPECT_FALSE(FindNH(&composite_nh_key1)); - DelVrf("vrf1"); -} - -//Add a route pointing to tunnel NH -//Change the route to point to ECMP composite NH with no member -TEST_F(CfgTest, EcmpNH_12) { - AddVrf("vrf1"); - client->WaitForIdle(); - - Ip4Address ip1 = Ip4Address::from_string("100.1.1.1"); - Ip4Address remote_server_ip1 = Ip4Address::from_string("10.1.1.10"); - SecurityGroupList sg_id_list; - - //Change ip1 route nexthop to be unicast nexthop - Inet4TunnelRouteAdd(bgp_peer, "vrf1", ip1, 32, remote_server_ip1, - TunnelType::AllType(), 8, "vn1", - SecurityGroupList(), PathPreference()); - client->WaitForIdle(); - - InetUnicastRouteEntry *rt1 = RouteGet("vrf1", ip1, 32); - EXPECT_TRUE(rt1->GetActiveNextHop()->GetType() == NextHop::TUNNEL); - client->WaitForIdle(); - - ComponentNHKeyList comp_nh_list; - EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip1, 32, - comp_nh_list, false, "vn1", sg_id_list, PathPreference()); - client->WaitForIdle(); - - rt1 = RouteGet("vrf1", ip1, 32); - EXPECT_TRUE(rt1->GetActiveNextHop()->GetType() == NextHop::COMPOSITE); - - //Delete all the routes and make sure nexthop is also deleted - agent_->fabric_inet4_unicast_table()-> - DeleteReq(bgp_peer, "vrf1", ip1, 32, NULL); - client->WaitForIdle(); - - CompositeNHKey composite_nh_key(Composite::ECMP, true, comp_nh_list, "vrf1"); - EXPECT_FALSE(FindNH(&composite_nh_key)); - DelVrf("vrf1"); -} - -//Verify renewal of composite NH -TEST_F(CfgTest, EcmpNH_13) { - AddVrf("vrf1"); - client->WaitForIdle(); - Ip4Address remote_server_ip1 = Ip4Address::from_string("10.10.10.100"); - Ip4Address remote_server_ip2 = Ip4Address::from_string("10.10.10.101"); - - ComponentNHKeyPtr nh_data1(new ComponentNHKey(30, agent_->fabric_vrf_name(), - agent_->router_id(), - remote_server_ip1, - false, - TunnelType::DefaultType())); - ComponentNHKeyPtr nh_data2(new ComponentNHKey(20, agent_->fabric_vrf_name(), - agent_->router_id(), - remote_server_ip2, - false, - TunnelType::DefaultType())); - ComponentNHKeyList comp_nh_list; - comp_nh_list.push_back(nh_data1); - comp_nh_list.push_back(nh_data2); - - Ip4Address ip1 = Ip4Address::from_string("100.1.1.1"); - SecurityGroupList sg_id_list; - EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip1, 32, - comp_nh_list, false, "vn1", sg_id_list, PathPreference()); - client->WaitForIdle(); - - //Delete composite NH - CompositeNHKey composite_nh_key(Composite::ECMP, true, comp_nh_list, "vrf1"); - const CompositeNH *comp_nh = static_cast( - GetNH(&composite_nh_key)); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 2); - - DBRequest req; - req.oper = DBRequest::DB_ENTRY_DELETE; - NextHopKey *key = new CompositeNHKey(Composite::ECMP, true, - comp_nh_list, "vrf1"); - req.key.reset(key); - req.data.reset(NULL); - NextHopTable::GetInstance()->Enqueue(&req); - client->WaitForIdle(); - EXPECT_TRUE(comp_nh->ActiveComponentNHCount() == 0); - client->NextHopReset(); - - req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; - key = new CompositeNHKey(Composite::ECMP, true, - comp_nh_list, "vrf1"); - ((CompositeNHKey *)key)->CreateTunnelNHReq(agent_); - req.key.reset(key); - req.data.reset(NULL); - NextHopTable::GetInstance()->Enqueue(&req); - client->WaitForIdle(); - client->CompositeNHWait(1); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 2); - - //Delete all the routes and make sure nexthop is also deleted - agent_->fabric_inet4_unicast_table()-> - DeleteReq(bgp_peer, "vrf1", ip1, 32, NULL); - client->WaitForIdle(); - - EXPECT_FALSE(FindNH(&composite_nh_key)); - DelVrf("vrf1"); -} - -TEST_F(CfgTest, EcmpNH_14) { - //Create mutliple VM interface with same IP - struct PortInfo input1[] = { - {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1}, - {"vnet2", 2, "1.1.1.1", "00:00:00:01:01:01", 1, 2} - }; - - CreateVmportWithEcmp(input1, 1); - client->WaitForIdle(); - //First VM added, route points to composite NH - Ip4Address ip = Ip4Address::from_string("1.1.1.1"); - InetUnicastRouteEntry *rt = RouteGet("vrf1", ip, 32); - EXPECT_TRUE(rt != NULL); - const NextHop *nh = rt->GetActiveNextHop(); - EXPECT_TRUE(nh->GetType() == NextHop::INTERFACE); - - DBEntryBase::KeyPtr db_nh_key = nh->GetDBRequestKey(); - NextHopKey *nh_key = static_cast(db_nh_key.release()); - std::auto_ptr nh_key_ptr(nh_key); - ComponentNHKeyPtr nh_data1(new ComponentNHKey(rt->GetActiveLabel(), - nh_key_ptr)); - Ip4Address remote_server_ip1 = Ip4Address::from_string("11.1.1.1"); - //Leak the route via BGP peer - ComponentNHKeyPtr nh_data2(new ComponentNHKey(30, agent_->fabric_vrf_name(), - agent_->router_id(), - remote_server_ip1, - false, - TunnelType::DefaultType())); - ComponentNHKeyList comp_nh_list; - comp_nh_list.push_back(nh_data1); - comp_nh_list.push_back(nh_data2); - - SecurityGroupList sg_id_list; - EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip, 32, - comp_nh_list, false, "vn1", sg_id_list, - PathPreference()); - client->WaitForIdle(); - - //Deactivate vm interface - DelLink("virtual-network", "vn1", "virtual-machine-interface", "vnet1"); - //Transition ecmp to tunnel NH - Inet4TunnelRouteAdd(bgp_peer, "vrf1", ip, 32, remote_server_ip1, - TunnelType::DefaultType(), 30, "vn2", - SecurityGroupList(), PathPreference()); - client->WaitForIdle(); - - //Resync the route - rt->EnqueueRouteResync(); - client->WaitForIdle(); - - DeleteVmportEnv(input1, 2, true); - client->WaitForIdle(); - EXPECT_FALSE(VrfFind("vrf1", true)); -} - -//Create a remote route with ECMP component NH in order A,B and C -//Enqueue change for the same route in different order of composite NH -//verify that nexthop doesnt change -TEST_F(CfgTest, EcmpNH_15) { - AddVrf("vrf2"); - client->WaitForIdle(); - - Ip4Address remote_vm_ip = Ip4Address::from_string("1.1.1.1"); - Ip4Address remote_server_ip1 = Ip4Address::from_string("10.10.10.100"); - Ip4Address remote_server_ip2 = Ip4Address::from_string("10.10.10.101"); - Ip4Address remote_server_ip3 = Ip4Address::from_string("10.10.10.102"); - //Create component NH list - //Transition remote VM route to ECMP route - ComponentNHKeyPtr nh_data1(new ComponentNHKey(15, agent_->fabric_vrf_name(), - agent_->router_id(), - remote_server_ip1, - false, - TunnelType::DefaultType())); - ComponentNHKeyPtr nh_data2(new ComponentNHKey(20, - agent_->fabric_vrf_name(), - agent_->router_id(), - remote_server_ip2, - false, - TunnelType::DefaultType())); - ComponentNHKeyPtr nh_data3(new ComponentNHKey(25, - agent_->fabric_vrf_name(), - agent_->router_id(), - remote_server_ip3, - false, - TunnelType::DefaultType())); - - ComponentNHKeyList comp_nh_list; - //Insert new NH first and then existing route NH - comp_nh_list.push_back(nh_data1); - comp_nh_list.push_back(nh_data2); - comp_nh_list.push_back(nh_data3); - - SecurityGroupList sg_list; - EcmpTunnelRouteAdd(NULL, "vrf2", remote_vm_ip, 32, - comp_nh_list, -1, "vn2", sg_list, PathPreference()); - client->WaitForIdle(); - InetUnicastRouteEntry *rt = RouteGet("vrf2", remote_vm_ip, 32); - EXPECT_TRUE(rt != NULL); - const NextHop *nh = rt->GetActiveNextHop(); - EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); - - const CompositeNH *comp_nh = static_cast(nh); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 3); - - //Verify all the component NH have right label and nexthop - ComponentNHList::const_iterator component_nh_it = - comp_nh->begin(); - const TunnelNH *tun_nh1 = static_cast - ((*component_nh_it)->nh()); - EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip1); - EXPECT_TRUE((*component_nh_it)->label() == 15); - - component_nh_it++; - tun_nh1 = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip2); - EXPECT_TRUE((*component_nh_it)->label() == 20); - - component_nh_it++; - tun_nh1 = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip3); - EXPECT_TRUE((*component_nh_it)->label() == 25); - - //Enqueue route change in different order - comp_nh_list.clear(); - comp_nh_list.push_back(nh_data2); - comp_nh_list.push_back(nh_data3); - comp_nh_list.push_back(nh_data1); - - EcmpTunnelRouteAdd(NULL, "vrf2", remote_vm_ip, 32, - comp_nh_list, -1, "vn2", sg_list, PathPreference()); - client->WaitForIdle(); - rt = RouteGet("vrf2", remote_vm_ip, 32); - EXPECT_TRUE(rt != NULL); - nh = rt->GetActiveNextHop(); - EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); - - comp_nh = static_cast(nh); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 3); - - //Verify all the component NH have right label and nexthop - component_nh_it = comp_nh->begin(); - tun_nh1 = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip1); - EXPECT_TRUE((*component_nh_it)->label() == 15); - - component_nh_it++; - tun_nh1 = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip2); - EXPECT_TRUE((*component_nh_it)->label() == 20); - - component_nh_it++; - tun_nh1 = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip3); - EXPECT_TRUE((*component_nh_it)->label() == 25); - - comp_nh_list.clear(); - comp_nh_list.push_back(nh_data3); - comp_nh_list.push_back(nh_data2); - comp_nh_list.push_back(nh_data1); - - EcmpTunnelRouteAdd(NULL, "vrf2", remote_vm_ip, 32, - comp_nh_list, -1, "vn2", sg_list, PathPreference()); - client->WaitForIdle(); - rt = RouteGet("vrf2", remote_vm_ip, 32); - EXPECT_TRUE(rt != NULL); - nh = rt->GetActiveNextHop(); - EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); - - comp_nh = static_cast(nh); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 3); - - //Verify all the component NH have right label and nexthop - component_nh_it = comp_nh->begin(); - tun_nh1 = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip1); - EXPECT_TRUE((*component_nh_it)->label() == 15); - - component_nh_it++; - tun_nh1 = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip2); - EXPECT_TRUE((*component_nh_it)->label() == 20); - - component_nh_it++; - tun_nh1 = static_cast((*component_nh_it)->nh()); - EXPECT_TRUE(*tun_nh1->GetDip() == remote_server_ip3); - EXPECT_TRUE((*component_nh_it)->label() == 25); - - agent_->fabric_inet4_unicast_table()->DeleteReq(NULL, "vrf2", - remote_vm_ip, 32, NULL); - DelVrf("vrf2"); - WAIT_FOR(100, 1000, (VrfFind("vrf2") == false)); - client->WaitForIdle(); - EXPECT_FALSE(VrfFind("vrf2")); -} - -//Create a composite NH with one interface NH which is not present -//Add the interface, trigger route change and verify that component NH -//list get populated -TEST_F(CfgTest, EcmpNH_16) { - AddVrf("vrf2"); - client->WaitForIdle(); - Ip4Address remote_vm_ip = Ip4Address::from_string("1.1.1.1"); - //Transition remote VM route to ECMP route - ComponentNHKeyPtr nh_data1(new ComponentNHKey(15, MakeUuid(1), - InterfaceNHFlags::INET4)); - ComponentNHKeyList comp_nh_list; - //Insert new NH first and then existing route NH - comp_nh_list.push_back(nh_data1); - SecurityGroupList sg_list; - EcmpTunnelRouteAdd(NULL, "vrf2", remote_vm_ip, 32, - comp_nh_list, -1, "vn2", sg_list, PathPreference()); - client->WaitForIdle(); - - //Nexthop is not found, hence component NH count is 0 - InetUnicastRouteEntry *rt = RouteGet("vrf2", remote_vm_ip, 32); - EXPECT_TRUE(rt != NULL); - const NextHop *nh = rt->GetActiveNextHop(); - EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); - - const CompositeNH *comp_nh = static_cast(nh); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 1); - //Verify all the component NH have right label and nexthop - ComponentNHList::const_iterator component_nh_it = - comp_nh->begin(); - EXPECT_TRUE(*component_nh_it == NULL); - - //Add interface - struct PortInfo input[] = { - {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1}, - }; - CreateVmportEnv(input, 1); - client->WaitForIdle(); - - client->NextHopReset(); - EcmpTunnelRouteAdd(NULL, "vrf2", remote_vm_ip, 32, - comp_nh_list, -1, "vn2", sg_list, PathPreference()); - client->WaitForIdle(); - - EXPECT_TRUE(client->CompositeNHWait(1)); - //Nexthop is not found, hence component NH count is 0 - rt = RouteGet("vrf2", remote_vm_ip, 32); - EXPECT_TRUE(rt != NULL); - nh = rt->GetActiveNextHop(); - EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); - comp_nh = static_cast(nh); - EXPECT_TRUE(comp_nh->ComponentNHCount() == 1); - component_nh_it = comp_nh->begin(); - EXPECT_TRUE(*component_nh_it != NULL); - EXPECT_TRUE((*component_nh_it)->nh()->GetType() == NextHop::INTERFACE); - - DeleteVmportEnv(input, 1, true); - agent_->fabric_inet4_unicast_table()->DeleteReq(NULL, "vrf2", - remote_vm_ip, 32, NULL); - DelVrf("vrf2"); - WAIT_FOR(100, 1000, (VrfFind("vrf2") == false)); - WAIT_FOR(100, 1000, (VrfFind("vrf1") == false)); - client->WaitForIdle(); - EXPECT_FALSE(VrfFind("vrf2")); -} - -//Add a interface NH with policy -//Add a BGP peer route with one interface NH and one tunnel NH -//make sure interface NH gets added without policy -TEST_F(CfgTest, EcmpNH_17) { - //Add interface - struct PortInfo input[] = { - {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1}, - }; - CreateVmportEnv(input, 1, 1); - client->WaitForIdle(); - - VnListType vn_list; - vn_list.insert("vn1"); - const VmInterface *intf = static_cast(VmPortGet(1)); - Ip4Address ip = Ip4Address::from_string("1.1.1.1"); - agent_->fabric_inet4_unicast_table()-> - AddLocalVmRouteReq(bgp_peer, "vrf1", ip, 32, - MakeUuid(1), vn_list, intf->label(), - SecurityGroupList(), CommunityList(), false, PathPreference(), - Ip4Address(0), EcmpLoadBalance()); - client->WaitForIdle(); - - InetUnicastRouteEntry *rt = RouteGet("vrf1", ip, 32); - EXPECT_TRUE(rt != NULL); - const NextHop *nh = rt->GetActiveNextHop(); - - Ip4Address remote_server_ip1 = Ip4Address::from_string("10.10.10.100"); - //Create component NH list - //Transition remote VM route to ECMP route - ComponentNHKeyPtr nh_data1(new ComponentNHKey(15, agent_->fabric_vrf_name(), - agent_->router_id(), - remote_server_ip1, - false, - TunnelType::DefaultType())); - DBEntryBase::KeyPtr key = nh->GetDBRequestKey(); - NextHopKey *nh_key = static_cast(key.release()); - std::auto_ptr nh_akey(nh_key); - nh_key->SetPolicy(false); - ComponentNHKeyPtr nh_data2(new ComponentNHKey(intf->label(), nh_akey)); - - ComponentNHKeyList comp_nh_list; - //Insert new NH first and then existing route NH - comp_nh_list.push_back(nh_data1); - comp_nh_list.push_back(nh_data2); - - SecurityGroupList sg_list; - EcmpTunnelRouteAdd(bgp_peer, "vrf1", ip, 32, - comp_nh_list, false, "vn1", sg_list, PathPreference()); - client->WaitForIdle(); - - rt = RouteGet("vrf1", ip, 32); - EXPECT_TRUE(rt != NULL); - nh = rt->GetActiveNextHop(); - EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); - const CompositeNH *comp_nh = static_cast(nh); - const InterfaceNH *intf_nh = static_cast(comp_nh->Get(0)->nh()); - EXPECT_TRUE(intf_nh->PolicyEnabled() == false); - EXPECT_TRUE(intf_nh->GetInterface()->name() == "vnet1"); - - DeleteVmportEnv(input, 1, true); - WAIT_FOR(100, 1000, (VrfFind("vrf1") == false)); - client->WaitForIdle(); - EXPECT_FALSE(RouteFind("vrf1", ip, 32)); -} - TEST_F(CfgTest, TunnelType_1) { AddEncapList("MPLSoGRE", NULL, NULL); client->WaitForIdle(); diff --git a/src/vnsw/agent/test/test_util.cc b/src/vnsw/agent/test/test_util.cc index d9fdf4adc97..5395a30617e 100644 --- a/src/vnsw/agent/test/test_util.cc +++ b/src/vnsw/agent/test/test_util.cc @@ -1221,7 +1221,7 @@ void DeleteRoute(const char *vrf, const char *ip, uint8_t plen, new ControllerVmRoute(bgp_peer)); } client->WaitForIdle(); - WAIT_FOR(1000, 1, (RouteFind(vrf, addr, 32) == false)); + WAIT_FOR(1000, 1000, (RouteFind(vrf, addr, 32) == false)); } bool RouteFind(const string &vrf_name, const Ip4Address &addr, int plen) { @@ -1482,7 +1482,7 @@ bool EcmpTunnelRouteAdd(const Peer *peer, const string &vrf_name, const Ip4Addre type = Composite::LOCAL_ECMP; } DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE); - nh_req.key.reset(new CompositeNHKey(type, true, + nh_req.key.reset(new CompositeNHKey(type, false, comp_nh_list, vrf_name)); nh_req.data.reset(new CompositeNHData()); @@ -2656,7 +2656,6 @@ void DeleteVmportEnv(struct PortInfo *input, int count, int del_vn, int acl_id, sprintf(vrf_name, "%s", vrf); else sprintf(vrf_name, "vrf%d", input[i].vn_id); - sprintf(vm_name, "vm%d", input[i].vm_id); DelLink("virtual-network", vn_name, "routing-instance", vrf_name); if (acl_id) { DelLink("virtual-network", vn_name, "access-control-list", acl_name);