Skip to content

Commit

Permalink
Support pagination of output for rtarget group 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 be
displayed.

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:

- Move introspect commands to bgp_peer.sandesh
- Move code from rtarget_group_mgr.cc to bgp_show_rtarget_group.cc
- Use class template BgpShowHandler to avoid code duplication
- Implement iteration limit to avoid hogging CPU from introspect
- Make some typedefs in RTargetGroupMgr private
- Add unit tests to cover combinations of page and iteration limits

Change-Id: I526b983b03024d248f5220d4692b0ef5880dcb9a
Closes-Bug: 1485726
  • Loading branch information
Nischal Sheth committed Aug 20, 2015
1 parent 4093db7 commit a33deea
Show file tree
Hide file tree
Showing 16 changed files with 1,079 additions and 177 deletions.
1 change: 1 addition & 0 deletions src/bgp/SConscript
Expand Up @@ -65,6 +65,7 @@ libbgp = env.Library('bgp',
'bgp_show_route.cc',
'bgp_show_route_summary.cc',
'bgp_show_routing_instance.cc',
'bgp_show_rtarget_group.cc',
'bgp_table.cc',
'bgp_update.cc',
'bgp_update_monitor.cc',
Expand Down
43 changes: 43 additions & 0 deletions src/bgp/bgp_peer.sandesh
Expand Up @@ -262,6 +262,49 @@ request sandesh ShowRoutingInstanceSummaryReq {
1: string search_string;
}

struct ShowRtGroupMemberTableList {
1: string family;
2: list<string> tables;
}

struct ShowRtGroupInfo {
1: string rtarget (link="ShowRtGroupReq");
2: list<ShowRtGroupMemberTableList> import_members;
3: list<ShowRtGroupMemberTableList> export_members;
4: optional list<string> peers_interested;
5: optional list<string> dep_route;
}

response sandesh ShowRtGroupResp {
1: list<ShowRtGroupInfo> rtgroup_list;
2: optional string next_batch (link="ShowRtGroupReqIterate",
link_title="next_batch");
}

request sandesh ShowRtGroupReq {
1: string search_string;
}

response sandesh ShowRtGroupSummaryResp {
1: list<ShowRtGroupInfo> rtgroup_list;
2: optional string next_batch (link="ShowRtGroupSummaryReqIterate",
link_title="next_batch");
}

request sandesh ShowRtGroupSummaryReq {
1: string search_string;
}

response sandesh ShowRtGroupPeerResp {
1: list<ShowRtGroupInfo> rtgroup_list;
2: optional string next_batch (link="ShowRtGroupPeerReqIterate",
link_title="next_batch");
}

request sandesh ShowRtGroupPeerReq {
1: string search_string;
}

struct ShowEvpnTable {
1: string name (link="ShowRouteReq");
2: u64 mac_routes;
Expand Down
12 changes: 12 additions & 0 deletions src/bgp/bgp_peer_internal.sandesh
Expand Up @@ -50,6 +50,18 @@ request sandesh ShowRoutingInstanceSummaryReqIterate {
1: string iterate_info;
}

request sandesh ShowRtGroupReqIterate {
1: string iterate_info;
}

request sandesh ShowRtGroupSummaryReqIterate {
1: string iterate_info;
}

request sandesh ShowRtGroupPeerReqIterate {
1: string iterate_info;
}

request sandesh ShowEvpnTableReqIterate {
1: string iterate_info;
}
Expand Down
3 changes: 3 additions & 0 deletions src/bgp/bgp_server.h
Expand Up @@ -78,6 +78,9 @@ class BgpServer {
return inst_mgr_.get();
}
RTargetGroupMgr *rtarget_group_mgr() { return rtarget_group_mgr_.get(); }
const RTargetGroupMgr *rtarget_group_mgr() const {
return rtarget_group_mgr_.get();
}
BgpConditionListener *condition_listener(Address::Family family) {
if (family == Address::INET)
return inet_condition_listener_.get();
Expand Down
307 changes: 307 additions & 0 deletions src/bgp/bgp_show_rtarget_group.cc
@@ -0,0 +1,307 @@
/*
* Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
*/

#include "bgp/bgp_show_handler.h"

#include <boost/bind.hpp>

#include "bgp/bgp_peer_internal_types.h"
#include "bgp/bgp_peer_types.h"
#include "bgp/bgp_server.h"
#include "bgp/routing-instance/rtarget_group.h"
#include "bgp/routing-instance/rtarget_group_mgr.h"

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

//
// Fill in information for list of rtarget groups.
//
// Allows regular, summary and peer introspect to share code.
// Assumes that search_string is the peer name if match_peer is true.
//
static bool FillRtGroupInfoList(const BgpSandeshContext *bsc,
bool summary, bool match_peer, uint32_t page_limit, uint32_t iter_limit,
const string &start_rtarget_str, const string &search_string,
vector<ShowRtGroupInfo> *srtg_list, string *next_rtarget_str) {
RouteTarget rtarget;

// Bail if start_rtarget_str is bad.
if (!start_rtarget_str.empty()) {
rtarget = RouteTarget::FromString(start_rtarget_str);
if (rtarget.IsNull())
return true;
}

// Bail if there's no peer specified when doing a peer introspect.
if (match_peer && search_string.empty())
return true;

const RTargetGroupMgr *rtgroup_mgr = bsc->bgp_server->rtarget_group_mgr();
RTargetGroupMgr::const_iterator it = rtgroup_mgr->lower_bound(rtarget);
for (uint32_t iter_count = 0; it != rtgroup_mgr->end();
++it, ++iter_count) {
const RtGroup *rtgroup = it->second;
if (!match_peer && !search_string.empty() &&
(rtgroup->ToString().find(search_string) == string::npos)) {
continue;
}
ShowRtGroupInfo srtg;
if (match_peer) {
if (!rtgroup->HasInterestedPeer(search_string))
continue;
rtgroup->FillShowPeerInfo(&srtg);
} else if (summary) {
rtgroup->FillShowSummaryInfo(&srtg);
} else {
rtgroup->FillShowInfo(&srtg);
}
srtg_list->push_back(srtg);
if (srtg_list->size() >= page_limit)
break;
if (iter_count >= iter_limit)
break;
}

// All done if we've looked at all rtarget groups.
if (it == rtgroup_mgr->end() || ++it == rtgroup_mgr->end())
return true;

// Return true if we've reached the page limit, false if we've reached the
// iteration limit.
bool done = srtg_list->size() >= page_limit;
*next_rtarget_str = it->second->ToString();
return done;
}

//
// Specialization of BgpShowHandler<>::CallbackCommon for regular introspect.
//
template <>
bool BgpShowHandler<ShowRtGroupReq, ShowRtGroupReqIterate,
ShowRtGroupResp, ShowRtGroupInfo>::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;
string next_rtarget_str;
bool done = FillRtGroupInfoList(bsc, false, false, page_limit, iter_limit,
data->next_entry, data->search_string, &data->show_list,
&next_rtarget_str);
if (!next_rtarget_str.empty())
SaveContextToData(next_rtarget_str, done, data);
return done;
}

//
// Specialization of BgpShowHandler<>::FillShowList for regular introspect.
//
template <>
void BgpShowHandler<ShowRtGroupReq, ShowRtGroupReqIterate,
ShowRtGroupResp, ShowRtGroupInfo>::FillShowList(
ShowRtGroupResp *resp,
const vector<ShowRtGroupInfo> &show_list) {
resp->set_rtgroup_list(show_list);
}

//
// Specialization of BgpShowHandler<>::CallbackCommon for summary introspect.
//
template <>
bool BgpShowHandler<ShowRtGroupSummaryReq, ShowRtGroupSummaryReqIterate,
ShowRtGroupSummaryResp, ShowRtGroupInfo>::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;
string next_rtarget_str;
bool done = FillRtGroupInfoList(bsc, true, false, page_limit, iter_limit,
data->next_entry, data->search_string, &data->show_list,
&next_rtarget_str);
if (!next_rtarget_str.empty())
SaveContextToData(next_rtarget_str, done, data);
return done;
}

//
// Specialization of BgpShowHandler<>::FillShowList for summary introspect.
//
template <>
void BgpShowHandler<ShowRtGroupSummaryReq, ShowRtGroupSummaryReqIterate,
ShowRtGroupSummaryResp, ShowRtGroupInfo>::FillShowList(
ShowRtGroupSummaryResp *resp,
const vector<ShowRtGroupInfo> &show_list) {
resp->set_rtgroup_list(show_list);
}

//
// Specialization of BgpShowHandler<>::CallbackCommon for peer introspect.
//
template <>
bool BgpShowHandler<ShowRtGroupPeerReq, ShowRtGroupPeerReqIterate,
ShowRtGroupPeerResp, ShowRtGroupInfo>::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;
string next_rtarget_str;
bool done = FillRtGroupInfoList(bsc, false, true, page_limit, iter_limit,
data->next_entry, data->search_string, &data->show_list,
&next_rtarget_str);
if (!next_rtarget_str.empty())
SaveContextToData(next_rtarget_str, done, data);
return done;
}

