Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "bgp/bgp_sandesh.h"
6 : #include "bgp/bgp_show_route.h"
7 :
8 : #include <boost/assign/list_of.hpp>
9 : #include <sandesh/request_pipeline.h>
10 :
11 : #include "base/regex.h"
12 : #include "bgp/bgp_peer_internal_types.h"
13 : #include "bgp/bgp_route.h"
14 : #include "bgp/bgp_server.h"
15 : #include "bgp/bgp_table.h"
16 : #include "bgp/routing-instance/routing_instance.h"
17 :
18 : using boost::assign::list_of;
19 : using std::unique_ptr;
20 : using std::string;
21 : using std::vector;
22 :
23 24362 : static bool IsLess(const ShowRoute &lhs, const ShowRoute &rhs,
24 : const BgpSandeshContext *bsc, const string &table_name) {
25 : BgpTable *table = static_cast<BgpTable *>
26 24362 : (bsc->bgp_server->database()->FindTable(table_name));
27 24362 : if (!table) {
28 0 : return false;
29 : }
30 24362 : unique_ptr<DBEntry> lhs_entry = table->AllocEntryStr(lhs.get_prefix());
31 24362 : unique_ptr<DBEntry> rhs_entry = table->AllocEntryStr(rhs.get_prefix());
32 :
33 24362 : Route *lhs_route = static_cast<Route *>(lhs_entry.get());
34 24362 : Route *rhs_route = static_cast<Route *>(rhs_entry.get());
35 :
36 24362 : return lhs_route->IsLess(*rhs_route);
37 24362 : }
38 :
39 1053 : static bool IsLess(const ShowRouteTable &lhs, const ShowRouteTable &rhs,
40 : const BgpSandeshContext *bsc, const string &table_name) {
41 1053 : if (lhs.get_routing_instance() < rhs.get_routing_instance()) {
42 33 : return true;
43 : }
44 1020 : if (lhs.get_routing_instance() == rhs.get_routing_instance()) {
45 962 : return lhs.get_routing_table_name() < rhs.get_routing_table_name();
46 : }
47 58 : return false;
48 : }
49 :
50 : template <class T>
51 : void MergeSort(vector<T> *result, vector<const vector<T> *> *input, int limit,
52 : const BgpSandeshContext *bsc, const string &table_name);
53 :
54 3328 : int MergeValues(ShowRoute *result, vector<const ShowRoute *> *input,
55 : int limit, const BgpSandeshContext *bsc) {
56 3328 : assert(input->size() == 1);
57 3328 : *result = *input->at(0);
58 3328 : return 1;
59 : }
60 :
61 229 : int MergeValues(ShowRouteTable *result, vector<const ShowRouteTable *> *input,
62 : int limit, const BgpSandeshContext *bsc) {
63 229 : vector<const vector<ShowRoute> *> list;
64 229 : result->set_routing_instance(input->at(0)->get_routing_instance());
65 229 : result->set_routing_table_name(input->at(0)->get_routing_table_name());
66 229 : result->set_deleted(input->at(0)->get_deleted());
67 229 : result->set_deleted_at(input->at(0)->get_deleted_at());
68 229 : result->set_prefixes(input->at(0)->get_prefixes());
69 229 : result->set_primary_paths(input->at(0)->get_primary_paths());
70 229 : result->set_secondary_paths(input->at(0)->get_secondary_paths());
71 229 : result->set_infeasible_paths(input->at(0)->get_infeasible_paths());
72 229 : result->set_stale_paths(input->at(0)->get_stale_paths());
73 229 : result->set_llgr_stale_paths(input->at(0)->get_llgr_stale_paths());
74 229 : result->set_paths(input->at(0)->get_paths());
75 229 : result->set_listeners(input->at(0)->get_listeners());
76 :
77 229 : int count = 0;
78 620 : for (size_t i = 0; i < input->size(); ++i) {
79 391 : if (input->at(i)->get_routes().size())
80 391 : list.push_back(&input->at(i)->get_routes());
81 : }
82 229 : MergeSort(const_cast<vector<ShowRoute> *>(&result->get_routes()), &list,
83 : limit ? limit - count : 0, bsc,
84 229 : input->at(0)->get_routing_table_name());
85 229 : count += result->get_routes().size();
86 229 : return count;
87 229 : }
88 :
89 : //
90 : // Merge n number of vectors in result.
91 : // Input is a vector of pointers to vector.
92 : //
93 : template <class T>
94 421 : void MergeSort(vector<T> *result, vector<const vector<T> *> *input, int limit,
95 : const BgpSandeshContext *bsc, const string &table_name) {
96 421 : size_t size = input->size();
97 421 : vector<size_t> index(size, 0);
98 421 : int count = 0;
99 7535 : while (limit == 0 || count < limit) {
100 3910 : size_t best_index = size;
101 3910 : const T *best = NULL;
102 17077 : for (size_t i = 0; i < size; ++i) {
103 13167 : if (index[i] == input->at(i)->size())
104 657 : continue;
105 21463 : if (best == NULL ||
106 8953 : IsLess(input->at(i)->at(index[i]), *best, bsc, table_name)) {
107 5717 : best = &input->at(i)->at(index[i]);
108 5717 : best_index = i;
109 5717 : continue;
110 : }
111 : }
112 3910 : if (best_index >= size)
113 353 : break;
114 3557 : T table;
115 3557 : vector<const T *> list;
116 11845 : for (size_t j = best_index; j < size; ++j) {
117 8288 : if (index[j] == input->at(j)->size())
118 57 : continue;
119 16462 : if (IsLess(input->at(j)->at(index[j]), *best, bsc, table_name) ||
120 8231 : IsLess(*best, input->at(j)->at(index[j]), bsc, table_name)) {
121 4512 : continue;
122 : }
123 3719 : list.push_back(&input->at(j)->at(index[j]));
124 3719 : index[j]++;
125 : }
126 3557 : count += MergeValues(&table, &list, limit ? limit - count : 0, bsc);
127 3557 : result->push_back(table);
128 : }
129 421 : }
130 :
131 : char ShowRouteHandler::kIterSeparator[] = "||";
132 1098 : uint32_t ShowRouteHandler::GetMaxCount(bool test_mode) {
133 1098 : if (test_mode) {
134 300 : return kUnitTestMaxCount;
135 : } else {
136 798 : return kMaxCount;
137 : }
138 : }
139 :
140 763 : ShowRouteHandler::ShowRouteHandler(const ShowRouteReq *req, int inst_id) :
141 763 : req_(req), inst_id_(inst_id), prefix_expr_(req->get_prefix()) {
142 768 : }
143 :
144 : // Search for interesting prefixes in a given table for given partition
145 6664 : void ShowRouteHandler::BuildShowRouteTable(BgpTable *table,
146 : vector<ShowRoute> *route_list, int count) {
147 6664 : if (inst_id_ >= table->PartitionCount())
148 1550 : return;
149 : DBTablePartition *partition =
150 5108 : static_cast<DBTablePartition *>(table->GetTablePartition(inst_id_));
151 5118 : BgpRoute *route = NULL;
152 :
153 5118 : if (table->name() == req_->get_start_routing_table()) {
154 : unique_ptr<DBEntry> key =
155 92 : table->AllocEntryStr(req_->get_start_prefix());
156 92 : route = static_cast<BgpRoute *>(partition->lower_bound(key.get()));
157 92 : } else {
158 5027 : route = static_cast<BgpRoute *>(partition->GetFirst());
159 : }
160 12063 : for (int i = 0; route && (!count || i < count);
161 6907 : route = static_cast<BgpRoute *>(partition->GetNext(route)), ++i) {
162 6913 : if (!MatchPrefix(req_->get_prefix(), route,
163 6913 : req_->get_longer_match(),
164 6913 : req_->get_shorter_match()))
165 855 : continue;
166 6052 : ShowRoute show_route;
167 6046 : route->FillRouteInfo(table, &show_route, req_->get_source(),
168 6046 : req_->get_protocol());
169 6047 : if (!show_route.get_paths().empty())
170 5292 : route_list->push_back(show_route);
171 6048 : }
172 : }
173 :
174 6912 : bool ShowRouteHandler::MatchPrefix(const string &expected_prefix,
175 : BgpRoute *route, bool longer_match,
176 : bool shorter_match) {
177 6912 : if (expected_prefix.empty())
178 5054 : return true;
179 1858 : if (!longer_match && !shorter_match)
180 303 : return regex_search(route->ToString(), prefix_expr_);
181 :
182 : // Do longer match.
183 1555 : if (longer_match && route->IsMoreSpecific(expected_prefix))
184 936 : return true;
185 :
186 : // Do shorter match.
187 614 : if (shorter_match && route->IsLessSpecific(expected_prefix))
188 14 : return true;
189 :
190 600 : return false;
191 : }
192 :
193 9005 : bool ShowRouteHandler::match(const string &expected, const string &actual) {
194 9005 : if (expected == "")
195 7462 : return true;
196 1542 : return expected == actual;
197 : }
198 :
199 960 : RequestPipeline::InstData *ShowRouteHandler::CreateData(int stage) {
200 960 : return static_cast<RequestPipeline::InstData *>(new ShowRouteData);
201 : }
202 :
203 1100 : uint32_t ShowRouteHandler::GetMaxRouteCount(const ShowRouteReq *req) {
204 : BgpSandeshContext *bsc =
205 1100 : static_cast<BgpSandeshContext *>(req->client_context());
206 : uint32_t max_count =
207 1098 : ShowRouteHandler::GetMaxCount(bsc->test_mode());
208 :
209 1098 : uint32_t route_count = req->get_count() + 1;
210 1097 : if (!req->get_count() || (req->get_count() > max_count)) {
211 : // Set the count to our default if input is zero or too high
212 935 : route_count = max_count + 1;
213 : }
214 1096 : return route_count;
215 : }
216 :
217 : // Get the information from req_iterate and fill into req
218 12 : bool ShowRouteHandler::ConvertReqIterateToReq(
219 : const ShowRouteReqIterate *req_iterate, ShowRouteReq *req) {
220 : // First, set the context from the original request since we might return
221 : // due to parsing errors.
222 12 : req->set_context(req_iterate->context());
223 :
224 : // Format of route_info:
225 : // UserRI||UserRT||UserPfx||NextRI||NextRT||NextPfx||count||longer_match||
226 : // shorter_match
227 : //
228 : // User* values were entered by the user and Next* values indicate 'where'
229 : // we need to start this iteration.
230 12 : string route_info = req_iterate->get_route_info();
231 12 : size_t sep_size = strlen(kIterSeparator);
232 :
233 12 : size_t pos1 = route_info.find(kIterSeparator);
234 12 : if (pos1 == string::npos) {
235 1 : return false;
236 : }
237 11 : string user_ri = route_info.substr(0, pos1);
238 :
239 11 : size_t pos2 = route_info.find(kIterSeparator, (pos1 + sep_size));
240 11 : if (pos2 == string::npos) {
241 1 : return false;
242 : }
243 : string user_rt = route_info.substr((pos1 + sep_size),
244 10 : pos2 - (pos1 + sep_size));
245 :
246 10 : size_t pos3 = route_info.find(kIterSeparator, (pos2 + sep_size));
247 10 : if (pos3 == string::npos) {
248 1 : return false;
249 : }
250 : string user_prefix = route_info.substr((pos2 + sep_size),
251 9 : pos3 - (pos2 + sep_size));
252 :
253 9 : size_t pos4 = route_info.find(kIterSeparator, (pos3 + sep_size));
254 9 : if (pos4 == string::npos) {
255 1 : return false;
256 : }
257 : string next_ri = route_info.substr((pos3 + sep_size),
258 8 : pos4 - (pos3 + sep_size));
259 :
260 8 : size_t pos5 = route_info.find(kIterSeparator, (pos4 + sep_size));
261 8 : if (pos5 == string::npos) {
262 1 : return false;
263 : }
264 : string next_rt = route_info.substr((pos4 + sep_size),
265 7 : pos5 - (pos4 + sep_size));
266 :
267 7 : size_t pos6 = route_info.find(kIterSeparator, (pos5 + sep_size));
268 7 : if (pos6 == string::npos) {
269 1 : return false;
270 : }
271 : string next_prefix = route_info.substr((pos5 + sep_size),
272 6 : pos6 - (pos5 + sep_size));
273 :
274 6 : size_t pos7 = route_info.find(kIterSeparator, (pos6 + sep_size));
275 6 : if (pos7 == string::npos) {
276 1 : return false;
277 : }
278 : string count_str = route_info.substr((pos6 + sep_size),
279 5 : pos7 - (pos6 + sep_size));
280 :
281 5 : size_t pos8 = route_info.find(kIterSeparator, (pos7 + sep_size));
282 5 : if (pos8 == string::npos) {
283 1 : return false;
284 : }
285 : string user_source = route_info.substr((pos7 + sep_size),
286 4 : pos8 - (pos7 + sep_size));
287 :
288 4 : size_t pos9 = route_info.find(kIterSeparator, (pos8 + sep_size));
289 4 : if (pos9 == string::npos) {
290 1 : return false;
291 : }
292 : string user_protocol = route_info.substr((pos8 + sep_size),
293 3 : pos9 - (pos8 + sep_size));
294 :
295 3 : size_t pos10 = route_info.find(kIterSeparator, (pos9 + sep_size));
296 3 : if (pos10 == string::npos) {
297 1 : return false;
298 : }
299 : string user_family = route_info.substr((pos9 + sep_size),
300 2 : pos10 - (pos9 + sep_size));
301 :
302 2 : size_t pos11 = route_info.find(kIterSeparator, (pos10 + sep_size));
303 2 : if (pos11 == string::npos) {
304 1 : return false;
305 : }
306 : string longer_match = route_info.substr((pos10 + sep_size),
307 1 : pos11 - (pos10 + sep_size));
308 :
309 1 : string shorter_match = route_info.substr(pos11 + sep_size);
310 :
311 1 : req->set_routing_instance(user_ri);
312 1 : req->set_routing_table(user_rt);
313 1 : req->set_prefix(user_prefix);
314 1 : req->set_start_routing_instance(next_ri);
315 1 : req->set_start_routing_table(next_rt);
316 1 : req->set_start_prefix(next_prefix);
317 1 : req->set_count(atoi(count_str.c_str()));
318 1 : req->set_source(user_source);
319 1 : req->set_protocol(user_protocol);
320 1 : req->set_family(user_family);
321 1 : req->set_longer_match(StringToBool(longer_match));
322 1 : req->set_shorter_match(StringToBool(shorter_match));
323 :
324 1 : return true;
325 12 : }
326 :
327 768 : bool ShowRouteHandler::CallbackS1Common(const ShowRouteReq *req, int inst_id,
328 : ShowRouteData *mydata) {
329 768 : uint32_t max_count = ShowRouteHandler::GetMaxRouteCount(req);
330 :
331 763 : ShowRouteHandler handler(req, inst_id);
332 : BgpSandeshContext *bsc =
333 768 : static_cast<BgpSandeshContext *>(req->client_context());
334 768 : RoutingInstanceMgr *rim = bsc->bgp_server->routing_instance_mgr();
335 :
336 768 : string exact_routing_table = req->get_routing_table();
337 768 : string exact_routing_instance;
338 768 : string start_routing_instance;
339 768 : if (exact_routing_table.empty()) {
340 516 : exact_routing_instance = req->get_routing_instance();
341 : } else {
342 : exact_routing_instance =
343 252 : RoutingInstance::GetVrfFromTableName(exact_routing_table);
344 : }
345 766 : if (exact_routing_instance.empty()) {
346 384 : start_routing_instance = req->get_start_routing_instance();
347 : } else {
348 382 : start_routing_instance = exact_routing_instance;
349 : }
350 :
351 : RoutingInstanceMgr::name_iterator i =
352 766 : rim->name_lower_bound(start_routing_instance);
353 764 : uint32_t count = 0;
354 2085 : while (i != rim->name_end()) {
355 1567 : if (!handler.match(exact_routing_instance, i->first)) {
356 247 : break;
357 : }
358 1344 : RoutingInstance::RouteTableList::const_iterator j;
359 1344 : if (req->get_start_routing_instance() == i->first) {
360 206 : j = i->second->GetTables().
361 206 : lower_bound(req->get_start_routing_table());
362 : } else {
363 1239 : j = i->second->GetTables().begin();
364 : }
365 9248 : for (; j != i->second->GetTables().end(); ++j) {
366 7925 : BgpTable *table = j->second;
367 8491 : if (!req->get_family().empty() && req->get_family() !=
368 8493 : Address::FamilyToTableString(table->family())) {
369 1274 : continue;
370 : }
371 7450 : if (!handler.match(req->get_routing_table(), table->name())) {
372 800 : continue;
373 : }
374 6650 : ShowRouteTable srt;
375 6640 : srt.set_routing_instance(i->first);
376 6641 : srt.set_routing_table_name(table->name());
377 6635 : srt.set_deleted(table->IsDeleted());
378 6621 : srt.set_deleted_at(
379 13246 : UTCUsecToString(table->deleter()->delete_time_stamp_usecs()));
380 :
381 : // Encode routing-table stats.
382 6622 : srt.set_prefixes(table->Size());
383 6611 : srt.set_primary_paths(table->GetPrimaryPathCount());
384 6616 : srt.set_secondary_paths(table->GetSecondaryPathCount());
385 6616 : srt.set_infeasible_paths(table->GetInfeasiblePathCount());
386 6610 : srt.set_stale_paths(table->GetStalePathCount());
387 6606 : srt.set_llgr_stale_paths(table->GetLlgrStalePathCount());
388 6602 : srt.set_paths(srt.get_primary_paths() + srt.get_secondary_paths());
389 :
390 6598 : vector<ShowTableListener> listeners;
391 6601 : table->FillListeners(&listeners);
392 6708 : srt.set_listeners(listeners);
393 :
394 6668 : vector<ShowRoute> route_list;
395 13326 : handler.BuildShowRouteTable(table, &route_list,
396 6663 : max_count ? max_count - count : 0);
397 6696 : if (route_list.size() || table->IsDeleted()) {
398 409 : srt.set_routes(route_list);
399 409 : mydata->route_table_list.push_back(srt);
400 : }
401 6688 : count += route_list.size();
402 6686 : if (count >= max_count) {
403 23 : break;
404 : }
405 6732 : }
406 1344 : if (count >= max_count) {
407 23 : break;
408 : }
409 :
410 1321 : i++;
411 : }
412 :
413 767 : return true;
414 764 : }
415 :
416 768 : bool ShowRouteHandler::CallbackS1(const Sandesh *sr,
417 : const RequestPipeline::PipeSpec ps,
418 : int stage, int instNum, RequestPipeline::InstData *data) {
419 768 : ShowRouteData *mydata = static_cast<ShowRouteData *>(data);
420 768 : int inst_id = ps.stages_[stage].instances_[instNum];
421 : const ShowRouteReq *req =
422 768 : static_cast<const ShowRouteReq *>(ps.snhRequest_.get());
423 :
424 768 : return CallbackS1Common(req, inst_id, mydata);
425 : }
426 :
427 0 : bool ShowRouteHandler::CallbackS1Iterate(const Sandesh *sr,
428 : const RequestPipeline::PipeSpec ps,
429 : int stage, int instNum, RequestPipeline::InstData *data) {
430 0 : ShowRouteData *mydata = static_cast<ShowRouteData *>(data);
431 0 : int inst_id = ps.stages_[stage].instances_[instNum];
432 : const ShowRouteReqIterate *req_iterate =
433 0 : static_cast<const ShowRouteReqIterate *>(ps.snhRequest_.get());
434 :
435 0 : ShowRouteReq *req = new ShowRouteReq;
436 0 : bool success = ConvertReqIterateToReq(req_iterate, req);
437 0 : if (success) {
438 0 : CallbackS1Common(req, inst_id, mydata);
439 : }
440 0 : req->Release();
441 0 : return true;
442 : }
443 :
444 192 : string ShowRouteHandler::SaveContextAndPopLast(const ShowRouteReq *req,
445 : vector<ShowRouteTable> *route_table_list) {
446 : // If there are no output results for the input parameters, we dont need to
447 : // save anything since there will be no subsequent iteration and there is
448 : // nothing to pop off.
449 192 : if (route_table_list->empty()) {
450 52 : return string("");
451 : }
452 :
453 : // Get the total number of routes that we have collected in this iteration
454 : // after the mergesort.
455 140 : uint32_t total_count = 0;
456 369 : for (size_t i = 0; i < route_table_list->size(); ++i) {
457 229 : total_count += route_table_list->at(i).get_routes().size();
458 : }
459 :
460 : ShowRouteTable *last_route_table =
461 140 : &route_table_list->at(route_table_list->size() - 1);
462 140 : string next_batch;
463 :
464 : // We always attempt to read one extra entry (GetMaxRouteCount() adds 1).
465 : // Case 1: (total_count > GetMaxRouteCount())
466 : // This cannot happen since the merge sort has already trimmed the list to
467 : // GetMaxRouteCount
468 :
469 : // Case 2: (total_count < GetMaxRouteCount())
470 : // There are no more entries matching the input criteria and we are done.
471 140 : if (total_count < ShowRouteHandler::GetMaxRouteCount(req)) {
472 106 : return next_batch;
473 : }
474 :
475 : // Case 3: (total_count == GetMaxRouteCount())
476 : // If total_count is equal to GetMaxRouteCount(), we have at least 1 entry
477 : // for the next round i.e. we are not done and we need to init next_batch
478 : // with the right values from the extra entry and we also need to pop off
479 : // the extra entry.
480 :
481 : int new_count;
482 34 : bool next_round = true;
483 34 : if (req->get_count()) {
484 : // This is required for the last round if the user gave a count. Even
485 : // though we have read an extra entry, we are done and we do not want
486 : // to display any 'next_batch' http links.
487 31 : new_count = req->get_count() - total_count + 1;
488 31 : if (!new_count) {
489 21 : next_round = false;
490 : }
491 : } else {
492 : // If the user did not fill in the count, keep using zero.
493 3 : new_count = req->get_count();
494 : }
495 :
496 34 : if (next_round) {
497 : ShowRoute last_route =
498 26 : last_route_table->get_routes().at(
499 26 : last_route_table->get_routes().size() - 1);
500 : next_batch =
501 26 : req->get_routing_instance() + kIterSeparator +
502 39 : req->get_routing_table() + kIterSeparator +
503 39 : req->get_prefix() + kIterSeparator +
504 39 : last_route_table->get_routing_instance() + kIterSeparator +
505 39 : last_route_table->get_routing_table_name() + kIterSeparator +
506 39 : last_route.get_prefix() + kIterSeparator +
507 52 : integerToString(new_count) + kIterSeparator +
508 39 : req->get_source() + kIterSeparator +
509 39 : req->get_protocol() + kIterSeparator +
510 39 : req->get_family() + kIterSeparator +
511 52 : BoolToString(req->get_longer_match()) + kIterSeparator +
512 39 : BoolToString(req->get_shorter_match());
513 13 : }
514 :
515 : // Pop off the last entry only after we have captured its values in
516 : // 'next_batch' above.
517 : const_cast<vector<ShowRoute> *>(
518 34 : &last_route_table->get_routes())->pop_back();
519 34 : if (last_route_table->get_routes().empty()) {
520 4 : route_table_list->pop_back();
521 : }
522 :
523 34 : return next_batch;
524 140 : }
525 :
526 192 : void ShowRouteHandler::CallbackS2Common(const ShowRouteReq *req,
527 : const RequestPipeline::PipeSpec ps,
528 : ShowRouteResp *resp) {
529 : BgpSandeshContext *bsc =
530 192 : static_cast<BgpSandeshContext *>(req->client_context());
531 192 : const RequestPipeline::StageData *sd = ps.GetStageData(0);
532 192 : vector<ShowRouteTable> route_table_list;
533 192 : vector<const vector<ShowRouteTable> *> table_lists;
534 960 : for (size_t i = 0; i < sd->size(); ++i) {
535 : const ShowRouteData &old_data =
536 768 : static_cast<const ShowRouteData &>(sd->at(i));
537 768 : if (old_data.route_table_list.size()) {
538 262 : table_lists.push_back(&old_data.route_table_list);
539 : }
540 : }
541 384 : MergeSort(&route_table_list, &table_lists,
542 192 : ShowRouteHandler::GetMaxRouteCount(req), bsc, "");
543 :
544 192 : string next_batch = SaveContextAndPopLast(req, &route_table_list);
545 192 : resp->set_next_batch(next_batch);
546 :
547 : // Save the table in the message *after* popping the last entry above.
548 192 : resp->set_tables(route_table_list);
549 192 : }
550 :
551 192 : bool ShowRouteHandler::CallbackS2(const Sandesh *sr,
552 : const RequestPipeline::PipeSpec &ps, int stage, int instNum,
553 : RequestPipeline::InstData *data) {
554 : const ShowRouteReq *req =
555 192 : static_cast<const ShowRouteReq *>(ps.snhRequest_.get());
556 :
557 192 : ShowRouteResp *resp = new ShowRouteResp;
558 192 : CallbackS2Common(req, ps, resp);
559 192 : resp->set_context(req->context());
560 192 : resp->Response();
561 192 : return true;
562 : }
563 :
564 0 : bool ShowRouteHandler::CallbackS2Iterate(const Sandesh *sr,
565 : const RequestPipeline::PipeSpec ps, int stage, int instNum,
566 : RequestPipeline::InstData *data) {
567 : const ShowRouteReqIterate *req_iterate =
568 0 : static_cast<const ShowRouteReqIterate *>(ps.snhRequest_.get());
569 :
570 0 : ShowRouteResp *resp = new ShowRouteResp;
571 0 : ShowRouteReq *req = new ShowRouteReq;
572 0 : bool success = ConvertReqIterateToReq(req_iterate, req);
573 0 : if (success) {
574 0 : CallbackS2Common(req, ps, resp);
575 : }
576 0 : resp->set_context(req->context());
577 0 : resp->Response();
578 0 : req->Release();
579 0 : return true;
580 : }
581 :
582 : // handler for 'show route'
583 192 : void ShowRouteReq::HandleRequest() const {
584 192 : BgpSandeshContext *bsc = static_cast<BgpSandeshContext *>(client_context());
585 :
586 192 : RequestPipeline::PipeSpec ps(this);
587 :
588 : // Request pipeline has 2 stages. In first stage, we spawn one task per
589 : // partition and generate the list of routes. In second stage, we look
590 : // at the generated list and merge it so that we can send it back.
591 192 : RequestPipeline::StageSpec s1, s2;
592 192 : TaskScheduler *scheduler = TaskScheduler::GetInstance();
593 192 : s1.taskId_ = scheduler->GetTaskId("db::DBTable");
594 192 : s1.allocFn_ = ShowRouteHandler::CreateData;
595 :
596 192 : s1.cbFn_ = ShowRouteHandler::CallbackS1;
597 960 : for (int i = 0; i < bsc->bgp_server->database()->PartitionCount(); ++i) {
598 768 : s1.instances_.push_back(i);
599 : }
600 :
601 192 : s2.taskId_ = scheduler->GetTaskId("bgp::ShowCommand");
602 192 : s2.allocFn_ = ShowRouteHandler::CreateData;
603 192 : s2.cbFn_ = ShowRouteHandler::CallbackS2;
604 192 : s2.instances_.push_back(0);
605 :
606 192 : ps.stages_= list_of(s1)(s2)
607 192 : .convert_to_container<vector<RequestPipeline::StageSpec> >();
608 192 : RequestPipeline rp(ps);
609 192 : }
610 :
611 : // handler for 'show route' that shows batches of routes, iteratively
612 0 : void ShowRouteReqIterate::HandleRequest() const {
613 0 : BgpSandeshContext *bsc = static_cast<BgpSandeshContext *>(client_context());
614 :
615 0 : RequestPipeline::PipeSpec ps(this);
616 :
617 : // Request pipeline has 2 stages. In first stage, we spawn one task per
618 : // partition and generate the list of routes. In second stage, we look
619 : // at the generated list and merge it so that we can send it back.
620 0 : RequestPipeline::StageSpec s1, s2;
621 0 : TaskScheduler *scheduler = TaskScheduler::GetInstance();
622 :
623 0 : s1.taskId_ = scheduler->GetTaskId("db::DBTable");
624 0 : s1.allocFn_ = ShowRouteHandler::CreateData;
625 0 : s1.cbFn_ = ShowRouteHandler::CallbackS1Iterate;
626 0 : for (int i = 0; i < bsc->bgp_server->database()->PartitionCount(); ++i) {
627 0 : s1.instances_.push_back(i);
628 : }
629 :
630 0 : s2.taskId_ = scheduler->GetTaskId("bgp::ShowCommand");
631 0 : s2.allocFn_ = ShowRouteHandler::CreateData;
632 0 : s2.cbFn_ = ShowRouteHandler::CallbackS2Iterate;
633 0 : s2.instances_.push_back(0);
634 :
635 0 : ps.stages_= list_of(s1)(s2)
636 0 : .convert_to_container<vector<RequestPipeline::StageSpec> >();
637 0 : RequestPipeline rp(ps);
638 0 : }
|