OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
bgp_show_handler.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #ifndef SRC_BGP_BGP_SHOW_HANDLER_H__
6 #define SRC_BGP_BGP_SHOW_HANDLER_H__
7 
8 #include "bgp/bgp_sandesh.h"
9 
10 #include <sandesh/request_pipeline.h>
11 
12 #include <string>
13 #include <vector>
14 
15 static char kIterSeparator[] = "||";
16 
17 //
18 // Class template to handle single stage show commands with single key and
19 // a search string.
20 //
21 // Supports pagination of output as specified by page limit.
22 //
23 // Also supports an iteration limit, which is the maximum number of entries
24 // examined in one run. This is useful when the search string is non-empty
25 // and there are a large number of entries in table. We don't want to look
26 // at potentially all entries in one shot in cases where most of them don't
27 // match the search string.
28 //
29 // Data is used to store partial pages of results as well as other context
30 // that needs to be maintained between successive runs of the callbacks in
31 // cases where we don't manage to fill a page of results in one run.
32 //
33 // Note that the infrastructure automatically reschedules and invokes the
34 // callback function again if it returns false.
35 //
36 template <typename ReqT, typename ReqIterateT, typename RespT, typename ShowT>
38 public:
39  static const uint32_t kPageLimit = 64;
40  static const uint32_t kIterLimit = 1024;
41 
42  struct Data : public RequestPipeline::InstData {
43  Data() : initialized(false) {
44  }
45 
47  std::string search_string;
48  std::string next_entry;
49  std::string next_batch;
50  std::vector<ShowT> show_list;
51  };
52 
54  return (new Data);
55  }
56 
57  static void ConvertReqToData(const ReqT *req, Data *data);
58  static bool ConvertReqIterateToData(const ReqIterateT *req_iterate,
59  Data *data);
60  static void SaveContextToData(const std::string &next_entry, bool done,
61  Data *data);
62 
63  static void FillShowList(RespT *resp, const std::vector<ShowT> &show_list);
64  static bool CallbackCommon(const BgpSandeshContext *bsc, Data *data);
65  static bool Callback(const Sandesh *sr,
67  int stage, int instNum, RequestPipeline::InstData *data);
68  static bool CallbackIterate(const Sandesh *sr,
70  int stage, int instNum, RequestPipeline::InstData *data);
71 };
72 
73 //
74 // Initialize Data from ReqT.
75 //
76 template <typename ReqT, typename ReqIterateT, typename RespT, typename ShowT>
78  const ReqT *req, Data *data) {
79  if (data->initialized)
80  return;
81  data->initialized = true;
82  data->search_string = req->get_search_string();
83 }
84 
85 //
86 // Initialize Data from ReqInterateT.
87 //
88 // Return false if there's a problem parsing the iterate_info string.
89 //
90 template <typename ReqT, typename ReqIterateT, typename RespT, typename ShowT>
92  const ReqIterateT *req_iterate, Data *data) {
93  if (data->initialized)
94  return true;
95  data->initialized = true;
96 
97  // Format of iterate_info:
98  // next_entry||search_string
99  std::string iterate_info = req_iterate->get_iterate_info();
100  size_t sep_size = strlen(kIterSeparator);
101 
102  size_t pos1 = iterate_info.find(kIterSeparator);
103  if (pos1 == std::string::npos)
104  return false;
105 
106  data->next_entry = iterate_info.substr(0, pos1);
107  data->search_string = iterate_info.substr(pos1 + sep_size);
108  return true;
109 }
110 
111 //
112 // Save context into Data.
113 // The next_entry field gets used in the subsequent invocation of callback
114 // routine when the callback routine returns false.
115 // The next_batch string is used if the page is filled (i.e. done is true).
116 //
117 template <typename ReqT, typename ReqIterateT, typename RespT, typename ShowT>
119  const std::string &next_entry, bool done, Data *data) {
120  data->next_entry = next_entry;
121  if (done)
122  data->next_batch = next_entry + kIterSeparator + data->search_string;
123 }
124 
125 //
126 // Fill show_list into RespT.
127 // Should be specialized to allow each RespT to have a potentially different
128 // name for the list of entries.
129 //
130 template <typename ReqT, typename ReqIterateT, typename RespT, typename ShowT>
132  RespT *resp, const std::vector<ShowT> &show_list) {
133 }
134 
135 //
136 // Common routine for regular and iterate requests.
137 // Assumes that Data has been initialized properly by caller.
138 // Examine specified maximum entries starting at data->next_entry.
139 //
140 // Should be specialized to handle specifics of the show command being
141 // handled.
142 //
143 // Return true if we're examined all entries or reached the page limit.
144 //
145 template <typename ReqT, typename ReqIterateT, typename RespT, typename ShowT>
147  const BgpSandeshContext *bsc, Data *data) {
148  return true;
149 }
150 
151 //
152 // Callback for ReqT. This gets called for initial request and subsequently in
153 // cases where the iteration count is reached.
154 //
155 // Return false if the iteration count is reached before page gets filled.
156 // Return true if the page gets filled or we've examined all entries.
157 //
158 template <typename ReqT, typename ReqIterateT, typename RespT, typename ShowT>
160  const Sandesh *sr, const RequestPipeline::PipeSpec ps,
161  int stage, int instNum, RequestPipeline::InstData *data) {
162  Data *mydata = static_cast<Data *>(data);
163  const ReqT *req = static_cast<const ReqT *>(ps.snhRequest_.get());
164  const BgpSandeshContext *bsc =
165  static_cast<const BgpSandeshContext *>(req->client_context());
166 
167  // Parse request and save state in Data.
168  ConvertReqToData(req, mydata);
169 
170  // Return false and reschedule ourselves if we've reached the limit of
171  // the number of entries examined.
172  if (!CallbackCommon(bsc, mydata))
173  return false;
174 
175  // All done - ship the response.
176  RespT *resp = new RespT;
177  resp->set_context(req->context());
178  if (!mydata->show_list.empty())
179  FillShowList(resp, mydata->show_list);
180  if (!mydata->next_batch.empty())
181  resp->set_next_batch(mydata->next_batch);
182  resp->Response();
183  return true;
184 }
185 
186 //
187 // Callback for ReqIterate. This is called for initial request and subsequently
188 // in cases where the iteration count is reached. Parse the iterate_info string
189 // to figure out the next entry to examine.
190 //
191 // Return false if the iteration limit is reached before page gets filled.
192 // Return true if the page gets filled or we've examined all entries.
193 //
194 template <typename ReqT, typename ReqIterateT, typename RespT, typename ShowT>
196  const Sandesh *sr, const RequestPipeline::PipeSpec ps,
197  int stage, int instNum, RequestPipeline::InstData *data) {
198  Data *mydata = static_cast<Data *>(data);
199  const ReqIterateT *req_iterate =
200  static_cast<const ReqIterateT *>(ps.snhRequest_.get());
201  const BgpSandeshContext *bsc =
202  static_cast<const BgpSandeshContext *>(req_iterate->client_context());
203 
204  // Parse request and save state in Data.
205  if (!ConvertReqIterateToData(req_iterate, mydata)) {
206  RespT *resp = new RespT;
207  resp->set_context(req_iterate->context());
208  resp->Response();
209  return true;
210  }
211 
212  // Return false and reschedule ourselves if we've reached the limit of
213  // the number of entries examined.
214  if (!CallbackCommon(bsc, mydata))
215  return false;
216 
217  // All done - ship the response.
218  RespT *resp = new RespT;
219  resp->set_context(req_iterate->context());
220  if (!mydata->show_list.empty())
221  FillShowList(resp, mydata->show_list);
222  if (!mydata->next_batch.empty())
223  resp->set_next_batch(mydata->next_batch);
224  resp->Response();
225  return true;
226 }
227 
228 #endif // SRC_BGP_BGP_SHOW_HANDLER_H__
static void FillShowList(RespT *resp, const std::vector< ShowT > &show_list)
static bool CallbackCommon(const BgpSandeshContext *bsc, Data *data)
static void ConvertReqToData(const ReqT *req, Data *data)
static const uint32_t kIterLimit
static const uint32_t kPageLimit
std::vector< ShowT > show_list
static bool Callback(const Sandesh *sr, const RequestPipeline::PipeSpec ps, int stage, int instNum, RequestPipeline::InstData *data)
static void SaveContextToData(const std::string &next_entry, bool done, Data *data)
static char kIterSeparator[]
boost::shared_ptr< const SandeshRequest > snhRequest_
static bool ConvertReqIterateToData(const ReqIterateT *req_iterate, Data *data)
static RequestPipeline::InstData * CreateData(int stage)
static bool CallbackIterate(const Sandesh *sr, const RequestPipeline::PipeSpec ps, int stage, int instNum, RequestPipeline::InstData *data)