LCOV - code coverage report
Current view: top level - bgp - bgp_show_route.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 331 371 89.2 %
Date: 2026-06-11 01:56:02 Functions: 20 23 87.0 %
Legend: Lines: hit not hit

          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       24372 : static bool IsLess(const ShowRoute &lhs, const ShowRoute &rhs,
      24             :                    const BgpSandeshContext *bsc, const string &table_name) {
      25             :     BgpTable *table = static_cast<BgpTable *>
      26       24372 :         (bsc->bgp_server->database()->FindTable(table_name));
      27       24372 :     if (!table) {
      28           0 :         return false;
      29             :     }
      30       24372 :     unique_ptr<DBEntry> lhs_entry = table->AllocEntryStr(lhs.get_prefix());
      31       24372 :     unique_ptr<DBEntry> rhs_entry = table->AllocEntryStr(rhs.get_prefix());
      32             : 
      33       24372 :     Route *lhs_route = static_cast<Route *>(lhs_entry.get());
      34       24372 :     Route *rhs_route = static_cast<Route *>(rhs_entry.get());
      35             : 
      36       24372 :     return lhs_route->IsLess(*rhs_route);
      37       24372 : }
      38             : 
      39        1060 : static bool IsLess(const ShowRouteTable &lhs, const ShowRouteTable &rhs,
      40             :                    const BgpSandeshContext *bsc, const string &table_name) {
      41        1060 :     if (lhs.get_routing_instance() < rhs.get_routing_instance()) {
      42          33 :         return true;
      43             :     }
      44        1027 :     if (lhs.get_routing_instance() == rhs.get_routing_instance()) {
      45         969 :         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        3333 : int MergeValues(ShowRoute *result, vector<const ShowRoute *> *input,
      55             :                 int limit, const BgpSandeshContext *bsc) {
      56        3333 :     assert(input->size() == 1);
      57        3333 :     *result = *input->at(0);
      58        3333 :     return 1;
      59             : }
      60             : 
      61         232 : int MergeValues(ShowRouteTable *result, vector<const ShowRouteTable *> *input,
      62             :                 int limit, const BgpSandeshContext *bsc) {
      63         232 :     vector<const vector<ShowRoute> *> list;
      64         232 :     result->set_routing_instance(input->at(0)->get_routing_instance());
      65         232 :     result->set_routing_table_name(input->at(0)->get_routing_table_name());
      66         232 :     result->set_deleted(input->at(0)->get_deleted());
      67         232 :     result->set_deleted_at(input->at(0)->get_deleted_at());
      68         232 :     result->set_prefixes(input->at(0)->get_prefixes());
      69         232 :     result->set_primary_paths(input->at(0)->get_primary_paths());
      70         232 :     result->set_secondary_paths(input->at(0)->get_secondary_paths());
      71         232 :     result->set_infeasible_paths(input->at(0)->get_infeasible_paths());
      72         232 :     result->set_stale_paths(input->at(0)->get_stale_paths());
      73         232 :     result->set_llgr_stale_paths(input->at(0)->get_llgr_stale_paths());
      74         232 :     result->set_paths(input->at(0)->get_paths());
      75         232 :     result->set_listeners(input->at(0)->get_listeners());
      76             : 
      77         232 :     int count = 0;
      78         626 :     for (size_t i = 0; i < input->size(); ++i) {
      79         394 :         if (input->at(i)->get_routes().size())
      80         394 :             list.push_back(&input->at(i)->get_routes());
      81             :     }
      82         232 :     MergeSort(const_cast<vector<ShowRoute> *>(&result->get_routes()), &list,
      83             :               limit ? limit - count : 0, bsc,
      84         232 :               input->at(0)->get_routing_table_name());
      85         232 :     count += result->get_routes().size();
      86         232 :     return count;
      87         232 : }
      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         424 : void MergeSort(vector<T> *result, vector<const vector<T> *> *input, int limit,
      95             :                const BgpSandeshContext *bsc, const string &table_name) {
      96         424 :     size_t size = input->size();
      97         424 :     vector<size_t> index(size, 0);
      98         424 :     int count = 0;
      99        7554 :     while (limit == 0 || count < limit) {
     100        3921 :         size_t best_index = size;
     101        3921 :         const T *best = NULL;
     102       17103 :         for (size_t i = 0; i < size; ++i) {
     103       13182 :             if (index[i] == input->at(i)->size())
     104         663 :                 continue;
     105       21473 :             if (best == NULL ||
     106        8954 :                 IsLess(input->at(i)->at(index[i]), *best, bsc, table_name)) {
     107        5726 :                 best = &input->at(i)->at(index[i]);
     108        5726 :                 best_index = i;
     109        5726 :                 continue;
     110             :             }
     111             :         }
     112        3921 :         if (best_index >= size)
     113         356 :             break;
     114        3565 :         T table;
     115        3565 :         vector<const T *> list;
     116       11863 :         for (size_t j = best_index; j < size; ++j) {
     117        8298 :             if (index[j] == input->at(j)->size())
     118          59 :                 continue;
     119       16478 :             if (IsLess(input->at(j)->at(index[j]), *best, bsc, table_name) ||
     120        8239 :                 IsLess(*best, input->at(j)->at(index[j]), bsc, table_name)) {
     121        4512 :                 continue;
     122             :             }
     123        3727 :             list.push_back(&input->at(j)->at(index[j]));
     124        3727 :             index[j]++;
     125             :         }
     126        3565 :         count += MergeValues(&table, &list, limit ? limit - count : 0, bsc);
     127        3565 :         result->push_back(table);
     128             :     }
     129         424 : }
     130             : 
     131             : char ShowRouteHandler::kIterSeparator[] = "||";
     132        1096 : uint32_t ShowRouteHandler::GetMaxCount(bool test_mode) {
     133        1096 :     if (test_mode) {
     134         300 :         return kUnitTestMaxCount;
     135             :     } else {
     136         796 :         return kMaxCount;
     137             :     }
     138             : }
     139             : 
     140         764 : ShowRouteHandler::ShowRouteHandler(const ShowRouteReq *req, int inst_id) :
     141         764 :         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        6708 : void ShowRouteHandler::BuildShowRouteTable(BgpTable *table,
     146             :         vector<ShowRoute> *route_list, int count) {
     147        6708 :     if (inst_id_ >= table->PartitionCount())
     148        1560 :         return;
     149             :     DBTablePartition *partition =
     150        5149 :         static_cast<DBTablePartition *>(table->GetTablePartition(inst_id_));
     151        5158 :     BgpRoute *route = NULL;
     152             : 
     153        5158 :     if (table->name() == req_->get_start_routing_table()) {
     154             :         unique_ptr<DBEntry> key =
     155          90 :             table->AllocEntryStr(req_->get_start_prefix());
     156          91 :         route = static_cast<BgpRoute *>(partition->lower_bound(key.get()));
     157          92 :     } else {
     158        5066 :         route = static_cast<BgpRoute *>(partition->GetFirst());
     159             :     }
     160       12087 :     for (int i = 0; route && (!count || i < count);
     161        6914 :          route = static_cast<BgpRoute *>(partition->GetNext(route)), ++i) {
     162        6915 :         if (!MatchPrefix(req_->get_prefix(), route,
     163        6915 :                          req_->get_longer_match(),
     164        6916 :                          req_->get_shorter_match()))
     165         859 :             continue;
     166        6055 :         ShowRoute show_route;
     167        6053 :         route->FillRouteInfo(table, &show_route, req_->get_source(),
     168        6054 :                              req_->get_protocol());
     169        6050 :         if (!show_route.get_paths().empty())
     170        5294 :             route_list->push_back(show_route);
     171        6055 :     }
     172             : }
     173             : 
     174        6915 : bool ShowRouteHandler::MatchPrefix(const string &expected_prefix,
     175             :                                    BgpRoute *route, bool longer_match,
     176             :                                    bool shorter_match) {
     177        6915 :     if (expected_prefix.empty())
     178        5056 :         return true;
     179        1859 :     if (!longer_match && !shorter_match)
     180         303 :         return regex_search(route->ToString(), prefix_expr_);
     181             : 
     182             :     // Do longer match.
     183        1556 :     if (longer_match && route->IsMoreSpecific(expected_prefix))
     184         938 :         return true;
     185             : 
     186             :     // Do shorter match.
     187         618 :     if (shorter_match && route->IsLessSpecific(expected_prefix))
     188          14 :         return true;
     189             : 
     190         604 :     return false;
     191             : }
     192             : 
     193        9049 : bool ShowRouteHandler::match(const string &expected, const string &actual) {
     194        9049 :     if (expected == "")
     195        7507 :         return true;
     196        1541 :     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        1097 : uint32_t ShowRouteHandler::GetMaxRouteCount(const ShowRouteReq *req) {
     204             :     BgpSandeshContext *bsc =
     205        1097 :         static_cast<BgpSandeshContext *>(req->client_context());
     206             :     uint32_t max_count =
     207        1097 :         ShowRouteHandler::GetMaxCount(bsc->test_mode());
     208             : 
     209        1096 :     uint32_t route_count = req->get_count() + 1;
     210        1096 :     if (!req->get_count() || (req->get_count() > max_count)) {
     211             :         // Set the count to our default if input is zero or too high
     212         934 :         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         765 : bool ShowRouteHandler::CallbackS1Common(const ShowRouteReq *req, int inst_id,
     328             :                                         ShowRouteData *mydata) {
     329         765 :     uint32_t max_count = ShowRouteHandler::GetMaxRouteCount(req);
     330             : 
     331         764 :     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         767 :     string exact_routing_instance;
     338         767 :     string start_routing_instance;
     339         767 :     if (exact_routing_table.empty()) {
     340         516 :         exact_routing_instance = req->get_routing_instance();
     341             :     } else {
     342             :         exact_routing_instance =
     343         251 :             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         767 :         rim->name_lower_bound(start_routing_instance);
     353         763 :     uint32_t count = 0;
     354        2094 :     while (i != rim->name_end()) {
     355        1576 :         if (!handler.match(exact_routing_instance, i->first)) {
     356         250 :             break;
     357             :         }
     358        1349 :         RoutingInstance::RouteTableList::const_iterator j;
     359        1349 :         if (req->get_start_routing_instance() == i->first) {
     360         205 :             j = i->second->GetTables().
     361         205 :                                 lower_bound(req->get_start_routing_table());
     362             :         } else {
     363        1246 :             j = i->second->GetTables().begin();
     364             :         }
     365        9310 :         for (; j != i->second->GetTables().end(); ++j) {
     366        7971 :             BgpTable *table = j->second;
     367        8543 :             if (!req->get_family().empty() && req->get_family() !=
     368        8544 :                     Address::FamilyToTableString(table->family())) {
     369        1278 :                 continue;
     370             :             }
     371        7485 :             if (!handler.match(req->get_routing_table(), table->name())) {
     372         796 :                 continue;
     373             :             }
     374        6689 :             ShowRouteTable srt;
     375        6676 :             srt.set_routing_instance(i->first);
     376        6682 :             srt.set_routing_table_name(table->name());
     377        6678 :             srt.set_deleted(table->IsDeleted());
     378        6669 :             srt.set_deleted_at(
     379       13353 :                 UTCUsecToString(table->deleter()->delete_time_stamp_usecs()));
     380             : 
     381             :             // Encode routing-table stats.
     382        6673 :             srt.set_prefixes(table->Size());
     383        6670 :             srt.set_primary_paths(table->GetPrimaryPathCount());
     384        6665 :             srt.set_secondary_paths(table->GetSecondaryPathCount());
     385        6665 :             srt.set_infeasible_paths(table->GetInfeasiblePathCount());
     386        6664 :             srt.set_stale_paths(table->GetStalePathCount());
     387        6665 :             srt.set_llgr_stale_paths(table->GetLlgrStalePathCount());
     388        6663 :             srt.set_paths(srt.get_primary_paths() + srt.get_secondary_paths());
     389             : 
     390        6661 :             vector<ShowTableListener> listeners;
     391        6659 :             table->FillListeners(&listeners);
     392        6729 :             srt.set_listeners(listeners);
     393             : 
     394        6709 :             vector<ShowRoute> route_list;
     395       13418 :             handler.BuildShowRouteTable(table, &route_list,
     396        6709 :                                         max_count ? max_count - count : 0);
     397        6730 :             if (route_list.size() || table->IsDeleted()) {
     398         412 :                 srt.set_routes(route_list);
     399         412 :                 mydata->route_table_list.push_back(srt);
     400             :             }
     401        6725 :             count += route_list.size();
     402        6724 :             if (count >= max_count) {
     403          23 :                 break;
     404             :             }
     405        6770 :         }
     406        1354 :         if (count >= max_count) {
     407          23 :             break;
     408             :         }
     409             : 
     410        1331 :         i++;
     411             :     }
     412             : 
     413         768 :     return true;
     414         767 : }
     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         767 :         static_cast<const ShowRouteReq *>(ps.snhRequest_.get());
     423             : 
     424         767 :     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         372 :     for (size_t i = 0; i < route_table_list->size(); ++i) {
     457         232 :         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         263 :             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 : }

Generated by: LCOV version 1.14