diff --git a/src/bgp/SConscript b/src/bgp/SConscript index 0bbcb8d0051..7915a4d6e8d 100644 --- a/src/bgp/SConscript +++ b/src/bgp/SConscript @@ -60,6 +60,7 @@ libbgp = env.Library('bgp', 'bgp_session.cc', 'bgp_show_config.cc', 'bgp_show_evpn_table.cc', + 'bgp_show_multicast_manager.cc', 'bgp_show_neighbor.cc', 'bgp_show_route_summary.cc', 'bgp_show_routing_instance.cc', diff --git a/src/bgp/bgp_multicast.cc b/src/bgp/bgp_multicast.cc index 45f7feb2c4c..c64c6740a87 100644 --- a/src/bgp/bgp_multicast.cc +++ b/src/bgp/bgp_multicast.cc @@ -1013,3 +1013,17 @@ LifetimeActor *McastTreeManager::deleter() { return deleter_.get(); } +// +// Return the LifetimeActor for the McastTreeManager. +// Const version. +// +const LifetimeActor *McastTreeManager::deleter() const { + return deleter_.get(); +} + +// +// Return true if the McastTreeManager is deleted. +// +bool McastTreeManager::deleted() const { + return deleter_->IsDeleted(); +} diff --git a/src/bgp/bgp_multicast.h b/src/bgp/bgp_multicast.h index a3f070236c7..6e22acd69ef 100644 --- a/src/bgp/bgp_multicast.h +++ b/src/bgp/bgp_multicast.h @@ -312,8 +312,8 @@ class McastManagerPartition { BgpServer *server(); McastTreeManager *tree_manager() const { return tree_manager_; } - bool empty() { return sg_list_.empty(); } - size_t size() { return sg_list_.size(); } + bool empty() const { return sg_list_.empty(); } + size_t size() const { return sg_list_.size(); } private: friend class BgpMulticastTest; @@ -370,6 +370,9 @@ class McastTreeManager { public: static const int kDegree = 4; + typedef std::vector PartitionList; + typedef PartitionList::const_iterator const_iterator; + enum NodeLevel { LevelFirst = 0, LevelNative = 0, @@ -380,6 +383,9 @@ class McastTreeManager { explicit McastTreeManager(ErmVpnTable *table); virtual ~McastTreeManager(); + const_iterator begin() const { return partitions_.begin(); } + const_iterator end() const { return partitions_.end(); } + virtual void Initialize(); virtual void Terminate(); @@ -395,13 +401,14 @@ class McastTreeManager { void RetryDelete(); LifetimeActor *deleter(); + const LifetimeActor *deleter() const; + bool deleted() const; private: friend class BgpMulticastTest; friend class ShowMulticastManagerDetailHandler; class DeleteActor; - typedef std::vector PartitionList; void AllocPartitions(); void FreePartitions(); diff --git a/src/bgp/bgp_peer.sandesh b/src/bgp/bgp_peer.sandesh index fe472327f51..188586fffbe 100644 --- a/src/bgp/bgp_peer.sandesh +++ b/src/bgp/bgp_peer.sandesh @@ -294,10 +294,14 @@ request sandesh ShowEvpnTableSummaryReq { struct ShowMulticastManager { 1: string name (link="ShowMulticastManagerDetailReq"); 2: u32 total_trees; + 3: bool deleted; + 4: string deleted_at; } response sandesh ShowMulticastManagerResp { 1: list managers; + 2: optional string next_batch (link="ShowMulticastManagerReqIterate", + link_title="next_batch"); } request sandesh ShowMulticastManagerReq { diff --git a/src/bgp/bgp_peer_internal.sandesh b/src/bgp/bgp_peer_internal.sandesh index f190a588ebb..58773473b30 100644 --- a/src/bgp/bgp_peer_internal.sandesh +++ b/src/bgp/bgp_peer_internal.sandesh @@ -58,6 +58,10 @@ request sandesh ShowEvpnTableSummaryReqIterate { 1: string iterate_info; } +request sandesh ShowMulticastManagerReqIterate { + 1: string iterate_info; +} + response sandesh ShowMulticastManagerDetailResp { 1: list trees; } diff --git a/src/bgp/bgp_sandesh.cc b/src/bgp/bgp_sandesh.cc index c40a4b5543e..ce3e611932d 100644 --- a/src/bgp/bgp_sandesh.cc +++ b/src/bgp/bgp_sandesh.cc @@ -763,147 +763,6 @@ void ClearBgpNeighborReq::HandleRequest() const { RequestPipeline rp(ps); } -class ShowMulticastManagerHandler { -public: - struct MulticastManagerDataKey { - string routing_table; - bool operator<(const MulticastManagerDataKey &rhs) const { - return (routing_table < rhs.routing_table); - } - }; - - struct MulticastManagerData : public RequestPipeline::InstData { - typedef map Map; - Map table_map; - }; - - static RequestPipeline::InstData *CreateData(int stage) { - return (new MulticastManagerData); - } - - static void FillMulticastManagerStats(MulticastManagerData *data, - ErmVpnTable *table, int inst_id) { - MulticastManagerDataKey key; - key.routing_table = table->name(); - McastTreeManager *tm = table->GetTreeManager(); - McastManagerPartition *partition = tm->GetPartition(inst_id); - data->table_map[key] = partition->size(); - } - - static bool CallbackS1(const Sandesh *sr, - const RequestPipeline::PipeSpec ps, - int stage, int instNum, - RequestPipeline::InstData *data) { - int inst_id = ps.stages_[stage].instances_[instNum]; - - MulticastManagerData *mydata = - static_cast(data); - const ShowMulticastManagerReq *req = - static_cast(ps.snhRequest_.get()); - const string &search_string = req->get_search_string(); - BgpSandeshContext *bsc = - static_cast(req->client_context()); - RoutingInstanceMgr *rim = bsc->bgp_server->routing_instance_mgr(); - for (RoutingInstanceMgr::name_iterator it = rim->name_begin(); - it != rim->name_end(); it++) { - RoutingInstance *ri = it->second; - if (ri->IsDefaultRoutingInstance()) - continue; - ErmVpnTable *table = - static_cast(ri->GetTable(Address::ERMVPN)); - if (!table) - continue; - if (!search_string.empty() && - table->name().find(search_string) == string::npos) { - continue; - } - FillMulticastManagerStats(mydata, table, inst_id); - } - - return true; - } - - static void FillMulticastManagerInfo(const RequestPipeline::StageData *sd, - vector &mgr_list, ErmVpnTable *table) { - ShowMulticastManager mgr; - MulticastManagerDataKey key; - key.routing_table = table->name(); - for (size_t idx = 0; idx < sd->size(); idx++) { - const MulticastManagerData &data = - static_cast(sd->at(idx)); - MulticastManagerData::Map::const_iterator dit = - data.table_map.find(key); - if (dit != data.table_map.end()) { - mgr.total_trees += dit->second; - } - } - - mgr.set_name(table->name()); - mgr_list.push_back(mgr); - } - - static bool CallbackS2(const Sandesh *sr, - const RequestPipeline::PipeSpec ps, - int stage, int instNum, - RequestPipeline::InstData *data) { - const ShowMulticastManagerReq *req = - static_cast(ps.snhRequest_.get()); - const string &search_string = req->get_search_string(); - BgpSandeshContext *bsc = - static_cast(req->client_context()); - RoutingInstanceMgr *rim = bsc->bgp_server->routing_instance_mgr(); - vector mgr_list; - const RequestPipeline::StageData *sd = ps.GetStageData(0); - for (RoutingInstanceMgr::name_iterator it = rim->name_begin(); - it != rim->name_end(); it++) { - RoutingInstance *ri = it->second; - if (ri->IsDefaultRoutingInstance()) - continue; - ErmVpnTable *table = - static_cast(ri->GetTable(Address::ERMVPN)); - if (!table) - continue; - if (!search_string.empty() && - table->name().find(search_string) == string::npos) { - continue; - } - FillMulticastManagerInfo(sd, mgr_list, table); - } - - - ShowMulticastManagerResp *resp = new ShowMulticastManagerResp; - resp->set_managers(mgr_list); - resp->set_context(req->context()); - resp->Response(); - return true; - } -}; - -void ShowMulticastManagerReq::HandleRequest() const { - RequestPipeline::PipeSpec ps(this); - BgpSandeshContext *bsc = static_cast(client_context()); - - // Request pipeline has 2 stages. - // First stage to collect multicast manager stats. - // Second stage to fill stats from stage 1 and respond to the request. - RequestPipeline::StageSpec s1, s2; - TaskScheduler *scheduler = TaskScheduler::GetInstance(); - - s1.taskId_ = scheduler->GetTaskId("db::DBTable"); - s1.allocFn_ = ShowMulticastManagerHandler::CreateData; - s1.cbFn_ = ShowMulticastManagerHandler::CallbackS1; - for (int i = 0; i < bsc->bgp_server->database()->PartitionCount(); i++) { - s1.instances_.push_back(i); - } - - s2.taskId_ = scheduler->GetTaskId("bgp::ShowCommand"); - s2.cbFn_ = ShowMulticastManagerHandler::CallbackS2; - s2.instances_.push_back(0); - - ps.stages_ = list_of(s1)(s2); - RequestPipeline rp(ps); -} - class ShowMulticastManagerDetailHandler { public: struct MulticastManagerDetailData : public RequestPipeline::InstData { @@ -973,7 +832,7 @@ class ShowMulticastManagerDetailHandler { static_cast(req->client_context()); DBTableBase *table = bsc->bgp_server->database()->FindTable(req->get_name()); ErmVpnTable *mcast_table = dynamic_cast(table); - if (mcast_table) + if (mcast_table && !mcast_table->IsVpnTable()) FillMulticastPartitionInfo(mydata, mcast_table, inst_id); return true; diff --git a/src/bgp/bgp_show_multicast_manager.cc b/src/bgp/bgp_show_multicast_manager.cc new file mode 100644 index 00000000000..0d217377503 --- /dev/null +++ b/src/bgp/bgp_show_multicast_manager.cc @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. + */ + +#include "bgp/bgp_show_handler.h" + +#include +#include + +#include "base/time_util.h" +#include "bgp/bgp_peer_internal_types.h" +#include "bgp/bgp_server.h" +#include "bgp/bgp_table.h" +#include "bgp/bgp_multicast.h" +#include "bgp/ermvpn/ermvpn_table.h" +#include "bgp/routing-instance/routing_instance.h" + +using std::string; +using std::vector; + +// +// Fill in information for an ermvpn table. +// +static void FillMulticastManagerInfo(ShowMulticastManager *smm, + const BgpSandeshContext *bsc, const ErmVpnTable *table) { + smm->set_name(table->name()); + const McastTreeManager *manager = table->GetTreeManager(); + if (!manager) + return; + + smm->set_deleted(manager->deleted()); + smm->set_deleted_at( + UTCUsecToString(manager->deleter()->delete_time_stamp_usecs())); + + uint32_t total_trees = 0; + for (McastTreeManager::const_iterator it = manager->begin(); + it != manager->end(); ++it) { + const McastManagerPartition *partition = *it; + total_trees += partition->size(); + } + smm->set_total_trees(total_trees); +} + +// +// Specialization of BgpShowHandler<>::CallbackCommon. +// +template <> +bool BgpShowHandler::CallbackCommon( + const BgpSandeshContext *bsc, Data *data) { + uint32_t page_limit = bsc->page_limit() ? bsc->page_limit() : kPageLimit; + uint32_t iter_limit = bsc->iter_limit() ? bsc->iter_limit() : kIterLimit; + RoutingInstanceMgr *rim = bsc->bgp_server->routing_instance_mgr(); + + RoutingInstanceMgr::const_name_iterator it = + rim->name_clower_bound(data->next_entry); + for (uint32_t iter_count = 0; it != rim->name_cend(); ++it, ++iter_count) { + const RoutingInstance *rtinstance = it->second; + const ErmVpnTable *table = static_cast( + rtinstance->GetTable(Address::ERMVPN)); + if (!table) + continue; + if (!data->search_string.empty() && + (table->name().find(data->search_string) == string::npos) && + (data->search_string != "deleted" || !table->IsDeleted())) { + continue; + } + ShowMulticastManager smm; + FillMulticastManagerInfo(&smm, bsc, table); + data->show_list.push_back(smm); + if (data->show_list.size() >= page_limit) + break; + if (iter_count >= iter_limit) + break; + } + + // All done if we've looked at all instances. + if (it == rim->name_cend() || ++it == rim->name_cend()) + return true; + + // Return true if we've reached the page limit, false if we've reached the + // iteration limit. + bool done = data->show_list.size() >= page_limit; + SaveContextToData(it->second->name(), done, data); + return done; + + return done; +} + +// +// Specialization of BgpShowHandler<>::FillShowList. +// +template <> +void BgpShowHandler::FillShowList( + ShowMulticastManagerResp *resp, + const vector &show_list) { + resp->set_managers(show_list); +} + +// +// Handler for ShowMulticastManagerReq. +// +void ShowMulticastManagerReq::HandleRequest() const { + RequestPipeline::PipeSpec ps(this); + RequestPipeline::StageSpec s1; + TaskScheduler *scheduler = TaskScheduler::GetInstance(); + + s1.taskId_ = scheduler->GetTaskId("bgp::ShowCommand"); + s1.cbFn_ = boost::bind(&BgpShowHandler< + ShowMulticastManagerReq, + ShowMulticastManagerReqIterate, + ShowMulticastManagerResp, + ShowMulticastManager>::Callback, _1, _2, _3, _4, _5); + s1.allocFn_ = BgpShowHandler< + ShowMulticastManagerReq, + ShowMulticastManagerReqIterate, + ShowMulticastManagerResp, + ShowMulticastManager>::CreateData; + s1.instances_.push_back(0); + ps.stages_.push_back(s1); + RequestPipeline rp(ps); +} + +// +// Handler for ShowMulticastManagerReqIterate. +// +void ShowMulticastManagerReqIterate::HandleRequest() const { + RequestPipeline::PipeSpec ps(this); + RequestPipeline::StageSpec s1; + TaskScheduler *scheduler = TaskScheduler::GetInstance(); + + s1.taskId_ = scheduler->GetTaskId("bgp::ShowCommand"); + s1.cbFn_ = boost::bind(&BgpShowHandler< + ShowMulticastManagerReq, + ShowMulticastManagerReqIterate, + ShowMulticastManagerResp, + ShowMulticastManager>::CallbackIterate, _1, _2, _3, _4, _5); + s1.allocFn_ = BgpShowHandler< + ShowMulticastManagerReq, + ShowMulticastManagerReqIterate, + ShowMulticastManagerResp, + ShowMulticastManager>::CreateData; + s1.instances_.push_back(0); + ps.stages_.push_back(s1); + RequestPipeline rp(ps); +} diff --git a/src/bgp/ermvpn/ermvpn_table.cc b/src/bgp/ermvpn/ermvpn_table.cc index 13410c8cc57..29331cf0f96 100644 --- a/src/bgp/ermvpn/ermvpn_table.cc +++ b/src/bgp/ermvpn/ermvpn_table.cc @@ -201,6 +201,10 @@ McastTreeManager *ErmVpnTable::GetTreeManager() { return tree_manager_; } +const McastTreeManager *ErmVpnTable::GetTreeManager() const { + return tree_manager_; +} + void ErmVpnTable::set_routing_instance(RoutingInstance *rtinstance) { BgpTable::set_routing_instance(rtinstance); CreateTreeManager(); diff --git a/src/bgp/ermvpn/ermvpn_table.h b/src/bgp/ermvpn/ermvpn_table.h index 50cea6a124e..bb851c6406e 100644 --- a/src/bgp/ermvpn/ermvpn_table.h +++ b/src/bgp/ermvpn/ermvpn_table.h @@ -51,6 +51,7 @@ class ErmVpnTable : public BgpTable { void CreateTreeManager(); void DestroyTreeManager(); McastTreeManager *GetTreeManager(); + const McastTreeManager *GetTreeManager() const; virtual void set_routing_instance(RoutingInstance *rtinstance); private: diff --git a/src/bgp/test/SConscript b/src/bgp/test/SConscript index 70e4d87dd1b..0387210c098 100644 --- a/src/bgp/test/SConscript +++ b/src/bgp/test/SConscript @@ -230,6 +230,11 @@ bgp_show_instance_config_test = env.UnitTest('bgp_show_instance_config_test', env.Alias('src/bgp:bgp_show_instance_config_test', bgp_show_instance_config_test) +bgp_show_multicast_manager_test = env.UnitTest( + 'bgp_show_multicast_manager_test', ['bgp_show_multicast_manager_test.cc']) +env.Alias('src/bgp:bgp_show_multicast_manager_test', + bgp_show_multicast_manager_test) + bgp_show_neighbor_test = env.UnitTest('bgp_show_neighbor_test', ['bgp_show_neighbor_test.cc']) env.Alias('src/bgp:bgp_show_neighbor_test', @@ -408,6 +413,7 @@ test_suite = [ bgp_sg_test, bgp_show_evpn_table_test, bgp_show_instance_config_test, + bgp_show_multicast_manager_test, bgp_show_neighbor_test, bgp_show_route_summary_test, bgp_show_routing_instance_test, diff --git a/src/bgp/test/bgp_show_multicast_manager_test.cc b/src/bgp/test/bgp_show_multicast_manager_test.cc new file mode 100644 index 00000000000..a1833a443e7 --- /dev/null +++ b/src/bgp/test/bgp_show_multicast_manager_test.cc @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. + */ + +#include "bgp/test/bgp_show_instance_or_table_test.h" + +typedef TypeDefinition< + ShowMulticastManagerReq, + ShowMulticastManagerReqIterate, + ShowMulticastManagerResp> MulticastReq; + +// Specialization of AddInstanceOrTableName. +template<> +void BgpShowInstanceOrTableTest::AddInstanceOrTableName( + vector *names, const string &name) { + string table_name; + if (name == BgpConfigManager::kMasterInstance) { + table_name = "bgp.ermvpn.0"; + } else { + table_name = name + ".ermvpn.0"; + } + names->push_back(table_name); +} + +// Specialization of ValidateResponse. +template<> +void BgpShowInstanceOrTableTest::ValidateResponse( + Sandesh *sandesh, vector &result, const string &next_batch) { + MulticastReq::RespT *resp = dynamic_cast(sandesh); + TASK_UTIL_EXPECT_TRUE(resp != NULL); + TASK_UTIL_EXPECT_EQ(result.size(), resp->get_managers().size()); + TASK_UTIL_EXPECT_EQ(next_batch, resp->get_next_batch()); + for (size_t i = 0; i < resp->get_managers().size(); ++i) { + TASK_UTIL_EXPECT_EQ(result[i], resp->get_managers()[i].get_name()); + cout << resp->get_managers()[i].log() << endl; + } + validate_done_ = true; +} + +// Instantiate all test patterns for ShowMulticastManagerReq. +INSTANTIATE_TYPED_TEST_CASE_P(Config, BgpShowInstanceOrTableTest, MulticastReq); + +class TestEnvironment : public ::testing::Environment { + virtual ~TestEnvironment() { } +}; + +static void SetUp() { + ControlNode::SetDefaultSchedulingPolicy(); + BgpServerTest::GlobalSetUp(); + XmppObjectFactory::Register( + boost::factory()); + BgpObjectFactory::Register( + boost::factory()); +} + +static void TearDown() { + task_util::WaitForIdle(); + TaskScheduler *scheduler = TaskScheduler::GetInstance(); + scheduler->Terminate(); +} + +int main(int argc, char **argv) { + bgp_log_test::init(); + ::testing::InitGoogleTest(&argc, argv); + ::testing::AddGlobalTestEnvironment(new TestEnvironment()); + SetUp(); + int result = RUN_ALL_TESTS(); + TearDown(); + return result; +} diff --git a/src/bgp/test/bgp_xmpp_mcast_test.cc b/src/bgp/test/bgp_xmpp_mcast_test.cc index 9774a975c06..e3e60409ed3 100644 --- a/src/bgp/test/bgp_xmpp_mcast_test.cc +++ b/src/bgp/test/bgp_xmpp_mcast_test.cc @@ -54,29 +54,6 @@ class BgpXmppMcastTest : public ::testing::Test { validate_done_ = 1; } - static void ValidateShowManagerMulticastResponse(Sandesh *sandesh, - vector &result) { - ShowMulticastManagerResp *resp = - dynamic_cast(sandesh); - EXPECT_NE((ShowMulticastManagerResp *)NULL, resp); - - TASK_UTIL_EXPECT_EQ(result.size(), resp->get_managers().size()); - cout << "*******************************************************"<get_managers().size(); ++i) { - cout << resp->get_managers()[i].log() << endl; - bool found = false; - BOOST_FOREACH(const string &manager_name, result) { - if (resp->get_managers()[i].get_name() == manager_name) { - found = true; - break; - } - } - EXPECT_TRUE(found); - } - cout << "*******************************************************"< &result) { ShowMulticastManagerDetailResp *resp = @@ -780,78 +757,6 @@ TEST_F(BgpXmppMcastMultiAgentTest, ValidateShowRoute) { TASK_UTIL_EXPECT_EQ(1, validate_done_); }; -TEST_F(BgpXmppMcastMultiAgentTest, ValidateShowMulticastManager) { - Subscribe("pink", 2); - - const char *mroute = "225.0.0.1,90.1.1.1"; - const char *networks[] = { "blue", "pink" }; - - // Add mcast routes for all agents. - BOOST_FOREACH(const char *net, networks) { - agent_xa_->AddMcastRoute(net, mroute, "10.1.1.1", "10000-19999"); - agent_xb_->AddMcastRoute(net, mroute, "10.1.1.2", "20000-29999"); - agent_xc_->AddMcastRoute(net, mroute, "10.1.1.3", "30000-39999"); - task_util::WaitForIdle(); - } - - // Verify that all agents have the routes. - TASK_UTIL_EXPECT_EQ(2, agent_xa_->McastRouteCount()); - TASK_UTIL_EXPECT_EQ(2, agent_xb_->McastRouteCount()); - TASK_UTIL_EXPECT_EQ(2, agent_xc_->McastRouteCount()); - - // Verify multicast manager via sandesh. - BgpSandeshContext sandesh_context; - RegisterSandeshShowXmppExtensions(&sandesh_context); - sandesh_context.bgp_server = bs_x_.get(); - sandesh_context.xmpp_peer_manager = bcm_x_.get(); - Sandesh::set_client_context(&sandesh_context); - vector result = list_of("blue.ermvpn.0")("pink.ermvpn.0"); - Sandesh::set_response_callback( - boost::bind(ValidateShowManagerMulticastResponse, _1, result)); - ShowMulticastManagerReq *show_req = new ShowMulticastManagerReq; - validate_done_ = 0; - show_req->HandleRequest(); - show_req->Release(); - task_util::WaitForIdle(); - TASK_UTIL_EXPECT_EQ(1, validate_done_); - - // Match "". - result = list_of("blue.ermvpn.0")("pink.ermvpn.0"); - Sandesh::set_response_callback( - boost::bind(ValidateShowManagerMulticastResponse, _1, result)); - show_req = new ShowMulticastManagerReq; - validate_done_ = 0; - show_req->set_search_string(""); - show_req->HandleRequest(); - show_req->Release(); - task_util::WaitForIdle(); - TASK_UTIL_EXPECT_EQ(1, validate_done_); - - // Match "ermvpn.0". - result = list_of("blue.ermvpn.0")("pink.ermvpn.0"); - Sandesh::set_response_callback( - boost::bind(ValidateShowManagerMulticastResponse, _1, result)); - show_req = new ShowMulticastManagerReq; - validate_done_ = 0; - show_req->set_search_string("ermvpn.0"); - show_req->HandleRequest(); - show_req->Release(); - task_util::WaitForIdle(); - TASK_UTIL_EXPECT_EQ(1, validate_done_); - - // Match "pink". - result = list_of("pink.ermvpn.0"); - Sandesh::set_response_callback( - boost::bind(ValidateShowManagerMulticastResponse, _1, result)); - show_req = new ShowMulticastManagerReq; - validate_done_ = 0; - show_req->set_search_string("pink"); - show_req->HandleRequest(); - show_req->Release(); - task_util::WaitForIdle(); - TASK_UTIL_EXPECT_EQ(1, validate_done_); -}; - TEST_F(BgpXmppMcastMultiAgentTest, ValidateShowMulticastManagerDetail) { const char *mroutes[] = { "225.0.0.1,90.1.1.1", "225.0.0.2,90.1.1.1" };