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