LCOV - code coverage report
Current view: top level - vlibmemory - socket_api.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 326 386 84.5 %
Date: 2023-07-05 22:20:52 Functions: 27 30 90.0 %

          Line data    Source code
       1             : /*
       2             :  *------------------------------------------------------------------
       3             :  * socket_api.c
       4             :  *
       5             :  * Copyright (c) 2009 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 <sys/types.h>
      21             : #include <sys/socket.h>
      22             : #include <netinet/in.h>
      23             : #include <sys/ioctl.h>
      24             : #include <fcntl.h>
      25             : #include <sys/stat.h>
      26             : 
      27             : #include <vppinfra/byte_order.h>
      28             : #include <svm/ssvm.h>
      29             : #include <vlibmemory/api.h>
      30             : 
      31             : #include <vlibmemory/vl_memory_msg_enum.h>
      32             : 
      33             : #define vl_typedefs             /* define message structures */
      34             : #include <vlibmemory/vl_memory_api_h.h>
      35             : #undef vl_typedefs
      36             : 
      37             : /* instantiate all the print functions we know about */
      38             : #define vl_printfun
      39             : #include <vlibmemory/vl_memory_api_h.h>
      40             : #undef vl_printfun
      41             : 
      42             : /* instantiate all the endian swap functions we know about */
      43             : #define vl_endianfun
      44             : #include <vlibmemory/vl_memory_api_h.h>
      45             : #undef vl_endianfun
      46             : 
      47             : #define vl_calcsizefun
      48             : #include <vlibmemory/vl_memory_api_h.h>
      49             : #undef vl_calcsizefun
      50             : 
      51             : socket_main_t socket_main;
      52             : 
      53             : #define SOCK_API_REG_HANDLE_BIT (1<<31)
      54             : 
      55             : static u32
      56        1761 : sock_api_registration_handle (vl_api_registration_t * regp)
      57             : {
      58        1761 :   ASSERT (regp->vl_api_registration_pool_index < SOCK_API_REG_HANDLE_BIT);
      59        1761 :   return regp->vl_api_registration_pool_index | SOCK_API_REG_HANDLE_BIT;
      60             : }
      61             : 
      62             : static u32
      63      426170 : socket_api_registration_handle_to_index (u32 reg_index)
      64             : {
      65      426170 :   return (reg_index & ~SOCK_API_REG_HANDLE_BIT);
      66             : }
      67             : 
      68             : u8
      69      426304 : vl_socket_api_registration_handle_is_valid (u32 reg_handle)
      70             : {
      71      426304 :   return ((reg_handle & SOCK_API_REG_HANDLE_BIT) != 0);
      72             : }
      73             : 
      74             : void
      75           0 : vl_sock_api_dump_clients (vlib_main_t * vm, api_main_t * am)
      76             : {
      77             :   vl_api_registration_t *reg;
      78           0 :   socket_main_t *sm = &socket_main;
      79             :   clib_file_t *f;
      80             : 
      81             :   /*
      82             :    * Must have at least one active client, not counting the
      83             :    * REGISTRATION_TYPE_SOCKET_LISTEN bind/accept socket
      84             :    */
      85           0 :   if (pool_elts (sm->registration_pool) < 2)
      86           0 :     return;
      87             : 
      88           0 :   vlib_cli_output (vm, "Socket clients");
      89           0 :   vlib_cli_output (vm, "%20s %8s", "Name", "Fildesc");
      90             :     /* *INDENT-OFF* */
      91           0 :     pool_foreach (reg, sm->registration_pool)
      92             :      {
      93           0 :         if (reg->registration_type == REGISTRATION_TYPE_SOCKET_SERVER) {
      94           0 :             f = vl_api_registration_file (reg);
      95           0 :             vlib_cli_output (vm, "%20s %8d", reg->name, f->file_descriptor);
      96             :         }
      97             :     }
      98             : /* *INDENT-ON* */
      99             : }
     100             : 
     101             : vl_api_registration_t *
     102      425611 : vl_socket_api_client_handle_to_registration (u32 handle)
     103             : {
     104      425611 :   socket_main_t *sm = &socket_main;
     105      425611 :   u32 index = socket_api_registration_handle_to_index (handle);
     106      425611 :   if (pool_is_free_index (sm->registration_pool, index))
     107             :     {
     108             : #if DEBUG > 2
     109             :       clib_warning ("Invalid index %d\n", index);
     110             : #endif
     111           0 :       return 0;
     112             :     }
     113      425611 :   return pool_elt_at_index (sm->registration_pool, index);
     114             : }
     115             : 
     116             : void
     117      682857 : vl_socket_api_send (vl_api_registration_t * rp, u8 * elem)
     118             : {
     119             : #if CLIB_DEBUG > 1
     120             :   u32 output_length;
     121             : #endif
     122      682857 :   socket_main_t *sm = &socket_main;
     123      682857 :   u16 msg_id = ntohs (*(u16 *) elem);
     124      682857 :   api_main_t *am = vlibapi_get_main ();
     125      682857 :   msgbuf_t *mb = (msgbuf_t *) (elem - offsetof (msgbuf_t, data));
     126             :   vl_api_registration_t *sock_rp;
     127      682857 :   clib_file_main_t *fm = &file_main;
     128             :   clib_error_t *error;
     129             :   clib_file_t *cf;
     130             : 
     131      682857 :   cf = vl_api_registration_file (rp);
     132      682857 :   ASSERT (rp->registration_type > REGISTRATION_TYPE_SHMEM);
     133             : 
     134      682857 :   if (msg_id >= vec_len (am->msg_data))
     135             :     {
     136           0 :       clib_warning ("id out of range: %d", msg_id);
     137           0 :       vl_msg_api_free ((void *) elem);
     138           0 :       return;
     139             :     }
     140             : 
     141      682857 :   sock_rp = pool_elt_at_index (sm->registration_pool,
     142             :                                rp->vl_api_registration_pool_index);
     143      682857 :   ASSERT (sock_rp);
     144             : 
     145             :   /* Add the msgbuf_t to the output vector */
     146      682857 :   vec_add (sock_rp->output_vector, (u8 *) mb, sizeof (*mb));
     147             : 
     148             :   /* Try to send the message and save any error like
     149             :    * we do in the input epoll loop */
     150      682857 :   vec_add (sock_rp->output_vector, elem, ntohl (mb->data_len));
     151      682857 :   error = clib_file_write (cf);
     152      682857 :   unix_save_error (&unix_main, error);
     153             : 
     154             :   /* If we didn't finish sending everything, wait for tx space */
     155      682857 :   if (vec_len (sock_rp->output_vector) > 0
     156       10119 :       && !(cf->flags & UNIX_FILE_DATA_AVAILABLE_TO_WRITE))
     157             :     {
     158         660 :       cf->flags |= UNIX_FILE_DATA_AVAILABLE_TO_WRITE;
     159         660 :       fm->file_update (cf, UNIX_FILE_UPDATE_MODIFY);
     160             :     }
     161             : 
     162             : #if CLIB_DEBUG > 1
     163             :   output_length = sizeof (*mb) + ntohl (mb->data_len);
     164             :   clib_warning ("wrote %u bytes to fd %d", output_length,
     165             :                 cf->file_descriptor);
     166             : #endif
     167             : 
     168      682857 :   vl_msg_api_free ((void *) elem);
     169             : }
     170             : 
     171             : void
     172        1160 : vl_socket_free_registration_index (u32 pool_index)
     173             : {
     174             :   int i;
     175             :   vl_api_registration_t *rp;
     176             :   void vl_api_call_reaper_functions (u32 client_index);
     177             : 
     178        1160 :   if (pool_is_free_index (socket_main.registration_pool, pool_index))
     179             :     {
     180           0 :       clib_warning ("main pool index %d already free", pool_index);
     181           0 :       return;
     182             :     }
     183        1160 :   rp = pool_elt_at_index (socket_main.registration_pool, pool_index);
     184             : 
     185        1160 :   vl_api_call_reaper_functions (
     186             :     clib_host_to_net_u32 (sock_api_registration_handle (rp)));
     187             : 
     188        1160 :   ASSERT (rp->registration_type != REGISTRATION_TYPE_FREE);
     189        1202 :   for (i = 0; i < vec_len (rp->additional_fds_to_close); i++)
     190          42 :     if (close (rp->additional_fds_to_close[i]) < 0)
     191           0 :       clib_unix_warning ("close");
     192        1160 :   vec_free (rp->additional_fds_to_close);
     193        1160 :   vec_free (rp->name);
     194        1160 :   vec_free (rp->unprocessed_input);
     195        1160 :   vec_free (rp->output_vector);
     196        1160 :   rp->registration_type = REGISTRATION_TYPE_FREE;
     197        1160 :   pool_put (socket_main.registration_pool, rp);
     198             : }
     199             : 
     200             : void
     201      425558 : vl_socket_process_api_msg (vl_api_registration_t * rp, i8 * input_v)
     202             : {
     203      425558 :   msgbuf_t *mbp = (msgbuf_t *) input_v;
     204             : 
     205      425558 :   u8 *the_msg = (u8 *) (mbp->data);
     206      425558 :   socket_main.current_rp = rp;
     207      425558 :   vl_msg_api_socket_handler (the_msg, ntohl (mbp->data_len));
     208      425558 :   socket_main.current_rp = 0;
     209      425558 : }
     210             : 
     211             : int
     212     1103350 : is_being_removed_reg_index (u32 reg_index)
     213             : {
     214     1103350 :   vl_api_registration_t *rp = vl_socket_get_registration (reg_index);
     215     1103350 :   ALWAYS_ASSERT (rp != 0);
     216     1103350 :   return (rp->is_being_removed);
     217             : }
     218             : 
     219             : static void
     220          42 : socket_cleanup_pending_remove_registration_cb (u32 *preg_index)
     221             : {
     222          42 :   vl_api_registration_t *rp = vl_socket_get_registration (*preg_index);
     223          42 :   if (!rp)
     224             :     {
     225             :       /* Might already have gone */
     226           0 :       return;
     227             :     }
     228             : 
     229          42 :   clib_file_main_t *fm = &file_main;
     230          42 :   u32 pending_remove_file_index = vl_api_registration_file_index (rp);
     231             : 
     232          42 :   clib_file_t *zf = fm->file_pool + pending_remove_file_index;
     233             : 
     234          42 :   clib_file_del (fm, zf);
     235          42 :   vl_socket_free_registration_index (rp - socket_main.registration_pool);
     236             : }
     237             : 
     238             : static void
     239          42 : vl_socket_request_remove_reg_index (u32 reg_index)
     240             : {
     241          42 :   vl_api_registration_t *rp = vl_socket_get_registration (reg_index);
     242          42 :   ALWAYS_ASSERT (rp != 0);
     243          42 :   if (rp->is_being_removed)
     244             :     {
     245           0 :       return;
     246             :     }
     247          42 :   rp->is_being_removed = 1;
     248          42 :   vl_api_force_rpc_call_main_thread (
     249             :     socket_cleanup_pending_remove_registration_cb, (void *) &reg_index,
     250             :     sizeof (u32));
     251             : }
     252             : 
     253             : /*
     254             :  * Read function for API socket.
     255             :  *
     256             :  * Read data from socket, invoke SOCKET_READ_EVENT
     257             :  * for each fully read API message, return 0.
     258             :  * Store incomplete data for next invocation to continue.
     259             :  *
     260             :  * On severe read error, the file is closed.
     261             :  *
     262             :  * As reading is single threaded,
     263             :  * socket_main.input_buffer is used temporarily.
     264             :  * Even its length is modified, but always restored before return.
     265             :  *
     266             :  * Incomplete data is copied into a vector,
     267             :  * pointer saved in registration's unprocessed_input.
     268             :  */
     269             : clib_error_t *
     270      419736 : vl_socket_read_ready (clib_file_t * uf)
     271             : {
     272      419736 :   vlib_main_t *vm = vlib_get_main ();
     273             :   vl_api_registration_t *rp;
     274             :   /* n is the size of data read to input_buffer */
     275             :   int n;
     276             :   /* msg_buffer vector can point to input_buffer or unprocessed_input */
     277      419736 :   i8 *msg_buffer = 0;
     278             :   /* data_for_process is a vector containing one full message, incl msgbuf_t */
     279             :   u8 *data_for_process;
     280             :   /* msgbuf_len is the size of one message, including sizeof (msgbuf_t) */
     281             :   u32 msgbuf_len;
     282      419736 :   u32 save_input_buffer_length = vec_len (socket_main.input_buffer);
     283             :   vl_socket_args_for_process_t *a;
     284      419736 :   u32 reg_index = uf->private_data;
     285      419736 :   if (is_being_removed_reg_index (reg_index))
     286             :     {
     287           0 :       return 0;
     288             :     }
     289             : 
     290      419736 :   rp = vl_socket_get_registration (reg_index);
     291             : 
     292             :   /* Ignore unprocessed_input for now, n describes input_buffer for now. */
     293      419736 :   n = read (uf->file_descriptor, socket_main.input_buffer,
     294      419736 :             vec_len (socket_main.input_buffer));
     295             : 
     296      419736 :   if (n <= 0)
     297             :     {
     298          42 :       if (errno != EAGAIN)
     299             :         {
     300             :           /* Severe error, close the file. */
     301          42 :           vl_socket_request_remove_reg_index (reg_index);
     302             :         }
     303             :       /* EAGAIN means we do not close the file, but no data to process anyway. */
     304          42 :       return 0;
     305             :     }
     306             : 
     307             :   /* Fake smaller length teporarily, so input_buffer can be used as msg_buffer. */
     308      419694 :   vec_set_len (socket_main.input_buffer, n);
     309             : 
     310             :   /*
     311             :    * Look for bugs here. This code is tricky because
     312             :    * data read from a stream socket does not honor message
     313             :    * boundaries. In the case of a long message (>4K bytes)
     314             :    * we have to do (at least) 2 reads, etc.
     315             :    */
     316             :   /* Determine msg_buffer. */
     317      419694 :   if (vec_len (rp->unprocessed_input))
     318             :     {
     319        6599 :       vec_append (rp->unprocessed_input, socket_main.input_buffer);
     320        6599 :       msg_buffer = rp->unprocessed_input;
     321             :     }
     322             :   else
     323             :     {
     324      413095 :       msg_buffer = socket_main.input_buffer;
     325             :     }
     326             :   /* Loop to process any full messages. */
     327      419694 :   ASSERT (vec_len (msg_buffer) > 0);
     328             :   do
     329             :     {
     330             :       /* Here, we are not sure how big a chunk of message we have left. */
     331             :       /* Do we at least know how big the full message will be? */
     332      432157 :       if (vec_len (msg_buffer) <= sizeof (msgbuf_t))
     333             :         /* No, so fragment is not a full message. */
     334        6549 :         goto save_and_split;
     335             : 
     336             :       /* Now we know how big the full message will be. */
     337      425608 :       msgbuf_len =
     338      425608 :         ntohl (((msgbuf_t *) msg_buffer)->data_len) + sizeof (msgbuf_t);
     339             : 
     340             :       /* But do we have a full message? */
     341      425608 :       if (msgbuf_len > vec_len (msg_buffer))
     342             :         {
     343          50 :         save_and_split:
     344             :           /* We don't have the entire message yet. */
     345             :           /* If msg_buffer is unprocessed_input, nothing needs to be done. */
     346        6599 :           if (msg_buffer == socket_main.input_buffer)
     347             :             /* But if we were using the input buffer, save the fragment. */
     348             :             {
     349        6566 :               ASSERT (vec_len (rp->unprocessed_input) == 0);
     350        6566 :               vec_validate (rp->unprocessed_input, vec_len (msg_buffer) - 1);
     351       13132 :               clib_memcpy_fast (rp->unprocessed_input, msg_buffer,
     352        6566 :                                 vec_len (msg_buffer));
     353        6566 :               vec_set_len (rp->unprocessed_input, vec_len (msg_buffer));
     354             :             }
     355             :           /* No more full messages, restore original input_buffer length. */
     356        6599 :           vec_set_len (socket_main.input_buffer, save_input_buffer_length);
     357        6599 :           return 0;
     358             :         }
     359             : 
     360             :       /*
     361             :        * We have at least one full message.
     362             :        * But msg_buffer can contain more data, so copy one message data
     363             :        * so we can overwrite its length to what single message has.
     364             :        */
     365      425558 :       data_for_process = (u8 *) vec_dup (msg_buffer);
     366      425558 :       vec_set_len (data_for_process, msgbuf_len);
     367             :       /* Everything is ready to signal the SOCKET_READ_EVENT. */
     368      425558 :       pool_get (socket_main.process_args, a);
     369      425558 :       a->reg_index = reg_index;
     370      425558 :       a->data = data_for_process;
     371             : 
     372      425558 :       vlib_process_signal_event (vm, vl_api_clnt_node.index,
     373             :                                  SOCKET_READ_EVENT,
     374      425558 :                                  a - socket_main.process_args);
     375      425558 :       if (vec_len (msg_buffer) > msgbuf_len)
     376             :         /* There are some fragments left. Shrink the msg_buffer to simplify logic. */
     377       12463 :         vec_delete (msg_buffer, msgbuf_len, 0);
     378             :       else
     379             :         /* We are done with msg_buffer. */
     380      413095 :         vec_set_len (msg_buffer, 0);
     381             :     }
     382      425558 :   while (vec_len (msg_buffer) > 0);
     383             : 
     384             :   /* Restore input_buffer, it could have been msg_buffer. */
     385      413095 :   vec_set_len (socket_main.input_buffer, save_input_buffer_length);
     386      413095 :   return 0;
     387             : }
     388             : 
     389             : clib_error_t *
     390      683614 : vl_socket_write_ready (clib_file_t * uf)
     391             : {
     392      683614 :   clib_file_main_t *fm = &file_main;
     393             :   vl_api_registration_t *rp;
     394             :   int n;
     395             : 
     396      683614 :   u32 reg_index = uf->private_data;
     397      683614 :   if (is_being_removed_reg_index (reg_index))
     398             :     {
     399           0 :       return 0;
     400             :     }
     401             : 
     402      683614 :   rp = pool_elt_at_index (socket_main.registration_pool, reg_index);
     403             : 
     404             :   /* Flush output vector. */
     405      683614 :   size_t total_bytes = vec_len (rp->output_vector);
     406      683614 :   size_t bytes_to_send, remaining_bytes = total_bytes;
     407      683614 :   void *p = rp->output_vector;
     408     1594400 :   while (remaining_bytes > 0)
     409             :     {
     410      921093 :       bytes_to_send = remaining_bytes > 4096 ? 4096 : remaining_bytes;
     411      921093 :       n = send (uf->file_descriptor, p, bytes_to_send, MSG_NOSIGNAL);
     412      921093 :       if (n < 0)
     413             :         {
     414       10303 :           if (errno == EAGAIN)
     415             :             {
     416       10303 :               break;
     417             :             }
     418             : #if DEBUG > 2
     419             :           clib_warning ("write error, close the file...\n");
     420             : #endif
     421           0 :           vl_socket_request_remove_reg_index (reg_index);
     422           0 :           return 0;
     423             :         }
     424      910790 :       remaining_bytes -= bytes_to_send;
     425      910790 :       p += bytes_to_send;
     426             :     }
     427             : 
     428      683614 :   vec_delete (rp->output_vector, total_bytes - remaining_bytes, 0);
     429      683614 :   if (vec_len (rp->output_vector) <= 0
     430      673311 :       && (uf->flags & UNIX_FILE_DATA_AVAILABLE_TO_WRITE))
     431             :     {
     432         660 :       uf->flags &= ~UNIX_FILE_DATA_AVAILABLE_TO_WRITE;
     433         660 :       fm->file_update (uf, UNIX_FILE_UPDATE_MODIFY);
     434             :     }
     435             : 
     436      683614 :   return 0;
     437             : }
     438             : 
     439             : clib_error_t *
     440           0 : vl_socket_error_ready (clib_file_t * uf)
     441             : {
     442           0 :   u32 reg_index = uf->private_data;
     443           0 :   vl_socket_request_remove_reg_index (reg_index);
     444           0 :   return 0;
     445             : }
     446             : 
     447             : void
     448         601 : socksvr_file_add (clib_file_main_t * fm, int fd)
     449             : {
     450             :   vl_api_registration_t *rp;
     451         601 :   clib_file_t template = { 0 };
     452             : 
     453         601 :   pool_get (socket_main.registration_pool, rp);
     454         601 :   clib_memset (rp, 0, sizeof (*rp));
     455             : 
     456         601 :   template.read_function = vl_socket_read_ready;
     457         601 :   template.write_function = vl_socket_write_ready;
     458         601 :   template.error_function = vl_socket_error_ready;
     459         601 :   template.file_descriptor = fd;
     460         601 :   template.description = format (0, "socksrv");
     461         601 :   template.private_data = rp - socket_main.registration_pool;
     462             : 
     463         601 :   rp->registration_type = REGISTRATION_TYPE_SOCKET_SERVER;
     464         601 :   rp->vl_api_registration_pool_index = rp - socket_main.registration_pool;
     465         601 :   rp->clib_file_index = clib_file_add (fm, &template);
     466         601 : }
     467             : 
     468             : static clib_error_t *
     469         601 : socksvr_accept_ready (clib_file_t * uf)
     470             : {
     471         601 :   clib_file_main_t *fm = &file_main;
     472         601 :   socket_main_t *sm = &socket_main;
     473         601 :   clib_socket_t *sock = &sm->socksvr_listen_socket;
     474             :   clib_socket_t client;
     475             :   clib_error_t *error;
     476             : 
     477         601 :   error = clib_socket_accept (sock, &client);
     478         601 :   if (error)
     479           0 :     return error;
     480             : 
     481         601 :   socksvr_file_add (fm, client.fd);
     482         601 :   return 0;
     483             : }
     484             : 
     485             : static clib_error_t *
     486           0 : socksvr_bogus_write (clib_file_t * uf)
     487             : {
     488           0 :   clib_warning ("why am I here?");
     489           0 :   return 0;
     490             : }
     491             : 
     492             : /*
     493             :  * vl_api_sockclnt_create_t_handler
     494             :  */
     495             : void
     496         601 : vl_api_sockclnt_create_t_handler (vl_api_sockclnt_create_t * mp)
     497             : {
     498             :   vl_api_registration_t *regp;
     499             :   vl_api_sockclnt_create_reply_t *rp;
     500         601 :   api_main_t *am = vlibapi_get_main ();
     501             :   hash_pair_t *hp;
     502         601 :   int rv = 0;
     503         601 :   u32 nmsg = hash_elts (am->msg_index_by_name_and_crc);
     504         601 :   u32 i = 0;
     505             : 
     506         601 :   regp = socket_main.current_rp;
     507             : 
     508             :   /* client already connected through shared memory? */
     509         601 :   if (!regp || regp->registration_type != REGISTRATION_TYPE_SOCKET_SERVER)
     510             :     {
     511           0 :       clib_warning (
     512             :         "unsupported API call: already connected though shared memory?");
     513           0 :       return;
     514             :     }
     515             : 
     516         601 :   regp->name = format (0, "%s%c", mp->name, 0);
     517             : 
     518         601 :   u32 size = sizeof (*rp) + (nmsg * sizeof (vl_api_message_table_entry_t));
     519         601 :   rp = vl_msg_api_alloc_zero (size);
     520         601 :   rp->_vl_msg_id = htons (VL_API_SOCKCLNT_CREATE_REPLY);
     521         601 :   rp->index = htonl (sock_api_registration_handle (regp));
     522         601 :   rp->context = mp->context;
     523         601 :   rp->response = htonl (rv);
     524         601 :   rp->count = htons (nmsg);
     525             : 
     526             :   /* *INDENT-OFF* */
     527     3508670 :   hash_foreach_pair (hp, am->msg_index_by_name_and_crc,
     528             :   ({
     529             :     rp->message_table[i].index = htons(hp->value[0]);
     530             :     (void) strncpy_s((char *)rp->message_table[i].name,
     531             :                      64 /* bytes of space at dst */,
     532             :                      (char *)hp->key,
     533             :                      64-1 /* chars to copy, without zero byte. */);
     534             :     i++;
     535             :   }));
     536             :   /* *INDENT-ON* */
     537         601 :   vl_api_send_msg (regp, (u8 *) rp);
     538             : }
     539             : 
     540             : /*
     541             :  * vl_api_sockclnt_delete_t_handler
     542             :  */
     543             : void
     544         559 : vl_api_sockclnt_delete_t_handler (vl_api_sockclnt_delete_t * mp)
     545             : {
     546             :   vl_api_registration_t *regp;
     547             :   vl_api_sockclnt_delete_reply_t *rp;
     548             : 
     549         559 :   regp = vl_api_client_index_to_registration (mp->client_index);
     550         559 :   if (!regp)
     551           0 :     return;
     552             : 
     553         559 :   u32 reg_index = socket_api_registration_handle_to_index (ntohl (mp->index));
     554         559 :   rp = vl_msg_api_alloc (sizeof (*rp));
     555         559 :   rp->_vl_msg_id = htons (VL_API_SOCKCLNT_DELETE_REPLY);
     556         559 :   rp->context = mp->context;
     557             : 
     558         559 :   if (!pool_is_free_index (socket_main.registration_pool, reg_index))
     559             :     {
     560         559 :       rp->response = htonl (1);
     561         559 :       vl_api_send_msg (regp, (u8 *) rp);
     562             : 
     563         559 :       vl_api_registration_del_file (regp);
     564         559 :       vl_socket_free_registration_index (reg_index);
     565             :     }
     566             :   else
     567             :     {
     568           0 :       clib_warning ("unknown client ID %d", reg_index);
     569           0 :       rp->response = htonl (-1);
     570           0 :       vl_api_send_msg (regp, (u8 *) rp);
     571             :     }
     572             : }
     573             : 
     574             : clib_error_t *
     575         115 : vl_sock_api_send_fd_msg (int socket_fd, int fds[], int n_fds)
     576         115 : {
     577         115 :   struct msghdr mh = { 0 };
     578             :   struct iovec iov[1];
     579         115 :   char ctl[CMSG_SPACE (sizeof (int) * n_fds)];
     580             :   struct cmsghdr *cmsg;
     581         115 :   char *msg = "fdmsg";
     582             :   int rv;
     583             : 
     584         115 :   iov[0].iov_base = msg;
     585         115 :   iov[0].iov_len = strlen (msg);
     586         115 :   mh.msg_iov = iov;
     587         115 :   mh.msg_iovlen = 1;
     588             : 
     589         115 :   clib_memset (&ctl, 0, sizeof (ctl));
     590         115 :   mh.msg_control = ctl;
     591         115 :   mh.msg_controllen = sizeof (ctl);
     592         115 :   cmsg = CMSG_FIRSTHDR (&mh);
     593         115 :   cmsg->cmsg_len = CMSG_LEN (sizeof (int) * n_fds);
     594         115 :   cmsg->cmsg_level = SOL_SOCKET;
     595         115 :   cmsg->cmsg_type = SCM_RIGHTS;
     596         115 :   clib_memcpy_fast (CMSG_DATA (cmsg), fds, sizeof (int) * n_fds);
     597             : 
     598         115 :   while ((rv = sendmsg (socket_fd, &mh, 0)) < 0 && errno == EAGAIN)
     599             :     ;
     600         115 :   if (rv < 0)
     601           0 :     return clib_error_return_unix (0, "sendmsg");
     602         115 :   return 0;
     603             : }
     604             : 
     605             : vl_api_shm_elem_config_t *
     606          42 : vl_api_make_shm_config (vl_api_sock_init_shm_t * mp)
     607             : {
     608          42 :   vl_api_shm_elem_config_t *config = 0, *c;
     609             :   u64 cfg;
     610             :   int i;
     611             : 
     612          42 :   if (!mp->nitems)
     613             :     {
     614          42 :       vec_validate (config, 6);
     615          42 :       config[0].type = VL_API_VLIB_RING;
     616          42 :       config[0].size = 256;
     617          42 :       config[0].count = 32;
     618             : 
     619          42 :       config[1].type = VL_API_VLIB_RING;
     620          42 :       config[1].size = 1024;
     621          42 :       config[1].count = 16;
     622             : 
     623          42 :       config[2].type = VL_API_VLIB_RING;
     624          42 :       config[2].size = 4096;
     625          42 :       config[2].count = 2;
     626             : 
     627          42 :       config[3].type = VL_API_CLIENT_RING;
     628          42 :       config[3].size = 256;
     629          42 :       config[3].count = 32;
     630             : 
     631          42 :       config[4].type = VL_API_CLIENT_RING;
     632          42 :       config[4].size = 1024;
     633          42 :       config[4].count = 16;
     634             : 
     635          42 :       config[5].type = VL_API_CLIENT_RING;
     636          42 :       config[5].size = 4096;
     637          42 :       config[5].count = 2;
     638             : 
     639          42 :       config[6].type = VL_API_QUEUE;
     640          42 :       config[6].count = 128;
     641          42 :       config[6].size = sizeof (uword);
     642             :     }
     643             :   else
     644             :     {
     645           0 :       vec_validate (config, mp->nitems - 1);
     646           0 :       for (i = 0; i < mp->nitems; i++)
     647             :         {
     648           0 :           cfg = mp->configs[i];
     649             :           /* Pretty much a hack but it avoids defining our own api type
     650             :            * in memclnt.api */
     651           0 :           c = (vl_api_shm_elem_config_t *) & cfg;
     652           0 :           config[i].type = c->type;
     653           0 :           config[i].count = c->count;
     654           0 :           config[i].size = c->size;
     655             :         }
     656             :     }
     657          42 :   return config;
     658             : }
     659             : 
     660             : /*
     661             :  * Bootstrap shm api using the socket api
     662             :  */
     663             : void
     664          42 : vl_api_sock_init_shm_t_handler (vl_api_sock_init_shm_t * mp)
     665             : {
     666             :   vl_api_sock_init_shm_reply_t *rmp;
     667          42 :   ssvm_private_t _memfd_private, *memfd = &_memfd_private;
     668          42 :   svm_map_region_args_t _args, *a = &_args;
     669             :   vl_api_registration_t *regp;
     670          42 :   api_main_t *am = vlibapi_get_main ();
     671             :   svm_region_t *vlib_rp;
     672             :   clib_file_t *cf;
     673          42 :   vl_api_shm_elem_config_t *config = 0;
     674             :   vl_shmem_hdr_t *shmem_hdr;
     675          42 :   int rv, tries = 1000;
     676             : 
     677          42 :   regp = vl_api_client_index_to_registration (mp->client_index);
     678          42 :   if (regp == 0)
     679             :     {
     680           0 :       clib_warning ("API client disconnected");
     681           0 :       return;
     682             :     }
     683          42 :   if (regp->registration_type != REGISTRATION_TYPE_SOCKET_SERVER)
     684             :     {
     685           0 :       clib_warning ("Invalid registration");
     686           0 :       return;
     687             :     }
     688             : 
     689             :   /*
     690             :    * Set up a memfd segment of the requested size wherein the
     691             :    * shmem data structures will be initialized
     692             :    */
     693          42 :   clib_memset (memfd, 0, sizeof (*memfd));
     694          42 :   memfd->ssvm_size = mp->requested_size;
     695          42 :   memfd->requested_va = 0ULL;
     696          42 :   memfd->is_server = 1;
     697          42 :   memfd->name = format (0, "%s%c", regp->name, 0);
     698             : 
     699          42 :   if ((rv = ssvm_server_init_memfd (memfd)))
     700           0 :     goto reply;
     701             : 
     702             :   /* delete the unused heap created in ssvm_server_init_memfd and mark it
     703             :    * accessible again for ASAN */
     704          42 :   clib_mem_destroy_heap (memfd->sh->heap);
     705          42 :   clib_mem_unpoison ((void *) memfd->sh->ssvm_va, memfd->ssvm_size);
     706             : 
     707             :   /* Remember to close this fd when the socket connection goes away */
     708          42 :   vec_add1 (regp->additional_fds_to_close, memfd->fd);
     709             : 
     710             :   /*
     711             :    * Create a plausible svm_region in the memfd backed segment
     712             :    */
     713          42 :   clib_memset (a, 0, sizeof (*a));
     714          42 :   a->baseva = memfd->sh->ssvm_va + MMAP_PAGESIZE;
     715          42 :   a->size = memfd->ssvm_size - MMAP_PAGESIZE;
     716             :   /* $$$$ might want a different config parameter */
     717          42 :   a->pvt_heap_size = am->api_pvt_heap_size;
     718          42 :   a->flags = SVM_FLAGS_MHEAP;
     719          42 :   svm_region_init_mapped_region (a, (svm_region_t *) a->baseva);
     720             : 
     721             :   /*
     722             :    * Part deux, initialize the svm_region_t shared-memory header
     723             :    * api allocation rings, and so on.
     724             :    */
     725          42 :   config = vl_api_make_shm_config (mp);
     726          42 :   vlib_rp = (svm_region_t *) a->baseva;
     727          42 :   vl_init_shmem (vlib_rp, config, 1 /* is_vlib (dont-care) */ ,
     728             :                  1 /* is_private */ );
     729             : 
     730             :   /* Remember who created this. Needs to be post vl_init_shmem */
     731          42 :   shmem_hdr = (vl_shmem_hdr_t *) vlib_rp->user_ctx;
     732          42 :   shmem_hdr->clib_file_index = vl_api_registration_file_index (regp);
     733             : 
     734          42 :   vec_add1 (am->vlib_private_rps, vlib_rp);
     735          42 :   memfd->sh->ready = 1;
     736          42 :   vec_free (config);
     737             : 
     738             :   /* Recompute the set of input queues to poll in memclnt_process */
     739          42 :   vec_reset_length (vl_api_queue_cursizes);
     740             : 
     741           0 : reply:
     742             : 
     743          42 :   rmp = vl_msg_api_alloc (sizeof (*rmp));
     744          42 :   rmp->_vl_msg_id = htons (VL_API_SOCK_INIT_SHM_REPLY);
     745          42 :   rmp->context = mp->context;
     746          42 :   rmp->retval = htonl (rv);
     747             : 
     748             :   /*
     749             :    * Note: The reply message needs to make it out the back door
     750             :    * before we send the magic fd message. That's taken care of by
     751             :    * the send function.
     752             :    */
     753          42 :   vl_socket_api_send (regp, (u8 *) rmp);
     754             : 
     755          42 :   if (rv != 0)
     756           0 :     return;
     757             : 
     758             :   /* Send the magic "here's your sign (aka fd)" socket message */
     759          42 :   cf = vl_api_registration_file (regp);
     760          42 :   if (!cf)
     761             :     {
     762           0 :       clib_warning ("cf removed");
     763           0 :       return;
     764             :     }
     765             : 
     766             :   /* Wait for reply to be consumed before sending the fd */
     767          60 :   while (tries-- > 0)
     768             :     {
     769             :       int bytes;
     770          60 :       rv = ioctl (cf->file_descriptor, TIOCOUTQ, &bytes);
     771          60 :       if (rv < 0)
     772             :         {
     773           0 :           clib_unix_warning ("ioctl returned");
     774          42 :           break;
     775             :         }
     776          60 :       if (bytes == 0)
     777          42 :         break;
     778          18 :       usleep (1e3);
     779             :     }
     780             : 
     781          42 :   vl_sock_api_send_fd_msg (cf->file_descriptor, &memfd->fd, 1);
     782             : }
     783             : 
     784             : #define foreach_vlib_api_msg                                                  \
     785             :   _ (SOCKCLNT_CREATE, sockclnt_create, 0)                                     \
     786             :   _ (SOCKCLNT_DELETE, sockclnt_delete, 0)                                     \
     787             :   _ (SOCK_INIT_SHM, sock_init_shm, 0)
     788             : 
     789             : clib_error_t *
     790         559 : vl_sock_api_init (vlib_main_t * vm)
     791             : {
     792         559 :   api_main_t *am = vlibapi_get_main ();
     793         559 :   clib_file_main_t *fm = &file_main;
     794         559 :   clib_file_t template = { 0 };
     795             :   vl_api_registration_t *rp;
     796         559 :   socket_main_t *sm = &socket_main;
     797         559 :   clib_socket_t *sock = &sm->socksvr_listen_socket;
     798             :   clib_error_t *error;
     799             : 
     800             :   /* If not explicitly configured, do not bind/enable, etc. */
     801         559 :   if (sm->socket_name == 0)
     802           0 :     return 0;
     803             : 
     804             : #define _(N, n, t)                                                            \
     805             :   vl_msg_api_config (&(vl_msg_api_msg_config_t){                              \
     806             :     .id = VL_API_##N,                                                         \
     807             :     .name = #n,                                                               \
     808             :     .handler = vl_api_##n##_t_handler,                                        \
     809             :     .endian = vl_api_##n##_t_endian,                                          \
     810             :     .format_fn = vl_api_##n##_t_format,                                       \
     811             :     .size = sizeof (vl_api_##n##_t),                                          \
     812             :     .traced = t,                                                              \
     813             :     .tojson = vl_api_##n##_t_tojson,                                          \
     814             :     .fromjson = vl_api_##n##_t_fromjson,                                      \
     815             :     .calc_size = vl_api_##n##_t_calc_size,                                    \
     816             :   });                                                                         \
     817             :   am->msg_data[VL_API_##N].replay_allowed = 0;
     818         559 :   foreach_vlib_api_msg;
     819             : #undef _
     820             : 
     821         559 :   vec_resize (sm->input_buffer, 4096);
     822             : 
     823         559 :   sock->config = (char *) sm->socket_name;
     824         559 :   sock->flags = CLIB_SOCKET_F_IS_SERVER | CLIB_SOCKET_F_ALLOW_GROUP_WRITE;
     825         559 :   error = clib_socket_init (sock);
     826         559 :   if (error)
     827           0 :     return error;
     828             : 
     829         559 :   pool_get (sm->registration_pool, rp);
     830         559 :   clib_memset (rp, 0, sizeof (*rp));
     831             : 
     832         559 :   rp->registration_type = REGISTRATION_TYPE_SOCKET_LISTEN;
     833             : 
     834         559 :   template.read_function = socksvr_accept_ready;
     835         559 :   template.write_function = socksvr_bogus_write;
     836         559 :   template.file_descriptor = sock->fd;
     837         559 :   template.description = format (0, "socksvr %s", sock->config);
     838         559 :   template.private_data = rp - sm->registration_pool;
     839             : 
     840         559 :   rp->clib_file_index = clib_file_add (fm, &template);
     841         559 :   return 0;
     842             : }
     843             : 
     844             : static clib_error_t *
     845         559 : socket_exit (vlib_main_t * vm)
     846             : {
     847         559 :   socket_main_t *sm = &socket_main;
     848             :   vl_api_registration_t *rp;
     849             : 
     850             :   /* Defensive driving in case something wipes out early */
     851         559 :   if (sm->registration_pool)
     852             :     {
     853             :       u32 index;
     854             :         /* *INDENT-OFF* */
     855        1118 :         pool_foreach (rp, sm->registration_pool)  {
     856         559 :           vl_api_registration_del_file (rp);
     857         559 :           index = rp->vl_api_registration_pool_index;
     858         559 :           vl_socket_free_registration_index (index);
     859             :         }
     860             : /* *INDENT-ON* */
     861             :     }
     862             : 
     863         559 :   return 0;
     864             : }
     865             : 
     866        3355 : VLIB_MAIN_LOOP_EXIT_FUNCTION (socket_exit);
     867             : 
     868             : static clib_error_t *
     869         559 : socksvr_config (vlib_main_t * vm, unformat_input_t * input)
     870             : {
     871         559 :   socket_main_t *sm = &socket_main;
     872             : 
     873        1118 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     874             :     {
     875         559 :       if (unformat (input, "socket-name %s", &sm->socket_name))
     876             :         ;
     877             :       /* DEPRECATE: default keyword is ignored */
     878           0 :       else if (unformat (input, "default"))
     879             :         ;
     880             :       else
     881             :         {
     882           0 :           return clib_error_return (0, "unknown input '%U'",
     883             :                                     format_unformat_error, input);
     884             :         }
     885             :     }
     886             : 
     887         559 :   if (!vec_len (sm->socket_name))
     888           0 :     sm->socket_name = format (0, "%s/%s", vlib_unix_get_runtime_dir (),
     889             :                               API_SOCKET_FILENAME);
     890         559 :   vec_terminate_c_string (sm->socket_name);
     891             : 
     892         559 :   return 0;
     893             : }
     894             : 
     895        7306 : VLIB_CONFIG_FUNCTION (socksvr_config, "socksvr");
     896             : 
     897             : void
     898         559 : vlibsocket_reference ()
     899             : {
     900         559 : }
     901             : 
     902             : /*
     903             :  * fd.io coding-style-patch-verification: ON
     904             :  *
     905             :  * Local Variables:
     906             :  * eval: (c-set-style "gnu")
     907             :  * End:
     908             :  */

Generated by: LCOV version 1.14