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

Generated by: LCOV version 1.14