Line data Source code
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>
37 : class BgpShowHandler {
38 : public:
39 : static const uint32_t kPageLimit = 64;
40 : static const uint32_t kIterLimit = 1024;
41 :
42 : struct Data : public RequestPipeline::InstData {
43 1544 : Data() : initialized(false) {
44 1544 : }
45 :
46 : bool initialized;
47 : std::string search_string;
48 : std::string next_entry;
49 : std::string next_batch;
50 : std::vector<ShowT> show_list;
51 : };
52 :
53 1544 : static RequestPipeline::InstData *CreateData(int stage) {
54 1544 : 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,
66 : const RequestPipeline::PipeSpec ps,
67 : int stage, int instNum, RequestPipeline::InstData *data);
68 : static bool CallbackIterate(const Sandesh *sr,
69 : const RequestPipeline::PipeSpec ps,
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>
77 2418 : void BgpShowHandler<ReqT, ReqIterateT, RespT, ShowT>::ConvertReqToData(
78 : const ReqT *req, Data *data) {
79 2418 : if (data->initialized)
80 1351 : return;
81 1067 : data->initialized = true;
82 1067 : 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>
91 1207 : bool BgpShowHandler<ReqT, ReqIterateT, RespT, ShowT>::ConvertReqIterateToData(
92 : const ReqIterateT *req_iterate, Data *data) {
93 1207 : if (data->initialized)
94 731 : return true;
95 476 : data->initialized = true;
96 :
97 : // Format of iterate_info:
98 : // next_entry||search_string
99 476 : std::string iterate_info = req_iterate->get_iterate_info();
100 476 : size_t sep_size = strlen(kIterSeparator);
101 :
102 476 : size_t pos1 = iterate_info.find(kIterSeparator);
103 476 : if (pos1 == std::string::npos)
104 118 : return false;
105 :
106 358 : data->next_entry = iterate_info.substr(0, pos1);
107 358 : data->search_string = iterate_info.substr(pos1 + sep_size);
108 358 : return true;
109 476 : }
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>
118 2388 : void BgpShowHandler<ReqT, ReqIterateT, RespT, ShowT>::SaveContextToData(
119 : const std::string &next_entry, bool done, Data *data) {
120 2388 : data->next_entry = next_entry;
121 2388 : if (done)
122 306 : data->next_batch = next_entry + kIterSeparator + data->search_string;
123 2388 : }
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>
131 : void BgpShowHandler<ReqT, ReqIterateT, RespT, ShowT>::FillShowList(
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>
146 : bool BgpShowHandler<ReqT, ReqIterateT, RespT, ShowT>::CallbackCommon(
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>
159 2419 : bool BgpShowHandler<ReqT, ReqIterateT, RespT, ShowT>::Callback(
160 : const Sandesh *sr, const RequestPipeline::PipeSpec ps,
161 : int stage, int instNum, RequestPipeline::InstData *data) {
162 2419 : Data *mydata = static_cast<Data *>(data);
163 2419 : const ReqT *req = static_cast<const ReqT *>(ps.snhRequest_.get());
164 : const BgpSandeshContext *bsc =
165 2419 : static_cast<const BgpSandeshContext *>(req->client_context());
166 :
167 : // Parse request and save state in Data.
168 2419 : ConvertReqToData(req, mydata);
169 :
170 : // Return false and reschedule ourselves if we've reached the limit of
171 : // the number of entries examined.
172 2419 : if (!CallbackCommon(bsc, mydata))
173 1351 : return false;
174 :
175 : // All done - ship the response.
176 1068 : RespT *resp = new RespT;
177 1068 : resp->set_context(req->context());
178 1068 : if (!mydata->show_list.empty())
179 952 : FillShowList(resp, mydata->show_list);
180 1068 : if (!mydata->next_batch.empty())
181 154 : resp->set_next_batch(mydata->next_batch);
182 1068 : resp->Response();
183 1068 : 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>
195 1207 : bool BgpShowHandler<ReqT, ReqIterateT, RespT, ShowT>::CallbackIterate(
196 : const Sandesh *sr, const RequestPipeline::PipeSpec ps,
197 : int stage, int instNum, RequestPipeline::InstData *data) {
198 1207 : Data *mydata = static_cast<Data *>(data);
199 : const ReqIterateT *req_iterate =
200 1207 : static_cast<const ReqIterateT *>(ps.snhRequest_.get());
201 : const BgpSandeshContext *bsc =
202 1207 : static_cast<const BgpSandeshContext *>(req_iterate->client_context());
203 :
204 : // Parse request and save state in Data.
205 1207 : if (!ConvertReqIterateToData(req_iterate, mydata)) {
206 118 : RespT *resp = new RespT;
207 118 : resp->set_context(req_iterate->context());
208 118 : resp->Response();
209 118 : return true;
210 : }
211 :
212 : // Return false and reschedule ourselves if we've reached the limit of
213 : // the number of entries examined.
214 1089 : if (!CallbackCommon(bsc, mydata))
215 731 : return false;
216 :
217 : // All done - ship the response.
218 358 : RespT *resp = new RespT;
219 358 : resp->set_context(req_iterate->context());
220 358 : if (!mydata->show_list.empty())
221 296 : FillShowList(resp, mydata->show_list);
222 358 : if (!mydata->next_batch.empty())
223 152 : resp->set_next_batch(mydata->next_batch);
224 358 : resp->Response();
225 358 : return true;
226 : }
227 :
228 : #endif // SRC_BGP_BGP_SHOW_HANDLER_H__
|