diff --git a/src/vnsw/agent/oper/inet_unicast_route.cc b/src/vnsw/agent/oper/inet_unicast_route.cc index 2dc89385007..2b1386b7101 100644 --- a/src/vnsw/agent/oper/inet_unicast_route.cc +++ b/src/vnsw/agent/oper/inet_unicast_route.cc @@ -352,40 +352,12 @@ bool InetUnicastRouteEntry::ModifyEcmpPath(const IpAddress &dest_addr, ret = true; } - path->set_tunnel_bmap(tunnel_bmap); - TunnelType::Type new_tunnel_type = - TunnelType::ComputeType(path->tunnel_bmap()); - if (path->tunnel_type() != new_tunnel_type) { - path->set_tunnel_type(new_tunnel_type); - ret = true; - } - - SecurityGroupList path_sg_list; - path_sg_list = path->sg_list(); - if (path_sg_list != sg_list) { - path->set_sg_list(sg_list); - ret = true; - } - - CommunityList path_communities; - path_communities = path->communities(); - if (path_communities != communities) { - path->set_communities(communities); - ret = true; - } - - if (path_preference != path->path_preference()) { - path->set_path_preference(path_preference); - ret = true; - } + ret = SyncEcmpPath(path, sg_list, communities, path_preference, + tunnel_bmap, ecmp_load_balance); path->set_dest_vn_list(vn_list); ret = true; path->set_unresolved(false); - if (path->ecmp_load_balance() != ecmp_load_balance) { - path->set_ecmp_load_balance(ecmp_load_balance); - ret = true; - } if (path->ChangeNH(agent, nh) == true) ret = true; @@ -571,6 +543,53 @@ bool InetUnicastRouteEntry::ReComputePathDeletion(AgentPath *path) { return EcmpDeletePath(path); } +bool InetUnicastRouteEntry::SyncEcmpPath(AgentPath *path, + const SecurityGroupList sg_list, + const CommunityList &communities, + const PathPreference &path_preference, + TunnelType::TypeBmap tunnel_bmap, + const EcmpLoadBalance + &ecmp_load_balance) { + if (!path) { + return false; + } + + bool ret = false; + path->set_tunnel_bmap(tunnel_bmap); + TunnelType::Type new_tunnel_type = + TunnelType::ComputeType(path->tunnel_bmap()); + if (path->tunnel_type() != new_tunnel_type) { + path->set_tunnel_type(new_tunnel_type); + ret = true; + } + + SecurityGroupList path_sg_list; + path_sg_list = path->sg_list(); + if (path_sg_list != sg_list) { + path->set_sg_list(sg_list); + ret = true; + } + + CommunityList path_communities; + path_communities = path->communities(); + if (path_communities != communities) { + path->set_communities(communities); + ret = true; + } + + if (path_preference != path->path_preference()) { + path->set_path_preference(path_preference); + ret = true; + } + + if (path->ecmp_load_balance() != ecmp_load_balance) { + path->set_ecmp_load_balance(ecmp_load_balance); + ret = true; + } + + return ret; +} + // Handle add/update of a path in route. // If there are more than one path of type LOCAL_VM_PORT_PEER, creates/updates // Composite-NH for them @@ -625,14 +644,24 @@ bool InetUnicastRouteEntry::EcmpAddPath(AgentPath *path) { return false; } + bool ret = false; if (count == 2 && ecmp == NULL) { // This is second path being added, make ECMP AllocateEcmpPath(agent, vm_port_path, path); + ret = true; } else if (count > 2) { // ECMP already present, add/update Component-NH for the path AppendEcmpPath(agent, path); + ret = true; + } else if (ecmp) { + AgentPath *ecmp_path = FindPath(agent->ecmp_peer()); + ret = SyncEcmpPath(ecmp_path, path->sg_list(), + path->communities(), path->path_preference(), + path->tunnel_bmap(), + path->ecmp_load_balance()); } - return true; + + return ret; } void InetUnicastRouteEntry::AppendEcmpPath(Agent *agent, diff --git a/src/vnsw/agent/oper/inet_unicast_route.h b/src/vnsw/agent/oper/inet_unicast_route.h index 06af1c24003..fdf8eb4e79c 100644 --- a/src/vnsw/agent/oper/inet_unicast_route.h +++ b/src/vnsw/agent/oper/inet_unicast_route.h @@ -88,6 +88,11 @@ class InetUnicastRouteEntry : public AgentRoute { DBRequest &nh_req, Agent* agent, AgentPath *path); + static bool SyncEcmpPath(AgentPath *path, SecurityGroupList sg_list, + const CommunityList &communities, + const PathPreference &path_preference, + TunnelType::TypeBmap tunnel_bmap, + const EcmpLoadBalance &ecmp_ecmp_load_balance); const IpAddress &addr() const { return addr_; } void set_addr(IpAddress addr) { addr_ = addr; }; diff --git a/src/vnsw/agent/test/test_nh.cc b/src/vnsw/agent/test/test_nh.cc index f448218385d..b416afa504b 100644 --- a/src/vnsw/agent/test/test_nh.cc +++ b/src/vnsw/agent/test/test_nh.cc @@ -2460,6 +2460,41 @@ TEST_F(CfgTest, EcmpNH_18) { EXPECT_FALSE(RouteFind("vrf1", ip, 32)); } +TEST_F(CfgTest, EcmpNH_18) { + //Add interface + struct PortInfo input[] = { + {"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(input, 2); + client->WaitForIdle(); + + Ip4Address ip = Ip4Address::from_string("1.1.1.1"); + InetUnicastRouteEntry *rt = RouteGet("vrf1", ip, 32); + EXPECT_TRUE(rt != NULL); + + //Update the SG for path + AddSg("sg1", 1); + AddAcl("acl1", 1); + AddLink("security-group", "sg1", "access-control-list", "acl1"); + AddLink("virtual-machine-interface", "vnet1", "security-group", "sg1"); + client->WaitForIdle(); + + EXPECT_TRUE(rt->GetActivePath()->sg_list().empty() == false); + + DelLink("virtual-machine-interface", "vnet1", "security-group", "sg1"); + DelLink("security-group", "sg1", "access-control-list", "acl1"); + DelAcl("acl1"); + DelNode("security-group", "sg1"); + client->WaitForIdle(); + + EXPECT_TRUE(rt->GetActivePath()->sg_list().empty() == true); + DeleteVmportEnv(input, 1, true); + WAIT_FOR(100, 1000, (VrfFind("vrf1") == false)); + client->WaitForIdle(); + EXPECT_FALSE(RouteFind("vrf1", ip, 32)); +} + int main(int argc, char **argv) { GETUSERARGS(); client = TestInit(init_file, ksync_init);