//
// Specialization of BgpShowHandler<>::FillShowList for peer introspect.
//
template <>
void BgpShowHandler<ShowRtGroupPeerReq, ShowRtGroupPeerReqIterate,
ShowRtGroupPeerResp, ShowRtGroupInfo>::FillShowList(
ShowRtGroupPeerResp *resp,
const vector<ShowRtGroupInfo> &show_list) {
resp->set_rtgroup_list(show_list);
}

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

s1.taskId_ = scheduler->GetTaskId("bgp::RTFilter");
s1.cbFn_ = boost::bind(&BgpShowHandler<
ShowRtGroupReq,
ShowRtGroupReqIterate,
ShowRtGroupResp,
ShowRtGroupInfo>::Callback, _1, _2, _3, _4, _5);
s1.allocFn_ = BgpShowHandler<
ShowRtGroupReq,
ShowRtGroupReqIterate,
ShowRtGroupResp,
ShowRtGroupInfo>::CreateData;
s1.instances_.push_back(0);
ps.stages_.push_back(s1);
RequestPipeline rp(ps);
}

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

s1.taskId_ = scheduler->GetTaskId("bgp::RTFilter");
s1.cbFn_ = boost::bind(&BgpShowHandler<
ShowRtGroupReq,
ShowRtGroupReqIterate,
ShowRtGroupResp,
ShowRtGroupInfo>::CallbackIterate, _1, _2, _3, _4, _5);
s1.allocFn_ = BgpShowHandler<
ShowRtGroupReq,
ShowRtGroupReqIterate,
ShowRtGroupResp,
ShowRtGroupInfo>::CreateData;
s1.instances_.push_back(0);
ps.stages_.push_back(s1);
RequestPipeline rp(ps);
}

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

