diff options
author | Dave Barach <dave@barachs.net> | 2017-09-10 15:04:27 -0400 |
---|---|---|
committer | Damjan Marion <dmarion.lists@gmail.com> | 2017-10-03 11:03:47 +0000 |
commit | 59b2565cd91a67ced650739f36129650830211ac (patch) | |
tree | 1ae3b8d69d7952500b07186169fb31e0f72ae04e /src/vlibmemory/socket_client.c | |
parent | 35ffa3e8f6b032f6e324234d495f769049d8feea (diff) |
Repair vlib API socket server
- Teach vpp_api_test to send/receive API messages over sockets
- Add memfd-based shared memory
- Add api messages to create memfd-based shared memory segments
- vpp_api_test supports both socket and shared memory segment connections
- vpp_api_test pivot from socket to shared memory API messaging
- add socket client support to libvlibclient.so
- dead client reaper sends ping messages, container-friendly
- dead client reaper falls back to kill (<pid>, 0) live checking
if e.g. a python app goes silent for tens of seconds
- handle ping messages in python client support code
- teach show api ring about pairwise shared-memory segments
- fix ip probing of already resolved destinations (VPP-998)
We'll need this work to implement proper host-stack client isolation
Change-Id: Ic23b65f75c854d0393d9a2e9d6b122a9551be769
Signed-off-by: Dave Barach <dave@barachs.net>
Signed-off-by: Dave Wallace <dwallacelf@gmail.com>
Signed-off-by: Florin Coras <fcoras@cisco.com>
Diffstat (limited to 'src/vlibmemory/socket_client.c')
-rw-r--r-- | src/vlibmemory/socket_client.c | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/src/vlibmemory/socket_client.c b/src/vlibmemory/socket_client.c new file mode 100644 index 00000000000..8519e7f5f7c --- /dev/null +++ b/src/vlibmemory/socket_client.c @@ -0,0 +1,240 @@ +/* + *------------------------------------------------------------------ + * socket_client.c - API message handling over sockets, client code. + * + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <setjmp.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include <signal.h> +#include <pthread.h> +#include <unistd.h> +#include <time.h> +#include <fcntl.h> +#include <string.h> +#include <vppinfra/clib.h> +#include <vppinfra/vec.h> +#include <vppinfra/hash.h> +#include <vppinfra/bitmap.h> +#include <vppinfra/fifo.h> +#include <vppinfra/time.h> +#include <vppinfra/mheap.h> +#include <vppinfra/heap.h> +#include <vppinfra/pool.h> +#include <vppinfra/format.h> + +#include <vlib/vlib.h> +#include <vlib/unix/unix.h> +#include <vlibmemory/api.h> + +#include <vlibmemory/vl_memory_msg_enum.h> + +#define vl_typedefs /* define message structures */ +#include <vlibmemory/vl_memory_api_h.h> +#undef vl_typedefs + +#define vl_endianfun /* define message structures */ +#include <vlibmemory/vl_memory_api_h.h> +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) clib_warning (__VA_ARGS__) +#define vl_printfun +#include <vlibmemory/vl_memory_api_h.h> +#undef vl_printfun + +socket_client_main_t socket_client_main; + +/* Debug aid */ +u32 vl (void *p) __attribute__ ((weak)); +u32 +vl (void *p) +{ + return vec_len (p); +} + +void +vl_socket_client_read_reply (socket_client_main_t * scm) +{ + int n, current_rx_index; + msgbuf_t *mbp; + + if (scm->socket_fd == 0 || scm->socket_enable == 0) + return; + + mbp = 0; + + while (1) + { + current_rx_index = vec_len (scm->socket_rx_buffer); + while (vec_len (scm->socket_rx_buffer) < + sizeof (*mbp) + 2 /* msg id */ ) + { + vec_validate (scm->socket_rx_buffer, current_rx_index + + scm->socket_buffer_size - 1); + _vec_len (scm->socket_rx_buffer) = current_rx_index; + n = read (scm->socket_fd, scm->socket_rx_buffer + current_rx_index, + scm->socket_buffer_size); + if (n < 0) + { + clib_unix_warning ("socket_read"); + return; + } + _vec_len (scm->socket_rx_buffer) += n; + } + +#if CLIB_DEBUG > 1 + if (n > 0) + clib_warning ("read %d bytes", n); +#endif + + if (mbp == 0) + mbp = (msgbuf_t *) (scm->socket_rx_buffer); + + if (vec_len (scm->socket_rx_buffer) >= ntohl (mbp->data_len) + + sizeof (*mbp)) + { + vl_msg_api_socket_handler ((void *) (mbp->data)); + + if (vec_len (scm->socket_rx_buffer) == ntohl (mbp->data_len) + + sizeof (*mbp)) + _vec_len (scm->socket_rx_buffer) = 0; + else + vec_delete (scm->socket_rx_buffer, ntohl (mbp->data_len) + + sizeof (*mbp), 0); + mbp = 0; + + /* Quit if we're out of data, and not expecting a ping reply */ + if (vec_len (scm->socket_rx_buffer) == 0 + && scm->control_pings_outstanding == 0) + break; + } + } +} + +int +vl_socket_client_connect (socket_client_main_t * scm, char *socket_path, + char *client_name, u32 socket_buffer_size) +{ + char buffer[256]; + char *rdptr; + int n, total_bytes; + vl_api_sockclnt_create_reply_t *rp; + vl_api_sockclnt_create_t *mp; + clib_socket_t *sock = &scm->client_socket; + msgbuf_t *mbp; + clib_error_t *error; + + /* Already connected? */ + if (scm->socket_fd) + return (-2); + + /* bogus call? */ + if (socket_path == 0 || client_name == 0) + return (-3); + + sock->config = socket_path; + sock->flags = CLIB_SOCKET_F_IS_CLIENT | CLIB_SOCKET_F_SEQPACKET; + + error = clib_socket_init (sock); + + if (error) + { + clib_error_report (error); + return (-1); + } + + scm->socket_fd = sock->fd; + + mbp = (msgbuf_t *) buffer; + mbp->q = 0; + mbp->data_len = ntohl (sizeof (*mp)); + mbp->gc_mark_timestamp = 0; + + mp = (vl_api_sockclnt_create_t *) mbp->data; + mp->_vl_msg_id = ntohs (VL_API_SOCKCLNT_CREATE); + strncpy ((char *) mp->name, client_name, sizeof (mp->name) - 1); + mp->name[sizeof (mp->name) - 1] = 0; + mp->context = 0xfeedface; + + n = write (scm->socket_fd, mbp, sizeof (*mbp) + ntohl (mbp->data_len)); + if (n < 0) + { + clib_unix_warning ("socket write (msg)"); + return (-1); + } + + memset (buffer, 0, sizeof (buffer)); + + total_bytes = 0; + rdptr = buffer; + do + { + n = read (scm->socket_fd, rdptr, sizeof (buffer) - (rdptr - buffer)); + if (n < 0) + { + clib_unix_warning ("socket read"); + } + total_bytes += n; + rdptr += n; + } + while (total_bytes < sizeof (vl_api_sockclnt_create_reply_t) + + sizeof (msgbuf_t)); + + rp = (vl_api_sockclnt_create_reply_t *) (buffer + sizeof (msgbuf_t)); + if (ntohs (rp->_vl_msg_id) != VL_API_SOCKCLNT_CREATE_REPLY) + { + clib_warning ("connect reply got msg id %d\n", ntohs (rp->_vl_msg_id)); + return (-1); + } + + /* allocate tx, rx buffers */ + scm->socket_buffer_size = socket_buffer_size ? socket_buffer_size : + SOCKET_CLIENT_DEFAULT_BUFFER_SIZE; + vec_validate (scm->socket_tx_buffer, scm->socket_buffer_size - 1); + vec_validate (scm->socket_rx_buffer, scm->socket_buffer_size - 1); + _vec_len (scm->socket_rx_buffer) = 0; + scm->socket_enable = 1; + + return (0); +} + +void +vl_socket_client_disconnect (socket_client_main_t * scm) +{ + if (scm->socket_fd && (close (scm->socket_fd) < 0)) + clib_unix_warning ("close"); + scm->socket_fd = 0; +} + +void +vl_socket_client_enable_disable (socket_client_main_t * scm, int enable) +{ + scm->socket_enable = enable; +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ |