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