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

Generated by: LCOV version 1.14