LCOV - code coverage report
Current view: top level - root/contrail/vrouter/dp-core - vr_info.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 53 101 52.5 %
Date: 2026-08-03 02:19:58 Functions: 2 2 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * vr_info.c -- vr_info functions
       3             :  *
       4             :  * Copyright (c) 2020 Juniper Networks, Inc. All rights reserved.
       5             :  */
       6             : 
       7             : #include <vr_os.h>
       8             : #if defined(__linux__)
       9             : #include <linux/version.h>
      10             : #endif
      11             : #include "vr_types.h"
      12             : #include "vr_sandesh.h"
      13             : #include "vr_message.h"
      14             : #include "vr_cpuid.h"
      15             : #include <vr_packet.h>
      16             : 
      17             : /* vr_info_buff_table_p pointer used to handle multiple clients in parallel.
      18             :  * When user callback function returns outbuf pointer, its stored in this
      19             :  * table and sends the msg buffer to its corresponding CLI client */
      20             : static struct vr_info_buff_table vr_info_buff_table_p[VR_INFO_MSG_BUF_TABLE];
      21             : 
      22             : /* Register the user callback function in below table */
      23             : struct vr_info_callback users_cb_reg[VR_INFO_MAX_CALLBACK];
      24             : 
      25             : /* Register callback using below function for vr_info.
      26             :  * */
      27             : static int
      28           1 : vr_info_callback_register(void)
      29             : {
      30             :     /* Below macro would be expanded and register each callback function in
      31             :      * users_cb_reg table */
      32           1 :     FOREACH_VR_INFO_CB_REG_INIT();
      33             : 
      34           1 :     return 0;
      35             : }
      36             : 
      37             : /* Sandesh handler for vr_info message */
      38             : void
      39           1 : vr_info_req_process(void *s_req)
      40             : {
      41           1 :     int i, ret = 0, buff_sz = 0, max_buff_sz = 0;
      42             :     vr_info_t msg_req;
      43           1 :     vr_info_req *req = (vr_info_req *)s_req;
      44             :     vr_info_req resp;
      45           1 :     struct vr_message_dumper *dumper = NULL;
      46           1 :     bool vr_info_last_buf = 0;
      47           1 :     char *trunc = "\n Message Truncated\n";
      48             : 
      49           1 :     if (req->h_op != SANDESH_OP_DUMP) {
      50           0 :         goto generate_response;
      51             :     }
      52             : 
      53             :     /* Copy request to response */
      54           1 :     resp = *req;
      55             : 
      56             :     /* Initialize the dumper buffer */
      57           1 :     dumper = vr_message_dump_init(req);
      58             : 
      59             :     /* Register callabck function before processing client request */
      60           1 :     ret = vr_info_callback_register();
      61           1 :     if(ret < 0) {
      62           0 :         vr_printf("vr_info: Callback registration failed\n with %d\n", ret);
      63           0 :         goto generate_response;
      64             :     }
      65             : 
      66             :     /* When CLI request comes, call the registered callback function and store
      67             :      * the address in msg_buff_table, If msginfo is more than 4K, split the
      68             :      * data into 4k chunks and send it serially to client. The client will
      69             :      * request back with vdu_buff_table_id and its index.
      70             :      * */
      71           1 :     if(!req->vdu_buff_table_id) {
      72             :         /* Maximum supported Client by server is 64, so based on that message
      73             :          * buffer table size is determined.
      74             :          * Buf table_id[0] is unused, so starting i with '1' */
      75           1 :         for(i = 1; i < VR_INFO_MSG_BUF_TABLE; i++) {
      76             :             /* Iterate through message buffer table and find the free entry */
      77           1 :             if(vr_info_buff_table_p[i].buff == NULL) {
      78             : 
      79           1 :                 memset(&msg_req, 0, sizeof(vr_info_t));
      80             : 
      81             :                 /* Copy Inbuf request to msg_req */
      82           1 :                 msg_req.inbuf = req->vdu_inbuf;
      83           1 :                 msg_req.inbuf_len = req->vdu_inbuf_size;
      84             : 
      85             :                 /* Check requested msginfo is within boundary range */
      86           1 :                 if((req->vdu_msginfo <= 0) || (req->vdu_msginfo >= INFO_MAX)) {
      87           0 :                     vr_printf("vr_info: Callback function is not registered \
      88           0 :                             for msginfo %d", req->vdu_msginfo);
      89           0 :                     goto generate_response;
      90             :                 }
      91             : 
      92             :                 /* If --bufsz is sent from CLI, then copy the value as part of
      93             :                  * msg_req */
      94           1 :                 if(req->vdu_outbufsz) {
      95           0 :                     msg_req.bufsz = req->vdu_outbufsz;
      96             :                 }
      97             : 
      98             :                 /* Check requested msginfo is avaialable in users callback
      99             :                  * registered table */
     100           1 :                 if(req->vdu_msginfo ==
     101           1 :                         users_cb_reg[req->vdu_msginfo].msginfo) {
     102           1 :                     ret = users_cb_reg[req->vdu_msginfo].cb_fn(&msg_req);
     103             :                 } else {
     104           0 :                     vr_printf("vr_info: Requested msginfo %d is not registered \
     105           0 :                             in VR_INFO_REG() table\n", req->vdu_msginfo);
     106           0 :                     goto generate_response;
     107             :                 }
     108             : 
     109             :                 /* Callback function returned failure msg */
     110           1 :                 if(ret < 0) {
     111           0 :                     vr_printf("vr_info: User callback function returned \
     112           0 :                             failure for msg %d", req->vdu_msginfo);
     113             :                     /* Suppose if message buffer is not completed, we append
     114             :                      * "Message Truncated" in the buffer and send to client */
     115           0 :                     if(ret == VR_INFO_MSG_TRUNC) {
     116           0 :                         snprintf(((msg_req.outbuf + msg_req.outbuf_len) - strlen(trunc)),
     117             :                                 VR_MESSAGE_PAGE_SIZE, "%s", trunc);
     118             :                     } else {
     119           0 :                         goto generate_response;
     120             :                     }
     121             :                 }
     122             :                 /* Copy buffer table id as part of response, so when
     123             :                  * dump_pending is true, will callback with same buf table id */
     124           1 :                 resp.vdu_buff_table_id = i;
     125             : 
     126             :                 /* Copy message buffer_ptr to buffer table */
     127           1 :                 vr_info_buff_table_p[i].buff = msg_req.outbuf;
     128             :                 /* Copy message buffer length to buff_table pointer */
     129           1 :                 vr_info_buff_table_p[i].buf_len = msg_req.outbuf_len;
     130             : 
     131             :                 /* Check if Output buffer has contents */
     132           1 :                 if(msg_req.outbuf == NULL) {
     133           0 :                     vr_printf("vrinfo: Output buffer is NULL \n");
     134           0 :                     vr_info_last_buf = true;
     135           0 :                     goto generate_response;
     136             : 
     137             :                 }
     138             :                 /* If outbuf_len is not supplied from callback, calculate it */
     139           1 :                 if(!msg_req.outbuf_len) {
     140           0 :                     buff_sz = strlen(msg_req.outbuf);
     141             :                 } else {
     142           1 :                     buff_sz = msg_req.outbuf_len;
     143             :                 }
     144             : 
     145           1 :                 if(!msg_req.outbuf_len) {
     146           0 :                     vr_printf("vrinfo: Output buffer is not filled\n");
     147           0 :                     vr_info_last_buf = true;
     148           0 :                     goto generate_response;
     149             :                 }
     150             : 
     151             :                 /* this is first iteration, so make vdu_marker as zero */
     152           1 :                 req->vdu_marker = 0;
     153           1 :                 break;
     154             :             }
     155             :         }
     156             :     } else {
     157           0 :         if(vr_info_buff_table_p[resp.vdu_buff_table_id].buff != NULL) {
     158           0 :             buff_sz = vr_info_buff_table_p[resp.vdu_buff_table_id].buf_len;
     159             :         } else {
     160           0 :             vr_printf("vr_info: vr_info_buff_table_p buf_id %d is NULL\n",
     161           0 :                     req->vdu_buff_table_id);
     162           0 :             vr_info_last_buf = true;
     163           0 :             goto generate_response;
     164             :         }
     165             :     }
     166             : 
     167             :     /* Sandesh has limitation of macro(VR_MESSAGE_PAGE_SIZE) size, so
     168             :      * calculating max buffer size, and those much amount of data would be sent
     169             :      * on each iteration */
     170           1 :     max_buff_sz = VR_MESSAGE_PAGE_SIZE - (sizeof(resp) +
     171             :             sizeof(struct vr_message_dumper));
     172             : 
     173             :     /* Check if the buffer size is greater than max buffer, If so, have to send
     174             :      * it through multiple iteration. */
     175           1 :     if(buff_sz > max_buff_sz) {
     176             :         /* To send whole buffer, (buff_sz/max_buff_sz + 1) => these many
     177             :          * number of times have to send it to client CLI. */
     178             :         while(1) {
     179             :             /* To find the last iteration */
     180           0 :             if( req->vdu_marker == buff_sz/max_buff_sz ) {
     181             :                 /* Calculate the number of remaining bytes to send it to
     182             :                  * client CLI */
     183           0 :                 resp.vdu_proc_info_size = (buff_sz -
     184           0 :                         (max_buff_sz * req->vdu_marker) + 1);
     185           0 :                 vr_info_last_buf = true;
     186             :             } else {
     187             :                 /* Increment with 1 to include the '\0' character */
     188           0 :                 resp.vdu_proc_info_size = max_buff_sz + 1;
     189             :             }
     190             : 
     191             :             /* Update the index value, querying for next iteration */
     192           0 :             resp.vdu_index = (req->vdu_marker + 1);
     193             : 
     194           0 :             resp.vdu_proc_info = vr_zalloc((resp.vdu_proc_info_size *
     195             :                         sizeof(uint8_t)), VR_INFO_REQ_OBJECT);
     196           0 :             if(resp.vdu_proc_info == NULL) {
     197           0 :                 vr_info_last_buf = true;
     198           0 :                 goto generate_response;
     199             :             }
     200             : 
     201             :             /* Copy the message to "resp.vdu_proc_info" from
     202             :              * "vr_info_buff_table_p[id]+offset". Here offset is calculated
     203             :              * from (max_buff_sz * req->vdu_marker) */
     204           0 :             snprintf(resp.vdu_proc_info, (resp.vdu_proc_info_size),
     205           0 :                     "%s", (vr_info_buff_table_p[resp.vdu_buff_table_id].buff +
     206           0 :                         (max_buff_sz * req->vdu_marker)));
     207             : 
     208             :             /* If message buffer copy is not complete, it will return with -1.
     209             :              * so it will send to client and client will request back. */
     210           0 :             ret = vr_message_dump_object(dumper, VR_INFO_OBJECT_ID, &resp);
     211             : 
     212           0 :             if(resp.vdu_proc_info != NULL) {
     213           0 :                 vr_free(resp.vdu_proc_info, VR_INFO_REQ_OBJECT);
     214             :             }
     215           0 :             if((ret <= 0) || vr_info_last_buf) {
     216             :                 break;
     217             :             }
     218             :         }
     219             :     } else {
     220             :         /* Total message buffer size is less than 4k, so it can send in
     221             :          * one iteration. */
     222           1 :         vr_info_last_buf = true;
     223           1 :         resp.vdu_proc_info_size = buff_sz;
     224             : 
     225           1 :         resp.vdu_proc_info = vr_zalloc((resp.vdu_proc_info_size *
     226             :                     sizeof(uint8_t)), VR_INFO_REQ_OBJECT);
     227           1 :         if(resp.vdu_proc_info == NULL) {
     228           0 :             goto generate_response;
     229             :         }
     230             : 
     231             :         /* Copy message buffer */
     232           1 :         snprintf(resp.vdu_proc_info, resp.vdu_proc_info_size, "%s", msg_req.outbuf);
     233           1 :         vr_message_dump_object(dumper, VR_INFO_OBJECT_ID, &resp);
     234             : 
     235           1 :         if(resp.vdu_proc_info) {
     236           1 :             vr_free(resp.vdu_proc_info, VR_INFO_REQ_OBJECT);
     237             :         }
     238             :     }
     239             : 
     240           0 : generate_response:
     241           1 :     vr_message_dump_exit(dumper, ret);
     242             : 
     243             :     /* Once last buffer element has reached, clear all message buffers.
     244             :      * Memory(malloc) is allocated by end users and infra will free the memory */
     245           1 :     if(vr_info_last_buf) {
     246           2 :         for (i = resp.vdu_buff_table_id; i > 0; i--) {
     247           1 :             if(vr_info_buff_table_p[i].buff != NULL) {
     248           1 :                 vr_free(vr_info_buff_table_p[i].buff, VR_INFO_REQ_OBJECT);
     249           1 :                 vr_info_buff_table_p[i].buff = NULL;
     250           1 :                 vr_info_buff_table_p[i].buf_len = 0;
     251             :             } else
     252           0 :                 vr_printf("Memory free failed for vr_info pointer instance %d\n", i);
     253             :         }
     254             :     }
     255             : 
     256           1 :     return;
     257             : }

Generated by: LCOV version 1.14