LCOV - code coverage report
Current view: top level - vpp-api/client - stat_client.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 0 254 0.0 %
Date: 2023-07-05 22:20:52 Functions: 0 27 0.0 %

          Line data    Source code
       1             : /*
       2             :  *------------------------------------------------------------------
       3             :  * stat_client.c - Library for access to VPP statistics segment
       4             :  *
       5             :  * Copyright (c) 2018 Cisco and/or its affiliates.
       6             :  * Licensed under the Apache License, Version 2.0 (the "License");
       7             :  * you may not use this file except in compliance with the License.
       8             :  * You may obtain a copy of the License at:
       9             :  *
      10             :  *     http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  * Unless required by applicable law or agreed to in writing, software
      13             :  * distributed under the License is distributed on an "AS IS" BASIS,
      14             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  * See the License for the specific language governing permissions and
      16             :  * limitations under the License.
      17             :  *------------------------------------------------------------------
      18             :  */
      19             : 
      20             : #include <stdio.h>
      21             : #include <errno.h>
      22             : #include <sys/types.h>
      23             : #include <sys/socket.h>
      24             : #include <sys/un.h>
      25             : #include <stdbool.h>
      26             : #include <sys/stat.h>
      27             : #include <regex.h>
      28             : #include <assert.h>
      29             : #include <vppinfra/vec.h>
      30             : #include <vppinfra/lock.h>
      31             : #include <stdatomic.h>
      32             : #include <vlib/vlib.h>
      33             : #include <vlib/stats/stats.h>
      34             : #include <vpp-api/client/stat_client.h>
      35             : 
      36             : stat_client_main_t stat_client_main;
      37             : 
      38             : stat_client_main_t *
      39           0 : stat_client_get (void)
      40             : {
      41             :   stat_client_main_t *sm;
      42           0 :   sm = (stat_client_main_t *) malloc (sizeof (stat_client_main_t));
      43           0 :   clib_memset (sm, 0, sizeof (stat_client_main_t));
      44           0 :   return sm;
      45             : }
      46             : 
      47             : void
      48           0 : stat_client_free (stat_client_main_t * sm)
      49             : {
      50           0 :   free (sm);
      51           0 : }
      52             : 
      53             : static int
      54           0 : recv_fd (int sock)
      55             : {
      56           0 :   struct msghdr msg = { 0 };
      57             :   struct cmsghdr *cmsg;
      58           0 :   int fd = -1;
      59             :   char iobuf[1];
      60           0 :   struct iovec io = {.iov_base = iobuf,.iov_len = sizeof (iobuf) };
      61             :   union
      62             :   {
      63             :     char buf[CMSG_SPACE (sizeof (fd))];
      64             :     struct cmsghdr align;
      65             :   } u;
      66           0 :   msg.msg_iov = &io;
      67           0 :   msg.msg_iovlen = 1;
      68           0 :   msg.msg_control = u.buf;
      69           0 :   msg.msg_controllen = sizeof (u.buf);
      70             : 
      71             :   ssize_t size;
      72           0 :   if ((size = recvmsg (sock, &msg, 0)) < 0)
      73             :     {
      74           0 :       perror ("recvmsg failed");
      75           0 :       return -1;
      76             :     }
      77           0 :   cmsg = CMSG_FIRSTHDR (&msg);
      78           0 :   if (cmsg && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
      79             :     {
      80           0 :       memmove (&fd, CMSG_DATA (cmsg), sizeof (fd));
      81             :     }
      82           0 :   return fd;
      83             : }
      84             : 
      85             : static vlib_stats_entry_t *
      86           0 : get_stat_vector_r (stat_client_main_t *sm)
      87             : {
      88           0 :   ASSERT (sm->shared_header);
      89           0 :   return stat_segment_adjust (sm,
      90           0 :                               (void *) sm->shared_header->directory_vector);
      91             : }
      92             : 
      93             : int
      94           0 : stat_segment_connect_r (const char *socket_name, stat_client_main_t * sm)
      95             : {
      96           0 :   int mfd = -1;
      97             :   int sock;
      98             : 
      99           0 :   clib_memset (sm, 0, sizeof (*sm));
     100           0 :   if ((sock = socket (AF_UNIX, SOCK_SEQPACKET, 0)) < 0)
     101             :     {
     102           0 :       perror ("Stat client couldn't open socket");
     103           0 :       return -1;
     104             :     }
     105             : 
     106           0 :   struct sockaddr_un un = { 0 };
     107           0 :   un.sun_family = AF_UNIX;
     108           0 :   strncpy ((char *) un.sun_path, socket_name, sizeof (un.sun_path) - 1);
     109           0 :   if (connect (sock, (struct sockaddr *) &un, sizeof (struct sockaddr_un)) <
     110             :       0)
     111             :     {
     112           0 :       close (sock);
     113           0 :       return -2;
     114             :     }
     115             : 
     116           0 :   if ((mfd = recv_fd (sock)) < 0)
     117             :     {
     118           0 :       close (sock);
     119           0 :       fprintf (stderr, "Receiving file descriptor failed\n");
     120           0 :       return -3;
     121             :     }
     122           0 :   close (sock);
     123             : 
     124             :   /* mmap shared memory segment. */
     125             :   void *memaddr;
     126           0 :   struct stat st = { 0 };
     127             : 
     128           0 :   if (fstat (mfd, &st) == -1)
     129             :     {
     130           0 :       close (mfd);
     131           0 :       perror ("mmap fstat failed");
     132           0 :       return -4;
     133             :     }
     134           0 :   if ((memaddr =
     135           0 :        mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, mfd, 0)) == MAP_FAILED)
     136             :     {
     137           0 :       close (mfd);
     138           0 :       perror ("mmap map failed");
     139           0 :       return -5;
     140             :     }
     141             : 
     142           0 :   close (mfd);
     143           0 :   sm->memory_size = st.st_size;
     144           0 :   sm->shared_header = memaddr;
     145           0 :   sm->directory_vector =
     146           0 :     stat_segment_adjust (sm, (void *) sm->shared_header->directory_vector);
     147             : 
     148           0 :   return 0;
     149             : }
     150             : 
     151             : int
     152           0 : stat_segment_connect (const char *socket_name)
     153             : {
     154           0 :   stat_client_main_t *sm = &stat_client_main;
     155           0 :   return stat_segment_connect_r (socket_name, sm);
     156             : }
     157             : 
     158             : void
     159           0 : stat_segment_disconnect_r (stat_client_main_t * sm)
     160             : {
     161           0 :   munmap (sm->shared_header, sm->memory_size);
     162           0 :   return;
     163             : }
     164             : 
     165             : void
     166           0 : stat_segment_disconnect (void)
     167             : {
     168           0 :   stat_client_main_t *sm = &stat_client_main;
     169           0 :   return stat_segment_disconnect_r (sm);
     170             : }
     171             : 
     172             : double
     173           0 : stat_segment_heartbeat_r (stat_client_main_t * sm)
     174             : {
     175             :   stat_segment_access_t sa;
     176             :   vlib_stats_entry_t *ep;
     177             : 
     178             :   /* Has directory been updated? */
     179           0 :   if (sm->shared_header->epoch != sm->current_epoch)
     180           0 :     return 0;
     181           0 :   if (stat_segment_access_start (&sa, sm))
     182           0 :     return 0;
     183           0 :   ep = vec_elt_at_index (sm->directory_vector, STAT_COUNTER_HEARTBEAT);
     184           0 :   if (!stat_segment_access_end (&sa, sm))
     185           0 :     return 0.0;
     186           0 :   return ep->value;
     187             : }
     188             : 
     189             : double
     190           0 : stat_segment_heartbeat (void)
     191             : {
     192           0 :   stat_client_main_t *sm = &stat_client_main;
     193           0 :   return stat_segment_heartbeat_r (sm);
     194             : }
     195             : 
     196             : #define stat_vec_dup(S,V)                             \
     197             :   ({                                                  \
     198             :   __typeof__ ((V)[0]) * _v(v) = 0;                    \
     199             :   if (V && ((void *)V > (void *)S->shared_header) &&  \
     200             :       (((void*)V + vec_bytes(V)) <                    \
     201             :        ((void *)S->shared_header + S->memory_size)))  \
     202             :     _v(v) = vec_dup(V);                               \
     203             :    _v(v);                                             \
     204             : })
     205             : 
     206             : static counter_t *
     207           0 : stat_vec_simple_init (counter_t c)
     208             : {
     209           0 :   counter_t *v = 0;
     210           0 :   vec_add1 (v, c);
     211           0 :   return v;
     212             : }
     213             : 
     214             : static vlib_counter_t *
     215           0 : stat_vec_combined_init (vlib_counter_t c)
     216             : {
     217           0 :   vlib_counter_t *v = 0;
     218           0 :   vec_add1 (v, c);
     219           0 :   return v;
     220             : }
     221             : 
     222             : /*
     223             :  * If index2 is specified copy out the column (the indexed value across all
     224             :  * threads), otherwise copy out all values.
     225             :  */
     226             : static stat_segment_data_t
     227           0 : copy_data (vlib_stats_entry_t *ep, u32 index2, char *name,
     228             :            stat_client_main_t *sm, bool via_symlink)
     229             : {
     230           0 :   stat_segment_data_t result = { 0 };
     231             :   int i;
     232             :   vlib_counter_t **combined_c;  /* Combined counter */
     233             :   counter_t **simple_c;         /* Simple counter */
     234             : 
     235           0 :   assert (sm->shared_header);
     236             : 
     237           0 :   result.type = ep->type;
     238           0 :   result.via_symlink = via_symlink;
     239           0 :   result.name = strdup (name ? name : ep->name);
     240             : 
     241           0 :   switch (ep->type)
     242             :     {
     243           0 :     case STAT_DIR_TYPE_SCALAR_INDEX:
     244           0 :       result.scalar_value = ep->value;
     245           0 :       break;
     246             : 
     247           0 :     case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE:
     248           0 :       simple_c = stat_segment_adjust (sm, ep->data);
     249           0 :       result.simple_counter_vec = stat_vec_dup (sm, simple_c);
     250           0 :       for (i = 0; i < vec_len (simple_c); i++)
     251             :         {
     252           0 :           counter_t *cb = stat_segment_adjust (sm, simple_c[i]);
     253           0 :           if (index2 != ~0)
     254           0 :             result.simple_counter_vec[i] = stat_vec_simple_init (cb[index2]);
     255             :           else
     256           0 :             result.simple_counter_vec[i] = stat_vec_dup (sm, cb);
     257             :         }
     258           0 :       break;
     259             : 
     260           0 :     case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED:
     261           0 :       combined_c = stat_segment_adjust (sm, ep->data);
     262           0 :       result.combined_counter_vec = stat_vec_dup (sm, combined_c);
     263           0 :       for (i = 0; i < vec_len (combined_c); i++)
     264             :         {
     265           0 :           vlib_counter_t *cb = stat_segment_adjust (sm, combined_c[i]);
     266           0 :           if (index2 != ~0)
     267           0 :             result.combined_counter_vec[i] =
     268           0 :               stat_vec_combined_init (cb[index2]);
     269             :           else
     270           0 :             result.combined_counter_vec[i] = stat_vec_dup (sm, cb);
     271             :         }
     272           0 :       break;
     273             : 
     274           0 :     case STAT_DIR_TYPE_NAME_VECTOR:
     275             :       {
     276           0 :         uint8_t **name_vector = stat_segment_adjust (sm, ep->data);
     277           0 :         result.name_vector = stat_vec_dup (sm, name_vector);
     278           0 :         for (i = 0; i < vec_len (name_vector); i++)
     279             :           {
     280           0 :             u8 *name = stat_segment_adjust (sm, name_vector[i]);
     281           0 :             result.name_vector[i] = stat_vec_dup (sm, name);
     282             :           }
     283             :       }
     284           0 :       break;
     285             : 
     286           0 :     case STAT_DIR_TYPE_SYMLINK:
     287             :       /* Gather info from all threads into a vector */
     288             :       {
     289             :         vlib_stats_entry_t *ep2;
     290           0 :         ep2 = vec_elt_at_index (sm->directory_vector, ep->index1);
     291             :         /* We do not intend to return the "result", avoid a leak */
     292           0 :         free (result.name);
     293           0 :         return copy_data (ep2, ep->index2, ep->name, sm, true);
     294             :       }
     295             : 
     296           0 :     case STAT_DIR_TYPE_EMPTY:
     297           0 :       break;
     298             : 
     299           0 :     default:
     300           0 :       fprintf (stderr, "Unknown type: %d\n", ep->type);
     301             :     }
     302           0 :   return result;
     303             : }
     304             : 
     305             : void
     306           0 : stat_segment_data_free (stat_segment_data_t * res)
     307             : {
     308             :   int i, j;
     309           0 :   for (i = 0; i < vec_len (res); i++)
     310             :     {
     311           0 :       switch (res[i].type)
     312             :         {
     313           0 :         case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE:
     314           0 :           for (j = 0; j < vec_len (res[i].simple_counter_vec); j++)
     315           0 :             vec_free (res[i].simple_counter_vec[j]);
     316           0 :           vec_free (res[i].simple_counter_vec);
     317           0 :           break;
     318           0 :         case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED:
     319           0 :           for (j = 0; j < vec_len (res[i].combined_counter_vec); j++)
     320           0 :             vec_free (res[i].combined_counter_vec[j]);
     321           0 :           vec_free (res[i].combined_counter_vec);
     322           0 :           break;
     323           0 :         case STAT_DIR_TYPE_NAME_VECTOR:
     324           0 :           for (j = 0; j < vec_len (res[i].name_vector); j++)
     325           0 :             vec_free (res[i].name_vector[j]);
     326           0 :           vec_free (res[i].name_vector);
     327           0 :           break;
     328           0 :         case STAT_DIR_TYPE_SCALAR_INDEX:
     329             :         case STAT_DIR_TYPE_EMPTY:
     330           0 :           break;
     331           0 :         default:
     332           0 :           assert (0);
     333             :         }
     334           0 :       free (res[i].name);
     335             :     }
     336           0 :   vec_free (res);
     337           0 : }
     338             : 
     339             : uint32_t *
     340           0 : stat_segment_ls_r (uint8_t ** patterns, stat_client_main_t * sm)
     341           0 : {
     342             :   stat_segment_access_t sa;
     343             : 
     344           0 :   uint32_t *dir = 0;
     345           0 :   regex_t regex[vec_len (patterns)];
     346             : 
     347             :   int i, j;
     348           0 :   for (i = 0; i < vec_len (patterns); i++)
     349             :     {
     350           0 :       int rv = regcomp (&regex[i], (const char *) patterns[i], 0);
     351           0 :       if (rv)
     352             :         {
     353           0 :           fprintf (stderr, "Could not compile regex %s\n", patterns[i]);
     354           0 :           return dir;
     355             :         }
     356             :     }
     357             : 
     358           0 :   if (stat_segment_access_start (&sa, sm))
     359           0 :     return 0;
     360             : 
     361           0 :   vlib_stats_entry_t *counter_vec = get_stat_vector_r (sm);
     362           0 :   for (j = 0; j < vec_len (counter_vec); j++)
     363             :     {
     364           0 :       for (i = 0; i < vec_len (patterns); i++)
     365             :         {
     366           0 :           int rv = regexec (&regex[i], counter_vec[j].name, 0, NULL, 0);
     367           0 :           if (rv == 0)
     368             :             {
     369           0 :               vec_add1 (dir, j);
     370           0 :               break;
     371             :             }
     372             :         }
     373           0 :       if (vec_len (patterns) == 0)
     374           0 :         vec_add1 (dir, j);
     375             :     }
     376             : 
     377           0 :   for (i = 0; i < vec_len (patterns); i++)
     378           0 :     regfree (&regex[i]);
     379             : 
     380           0 :   if (!stat_segment_access_end (&sa, sm))
     381             :     {
     382             :       /* Failed, clean up */
     383           0 :       vec_free (dir);
     384           0 :       return 0;
     385             : 
     386             :     }
     387             : 
     388             :   /* Update last version */
     389           0 :   sm->current_epoch = sa.epoch;
     390           0 :   return dir;
     391             : }
     392             : 
     393             : uint32_t *
     394           0 : stat_segment_ls (uint8_t ** patterns)
     395             : {
     396           0 :   stat_client_main_t *sm = &stat_client_main;
     397           0 :   return stat_segment_ls_r ((uint8_t **) patterns, sm);
     398             : }
     399             : 
     400             : stat_segment_data_t *
     401           0 : stat_segment_dump_r (uint32_t * stats, stat_client_main_t * sm)
     402             : {
     403             :   int i;
     404             :   vlib_stats_entry_t *ep;
     405           0 :   stat_segment_data_t *res = 0;
     406             :   stat_segment_access_t sa;
     407             : 
     408             :   /* Has directory been update? */
     409           0 :   if (sm->shared_header->epoch != sm->current_epoch)
     410           0 :     return 0;
     411             : 
     412           0 :   if (stat_segment_access_start (&sa, sm))
     413           0 :     return 0;
     414             : 
     415             :   /* preallocate the elements.
     416             :    * This takes care of a special case where
     417             :    * the vec_len(stats) == 0,
     418             :    * such that we return a vector of
     419             :    * length 0, rather than a null pointer
     420             :    * (since null pointer is an error)
     421             :    */
     422           0 :   vec_alloc (res, vec_len (stats));
     423             : 
     424           0 :   for (i = 0; i < vec_len (stats); i++)
     425             :     {
     426             :       /* Collect counter */
     427           0 :       ep = vec_elt_at_index (sm->directory_vector, stats[i]);
     428           0 :       vec_add1 (res, copy_data (ep, ~0, 0, sm, false));
     429             :     }
     430             : 
     431           0 :   if (stat_segment_access_end (&sa, sm))
     432           0 :     return res;
     433             : 
     434           0 :   fprintf (stderr, "Epoch changed while reading, invalid results\n");
     435             :   // TODO increase counter
     436           0 :   if (res)
     437           0 :     stat_segment_data_free (res);
     438           0 :   return 0;
     439             : }
     440             : 
     441             : stat_segment_data_t *
     442           0 : stat_segment_dump (uint32_t * stats)
     443             : {
     444           0 :   stat_client_main_t *sm = &stat_client_main;
     445           0 :   return stat_segment_dump_r (stats, sm);
     446             : }
     447             : 
     448             : /* Wrapper for accessing vectors from other languages */
     449             : int
     450           0 : stat_segment_vec_len (void *vec)
     451             : {
     452           0 :   return vec_len (vec);
     453             : }
     454             : 
     455             : void
     456           0 : stat_segment_vec_free (void *vec)
     457             : {
     458           0 :   vec_free (vec);
     459           0 : }
     460             : 
     461             : /* Create a vector from a string (or add to existing) */
     462             : uint8_t **
     463           0 : stat_segment_string_vector (uint8_t ** string_vector, const char *string)
     464             : {
     465           0 :   uint8_t *name = 0;
     466           0 :   size_t len = strlen (string);
     467             : 
     468           0 :   vec_validate_init_c_string (name, string, len);
     469           0 :   vec_add1 (string_vector, name);
     470           0 :   return string_vector;
     471             : }
     472             : 
     473             : stat_segment_data_t *
     474           0 : stat_segment_dump_entry_r (uint32_t index, stat_client_main_t * sm)
     475             : {
     476             :   vlib_stats_entry_t *ep;
     477           0 :   stat_segment_data_t *res = 0;
     478             :   stat_segment_access_t sa;
     479             : 
     480             :   /* Has directory been update? */
     481           0 :   if (sm->shared_header->epoch != sm->current_epoch)
     482           0 :     return 0;
     483             : 
     484           0 :   if (stat_segment_access_start (&sa, sm))
     485           0 :     return 0;
     486             : 
     487             :   /* Collect counter */
     488           0 :   ep = vec_elt_at_index (sm->directory_vector, index);
     489           0 :   vec_add1 (res, copy_data (ep, ~0, 0, sm, false));
     490             : 
     491           0 :   if (stat_segment_access_end (&sa, sm))
     492           0 :     return res;
     493           0 :   return 0;
     494             : }
     495             : 
     496             : stat_segment_data_t *
     497           0 : stat_segment_dump_entry (uint32_t index)
     498             : {
     499           0 :   stat_client_main_t *sm = &stat_client_main;
     500           0 :   return stat_segment_dump_entry_r (index, sm);
     501             : }
     502             : 
     503             : char *
     504           0 : stat_segment_index_to_name_r (uint32_t index, stat_client_main_t * sm)
     505             : {
     506             :   vlib_stats_entry_t *ep;
     507             :   stat_segment_access_t sa;
     508             :   vlib_stats_entry_t *vec;
     509             : 
     510             :   /* Has directory been update? */
     511           0 :   if (sm->shared_header->epoch != sm->current_epoch)
     512           0 :     return 0;
     513           0 :   if (stat_segment_access_start (&sa, sm))
     514           0 :     return 0;
     515           0 :   vec = get_stat_vector_r (sm);
     516           0 :   ep = vec_elt_at_index (vec, index);
     517           0 :   if (ep->type == STAT_DIR_TYPE_EMPTY)
     518             :     {
     519           0 :       stat_segment_access_end (&sa, sm);
     520           0 :       return 0;
     521             :     }
     522           0 :   if (!stat_segment_access_end (&sa, sm))
     523           0 :     return 0;
     524           0 :   return strdup (ep->name);
     525             : }
     526             : 
     527             : char *
     528           0 : stat_segment_index_to_name (uint32_t index)
     529             : {
     530           0 :   stat_client_main_t *sm = &stat_client_main;
     531           0 :   return stat_segment_index_to_name_r (index, sm);
     532             : }
     533             : 
     534             : uint64_t
     535           0 : stat_segment_version_r (stat_client_main_t * sm)
     536             : {
     537           0 :   ASSERT (sm->shared_header);
     538           0 :   return sm->shared_header->version;
     539             : }
     540             : 
     541             : uint64_t
     542           0 : stat_segment_version (void)
     543             : {
     544           0 :   stat_client_main_t *sm = &stat_client_main;
     545           0 :   return stat_segment_version_r (sm);
     546             : }
     547             : 
     548             : /*
     549             :  * fd.io coding-style-patch-verification: ON
     550             :  *
     551             :  * Local Variables:
     552             :  * eval: (c-set-style "gnu")
     553             :  * End:
     554             :  */

Generated by: LCOV version 1.14