summaryrefslogtreecommitdiffstats
path: root/src/vlibmemory/socket_client.c
diff options
context:
space:
mode:
authorDave Barach <dave@barachs.net>2017-09-10 15:04:27 -0400
committerDamjan Marion <dmarion.lists@gmail.com>2017-10-03 11:03:47 +0000
commit59b2565cd91a67ced650739f36129650830211ac (patch)
tree1ae3b8d69d7952500b07186169fb31e0f72ae04e /src/vlibmemory/socket_client.c
parent35ffa3e8f6b032f6e324234d495f769049d8feea (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.c240
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:
+ */