s1.taskId_ = scheduler->GetTaskId("bgp::RTFilter");
s1.cbFn_ = boost::bind(&BgpShowHandler<
ShowRtGroupSummaryReq,
ShowRtGroupSummaryReqIterate,
ShowRtGroupSummaryResp,
ShowRtGroupInfo>::Callback, _1, _2, _3, _4, _5);
s1.allocFn_ = BgpShowHandler<
ShowRtGroupSummaryReq,
ShowRtGroupSummaryReqIterate,
ShowRtGroupSummaryResp,
ShowRtGroupInfo>::CreateData;
s1.instances_.push_back(0);
ps.stages_.push_back(s1);
RequestPipeline rp(ps);
}

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

s1.taskId_ = scheduler->GetTaskId("bgp::RTFilter");
s1.cbFn_ = boost::bind(&BgpShowHandler<
ShowRtGroupSummaryReq,
ShowRtGroupSummaryReqIterate,
ShowRtGroupSummaryResp,
ShowRtGroupInfo>::CallbackIterate, _1, _2, _3, _4, _5);
s1.allocFn_ = BgpShowHandler<
ShowRtGroupSummaryReq,
ShowRtGroupSummaryReqIterate,
ShowRtGroupSummaryResp,
ShowRtGroupInfo>::CreateData;
s1.instances_.push_back(0);
ps.stages_.push_back(s1);
RequestPipeline rp(ps);
}

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

s1.taskId_ = scheduler->GetTaskId("bgp::RTFilter");
s1.cbFn_ = boost::bind(&BgpShowHandler<
ShowRtGroupPeerReq,
ShowRtGroupPeerReqIterate,
ShowRtGroupPeerResp,
ShowRtGroupInfo>::Callback, _1, _2, _3, _4, _5);
s1.allocFn_ = BgpShowHandler<
ShowRtGroupPeerReq,
ShowRtGroupPeerReqIterate,
ShowRtGroupPeerResp,
ShowRtGroupInfo>::CreateData;
s1.instances_.push_back(0);
ps.stages_.push_back(s1);
RequestPipeline rp(ps);
}

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

s1.taskId_ = scheduler->GetTaskId("bgp::RTFilter");
s1.cbFn_ = boost::bind(&BgpShowHandler<
ShowRtGroupPeerReq,
ShowRtGroupPeerReqIterate,
ShowRtGroupPeerResp,
ShowRtGroupInfo>::CallbackIterate, _1, _2, _3, _4, _5);
s1.allocFn_ = BgpShowHandler<
ShowRtGroupPeerReq,
ShowRtGroupPeerReqIterate,
ShowRtGroupPeerResp,
ShowRtGroupInfo>::CreateData;
s1.instances_.push_back(0);
ps.stages_.push_back(s1);
RequestPipeline rp(ps);
}

0 comments on commit a33deea

Please sign in to comment.