LCOV - code coverage report
Current view: top level - root/contrail/vrouter/utils - dropstats.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 47 242 19.4 %
Date: 2026-06-08 02:02:55 Functions: 5 16 31.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * dropstats.c - drop statistics
       3             :  *
       4             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       5             :  */
       6             : 
       7             : #include <stdio.h>
       8             : #include <stdlib.h>
       9             : #include <unistd.h>
      10             : #include <string.h>
      11             : #include <errno.h>
      12             : #include <inttypes.h>
      13             : #include <stdlib.h>
      14             : #include <stdbool.h>
      15             : #include <getopt.h>
      16             : 
      17             : #include <sys/types.h>
      18             : #include <sys/socket.h>
      19             : 
      20             : #include <net/if.h>
      21             : 
      22             : #include "ini_parser.h"
      23             : #include "vr_os.h"
      24             : #include "vr_types.h"
      25             : #include "vr_nexthop.h"
      26             : #include "ini_parser.h"
      27             : #include "nl_util.h"
      28             : #include "ini_parser.h"
      29             : #include "vr_packet.h"
      30             : 
      31             : static struct nl_client *cl;
      32             : static int help_set, core_set, offload_set, log_set, clear_set, clear_drop_log_set, debug_set, sock_dir_set;
      33             : static unsigned int core = (unsigned)-1;
      34             : static unsigned int stats_index = 0;
      35             : static int log_type_set, log_type_show, min_log_set;
      36             : static uint8_t pkt_drop_log_type  = VP_DROP_MAX;
      37             : static uint8_t show_pkt_drop_type = VP_DROP_MAX;
      38             : static uint8_t min_log = 0;
      39             : static int vr_get_pkt_drop_log(struct nl_client *cl,int core,int stats_index);
      40             : 
      41           0 : static void pkt_drop_log_req_process(void *s_req) {
      42             : 
      43             :     static int log_all_cores = 0, last_buffer_stats = 0, last_buffer_entry = 0;
      44           0 :     vr_pkt_drop_log_req *stats = (vr_pkt_drop_log_req *)s_req;
      45             : 
      46           0 :     char vr_pkt_droplog_rsn[][50] = {
      47             :         DROP_RSN_MAP(string)
      48             :     };
      49             : 
      50           0 :     if (log_type_set)
      51             :     {
      52           0 :         printf("\nDropstats log type set successfully %s\n\n",
      53           0 :                     vr_pkt_droplog_rsn[pkt_drop_log_type]);
      54           0 :         return;
      55             :     }
      56             : 
      57           0 :     if ((stats->vdl_pkt_droplog_type != show_pkt_drop_type) &&
      58           0 :         (show_pkt_drop_type != VP_DROP_MAX) &&
      59           0 :         ((stats->vdl_pkt_droplog_type > VP_DROP_INVALID) &&
      60           0 :          (stats->vdl_pkt_droplog_type < VP_DROP_MAX)))
      61             :     {
      62           0 :         printf("Pkt drop type already set to %s \n",
      63           0 :                 vr_pkt_droplog_rsn[stats->vdl_pkt_droplog_type]);
      64           0 :         return;
      65             :     }
      66             : 
      67             :     /* Below check ensures that pkt drop log sysctl enabled during runtime*/
      68           0 :     if(stats->vdl_pkt_droplog_sysctl_en == 1)
      69             :     {
      70             :         /* Below check ensures that drop stats support is enabled at load time*/
      71           0 :         if(stats->vdl_pkt_droplog_en == 1)
      72             :         {
      73             :             /* Print the drop stats log*/
      74           0 :             vr_print_pkt_drop_log(stats, show_pkt_drop_type);
      75             : 
      76             :             /* Since sandesh message doesn't support passing data more than 4KB,
      77             :              * So the message request sent in serial manner.
      78             :              * If the configured size  more than VR_PKT_DROPLOG_MAX_ALLOW_BUFSZ,
      79             :              * then index is maintained at utils side
      80             :              * and request data based on index
      81             :              * */
      82           0 :             if(stats->vdl_pkt_droplog_max_bufsz > VR_PKT_DROPLOG_MAX_ALLOW_BUFSZ)
      83             :             {
      84             :                 /* If stats->index reached MAX size, it will not be processed.
      85             :                  * stats->vdl_log_idx is used for printing serial numbers on
      86             :                  * the console */
      87           0 :                 if(stats->vdl_log_idx < (stats->vdl_pkt_droplog_max_bufsz -
      88             :                             VR_PKT_DROPLOG_MAX_ALLOW_BUFSZ))
      89             :                 {
      90             :                     /* Request packet drop buffer for next iteration by
      91             :                      * incrementing with MAX_ALLOWED_BUFFER  */
      92           0 :                     stats_index  = stats->vdl_log_idx +
      93             :                         VR_PKT_DROPLOG_MAX_ALLOW_BUFSZ;
      94           0 :                     vr_get_pkt_drop_log(cl, stats->vdl_core, stats_index);
      95             :                 }
      96             :                 /* Below condition will process last iteration buffer,
      97             :                  * If modulus is non-zero */
      98           0 :                 else if( stats->vdl_pkt_droplog_max_bufsz %
      99           0 :                         VR_PKT_DROPLOG_MAX_ALLOW_BUFSZ != 0)
     100             :                 {
     101             :                     /* Below condition to be processed only once per core */
     102           0 :                     if( ! last_buffer_entry)
     103             :                     {
     104           0 :                         stats_index  = stats->vdl_log_idx +
     105             :                             VR_PKT_DROPLOG_MAX_ALLOW_BUFSZ;
     106           0 :                         last_buffer_entry = 1;
     107           0 :                         vr_get_pkt_drop_log(cl, stats->vdl_core, stats_index);
     108             :                     }
     109             :                     else
     110             :                     {
     111             :                         /* Resetting index and last buffer entry because all
     112             :                          * processing done for this particular core*/
     113           0 :                         last_buffer_entry = 0;
     114           0 :                         stats_index = 0;
     115             :                     }
     116             :                 }
     117             :                 else
     118           0 :                     stats_index = 0;
     119             :             }
     120             :             /* When packet drop log is requested for all cores, below
     121             :              * condition would be enabled*/
     122           0 :             if(stats->vdl_core ==0 || log_all_cores == 1)
     123             :             {
     124             :                 /* Increment the core value*/
     125           0 :                 core++;
     126             : 
     127           0 :                 if(core < stats->vdl_max_num_cores){
     128           0 :                     log_all_cores = 1;
     129           0 :                     vr_get_pkt_drop_log(cl,core+1,stats_index);
     130             :                 }
     131             :                 else
     132             :                 {
     133           0 :                     log_all_cores = 0;
     134             :                 }
     135             : 
     136             :             }
     137             :         }
     138             :         else
     139             :         {
     140           0 :             printf("\n\nPkt drop stats log support is not enabled or misconfigured \
     141             :                     in vrouter module parameters. Configured value is %d\n",
     142           0 :                     stats->vdl_pkt_droplog_en);
     143           0 :             printf("You can enable by providing \"options vrouter \
     144             :                     vr_pkt_droplog_buf_en=1\" in /etc/modprobe.d/vrouter.conf\n");
     145             :         }
     146             :     }
     147             :     else
     148             :     {
     149           0 :         printf("\n\nPacket Drop Log sysctl is not enabled or misconfigured, \
     150           0 :                 Configured value is %d\n",stats->vdl_pkt_droplog_sysctl_en);
     151           0 :         printf("You can enable it by passing \"echo 1 > \
     152             :                 /proc/sys/net/vrouter/pkt_drop_log_enable\"\n");
     153             :     }
     154           0 :     return;
     155             : }
     156             : 
     157             : static void
     158           0 : pkt_drop_log_nlutils_callbacks()
     159             : {
     160             :     /* Registering callback for packet drop log in netlink process*/
     161           0 :     nl_cb.vr_pkt_drop_log_req_process = pkt_drop_log_req_process;
     162           0 : }
     163             : 
     164           0 : static int vr_get_pkt_drop_log(struct nl_client *cl,int core,int stats_index) {
     165           0 :     int ret = 0;
     166             : 
     167           0 :     vr_pkt_drop_log_request(cl, 0, core, stats_index);
     168           0 :     if(ret < 0)
     169           0 :         return ret;
     170             : 
     171           0 :     ret = vr_recvmsg(cl, false);
     172           0 :     if(ret <= 0)
     173           0 :         return ret;
     174             : 
     175           0 :     return 0;
     176             : }
     177             : 
     178             : static void
     179           1 : drop_stats_req_process(void *s_req)
     180             : {
     181           1 :     vr_drop_stats_req *stats = (vr_drop_stats_req *)s_req;
     182           1 :     int platform = get_platform();
     183             : 
     184           1 :     if(stats->h_op == SANDESH_OP_RESET)
     185             :     {
     186           0 :         printf("\nDropstats counters cleared successfully on all cores \n\n");
     187           0 :         return;
     188             :     }
     189             : 
     190           1 :     if (core == (unsigned)-2)
     191           0 :         printf("Statistics for NIC offloads\n\n");
     192           1 :     else if (core != (unsigned)-1)
     193           0 :         printf("Statistics for core %u\n\n", core);
     194             : 
     195           1 :     if(debug_set) {
     196           0 :         vr_print_drop_dbg_stats(stats, core);
     197           0 :         return;
     198             :     }
     199             : 
     200           1 :     vr_print_drop_stats(stats, core);
     201           1 :     return;
     202             : }
     203             : 
     204             : static void
     205           1 : dropstats_fill_nl_callbacks()
     206             : {
     207           1 :     nl_cb.vr_drop_stats_req_process = drop_stats_req_process;
     208           1 : }
     209             : 
     210             : static int
     211           1 : vr_get_drop_stats(struct nl_client *cl)
     212             : {
     213             :     int ret;
     214             : 
     215             :     /*
     216             :      * Implementation of getting per-core drop statistics is based on this
     217             :      * little trick to avoid making changes in how agent makes requests for
     218             :      * statistics. From vRouter's and agent's point of view, request for
     219             :      * stats for 0th core means a request for stats summed up for all the
     220             :      * cores. So cores are enumerated starting with 1.
     221             :      * Meanwhile, from user's point of view they are enumerated starting
     222             :      * with 0 (e.g. dropstats --core 0 means 'drop statistics for the very
     223             :      * first (0th) core'). This is how Linux enumerates CPUs, so it should
     224             :      * be more intuitive for the user.
     225             :      *
     226             :      * Agent is not aware of possibility of asking for per-core stats. Its
     227             :      * requests have vds_core implicitly set to 0. So we need to make a
     228             :      * conversion between those enumerating systems. The dropstats utility
     229             :      * increments by 1 the core number user asked for. Then it is
     230             :      * decremented back in vRouter.
     231             :      *
     232             :      * vRouter will return only the offloaded dropstats if the "core"
     233             :      * is passed in as -2.  This allows returning of only dropstats offloaded
     234             :      * on NIC using this same mechanism.  If all CPUs are requested, the
     235             :      * offloaded dropstats are included.
     236             :      */
     237           1 :     ret = vr_send_drop_stats_get(cl, 0, core + 1);
     238           1 :     if (ret < 0)
     239           0 :         return ret;
     240             : 
     241           1 :     ret = vr_recvmsg(cl, false);
     242           1 :     if (ret <= 0)
     243           0 :         return ret;
     244             : 
     245           1 :     return 0;
     246             : }
     247             : 
     248             : static int
     249           0 : vr_clear_pkt_drop_log(struct nl_client *cl)
     250             : {
     251           0 :     int ret = vr_pkt_drop_log_reset(cl);
     252           0 :     if (ret < 0)
     253           0 :         return ret;
     254             : 
     255           0 :     return 0;
     256             : }
     257             : 
     258             : static int
     259           0 : vr_clear_drop_stats(struct nl_client *cl)
     260             : {
     261           0 :     int ret = vr_drop_stats_reset(cl);
     262           0 :     if (ret < 0)
     263           0 :         return ret;
     264             : 
     265           0 :     return 0;
     266             : }
     267             : 
     268             : static int
     269           0 : vr_set_pkt_drop_log_type(struct nl_client *cl, uint8_t pkt_log_type)
     270             : {
     271             :     int ret;
     272           0 :     ret = vr_drop_type_set(cl, pkt_log_type);
     273           0 :     if (ret < 0)
     274           0 :         return ret;
     275             : 
     276           0 :     ret = vr_recvmsg(cl, false);
     277           0 :     if (ret <= 0)
     278           0 :         return ret;
     279             : 
     280           0 :     return 0;
     281             : }
     282             : 
     283             : static int
     284           0 : min_log_config(struct nl_client *cl, bool min_log_enable)
     285             : {
     286             :     int ret;
     287           0 :     ret = vr_min_log_enable(cl, min_log_enable);
     288           0 :     if (ret < 0)
     289           0 :         return ret;
     290             : 
     291           0 :     ret = vr_recvmsg(cl, false);
     292           0 :     if (ret <= 0)
     293           0 :         return ret;
     294             : 
     295           0 :     return 0;
     296             : }
     297             : 
     298             : enum opt_index {
     299             :     HELP_OPT_INDEX,
     300             :     CORE_OPT_INDEX,
     301             :     OFFL_OPT_INDEX,
     302             :     LOG_OPT_INDEX,
     303             :     CLEAR_OPT_INDEX,
     304             :     SOCK_DIR_OPT_INDEX,
     305             :     DEBUG_OPT_INDEX,
     306             :     DROP_LOG_TYPE_OPT_INDEX,
     307             :     SHOW_LOG_TYPE_OPT_INDEX,
     308             :     CLEAR_DROP_LOG_OPT_INDEX,
     309             :     MIN_LOG_OPT_INDEX,
     310             :     MAX_OPT_INDEX,
     311             : };
     312             : 
     313             : static struct option long_options[] = {
     314             :     [HELP_OPT_INDEX]    =   {"help",    no_argument,        &help_set,      1},
     315             :     [CORE_OPT_INDEX]    =   {"core",    required_argument,  &core_set,      1},
     316             :     [OFFL_OPT_INDEX]    =   {"offload", no_argument,        &offload_set,   1},
     317             :     [LOG_OPT_INDEX]     =   {"log",     required_argument,  &log_set,       1},
     318             :     [CLEAR_OPT_INDEX]   =   {"clear",   no_argument,        &clear_set,     1},
     319             :     [SOCK_DIR_OPT_INDEX]  = {"sock-dir", required_argument, &sock_dir_set,  1},
     320             :     [DEBUG_OPT_INDEX]   =   {"debug",   no_argument,        &debug_set,     1},
     321             :     [DROP_LOG_TYPE_OPT_INDEX]   =   {"drop-type",  required_argument,  &log_type_set,   1},
     322             :     [SHOW_LOG_TYPE_OPT_INDEX]   =   {"show",       required_argument,  &log_type_show,  1},
     323             :     [CLEAR_DROP_LOG_OPT_INDEX]   =   {"clear-drop-log",   no_argument, &clear_drop_log_set, 1},
     324             :     [MIN_LOG_OPT_INDEX]         =   {"min-log",    required_argument,  &min_log_set,    1},
     325             :     [MAX_OPT_INDEX]     =   {"NULL",    0,                  0,              0},
     326             : };
     327             : 
     328             : static void
     329           0 : Usage()
     330             : {
     331           0 :     printf("Usage: dropstats [--help]\n");
     332           0 :     printf("Usage: dropstats [--core|-c] <core number> %s\n\n",
     333           0 :             get_offload_enabled()?"[--offload|-o]":"");
     334           0 :     printf("--core <core number>\t Show statistics for a specified CPU core\n");
     335           0 :     printf("--sock-dir <netlink socket dir>\n");
     336           0 :     if (get_offload_enabled()) {
     337           0 :         printf("--offload\t\t Show statistics for pkts offloaded on NIC\n");
     338           0 :         printf("\t\t\t (offload stats included if no flags given)\n");
     339             :     }
     340           0 :     printf("--log <core number> [--show <drop-type>]\t Show Packet drops log for a specified core.. \
     341             :                 Core number starts from 1...n. If core number specified as zero, \
     342             :                 it will log for all cores \n");
     343           0 :     printf("--clear\t To clear stats counters on all cores\n");
     344           0 :     printf("--debug\t To Display Debug counters\n");
     345           0 :     printf("--drop-type <drop log type|help>\t Log specific Packet drops type. \
     346             :         Use VP_DROP_MAX to clear drop set type\n");
     347           0 :     printf("--clear-drop-log\t To clear packet drops log on all cores\n");
     348           0 :     printf("--min-log <1(enable)/ 0<disable)\t To set min log\n");
     349           0 :     exit(-EINVAL);
     350             : }
     351             : 
     352           0 : void display_supported_drop_type()
     353             : {
     354             :     int i;
     355           0 :     char vr_pkt_droplog_rsn[][50] = {
     356             :            DROP_RSN_MAP(string)};
     357             : 
     358           0 :     for(i=VP_DROP_DISCARD; i<VP_DROP_MAX; i++)
     359           0 :         printf("%s\n", vr_pkt_droplog_rsn[i]);
     360             : 
     361           0 :     exit(-EINVAL);
     362             : }
     363             : 
     364             : static int
     365           0 : parse_log_type(char *opt_arg)
     366             : {
     367             :     int i;
     368           0 :     char vr_pkt_droplog_rsn[][50] = {
     369             :          DROP_RSN_MAP(string)};
     370             : 
     371           0 :     for(i=VP_DROP_DISCARD; i<=VP_DROP_MAX; i++)
     372           0 :         if (!strcmp (opt_arg, vr_pkt_droplog_rsn[i]))
     373           0 :             return i;
     374             : 
     375           0 :     printf("Invalid log type %s\n", opt_arg);
     376           0 :     display_supported_drop_type();
     377           0 : }
     378             : 
     379             : /* Not using atoi and strtol as it returns 0
     380             :  * for invalid argument
     381             :  * ignoring -ve cases
     382             :  */
     383             : static int
     384           0 : is_valid_num(char *opt_arg)
     385             : {
     386           0 :    int result_num = 0, i = 0;
     387             : 
     388           0 :     while (opt_arg[i] == ' ')
     389             :     {
     390           0 :         i++;
     391             :     }
     392             : 
     393           0 :     for(; opt_arg[i] != '\0'; i++) {
     394           0 :         if (opt_arg[i] >= '0' && opt_arg[i] <= '9')
     395             :         {
     396           0 :             result_num = 10 * result_num + (opt_arg[i] - '0');
     397             :         } else {
     398           0 :             printf("Invalid argument %s\n", opt_arg);
     399           0 :             Usage();
     400             :         }
     401             :     }
     402             : 
     403           0 :     return result_num;
     404             : }
     405             : 
     406             : static void
     407           1 : parse_long_opts(int opt_index, char *opt_arg)
     408             : {
     409           1 :     errno = 0;
     410             : 
     411           1 :     switch (opt_index) {
     412           0 :     case CORE_OPT_INDEX:
     413           0 :         core = is_valid_num(opt_arg);
     414           0 :         break;
     415           0 :     case OFFL_OPT_INDEX:
     416           0 :         if (!get_offload_enabled()) {
     417           0 :             printf("Error: hardware offloads not enabled\n");
     418           0 :             Usage();
     419             :         }
     420           0 :         core = -2;
     421           0 :         break;
     422           0 :     case LOG_OPT_INDEX:
     423           0 :               core = is_valid_num(opt_arg);
     424           0 :               break;
     425           0 :     case CLEAR_OPT_INDEX:
     426             :     case CLEAR_DROP_LOG_OPT_INDEX:
     427             :     case DEBUG_OPT_INDEX:
     428           0 :         break;
     429           0 :     case DROP_LOG_TYPE_OPT_INDEX:
     430           0 :         pkt_drop_log_type = parse_log_type(opt_arg);
     431           0 :         break;
     432           0 :     case SHOW_LOG_TYPE_OPT_INDEX:
     433           0 :         show_pkt_drop_type = parse_log_type(opt_arg);
     434           0 :         log_type_show =1;
     435           0 :         break;
     436           0 :     case MIN_LOG_OPT_INDEX:
     437           0 :         min_log = is_valid_num(opt_arg);
     438             :         /* min-log value either 0 or 1 */
     439           0 :         if (min_log > 1)
     440           0 :             Usage();
     441           0 :         break;
     442           1 :     case SOCK_DIR_OPT_INDEX:
     443           1 :         vr_socket_dir = opt_arg;
     444           1 :         break;
     445           0 :     case HELP_OPT_INDEX:
     446             :     default:
     447           0 :         Usage();
     448             :     }
     449             : 
     450           1 :     return;
     451             : }
     452             : 
     453             : int
     454           1 : main(int argc, char *argv[])
     455             : {
     456             :     char opt;
     457           1 :     int ret, option_index, log_core = 0, i = 0;
     458             : 
     459           1 :     dropstats_fill_nl_callbacks();
     460             : 
     461           1 :     parse_ini_file();
     462             : 
     463           2 :     while (((opt = getopt_long(argc, argv, "h:c:o:l:s:m:",
     464           2 :                         long_options, &option_index)) >= 0)) {
     465           1 :         switch (opt) {
     466           0 :         case 'c':
     467           0 :             core_set = 1;
     468           0 :             parse_long_opts(CORE_OPT_INDEX, optarg);
     469           0 :             break;
     470             : 
     471           0 :         case 'o':
     472           0 :             offload_set = 1;
     473           0 :             parse_long_opts(OFFL_OPT_INDEX, optarg);
     474           0 :             break;
     475             : 
     476           0 :         case 'l':
     477           0 :             log_set = 1;
     478           0 :             parse_long_opts(LOG_OPT_INDEX, optarg);
     479           0 :             break;
     480             : 
     481           0 :         case 'm':
     482           0 :             min_log_set = 1;
     483           0 :             parse_long_opts(MIN_LOG_OPT_INDEX, optarg);
     484           0 :             break;
     485             : 
     486           0 :         case 's':
     487           0 :             sock_dir_set = 1;
     488           0 :             parse_long_opts(SOCK_DIR_OPT_INDEX, optarg);
     489           0 :             break;
     490             : 
     491           1 :         case 0:
     492           1 :             parse_long_opts(option_index, optarg);
     493           1 :             break;
     494             : 
     495           0 :         case 'h':
     496             :         default:
     497           0 :             Usage();
     498             :         }
     499             :     }
     500             : 
     501           1 :     if (sock_dir_set) {
     502           1 :         set_platform_vtest();
     503             :     }
     504           1 :     cl = vr_get_nl_client(VR_NETLINK_PROTO_DEFAULT);
     505           1 :     if (!cl)
     506           0 :         return -1;
     507             : 
     508           1 :     if ((option_index == SHOW_LOG_TYPE_OPT_INDEX) && (!log_set))
     509             :     {
     510           0 :          Usage();
     511             :     }
     512             : 
     513           1 :     if (log_type_set)
     514             :     {
     515           0 :         pkt_drop_log_nlutils_callbacks();
     516           0 :         vr_set_pkt_drop_log_type(cl, pkt_drop_log_type);
     517           0 :         return 0;
     518             :     }
     519             : 
     520           1 :     if (min_log_set)
     521             :     {
     522           0 :         min_log_config(cl, min_log == 1);
     523           0 :         return 0;
     524             :     }
     525             : 
     526           1 :     if (log_set)
     527             :     {
     528           0 :         log_core = is_valid_num(argv[2]);
     529             : 
     530             :         /* Register nl allback function for pkt drop log buffer*/
     531           0 :         pkt_drop_log_nlutils_callbacks();
     532             : 
     533           0 :         vr_get_pkt_drop_log(cl,log_core,stats_index);
     534           0 :         return 0;
     535             :     }
     536             : 
     537           1 :     if (option_index == CLEAR_DROP_LOG_OPT_INDEX)
     538             :     {
     539           0 :         vr_clear_pkt_drop_log(cl);
     540           0 :         return 0;
     541             :     }
     542             : 
     543           1 :     if (option_index == CLEAR_OPT_INDEX)
     544             :     {
     545           0 :         vr_clear_drop_stats(cl);
     546             : 
     547           0 :         ret = vr_recvmsg(cl, false);
     548           0 :         if (ret <= 0)
     549           0 :             return ret;
     550             :     }
     551             :     else
     552           1 :         vr_get_drop_stats(cl);
     553             : 
     554           1 :     return 0;
     555             : }

Generated by: LCOV version 1.14