LCOV - code coverage report
Current view: top level - bgp - bgp_show_handler.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 61 61 100.0 %
Date: 2026-06-22 02:21:21 Functions: 139 180 77.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #ifndef SRC_BGP_BGP_SHOW_HANDLER_H__
       6             : #define SRC_BGP_BGP_SHOW_HANDLER_H__
       7             : 
       8             : #include "bgp/bgp_sandesh.h"
       9             : 
      10             : #include <sandesh/request_pipeline.h>
      11             : 
      12             : #include <string>
      13             : #include <vector>
      14             : 
      15             : static char kIterSeparator[] = "||";
      16             : 
      17             : //
      18             : // Class template to handle single stage show commands with single key and
      19             : // a search string.
      20             : //
      21             : // Supports pagination of output as specified by page limit.
      22             : //
      23             : // Also supports an iteration limit, which is the maximum number of entries
      24             : // examined in one run. This is useful when the search string is non-empty
      25             : // and there are a large number of entries in table.  We don't want to look
      26             : // at potentially all entries in one shot in cases where most of them don't
      27             : // match the search string.
      28             : //
      29             : // Data is used to store partial pages of results as well as other context
      30             : // that needs to be maintained between successive runs of the callbacks in
      31             : // cases where we don't manage to fill a page of results in one run.
      32             : //
      33             : // Note that the infrastructure automatically reschedules and invokes the
      34             : // callback function again if it returns false.
      35             : //
      36             : template <typename ReqT, typename ReqIterateT, typename RespT, typename ShowT>
      37             : class BgpShowHandler {
      38             : public:
      39             :     static const uint32_t kPageLimit = 64;
      40             :     static const uint32_t kIterLimit = 1024;
      41             : 
      42             :     struct Data : public RequestPipeline::InstData {
      43        1544 :         Data() : initialized(false) {
      44        1544 :         }
      45             : 
      46             :         bool initialized;
      47             :         std::string search_string;
      48             :         std::string next_entry;
      49             :         std::string next_batch;
      50             :         std::vector<ShowT> show_list;
      51             :     };
      52             : 
      53        1544 :     static RequestPipeline::InstData *CreateData(int stage) {
      54        1544 :         return (new Data);
      55             :     }
      56             : 
      57             :     static void ConvertReqToData(const ReqT *req, Data *data);
      58             :     static bool ConvertReqIterateToData(const ReqIterateT *req_iterate,
      59             :         Data *data);
      60             :     static void SaveContextToData(const std::string &next_entry, bool done,
      61             :         Data *data);
      62             : 
      63             :     static void FillShowList(RespT *resp, const std::vector<ShowT> &show_list);
      64             :     static bool CallbackCommon(const BgpSandeshContext *bsc, Data *data);
      65             :     static bool Callback(const Sandesh *sr,
      66             :         const RequestPipeline::PipeSpec ps,
      67             :         int stage, int instNum, RequestPipeline::InstData *data);
      68             :     static bool CallbackIterate(const Sandesh *sr,
      69             :         const RequestPipeline::PipeSpec ps,
      70             :         int stage, int instNum, RequestPipeline::InstData *data);
      71             : };
      72             : 
      73             : //
      74             : // Initialize Data from ReqT.
      75             : //
      76             : template <typename ReqT, typename ReqIterateT, typename RespT, typename ShowT>
      77        2418 : void BgpShowHandler<ReqT, ReqIterateT, RespT, ShowT>::ConvertReqToData(
      78             :     const ReqT *req, Data *data) {
      79        2418 :     if (data->initialized)
      80        1351 :         return;
      81        1067 :     data->initialized = true;
      82        1067 :     data->search_string = req->get_search_string();
      83             : }
      84             : 
      85             : //
      86             : // Initialize Data from ReqInterateT.
      87             : //
      88             : // Return false if there's a problem parsing the iterate_info string.
      89             : //
      90             : template <typename ReqT, typename ReqIterateT, typename RespT, typename ShowT>
      91        1207 : bool BgpShowHandler<ReqT, ReqIterateT, RespT, ShowT>::ConvertReqIterateToData(
      92             :     const ReqIterateT *req_iterate, Data *data) {
      93        1207 :     if (data->initialized)
      94         731 :         return true;
      95         476 :     data->initialized = true;
      96             : 
      97             :     // Format of iterate_info:
      98             :     // next_entry||search_string
      99         476 :     std::string iterate_info = req_iterate->get_iterate_info();
     100         476 :     size_t sep_size = strlen(kIterSeparator);
     101             : 
     102         476 :     size_t pos1 = iterate_info.find(kIterSeparator);
     103         476 :     if (pos1 == std::string::npos)
     104         118 :         return false;
     105             : 
     106         358 :     data->next_entry = iterate_info.substr(0, pos1);
     107         358 :     data->search_string = iterate_info.substr(pos1 + sep_size);
     108         358 :     return true;
     109         476 : }
     110             : 
     111             : //
     112             : // Save context into Data.
     113             : // The next_entry field gets used in the subsequent invocation of callback
     114             : // routine when the callback routine returns false.
     115             : // The next_batch string is used if the page is filled (i.e. done is true).
     116             : //
     117             : template <typename ReqT, typename ReqIterateT, typename RespT, typename ShowT>
     118        2388 : void BgpShowHandler<ReqT, ReqIterateT, RespT, ShowT>::SaveContextToData(
     119             :     const std::string &next_entry, bool done, Data *data) {
     120        2388 :     data->next_entry = next_entry;
     121        2388 :     if (done)
     122         306 :         data->next_batch = next_entry + kIterSeparator + data->search_string;
     123        2388 : }
     124             : 
     125             : //
     126             : // Fill show_list into RespT.
     127             : // Should be specialized to allow each RespT to have a potentially different
     128             : // name for the list of entries.
     129             : //
     130             : template <typename ReqT, typename ReqIterateT, typename RespT, typename ShowT>
     131             : void BgpShowHandler<ReqT, ReqIterateT, RespT, ShowT>::FillShowList(
     132             :     RespT *resp, const std::vector<ShowT> &show_list) {
     133             : }
     134             : 
     135             : //
     136             : // Common routine for regular and iterate requests.
     137             : // Assumes that Data has been initialized properly by caller.
     138             : // Examine specified maximum entries starting at data->next_entry.
     139             : //
     140             : // Should be specialized to handle specifics of the show command being
     141             : // handled.
     142             : //
     143             : // Return true if we're examined all entries or reached the page limit.
     144             : //
     145             : template <typename ReqT, typename ReqIterateT, typename RespT, typename ShowT>
     146             : bool BgpShowHandler<ReqT, ReqIterateT, RespT, ShowT>::CallbackCommon(
     147             :     const BgpSandeshContext *bsc, Data *data) {
     148             :     return true;
     149             : }
     150             : 
     151             : //
     152             : // Callback for ReqT. This gets called for initial request and subsequently in
     153             : // cases where the iteration count is reached.
     154             : //
     155             : // Return false if the iteration count is reached before page gets filled.
     156             : // Return true if the page gets filled or we've examined all entries.
     157             : //
     158             : template <typename ReqT, typename ReqIterateT, typename RespT, typename ShowT>
     159        2419 : bool BgpShowHandler<ReqT, ReqIterateT, RespT, ShowT>::Callback(
     160             :     const Sandesh *sr, const RequestPipeline::PipeSpec ps,
     161             :     int stage, int instNum, RequestPipeline::InstData *data) {
     162        2419 :     Data *mydata = static_cast<Data *>(data);
     163        2419 :     const ReqT *req = static_cast<const ReqT *>(ps.snhRequest_.get());
     164             :     const BgpSandeshContext *bsc =
     165        2419 :         static_cast<const BgpSandeshContext *>(req->client_context());
     166             : 
     167             :     // Parse request and save state in Data.
     168        2419 :     ConvertReqToData(req, mydata);
     169             : 
     170             :     // Return false and reschedule ourselves if we've reached the limit of
     171             :     // the number of entries examined.
     172        2419 :     if (!CallbackCommon(bsc, mydata))
     173        1351 :         return false;
     174             : 
     175             :     // All done - ship the response.
     176        1068 :     RespT *resp = new RespT;
     177        1068 :     resp->set_context(req->context());
     178        1068 :     if (!mydata->show_list.empty())
     179         952 :         FillShowList(resp, mydata->show_list);
     180        1068 :     if (!mydata->next_batch.empty())
     181         154 :         resp->set_next_batch(mydata->next_batch);
     182        1068 :     resp->Response();
     183        1068 :     return true;
     184             : }
     185             : 
     186             : //
     187             : // Callback for ReqIterate. This is called for initial request and subsequently
     188             : // in cases where the iteration count is reached. Parse the iterate_info string
     189             : // to figure out the next entry to examine.
     190             : //
     191             : // Return false if the iteration limit is reached before page gets filled.
     192             : // Return true if the page gets filled or we've examined all entries.
     193             : //
     194             : template <typename ReqT, typename ReqIterateT, typename RespT, typename ShowT>
     195        1207 : bool BgpShowHandler<ReqT, ReqIterateT, RespT, ShowT>::CallbackIterate(
     196             :     const Sandesh *sr, const RequestPipeline::PipeSpec ps,
     197             :     int stage, int instNum, RequestPipeline::InstData *data) {
     198        1207 :     Data *mydata = static_cast<Data *>(data);
     199             :     const ReqIterateT *req_iterate =
     200        1207 :         static_cast<const ReqIterateT *>(ps.snhRequest_.get());
     201             :     const BgpSandeshContext *bsc =
     202        1207 :         static_cast<const BgpSandeshContext *>(req_iterate->client_context());
     203             : 
     204             :     // Parse request and save state in Data.
     205        1207 :     if (!ConvertReqIterateToData(req_iterate, mydata)) {
     206         118 :         RespT *resp = new RespT;
     207         118 :         resp->set_context(req_iterate->context());
     208         118 :         resp->Response();
     209         118 :         return true;
     210             :     }
     211             : 
     212             :     // Return false and reschedule ourselves if we've reached the limit of
     213             :     // the number of entries examined.
     214        1089 :     if (!CallbackCommon(bsc, mydata))
     215         731 :         return false;
     216             : 
     217             :     // All done - ship the response.
     218         358 :     RespT *resp = new RespT;
     219         358 :     resp->set_context(req_iterate->context());
     220         358 :     if (!mydata->show_list.empty())
     221         296 :         FillShowList(resp, mydata->show_list);
     222         358 :     if (!mydata->next_batch.empty())
     223         152 :         resp->set_next_batch(mydata->next_batch);
     224         358 :     resp->Response();
     225         358 :     return true;
     226             : }
     227             : 
     228             : #endif  // SRC_BGP_BGP_SHOW_HANDLER_H__

Generated by: LCOV version 1.14