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-11-09 02:10:49 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             :  * 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 : }

Generated by: LCOV version 1.14