LCOV - code coverage report
Current view: top level - plugins/memif - memif_test.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 0 283 0.0 %
Date: 2023-07-05 22:20:52 Functions: 0 14 0.0 %

          Line data    Source code
       1             : /*
       2             :  * memif VAT support
       3             :  *
       4             :  * Copyright (c) 2017 Cisco and/or its affiliates.
       5             :  * Licensed under the Apache License, Version 2.0 (the "License");
       6             :  * you may not use this file except in compliance with the License.
       7             :  * You may obtain a copy of the License at:
       8             :  *
       9             :  *     http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  * Unless required by applicable law or agreed to in writing, software
      12             :  * distributed under the License is distributed on an "AS IS" BASIS,
      13             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  * See the License for the specific language governing permissions and
      15             :  * limitations under the License.
      16             :  */
      17             : 
      18             : #include <inttypes.h>
      19             : 
      20             : #include <vat/vat.h>
      21             : #include <vlibapi/api.h>
      22             : #include <vlibmemory/api.h>
      23             : 
      24             : #include <vppinfra/error.h>
      25             : #include <vnet/ip/ip.h>
      26             : #include <memif/memif.h>
      27             : #include <memif/private.h>
      28             : 
      29             : #define __plugin_msg_base memif_test_main.msg_id_base
      30             : #include <vlibapi/vat_helper_macros.h>
      31             : 
      32             : /* declare message IDs */
      33             : #include <vnet/format_fns.h>
      34             : #include <memif/memif.api_enum.h>
      35             : #include <memif/memif.api_types.h>
      36             : #include <vlibmemory/vlib.api_types.h>
      37             : 
      38             : typedef struct
      39             : {
      40             :   /* API message ID base */
      41             :   u16 msg_id_base;
      42             :   u32 ping_id;
      43             :   vat_main_t *vat_main;
      44             : } memif_test_main_t;
      45             : 
      46             : memif_test_main_t memif_test_main;
      47             : 
      48             : static uword
      49           0 : unformat_memif_queues (unformat_input_t * input, va_list * args)
      50             : {
      51           0 :   u32 *rx_queues = va_arg (*args, u32 *);
      52           0 :   u32 *tx_queues = va_arg (*args, u32 *);
      53             : 
      54           0 :   if (unformat (input, "rx-queues %u", rx_queues))
      55             :     ;
      56           0 :   if (unformat (input, "tx-queues %u", tx_queues))
      57             :     ;
      58             : 
      59           0 :   return 1;
      60             : }
      61             : 
      62             : /* memif_socket_filename_add_del API */
      63             : static int
      64           0 : api_memif_socket_filename_add_del (vat_main_t * vam)
      65             : {
      66           0 :   unformat_input_t *i = vam->input;
      67             :   vl_api_memif_socket_filename_add_del_t *mp;
      68             :   u8 is_add;
      69             :   u32 socket_id;
      70             :   u8 *socket_filename;
      71             :   int ret;
      72             : 
      73           0 :   is_add = 1;
      74           0 :   socket_id = ~0;
      75           0 :   socket_filename = 0;
      76             : 
      77           0 :   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
      78             :     {
      79           0 :       if (unformat (i, "id %u", &socket_id))
      80             :         ;
      81           0 :       else if (unformat (i, "filename %s", &socket_filename))
      82             :         ;
      83           0 :       else if (unformat (i, "del"))
      84           0 :         is_add = 0;
      85           0 :       else if (unformat (i, "add"))
      86           0 :         is_add = 1;
      87             :       else
      88             :         {
      89           0 :           vec_free (socket_filename);
      90           0 :           clib_warning ("unknown input `%U'", format_unformat_error, i);
      91           0 :           return -99;
      92             :         }
      93             :     }
      94             : 
      95           0 :   if (socket_id == 0 || socket_id == ~0)
      96             :     {
      97           0 :       vec_free (socket_filename);
      98           0 :       errmsg ("Invalid socket id");
      99           0 :       return -99;
     100             :     }
     101             : 
     102           0 :   if (is_add && (!socket_filename || *socket_filename == 0))
     103             :     {
     104           0 :       vec_free (socket_filename);
     105           0 :       errmsg ("Invalid socket filename");
     106           0 :       return -99;
     107             :     }
     108             : 
     109           0 :   M2 (MEMIF_SOCKET_FILENAME_ADD_DEL, mp, strlen ((char *) socket_filename));
     110             : 
     111           0 :   mp->is_add = is_add;
     112           0 :   mp->socket_id = htonl (socket_id);
     113           0 :   char *p = (char *) &mp->socket_filename;
     114           0 :   p += vl_api_vec_to_api_string (socket_filename, (vl_api_string_t *) p);
     115             : 
     116           0 :   vec_free (socket_filename);
     117             : 
     118           0 :   S (mp);
     119           0 :   W (ret);
     120             : 
     121           0 :   return ret;
     122             : }
     123             : 
     124             : /* memif_socket_filename_add_del API */
     125             : static int
     126           0 : api_memif_socket_filename_add_del_v2 (vat_main_t *vam)
     127             : {
     128           0 :   unformat_input_t *i = vam->input;
     129             :   vl_api_memif_socket_filename_add_del_v2_t *mp;
     130             :   u8 is_add;
     131             :   u32 socket_id;
     132             :   u8 *socket_filename;
     133             :   int ret;
     134             : 
     135           0 :   is_add = 1;
     136           0 :   socket_id = ~0;
     137           0 :   socket_filename = 0;
     138             : 
     139           0 :   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
     140             :     {
     141           0 :       if (unformat (i, "id %u", &socket_id))
     142             :         ;
     143           0 :       else if (unformat (i, "filename %s", &socket_filename))
     144             :         ;
     145           0 :       else if (unformat (i, "del"))
     146           0 :         is_add = 0;
     147           0 :       else if (unformat (i, "add"))
     148           0 :         is_add = 1;
     149             :       else
     150             :         {
     151           0 :           vec_free (socket_filename);
     152           0 :           clib_warning ("unknown input `%U'", format_unformat_error, i);
     153           0 :           return -99;
     154             :         }
     155             :     }
     156             : 
     157           0 :   if (socket_id == 0 || socket_id == ~0)
     158             :     {
     159           0 :       vec_free (socket_filename);
     160           0 :       errmsg ("Invalid socket id");
     161           0 :       return -99;
     162             :     }
     163             : 
     164           0 :   if (is_add && (!socket_filename || *socket_filename == 0))
     165             :     {
     166           0 :       vec_free (socket_filename);
     167           0 :       errmsg ("Invalid socket filename");
     168           0 :       return -99;
     169             :     }
     170             : 
     171           0 :   M2 (MEMIF_SOCKET_FILENAME_ADD_DEL_V2, mp, strlen ((char *) socket_filename));
     172             : 
     173           0 :   mp->is_add = is_add;
     174           0 :   mp->socket_id = htonl (socket_id);
     175           0 :   char *p = (char *) &mp->socket_filename;
     176           0 :   p += vl_api_vec_to_api_string (socket_filename, (vl_api_string_t *) p);
     177             : 
     178           0 :   vec_free (socket_filename);
     179             : 
     180           0 :   S (mp);
     181           0 :   W (ret);
     182             : 
     183           0 :   return ret;
     184             : }
     185             : 
     186             : /* memif socket-create reply handler */
     187             : static void
     188           0 : vl_api_memif_socket_filename_add_del_v2_reply_t_handler (
     189             :   vl_api_memif_socket_filename_add_del_v2_reply_t *mp)
     190             : {
     191           0 :   vat_main_t *vam = memif_test_main.vat_main;
     192           0 :   i32 retval = ntohl (mp->retval);
     193             : 
     194           0 :   if (retval == 0)
     195             :     {
     196           0 :       fformat (vam->ofp, "created memif socket with socket_id %d\n",
     197             :                ntohl (mp->socket_id));
     198             :     }
     199             : 
     200           0 :   vam->retval = retval;
     201           0 :   vam->result_ready = 1;
     202           0 : }
     203             : 
     204             : /* memif_socket_filename_add_del reply handler */
     205             : #define VL_API_MEMIF_SOCKET_FILENAME_ADD_DEL_REPLY_T_HANDLER
     206           0 : static void vl_api_memif_socket_filename_add_del_reply_t_handler
     207             :   (vl_api_memif_socket_filename_add_del_reply_t * mp)
     208             : {
     209           0 :   vat_main_t *vam = memif_test_main.vat_main;
     210           0 :   i32 retval = ntohl (mp->retval);
     211             : 
     212           0 :   vam->retval = retval;
     213           0 :   vam->result_ready = 1;
     214           0 :   vam->regenerate_interface_table = 1;
     215           0 : }
     216             : 
     217             : /* memif-create API */
     218             : static int
     219           0 : api_memif_create (vat_main_t * vam)
     220             : {
     221           0 :   unformat_input_t *i = vam->input;
     222             :   vl_api_memif_create_t *mp;
     223           0 :   u32 id = 0;
     224           0 :   u32 socket_id = 0;
     225           0 :   u8 *secret = 0;
     226           0 :   u8 role = 1;
     227           0 :   u32 ring_size = 0;
     228           0 :   u32 buffer_size = 0;
     229           0 :   u8 hw_addr[6] = { 0 };
     230           0 :   u32 rx_queues = MEMIF_DEFAULT_RX_QUEUES;
     231           0 :   u32 tx_queues = MEMIF_DEFAULT_TX_QUEUES;
     232             :   int ret;
     233           0 :   u8 mode = MEMIF_INTERFACE_MODE_ETHERNET;
     234             : 
     235           0 :   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
     236             :     {
     237           0 :       if (unformat (i, "id %u", &id))
     238             :         ;
     239           0 :       else if (unformat (i, "socket-id %u", &socket_id))
     240             :         ;
     241           0 :       else if (unformat (i, "secret %s", &secret))
     242             :         ;
     243           0 :       else if (unformat (i, "ring_size %u", &ring_size))
     244             :         ;
     245           0 :       else if (unformat (i, "buffer_size %u", &buffer_size))
     246             :         ;
     247           0 :       else if (unformat (i, "master"))
     248           0 :         role = 0;
     249           0 :       else if (unformat (i, "slave %U",
     250             :                          unformat_memif_queues, &rx_queues, &tx_queues))
     251           0 :         role = 1;
     252           0 :       else if (unformat (i, "mode ip"))
     253           0 :         mode = MEMIF_INTERFACE_MODE_IP;
     254           0 :       else if (unformat (i, "hw_addr %U", unformat_ethernet_address, hw_addr))
     255             :         ;
     256             :       else
     257             :         {
     258           0 :           clib_warning ("unknown input '%U'", format_unformat_error, i);
     259           0 :           return -99;
     260             :         }
     261             :     }
     262             : 
     263           0 :   if (socket_id == ~0)
     264             :     {
     265           0 :       errmsg ("invalid socket-id\n");
     266           0 :       return -99;
     267             :     }
     268             : 
     269           0 :   if (!is_pow2 (ring_size))
     270             :     {
     271           0 :       errmsg ("ring size must be power of 2\n");
     272           0 :       return -99;
     273             :     }
     274             : 
     275           0 :   if (rx_queues > 255 || rx_queues < 1)
     276             :     {
     277           0 :       errmsg ("rx queue must be between 1 - 255\n");
     278           0 :       return -99;
     279             :     }
     280             : 
     281           0 :   if (tx_queues > 255 || tx_queues < 1)
     282             :     {
     283           0 :       errmsg ("tx queue must be between 1 - 255\n");
     284           0 :       return -99;
     285             :     }
     286             : 
     287           0 :   M2 (MEMIF_CREATE, mp, strlen ((char *) secret));
     288             : 
     289           0 :   mp->mode = mode;
     290           0 :   mp->id = clib_host_to_net_u32 (id);
     291           0 :   mp->role = role;
     292           0 :   mp->ring_size = clib_host_to_net_u32 (ring_size);
     293           0 :   mp->buffer_size = clib_host_to_net_u16 (buffer_size & 0xffff);
     294           0 :   mp->socket_id = clib_host_to_net_u32 (socket_id);
     295           0 :   if (secret != 0)
     296             :     {
     297           0 :       char *p = (char *) &mp->secret;
     298           0 :       p += vl_api_vec_to_api_string (secret, (vl_api_string_t *) p);
     299           0 :       vec_free (secret);
     300             :     }
     301           0 :   memcpy (mp->hw_addr, hw_addr, 6);
     302           0 :   mp->rx_queues = rx_queues;
     303           0 :   mp->tx_queues = tx_queues;
     304             : 
     305           0 :   S (mp);
     306           0 :   W (ret);
     307           0 :   return ret;
     308             : }
     309             : 
     310             : /* memif-create reply handler */
     311           0 : static void vl_api_memif_create_reply_t_handler
     312             :   (vl_api_memif_create_reply_t * mp)
     313             : {
     314           0 :   vat_main_t *vam = memif_test_main.vat_main;
     315           0 :   i32 retval = ntohl (mp->retval);
     316             : 
     317           0 :   if (retval == 0)
     318             :     {
     319           0 :       fformat (vam->ofp, "created memif with sw_if_index %d\n",
     320             :                ntohl (mp->sw_if_index));
     321             :     }
     322             : 
     323           0 :   vam->retval = retval;
     324           0 :   vam->result_ready = 1;
     325           0 :   vam->regenerate_interface_table = 1;
     326           0 : }
     327             : 
     328             : /* memif-create_v2 API */
     329             : static int
     330           0 : api_memif_create_v2 (vat_main_t *vam)
     331             : {
     332           0 :   unformat_input_t *i = vam->input;
     333             :   vl_api_memif_create_v2_t *mp;
     334           0 :   u32 id = 0;
     335           0 :   u32 socket_id = 0;
     336           0 :   u8 *secret = 0;
     337           0 :   u8 role = 1;
     338           0 :   u32 ring_size = 0;
     339           0 :   u8 use_dma = 0;
     340           0 :   u32 buffer_size = 0;
     341           0 :   u8 hw_addr[6] = { 0 };
     342           0 :   u32 rx_queues = MEMIF_DEFAULT_RX_QUEUES;
     343           0 :   u32 tx_queues = MEMIF_DEFAULT_TX_QUEUES;
     344             :   int ret;
     345           0 :   u8 mode = MEMIF_INTERFACE_MODE_ETHERNET;
     346             : 
     347           0 :   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
     348             :     {
     349           0 :       if (unformat (i, "id %u", &id))
     350             :         ;
     351           0 :       else if (unformat (i, "socket-id %u", &socket_id))
     352             :         ;
     353           0 :       else if (unformat (i, "secret %s", &secret))
     354             :         ;
     355           0 :       else if (unformat (i, "ring_size %u", &ring_size))
     356             :         ;
     357           0 :       else if (unformat (i, "buffer_size %u", &buffer_size))
     358             :         ;
     359           0 :       else if (unformat (i, "master"))
     360           0 :         role = 0;
     361           0 :       else if (unformat (i, "use_dma %u", &use_dma))
     362             :         ;
     363           0 :       else if (unformat (i, "slave %U", unformat_memif_queues, &rx_queues,
     364             :                          &tx_queues))
     365           0 :         role = 1;
     366           0 :       else if (unformat (i, "mode ip"))
     367           0 :         mode = MEMIF_INTERFACE_MODE_IP;
     368           0 :       else if (unformat (i, "hw_addr %U", unformat_ethernet_address, hw_addr))
     369             :         ;
     370             :       else
     371             :         {
     372           0 :           clib_warning ("unknown input '%U'", format_unformat_error, i);
     373           0 :           return -99;
     374             :         }
     375             :     }
     376             : 
     377           0 :   if (socket_id == ~0)
     378             :     {
     379           0 :       errmsg ("invalid socket-id\n");
     380           0 :       return -99;
     381             :     }
     382             : 
     383           0 :   if (!is_pow2 (ring_size))
     384             :     {
     385           0 :       errmsg ("ring size must be power of 2\n");
     386           0 :       return -99;
     387             :     }
     388             : 
     389           0 :   if (rx_queues > 255 || rx_queues < 1)
     390             :     {
     391           0 :       errmsg ("rx queue must be between 1 - 255\n");
     392           0 :       return -99;
     393             :     }
     394             : 
     395           0 :   if (tx_queues > 255 || tx_queues < 1)
     396             :     {
     397           0 :       errmsg ("tx queue must be between 1 - 255\n");
     398           0 :       return -99;
     399             :     }
     400             : 
     401           0 :   M2 (MEMIF_CREATE, mp, strlen ((char *) secret));
     402             : 
     403           0 :   mp->mode = mode;
     404           0 :   mp->id = clib_host_to_net_u32 (id);
     405           0 :   mp->role = role;
     406           0 :   mp->use_dma = use_dma;
     407           0 :   mp->ring_size = clib_host_to_net_u32 (ring_size);
     408           0 :   mp->buffer_size = clib_host_to_net_u16 (buffer_size & 0xffff);
     409           0 :   mp->socket_id = clib_host_to_net_u32 (socket_id);
     410             : 
     411           0 :   char *p = (char *) &mp->secret;
     412           0 :   p += vl_api_vec_to_api_string (secret, (vl_api_string_t *) p);
     413           0 :   vec_free (secret);
     414             : 
     415           0 :   memcpy (mp->hw_addr, hw_addr, 6);
     416           0 :   mp->rx_queues = rx_queues;
     417           0 :   mp->tx_queues = tx_queues;
     418             : 
     419           0 :   S (mp);
     420           0 :   W (ret);
     421           0 :   return ret;
     422             : }
     423             : 
     424             : /* memif-create_v2 reply handler */
     425             : static void
     426           0 : vl_api_memif_create_v2_reply_t_handler (vl_api_memif_create_reply_t *mp)
     427             : {
     428           0 :   vat_main_t *vam = memif_test_main.vat_main;
     429           0 :   i32 retval = ntohl (mp->retval);
     430             : 
     431           0 :   if (retval == 0)
     432             :     {
     433           0 :       fformat (vam->ofp, "created memif with sw_if_index %d\n",
     434             :                ntohl (mp->sw_if_index));
     435             :     }
     436             : 
     437           0 :   vam->retval = retval;
     438           0 :   vam->result_ready = 1;
     439           0 :   vam->regenerate_interface_table = 1;
     440           0 : }
     441             : 
     442             : /* memif-delete API */
     443             : static int
     444           0 : api_memif_delete (vat_main_t * vam)
     445             : {
     446           0 :   unformat_input_t *i = vam->input;
     447             :   vl_api_memif_delete_t *mp;
     448           0 :   u32 sw_if_index = 0;
     449           0 :   u8 index_defined = 0;
     450             :   int ret;
     451             : 
     452           0 :   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
     453             :     {
     454           0 :       if (unformat (i, "sw_if_index %u", &sw_if_index))
     455           0 :         index_defined = 1;
     456             :       else
     457             :         {
     458           0 :           clib_warning ("unknown input '%U'", format_unformat_error, i);
     459           0 :           return -99;
     460             :         }
     461             :     }
     462             : 
     463           0 :   if (!index_defined)
     464             :     {
     465           0 :       errmsg ("missing sw_if_index\n");
     466           0 :       return -99;
     467             :     }
     468             : 
     469           0 :   M (MEMIF_DELETE, mp);
     470             : 
     471           0 :   mp->sw_if_index = clib_host_to_net_u32 (sw_if_index);
     472             : 
     473           0 :   S (mp);
     474           0 :   W (ret);
     475           0 :   return ret;
     476             : }
     477             : 
     478             : /* memif-dump API */
     479             : static int
     480           0 : api_memif_dump (vat_main_t * vam)
     481             : {
     482           0 :   memif_test_main_t *mm = &memif_test_main;
     483             :   vl_api_memif_dump_t *mp;
     484             :   vl_api_control_ping_t *mp_ping;
     485             :   int ret;
     486             : 
     487           0 :   if (vam->json_output)
     488             :     {
     489           0 :       clib_warning ("JSON output not supported for memif_dump");
     490           0 :       return -99;
     491             :     }
     492             : 
     493           0 :   M (MEMIF_DUMP, mp);
     494           0 :   S (mp);
     495             : 
     496             :   /* Use a control ping for synchronization */
     497           0 :   if (!mm->ping_id)
     498           0 :     mm->ping_id = vl_msg_api_get_msg_index ((u8 *) (VL_API_CONTROL_PING_CRC));
     499           0 :   mp_ping = vl_msg_api_alloc_as_if_client (sizeof (*mp_ping));
     500           0 :   mp_ping->_vl_msg_id = htons (mm->ping_id);
     501           0 :   mp_ping->client_index = vam->my_client_index;
     502             : 
     503           0 :   fformat (vam->ofp, "Sending ping id=%d\n", mm->ping_id);
     504             : 
     505           0 :   vam->result_ready = 0;
     506           0 :   S (mp_ping);
     507             : 
     508           0 :   W (ret);
     509           0 :   return ret;
     510             : }
     511             : 
     512             : /* memif-details message handler */
     513             : static void
     514           0 : vl_api_memif_details_t_handler (vl_api_memif_details_t * mp)
     515             : {
     516           0 :   vat_main_t *vam = memif_test_main.vat_main;
     517             : 
     518           0 :   fformat (vam->ofp, "%s: sw_if_index %u mac %U\n"
     519             :            "   id %u socket-id %u role %s\n"
     520             :            "   ring_size %u buffer_size %u\n"
     521             :            "   state %s link %s\n",
     522           0 :            mp->if_name, ntohl (mp->sw_if_index), format_ethernet_address,
     523           0 :            mp->hw_addr, clib_net_to_host_u32 (mp->id),
     524             :            clib_net_to_host_u32 (mp->socket_id),
     525           0 :            mp->role ? "slave" : "master",
     526           0 :            ntohl (mp->ring_size), ntohs (mp->buffer_size),
     527           0 :            (mp->flags & IF_STATUS_API_FLAG_ADMIN_UP) ? "up" : "down",
     528           0 :            (mp->flags & IF_STATUS_API_FLAG_LINK_UP) ? "up" : "down");
     529           0 : }
     530             : 
     531             : /* memif_socket_filename_dump API */
     532             : static int
     533           0 : api_memif_socket_filename_dump (vat_main_t * vam)
     534             : {
     535           0 :   memif_test_main_t *mm = &memif_test_main;
     536             :   vl_api_memif_socket_filename_dump_t *mp;
     537             :   vl_api_control_ping_t *mp_ping;
     538             :   int ret;
     539             : 
     540           0 :   if (vam->json_output)
     541             :     {
     542           0 :       clib_warning
     543             :         ("JSON output not supported for memif_socket_filename_dump");
     544           0 :       return -99;
     545             :     }
     546             : 
     547           0 :   M (MEMIF_SOCKET_FILENAME_DUMP, mp);
     548           0 :   S (mp);
     549             : 
     550             :   /* Use a control ping for synchronization */
     551           0 :   if (!mm->ping_id)
     552           0 :     mm->ping_id = vl_msg_api_get_msg_index ((u8 *) (VL_API_CONTROL_PING_CRC));
     553           0 :   mp_ping = vl_msg_api_alloc_as_if_client (sizeof (*mp_ping));
     554           0 :   mp_ping->_vl_msg_id = htons (mm->ping_id);
     555           0 :   mp_ping->client_index = vam->my_client_index;
     556             : 
     557           0 :   fformat (vam->ofp, "Sending ping id=%d\n", mm->ping_id);
     558             : 
     559           0 :   vam->result_ready = 0;
     560           0 :   S (mp_ping);
     561             : 
     562           0 :   W (ret);
     563           0 :   return ret;
     564             : }
     565             : 
     566             : /* memif_socket_format_details message handler */
     567           0 : static void vl_api_memif_socket_filename_details_t_handler
     568             :   (vl_api_memif_socket_filename_details_t * mp)
     569             : {
     570           0 :   vat_main_t *vam = memif_test_main.vat_main;
     571             : 
     572           0 :   fformat (vam->ofp,
     573             :            "id %u : filename %s\n",
     574           0 :            ntohl (mp->socket_id), mp->socket_filename);
     575           0 : }
     576             : 
     577             : #include <memif/memif.api_test.c>
     578             : 
     579             : /*
     580             :  * fd.io coding-style-patch-verification: ON
     581             :  *
     582             :  * Local Variables:
     583             :  * eval: (c-set-style "gnu")
     584             :  * End:
     585             :  */

Generated by: LCOV version 1.14