Skip to content

Commit

Permalink
Support pagination of output for instance config introspect
Browse files Browse the repository at this point in the history
Limit the maximum number of entries displayed on a single page. A
next_batch link is generated if there are more entries to display.

Also limit maximum number of entries examined in one invocation of
the callback routine.  This comes into play when there is a search
string specified and many entries don't match it.  A partial page
is saved in user-allocated data and the next invocation of callback
appends to it.  This is repeated till there's a full page or there
are no more entries in the table.

Following changes are implemented:

- Add class template BgpShowHandler to facilitate code reuse
- Move code from bgp_sandesh.cc to bgp_show_config.cc
- Implement iteration limit to avoid hogging CPU from introspect
- Reuse typed tests to also cover instance config
- Fix a few typos in comments for typed tests

Change-Id: I48389edd40fd099539210723690d6cbad317efa8
Closes-Bug: 1478154
  • Loading branch information
Nischal Sheth committed Jul 27, 2015
1 parent aec3c13 commit 48541a2
Show file tree
Hide file tree
Showing 13 changed files with 487 additions and 123 deletions.
1 change: 1 addition & 0 deletions src/bgp/SConscript
Expand Up @@ -58,6 +58,7 @@ libbgp = env.Library('bgp',
'bgp_server.cc',
'bgp_session_manager.cc',
'bgp_session.cc',
'bgp_show_config.cc',
'bgp_show_route_summary.cc',
'bgp_show_routing_instance.cc',
'bgp_table.cc',
Expand Down
3 changes: 2 additions & 1 deletion src/bgp/bgp_config.h
Expand Up @@ -383,7 +383,8 @@ class BgpConfigManager {
virtual void Terminate() = 0;
virtual const std::string &localname() const = 0;

virtual InstanceMapRange InstanceMapItems() const = 0;
virtual InstanceMapRange InstanceMapItems(
const std::string &start_instance = std::string()) const = 0;
virtual NeighborMapRange NeighborMapItems(
const std::string &instance_name) const = 0;

Expand Down
9 changes: 5 additions & 4 deletions src/bgp/bgp_config_ifmap.cc
Expand Up @@ -922,8 +922,9 @@ const BgpIfmapPeeringConfig *BgpIfmapConfigData::FindPeering(
}

BgpConfigManager::InstanceMapRange
BgpIfmapConfigData::InstanceMapItems() const {
return make_pair(instance_config_map_.begin(), instance_config_map_.end());
BgpIfmapConfigData::InstanceMapItems(const string &start_name) const {
return make_pair(instance_config_map_.lower_bound(start_name),
instance_config_map_.end());
}

//
Expand Down Expand Up @@ -972,8 +973,8 @@ void BgpIfmapConfigManager::OnChange() {
}

BgpConfigManager::InstanceMapRange
BgpIfmapConfigManager::InstanceMapItems() const {
return config_->InstanceMapItems();
BgpIfmapConfigManager::InstanceMapItems(const string &start_name) const {
return config_->InstanceMapItems(start_name);
}

BgpConfigManager::NeighborMapRange
Expand Down
6 changes: 4 additions & 2 deletions src/bgp/bgp_config_ifmap.h
Expand Up @@ -274,7 +274,8 @@ class BgpIfmapConfigData {
const BgpIfmapPeeringConfig *FindPeering(const std::string &name) const;
int PeeringCount() const { return peerings_.size(); }

BgpConfigManager::InstanceMapRange InstanceMapItems() const;
BgpConfigManager::InstanceMapRange InstanceMapItems(
const std::string &start_name = std::string()) const;

const IfmapInstanceMap &instances() const { return instances_; }

Expand Down Expand Up @@ -317,7 +318,8 @@ class BgpIfmapConfigManager : public BgpConfigManager,
virtual void Terminate();
virtual const std::string &localname() const { return localname_; }

virtual InstanceMapRange InstanceMapItems() const;
virtual InstanceMapRange InstanceMapItems(
const std::string &start_name = std::string()) const;
virtual NeighborMapRange NeighborMapItems(
const std::string &instance_name) const;

Expand Down
4 changes: 2 additions & 2 deletions src/bgp/bgp_config_yaml.cc
Expand Up @@ -162,9 +162,9 @@ const string &BgpYamlConfigManager::localname() const {
}

BgpConfigManager::InstanceMapRange
BgpYamlConfigManager::InstanceMapItems() const {
BgpYamlConfigManager::InstanceMapItems(const string &start_name) const {
const BgpConfigManager::InstanceMap &map = data_->GetInstanceMap();
return make_pair(map.begin(), map.end());
return make_pair(map.lower_bound(start_name), map.end());
}

BgpConfigManager::NeighborMapRange BgpYamlConfigManager::NeighborMapItems(
Expand Down
3 changes: 2 additions & 1 deletion src/bgp/bgp_config_yaml.h
Expand Up @@ -27,7 +27,8 @@ class BgpYamlConfigManager : public BgpConfigManager {
virtual void Terminate();
virtual const std::string &localname() const;

virtual InstanceMapRange InstanceMapItems() const;
virtual InstanceMapRange InstanceMapItems(
const std::string &start_name = std::string()) const;
virtual NeighborMapRange NeighborMapItems(
const std::string &instance_name) const;

Expand Down
2 changes: 2 additions & 0 deletions src/bgp/bgp_peer.sandesh
Expand Up @@ -317,6 +317,8 @@ struct ShowBgpInstanceConfig {

response sandesh ShowBgpInstanceConfigResp {
1: list<ShowBgpInstanceConfig> instances;
2: optional string next_batch (link="ShowBgpInstanceConfigReqIterate",
link_title="next_batch");
}

request sandesh ShowBgpInstanceConfigReq {
Expand Down
4 changes: 4 additions & 0 deletions src/bgp/bgp_peer_internal.sandesh
Expand Up @@ -50,6 +50,10 @@ request sandesh ShowMulticastManagerDetailReq {
1: string name;
}

request sandesh ShowBgpInstanceConfigReqIterate {
1: string iterate_info;
}

response sandesh ShowBgpPeeringConfigResp {
1: list<bgp_peer.ShowBgpPeeringConfig> peerings;
}
Expand Down
91 changes: 0 additions & 91 deletions src/bgp/bgp_sandesh.cc
Expand Up @@ -1237,97 +1237,6 @@ void ShowRouteVrfReq::HandleRequest() const {
RequestPipeline rp(ps);
}

class ShowBgpInstanceConfigHandler {
public:
static bool CallbackS1(const Sandesh *sr,
const RequestPipeline::PipeSpec ps,
int stage, int instNum,
RequestPipeline::InstData *data) {
const ShowBgpInstanceConfigReq *req =
static_cast<const ShowBgpInstanceConfigReq *>(ps.snhRequest_.get());
const string &search_string = req->get_search_string();
BgpSandeshContext *bsc =
static_cast<BgpSandeshContext *>(req->client_context());
BgpConfigManager *bcm = bsc->bgp_server->config_manager();

vector<ShowBgpInstanceConfig> ri_list;
typedef std::pair<std::string, const BgpInstanceConfig *> pair_t;
BOOST_FOREACH(pair_t item, bcm->InstanceMapItems()) {
ShowBgpInstanceConfig inst;
const BgpInstanceConfig *instance = item.second;
if (!search_string.empty() &&
instance->name().find(search_string) == string::npos) {
continue;
}
inst.set_name(instance->name());
inst.set_virtual_network(instance->virtual_network());
inst.set_virtual_network_index(instance->virtual_network_index());
inst.set_vxlan_id(instance->vxlan_id());

std::vector<std::string> import_list;
BOOST_FOREACH(std::string rt, instance->import_list()) {
import_list.push_back(rt);
}
inst.set_import_target(import_list);

std::vector<std::string> export_list;
BOOST_FOREACH(std::string rt, instance->export_list()) {
export_list.push_back(rt);
}
inst.set_export_target(export_list);
inst.set_last_change_at(
UTCUsecToString(instance->last_change_at()));

if (!instance->service_chain_list().empty()) {
const ServiceChainConfig &sci =
instance->service_chain_list().front();
ShowBgpServiceChainConfig scc;
scc.set_routing_instance(sci.routing_instance);
scc.set_service_instance(sci.service_instance);
scc.set_chain_address(sci.service_chain_address);
scc.set_prefixes(sci.prefix);
inst.set_service_chain_info(scc);
}

std::vector<ShowBgpStaticRouteConfig> static_route_list;
BOOST_FOREACH(const StaticRouteConfig &rtconfig,
instance->static_routes()) {
ShowBgpStaticRouteConfig src;
std::stringstream prefix;
prefix << rtconfig.address.to_string() << "/"
<< rtconfig.prefix_length;
src.set_prefix(prefix.str());
src.set_targets(rtconfig.route_target);
src.set_nexthop(rtconfig.nexthop.to_string());
static_route_list.push_back(src);
}
if (!static_route_list.empty()) {
inst.set_static_routes(static_route_list);
}
ri_list.push_back(inst);
}
ShowBgpInstanceConfigResp *resp = new ShowBgpInstanceConfigResp;
resp->set_instances(ri_list);
resp->set_context(req->context());
resp->Response();
return true;
}
};

void ShowBgpInstanceConfigReq::HandleRequest() const {
RequestPipeline::PipeSpec ps(this);

// Request pipeline has single stage to collect instance config info
// and respond to the request
RequestPipeline::StageSpec s1;
TaskScheduler *scheduler = TaskScheduler::GetInstance();
s1.taskId_ = scheduler->GetTaskId("bgp::ShowCommand");
s1.cbFn_ = ShowBgpInstanceConfigHandler::CallbackS1;
s1.instances_.push_back(0);
ps.stages_ = list_of(s1);
RequestPipeline rp(ps);
}

class ShowBgpPeeringConfigHandler {
public:
static bool CallbackS1(const Sandesh *sr,
Expand Down
165 changes: 165 additions & 0 deletions src/bgp/bgp_show_config.cc
@@ -0,0 +1,165 @@
/*
* Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
*/

#include "bgp/bgp_show_handler.h"

#include <boost/bind.hpp>
#include <boost/foreach.hpp>

#include "base/time_util.h"
#include "bgp/bgp_config.h"
#include "bgp/bgp_peer_internal_types.h"
#include "bgp/bgp_peer_types.h"
#include "bgp/bgp_server.h"

using std::string;
using std::vector;

//
// Fill in information for an instance.
//
static void FillBgpInstanceConfigInfo(ShowBgpInstanceConfig *sbic,
const BgpSandeshContext *bsc, const BgpInstanceConfig *instance) {
sbic->set_name(instance->name());
sbic->set_virtual_network(instance->virtual_network());
sbic->set_virtual_network_index(instance->virtual_network_index());
sbic->set_vxlan_id(instance->vxlan_id());

vector<string> import_list;
BOOST_FOREACH(std::string rt, instance->import_list()) {
import_list.push_back(rt);
}
sbic->set_import_target(import_list);
vector<string> export_list;
BOOST_FOREACH(std::string rt, instance->export_list()) {
export_list.push_back(rt);
}
sbic->set_export_target(export_list);
sbic->set_last_change_at(UTCUsecToString(instance->last_change_at()));

if (!instance->service_chain_list().empty()) {
const ServiceChainConfig &sci = instance->service_chain_list().front();
ShowBgpServiceChainConfig sbscc;
sbscc.set_routing_instance(sci.routing_instance);
sbscc.set_service_instance(sci.service_instance);
sbscc.set_chain_address(sci.service_chain_address);
sbscc.set_prefixes(sci.prefix);
sbic->set_service_chain_info(sbscc);
}

vector<ShowBgpStaticRouteConfig> static_route_list;
BOOST_FOREACH(const StaticRouteConfig &rtconfig,
instance->static_routes()) {
ShowBgpStaticRouteConfig sbsrc;
string prefix = rtconfig.address.to_string() + "/";
prefix += integerToString(rtconfig.prefix_length);
sbsrc.set_prefix(prefix);
sbsrc.set_targets(rtconfig.route_target);
sbsrc.set_nexthop(rtconfig.nexthop.to_string());
static_route_list.push_back(sbsrc);
}
if (!static_route_list.empty())
sbic->set_static_routes(static_route_list);
}

//
// Specialization of BgpShowHandler<>::CallbackCommon.
//
template <>
bool BgpShowHandler<ShowBgpInstanceConfigReq, ShowBgpInstanceConfigReqIterate,
ShowBgpInstanceConfigResp, ShowBgpInstanceConfig>::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;
const BgpConfigManager *bcm = bsc->bgp_server->config_manager();

BgpConfigManager::InstanceMapRange range =
bcm->InstanceMapItems(data->next_entry);
BgpConfigManager::InstanceMap::const_iterator it = range.first;
BgpConfigManager::InstanceMap::const_iterator it_end = range.second;
for (uint32_t iter_count = 0; it != it_end; ++it, ++iter_count) {
const BgpInstanceConfig *instance = it->second;
if (!data->search_string.empty() &&
(instance->name().find(data->search_string) == string::npos)) {
continue;
}

ShowBgpInstanceConfig sbic;
FillBgpInstanceConfigInfo(&sbic, bsc, instance);
data->show_list.push_back(sbic);
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 == it_end || ++it == it_end)
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;
}

//
// Specialization of BgpShowHandler<>::FillShowList.
//
template <>
void BgpShowHandler<ShowBgpInstanceConfigReq, ShowBgpInstanceConfigReqIterate,
ShowBgpInstanceConfigResp, ShowBgpInstanceConfig>::FillShowList(
ShowBgpInstanceConfigResp *resp,
const vector<ShowBgpInstanceConfig> &show_list) {
resp->set_instances(show_list);
}

//
// Handler for ShowBgpInstanceConfigReq.
//
void ShowBgpInstanceConfigReq::HandleRequest() const {
RequestPipeline::PipeSpec ps(this);
RequestPipeline::StageSpec s1;
TaskScheduler *scheduler = TaskScheduler::GetInstance();

s1.taskId_ = scheduler->GetTaskId("bgp::ShowCommand");
s1.cbFn_ = boost::bind(&BgpShowHandler<
ShowBgpInstanceConfigReq,
ShowBgpInstanceConfigReqIterate,
ShowBgpInstanceConfigResp,
ShowBgpInstanceConfig>::Callback, _1, _2, _3, _4, _5);
s1.allocFn_ = BgpShowHandler<
ShowBgpInstanceConfigReq,
ShowBgpInstanceConfigReqIterate,
ShowBgpInstanceConfigResp,
ShowBgpInstanceConfig>::CreateData;
s1.instances_.push_back(0);
ps.stages_.push_back(s1);
RequestPipeline rp(ps);
}

//
// Handler for ShowBgpInstanceConfigReqIterate.
//
void ShowBgpInstanceConfigReqIterate::HandleRequest() const {
RequestPipeline::PipeSpec ps(this);
RequestPipeline::StageSpec s1;
TaskScheduler *scheduler = TaskScheduler::GetInstance();

s1.taskId_ = scheduler->GetTaskId("bgp::ShowCommand");
s1.cbFn_ = boost::bind(&BgpShowHandler<
ShowBgpInstanceConfigReq,
ShowBgpInstanceConfigReqIterate,
ShowBgpInstanceConfigResp,
ShowBgpInstanceConfig>::CallbackIterate, _1, _2, _3, _4, _5);
s1.allocFn_ = BgpShowHandler<
ShowBgpInstanceConfigReq,
ShowBgpInstanceConfigReqIterate,
ShowBgpInstanceConfigResp,
ShowBgpInstanceConfig>::CreateData;
s1.instances_.push_back(0);
ps.stages_.push_back(s1);
RequestPipeline rp(ps);
}

0 comments on commit 48541a2

Please sign in to comment.