diff --git a/src/vnsw/agent/pkt/flow_mgmt.cc b/src/vnsw/agent/pkt/flow_mgmt.cc index 77c9d2317a3..b8866bfcd81 100644 --- a/src/vnsw/agent/pkt/flow_mgmt.cc +++ b/src/vnsw/agent/pkt/flow_mgmt.cc @@ -1077,8 +1077,26 @@ bool RouteFlowMgmtTree::Delete(FlowMgmtKey *key, FlowEntry *flow) { return ret; } +void RouteFlowMgmtTree::SetDBEntry(const FlowMgmtRequest *req, + FlowMgmtKey *key) { + Tree::iterator it = tree_.find(key); + if (it == tree_.end()) { + return; + } + + if (it->first->db_entry()) { + assert(it->first->db_entry() == req->db_entry()); + return; + } + it->first->set_db_entry(req->db_entry()); + return; +} + bool RouteFlowMgmtTree::OperEntryDelete(const FlowMgmtRequest *req, FlowMgmtKey *key) { + // Set the db_entry if it was not set earlier. It is needed to send the + // FreeDBState message + SetDBEntry(req, key); bool ret = FlowMgmtTree::OperEntryDelete(req, key); RouteFlowMgmtKey *route_key = static_cast(key); mgr_->RetryVrfDelete(route_key->vrf_id()); @@ -1091,10 +1109,8 @@ bool RouteFlowMgmtTree::OperEntryAdd(const FlowMgmtRequest *req, if (req->db_entry() == NULL) return ret; - Tree::iterator it = tree_.find(key); - if (it != tree_.end()) { - it->first->set_db_entry(req->db_entry()); - } + // Set the DBEntry in the flow-mgmt-entry + SetDBEntry(req, key); return ret; } diff --git a/src/vnsw/agent/pkt/flow_mgmt.h b/src/vnsw/agent/pkt/flow_mgmt.h index dd780a1d815..56f7389820d 100644 --- a/src/vnsw/agent/pkt/flow_mgmt.h +++ b/src/vnsw/agent/pkt/flow_mgmt.h @@ -640,6 +640,7 @@ class RouteFlowMgmtTree : public FlowMgmtTree { virtual bool OperEntryDelete(const FlowMgmtRequest *req, FlowMgmtKey *key); virtual bool OperEntryAdd(const FlowMgmtRequest *req, FlowMgmtKey *key); private: + void SetDBEntry(const FlowMgmtRequest *req, FlowMgmtKey *key); DISALLOW_COPY_AND_ASSIGN(RouteFlowMgmtTree); }; diff --git a/src/vnsw/agent/pkt/test/SConscript b/src/vnsw/agent/pkt/test/SConscript index 6de6b83ad70..442b74f8640 100644 --- a/src/vnsw/agent/pkt/test/SConscript +++ b/src/vnsw/agent/pkt/test/SConscript @@ -19,6 +19,8 @@ env.Prepend(LIBS = 'agent_physical_devices_test_xml') pkt_test_suite = [] pkt_flaky_test_suite = [] +test_flow_mgmt_route = AgentEnv.MakeTestCmd(env, 'test_flow_mgmt_route', + pkt_test_suite) test_pkt = AgentEnv.MakeTestCmd(env, 'test_pkt', pkt_flaky_test_suite) test_pkt_flow_mock = AgentEnv.MakeTestCmd(env, 'test_pkt_flow_mock', pkt_flaky_test_suite) diff --git a/src/vnsw/agent/pkt/test/test_flow_mgmt_route.cc b/src/vnsw/agent/pkt/test/test_flow_mgmt_route.cc new file mode 100644 index 00000000000..b06bbf70888 --- /dev/null +++ b/src/vnsw/agent/pkt/test/test_flow_mgmt_route.cc @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved. + */ + +#include "base/os.h" +#include "test/test_cmn_util.h" +#include "test_flow_util.h" +#include "ksync/ksync_sock_user.h" +#include "oper/tunnel_nh.h" +#include "pkt/flow_mgmt.h" +#include + +#define vm1_ip "1.1.1.1" +#define vm2_ip "1.1.1.2" + +struct PortInfo input[] = { + {"vif0", 1, vm1_ip, "00:00:00:01:01:01", 1, 1}, + {"vif1", 2, vm2_ip, "00:00:00:01:01:02", 1, 2}, +}; + +class FlowMgmtRouteTest : public ::testing::Test { +public: + FlowMgmtRouteTest() : peer_(NULL), agent_(Agent::GetInstance()) { + flow_proto_ = agent_->pkt()->get_flow_proto(); + flow_mgmt_ = agent_->pkt()->flow_mgmt_manager(); + eth = EthInterfaceGet("vnet0"); + EXPECT_TRUE(eth != NULL); + } + + void FlushFlowTable() { + client->EnqueueFlowFlush(); + client->WaitForIdle(); + WAIT_FOR(100, 100, (flow_proto_->FlowCount() == 0)); + } + +protected: + virtual void SetUp() { + WAIT_FOR(100, 100, (flow_proto_->FlowCount() == 0)); + client->Reset(); + + CreateVmportEnv(input, 2, 1); + client->WaitForIdle(5); + + EXPECT_TRUE(VmPortActive(input, 0)); + EXPECT_TRUE(VmPortActive(input, 1)); + + vif0 = VmInterfaceGet(input[0].intf_id); + assert(vif0); + vif1 = VmInterfaceGet(input[1].intf_id); + assert(vif1); + + client->WaitForIdle(); + peer_ = CreateBgpPeer(Ip4Address(1), "BGP Peer 1"); + + client->WaitForIdle(); + } + + virtual void TearDown() { + FlushFlowTable(); + client->Reset(); + + DeleteVmportEnv(input, 3, true, 1); + client->WaitForIdle(3); + + EXPECT_FALSE(VmPortFind(input, 0)); + EXPECT_FALSE(VmPortFind(input, 1)); + + EXPECT_EQ(0U, agent()->vm_table()->Size()); + EXPECT_EQ(0U, agent()->vn_table()->Size()); + EXPECT_EQ(0U, agent()->acl_table()->Size()); + DeleteBgpPeer(peer_); + } + + Agent *agent() {return agent_;} + +protected: + BgpPeer *peer_; + Agent *agent_; + FlowProto *flow_proto_; + FlowMgmtManager *flow_mgmt_; + VmInterface *vif0; + VmInterface *vif1; + PhysicalInterface *eth; +}; + +TEST_F(FlowMgmtRouteTest, RouteDelete_1) { + EXPECT_EQ(0U, flow_proto_->FlowCount()); + + boost::system::error_code ec; + Ip4Address remote_subnet = Ip4Address::from_string("10.10.10.0", ec); + Ip4Address remote_ip = Ip4Address::from_string("10.10.10.1", ec); + Ip4Address remote_compute = Ip4Address::from_string("1.1.1.1", ec); + + string vrf_name = vif0->vrf()->GetName(); + string vn_name = vif0->vn()->GetName(); + Inet4TunnelRouteAdd(peer_, vrf_name, remote_subnet, 24, remote_compute, + TunnelType::AllType(), 10, vn_name, SecurityGroupList(), + PathPreference()); + client->WaitForIdle(); + + char router_id[80]; + strcpy(router_id, Agent::GetInstance()->router_id().to_string().c_str()); + TxIpMplsPacket(eth->id(), remote_compute.to_string().c_str(), + router_id, vif0->label(), remote_ip.to_string().c_str(), + vm1_ip, 1, 1); + client->WaitForIdle(); + + uint32_t vrf_id = vif0->vrf_id(); + FlowEntry *flow = FlowGet(vrf_id, remote_ip.to_string().c_str(), + vm1_ip, 1, 0, 0, vif0->flow_key_nh()->id()); + EXPECT_TRUE(flow != NULL); + + InetUnicastRouteKey key(peer_, vrf_name, remote_subnet, 24); + InetUnicastAgentRouteTable *table = + vif0->vrf()->GetInet4UnicastRouteTable(); + AgentRoute *rt = table->FindRoute(remote_ip); + + flow_mgmt_->DeleteEvent(rt, 0xFFFFFFFF); + client->WaitForIdle(); + + DeleteRoute(vrf_name.c_str(), remote_subnet.to_string().c_str(), 24, peer_); +} + +TEST_F(FlowMgmtRouteTest, RouteDelete_2) { + EXPECT_EQ(0U, flow_proto_->FlowCount()); + + boost::system::error_code ec; + Ip4Address remote_subnet = Ip4Address::from_string("10.10.10.0", ec); + Ip4Address remote_ip = Ip4Address::from_string("10.10.10.1", ec); + Ip4Address remote_compute = Ip4Address::from_string("1.1.1.1", ec); + + string vrf_name = vif0->vrf()->GetName(); + string vn_name = vif0->vn()->GetName(); + Inet4TunnelRouteAdd(peer_, vrf_name, remote_subnet, 24, remote_compute, + TunnelType::AllType(), 10, vn_name, SecurityGroupList(), + PathPreference()); + client->WaitForIdle(); + + char router_id[80]; + strcpy(router_id, Agent::GetInstance()->router_id().to_string().c_str()); + TxIpMplsPacket(eth->id(), remote_compute.to_string().c_str(), + router_id, vif0->label(), remote_ip.to_string().c_str(), + vm1_ip, 1, 1); + client->WaitForIdle(); + + uint32_t vrf_id = vif0->vrf_id(); + FlowEntry *flow = FlowGet(vrf_id, remote_ip.to_string().c_str(), + vm1_ip, 1, 0, 0, vif0->flow_key_nh()->id()); + EXPECT_TRUE(flow != NULL); + + InetUnicastRouteKey key(peer_, vrf_name, remote_subnet, 24); + InetUnicastAgentRouteTable *table = + vif0->vrf()->GetInet4UnicastRouteTable(); + AgentRoute *rt = table->FindRoute(remote_ip); + + flow_mgmt_->DeleteEvent(flow); + client->WaitForIdle(); + + flow_mgmt_->DeleteEvent(rt, 0xFFFFFFFF); + client->WaitForIdle(); + + DeleteRoute(vrf_name.c_str(), remote_subnet.to_string().c_str(), 24, peer_); +} + +int main(int argc, char *argv[]) { + int ret = 0; + + GETUSERARGS(); + client = TestInit(init_file, ksync_init, true, true, true, 100*1000); + ret = RUN_ALL_TESTS(); + usleep(100000); + TestShutdown(); + delete client; + return ret; +}