diff --git a/src/vnsw/agent/oper/path_preference.cc b/src/vnsw/agent/oper/path_preference.cc index c3e17de4415..2d89e7ba447 100644 --- a/src/vnsw/agent/oper/path_preference.cc +++ b/src/vnsw/agent/oper/path_preference.cc @@ -658,7 +658,7 @@ void PathPreferenceRouteListener::Init() { } void PathPreferenceRouteListener::Delete() { - deleted_ = true; + set_deleted(); DBTableWalker *walker = agent_->db()->GetWalker(); walker->WalkTable(rt_table_, NULL, boost::bind(&PathPreferenceRouteListener::DeleteState, @@ -702,6 +702,8 @@ void PathPreferenceRouteListener::Notify(DBTablePartBase *partition, return; } + if (deleted_) return; + AgentRoute *rt = static_cast(e); for (Route::PathList::iterator it = rt->GetPathList().begin(); it != rt->GetPathList().end(); ++it) { diff --git a/src/vnsw/agent/oper/path_preference.h b/src/vnsw/agent/oper/path_preference.h index 7da7d92714a..3389dcecdce 100644 --- a/src/vnsw/agent/oper/path_preference.h +++ b/src/vnsw/agent/oper/path_preference.h @@ -156,13 +156,16 @@ struct PathPreferenceVrfState: public DBState { struct PathPreferenceRouteListener : public DBState { PathPreferenceRouteListener(Agent *agent, AgentRouteTable *table); + virtual void Delete(); + void Notify(DBTablePartBase *partition, DBEntryBase *e); void Init(); - void Delete(); bool DeleteState(DBTablePartBase *partition, DBEntryBase *e); void Walkdone(DBTableBase *partition, PathPreferenceRouteListener *state); DBTableBase::ListenerId id() const { return id_;} void ManagedDelete(); + void set_deleted() {deleted_ = true;} + bool deleted() const {return deleted_;} private: Agent *agent_; AgentRouteTable *rt_table_; diff --git a/src/vnsw/agent/test/SConscript b/src/vnsw/agent/test/SConscript index 5cc3bd25ee5..7f1238be6ab 100644 --- a/src/vnsw/agent/test/SConscript +++ b/src/vnsw/agent/test/SConscript @@ -63,6 +63,9 @@ test_fip_cfg = AgentEnv.MakeTestCmd(env, 'test_fip_cfg', flaky_agent_suite) test_route = AgentEnv.MakeTestCmd(env, 'test_route', flaky_agent_suite) test_l2route = AgentEnv.MakeTestCmd(env, 'test_l2route', flaky_agent_suite) test_cfg = AgentEnv.MakeTestCmd(env, 'test_cfg', flaky_agent_suite) +test_path_preference_walker = AgentEnv.MakeTestCmd(env, + 'test_path_preference_walker', + agent_suite) test_xmpp_hv2 = AgentEnv.MakeTestCmd(env, 'test_xmpp_hv2', flaky_agent_suite) test_xmpp_non_hv = AgentEnv.MakeTestCmd(env, 'test_xmpp_non_hv', flaky_agent_suite) test_xmppcs_hv = AgentEnv.MakeTestCmd(env, 'test_xmppcs_hv', flaky_agent_suite) diff --git a/src/vnsw/agent/test/test_path_preference_walker.cc b/src/vnsw/agent/test/test_path_preference_walker.cc new file mode 100644 index 00000000000..1d1e96d55d7 --- /dev/null +++ b/src/vnsw/agent/test/test_path_preference_walker.cc @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. + */ + +#include "base/os.h" +#include +#include +#include + +#include "cfg/cfg_init.h" +#include "cfg/cfg_interface.h" +#include "oper/operdb_init.h" +#include "oper/agent_path.h" +#include "oper/path_preference.h" +#include "controller/controller_init.h" +#include "pkt/pkt_init.h" +#include "services/services_init.h" +#include "test_cmn_util.h" + +using namespace std; + +void RouterIdDepInit(Agent *agent) { +} + +static void ValidateSandeshResponse(Sandesh *sandesh, vector &result) { + //TBD + //Validate the response by the expectation +} + +struct PortInfo input_1[] = { + {"vnet1", 1, "1.1.1.10", "00:00:01:01:01:10", 1, 1}, +}; + +struct PortInfo input_2[] = { + {"vnet2", 2, "2.2.2.20", "00:00:02:02:02:20", 2, 2}, +}; + +struct PortInfo input_3[] = { + {"vnet3", 3, "3.3.3.30", "00:00:03:03:03:30", 3, 3}, +}; + +struct TestPathPreferenceRouteListener : public PathPreferenceRouteListener { + TestPathPreferenceRouteListener(Agent *agent, AgentRouteTable *table) : + PathPreferenceRouteListener(agent, table), walk_done_(false) { } + bool DeleteState(DBTablePartBase *partition, DBEntryBase *e) { + bool ret = PathPreferenceRouteListener::DeleteState(partition, e); + PathPreferenceRouteListener::Notify(partition, e); + return ret; + } + void Walkdone(DBTableBase *partition, PathPreferenceRouteListener *state) { + PathPreferenceRouteListener::Walkdone(partition, state); + walk_done_ = true; + } + virtual void Delete() { } //Dont call parent delete as it will start + // parallel walk + + bool walk_done_; +}; + +class PathPreferenceRouteTableWalkerTest : public ::testing::Test { +public: + PathPreferenceRouteTableWalkerTest() { + vrf_name_1_ = "vrf1"; + vrf_name_2_ = "vrf2"; + vrf_name_3_ = "vrf3"; + server_ip_ = Ip4Address::from_string("10.1.1.11"); + local_vm_ip_1_ = Ip4Address::from_string("1.1.1.10"); + local_vm_ip_2_ = Ip4Address::from_string("2.2.2.20"); + remote_vm_ip_ = Ip4Address::from_string("1.1.1.11"); + test_listener_ = NULL; + agent_ = Agent::GetInstance(); + }; + ~PathPreferenceRouteTableWalkerTest() { + } + + void SetupEnvironment(int num_vrfs) { + client->Reset(); + if (num_vrfs == 0) + return; + + if (num_vrfs > 0) { + VrfAddReq(vrf_name_1_.c_str()); + } + if (num_vrfs > 1) { + VrfAddReq(vrf_name_2_.c_str()); + } + if (num_vrfs > 2) { + VrfAddReq(vrf_name_3_.c_str()); + } + VrfEntry *vrf = VrfGet("vrf1", false); + WAIT_FOR(1000, 1000, vrf->GetEvpnRouteTable() != NULL); + EvpnAgentRouteTable *evpn_rt_table = + static_cast(vrf->GetEvpnRouteTable()); + test_listener_ = + new TestPathPreferenceRouteListener(agent_, evpn_rt_table); + client->WaitForIdle(); + test_listener_->Init(); + client->WaitForIdle(); + InetInterfaceKey vhost_intf_key( + Agent::GetInstance()->vhost_interface()->name()); + Agent::GetInstance()->fabric_inet4_unicast_table()->AddResolveRoute( + Agent::GetInstance()->local_peer(), + Agent::GetInstance()->fabric_vrf_name(), server_ip_, 24, + vhost_intf_key, 0, false, "", SecurityGroupList()); + client->WaitForIdle(); + client->WaitForIdle(); + if (num_vrfs > 0) { + CreateVmportEnv(input_1, 1); + } + if (num_vrfs > 1) { + CreateVmportEnv(input_2, 1); + } + if (num_vrfs > 2) { + CreateVmportEnv(input_3, 1); + } + client->WaitForIdle(); + client->Reset(); + } + + void DeleteEnvironment(int num_vrfs) { + client->Reset(); + + if (num_vrfs == 0) + return; + + if (num_vrfs > 0) { + DeleteVmportEnv(input_1, 1, true); + } + if (num_vrfs > 1) { + DeleteVmportEnv(input_2, 1, true); + } + if (num_vrfs > 2) { + DeleteVmportEnv(input_3, 1, true); + } + client->WaitForIdle(); + if (num_vrfs > 0) { + VrfDelReq(vrf_name_1_.c_str()); + client->WaitForIdle(); + WAIT_FOR(100, 100, (VrfFind(vrf_name_1_.c_str()) != true)); + } + if (num_vrfs > 1) { + VrfDelReq(vrf_name_2_.c_str()); + client->WaitForIdle(); + WAIT_FOR(100, 100, (VrfFind(vrf_name_2_.c_str()) != true)); + } + if (num_vrfs > 2) { + VrfDelReq(vrf_name_3_.c_str()); + client->WaitForIdle(); + WAIT_FOR(100, 100, (VrfFind(vrf_name_3_.c_str()) != true)); + } + client->WaitForIdle(); + } + + virtual void SetUp() { + client->Reset(); + VxLanNetworkIdentifierMode(false); + client->WaitForIdle(); + AddEncapList("MPLSoGRE", "MPLSoUDP", "VXLAN"); + client->WaitForIdle(); + } + + virtual void TearDown() { + client->Reset(); + DelEncapList(); + client->WaitForIdle(); + } + + std::string vrf_name_1_; + std::string vrf_name_2_; + std::string vrf_name_3_; + Ip4Address local_vm_ip_1_; + Ip4Address local_vm_ip_2_; + Ip4Address remote_vm_ip_; + Ip4Address server_ip_; + TestPathPreferenceRouteListener *test_listener_; + Agent *agent_; +}; + +TEST_F(PathPreferenceRouteTableWalkerTest, notify_on_deleted_before_walk_done) { + client->Reset(); + SetupEnvironment(3); + VrfDelReq("vrf1"); + client->WaitForIdle(); + DBTableWalker *walker = agent_->db()->GetWalker(); + VrfEntry *vrf = VrfGet("vrf1", true); + EvpnAgentRouteTable *evpn_rt_table = + static_cast(vrf->GetEvpnRouteTable()); + test_listener_->set_deleted();//Artificially mark it for delete + walker->WalkTable(evpn_rt_table, NULL, + boost::bind(&TestPathPreferenceRouteListener::DeleteState, + test_listener_, _1, _2), + boost::bind(&TestPathPreferenceRouteListener::Walkdone, + test_listener_, _1, test_listener_)); + WAIT_FOR(1000, 1000, (test_listener_->walk_done_ == true)); + DeleteEnvironment(3); +} + +//TODO REMAINING TESTS +// - based on walktype - unicast/multicast/all +// +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; +}