STATS: Separate socket for fd exchange. 53/13053/3
authorOle Troan <ot@cisco.com>
Thu, 14 Jun 2018 12:42:14 +0000 (14:42 +0200)
committerDave Barach <openvpp@barachs.net>
Fri, 15 Jun 2018 12:16:32 +0000 (12:16 +0000)
stats { interval <no> socket-name <name> | default }
Where the default socket is in /run/vpp/stats.sock

Change-Id: Idd501b328c662804d4ccd58034b0ea6b8aa1f89a
Signed-off-by: Ole Troan <ot@cisco.com>
src/vat/api_format.c
src/vpp/app/stat_client.c
src/vpp/app/stat_client.h
src/vpp/stats/stats.api
src/vpp/stats/stats.c
src/vpp/stats/stats.h

index b9f0804..f2d10b7 100644 (file)
@@ -5930,8 +5930,7 @@ _(SESSION_RULE_ADD_DEL_REPLY, session_rule_add_del_reply)         \
 _(SESSION_RULES_DETAILS, session_rules_details)                                \
 _(IP_CONTAINER_PROXY_ADD_DEL_REPLY, ip_container_proxy_add_del_reply)  \
 _(OUTPUT_ACL_SET_INTERFACE_REPLY, output_acl_set_interface_reply)       \
-_(QOS_RECORD_ENABLE_DISABLE_REPLY, qos_record_enable_disable_reply)    \
-_(MAP_STATS_SEGMENT_REPLY, map_stats_segment_reply)
+_(QOS_RECORD_ENABLE_DISABLE_REPLY, qos_record_enable_disable_reply)
 
 #define foreach_standalone_reply_msg                                   \
 _(SW_INTERFACE_EVENT, sw_interface_event)                               \
@@ -22531,92 +22530,6 @@ api_app_namespace_add_del (vat_main_t * vam)
   return ret;
 }
 
-static void vl_api_map_stats_segment_reply_t_handler
-  (vl_api_map_stats_segment_reply_t * mp)
-{
-#if VPP_API_TEST_BUILTIN == 0
-  vat_main_t *vam = &vat_main;
-  ssvm_private_t *ssvmp = &vam->stat_segment;
-  ssvm_shared_header_t *shared_header;
-  socket_client_main_t *scm = vam->socket_client_main;
-  int rv = ntohl (mp->retval);
-  int my_fd, retval;
-  clib_error_t *error;
-
-  vam->retval = rv;
-
-  if (rv != 0)
-    {
-      vam->result_ready = 1;
-      return;
-    }
-
-  /*
-   * Check the socket for the magic fd
-   */
-  error = vl_sock_api_recv_fd_msg (scm->socket_fd, &my_fd, 5);
-  if (error)
-    {
-      clib_error_report (error);
-      vam->retval = -99;
-      vam->result_ready = 1;
-      return;
-    }
-
-  memset (ssvmp, 0, sizeof (*ssvmp));
-  ssvmp->fd = my_fd;
-
-  /* Note: this closes memfd.fd */
-  retval = ssvm_slave_init_memfd (ssvmp);
-  if (retval)
-    {
-      clib_warning ("WARNING: segment map returned %d", retval);
-      vam->retval = -99;
-      vam->result_ready = 1;
-      return;
-    }
-  else
-    errmsg ("stat segment mapped OK...");
-
-  ASSERT (ssvmp && ssvmp->sh);
-
-  /* Pick up the segment lock from the shared memory header */
-  shared_header = ssvmp->sh;
-  vam->stat_segment_lockp = (clib_spinlock_t *) (shared_header->opaque[0]);
-  vam->retval = 0;
-  vam->result_ready = 1;
-#endif
-}
-
-static void vl_api_map_stats_segment_reply_t_handler_json
-  (vl_api_map_stats_segment_reply_t * mp)
-{
-#if VPP_API_TEST_BUILTIN == 0
-  vat_main_t *vam = &vat_main;
-  clib_warning ("not implemented");
-  vam->retval = -99;
-  vam->result_ready = 1;
-#endif
-}
-
-static int
-api_map_stats_segment (vat_main_t * vam)
-{
-#if VPP_API_TEST_BUILTIN == 0
-  vl_api_map_stats_segment_t *mp;
-  int ret;
-
-  M (MAP_STATS_SEGMENT, mp);
-  S (mp);
-  W (ret);
-
-  return ret;
-#else
-  errmsg ("api unavailable");
-  return -99;
-#endif
-}
-
 static int
 api_sock_init_shm (vat_main_t * vam)
 {
@@ -24063,8 +23976,7 @@ _(ip_container_proxy_add_del, "[add|del] <address> <sw_if_index>")      \
 _(output_acl_set_interface,                                             \
   "<intfc> | sw_if_index <nn> [ip4-table <nn>] [ip6-table <nn>]\n"      \
   "  [l2-table <nn>] [del]")                                            \
-_(qos_record_enable_disable, "<record-source> <intfc> | sw_if_index <id> [disable]") \
-_(map_stats_segment, "<no-args>")
+_(qos_record_enable_disable, "<record-source> <intfc> | sw_if_index <id> [disable]")
 
 /* List of command functions, CLI names map directly to functions */
 #define foreach_cli_function                                    \
index b3dee53..0ee78d2 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *------------------------------------------------------------------
- * api_format.c
+ * stat_client.c
  *
  * Copyright (c) 2018 Cisco and/or its affiliates.
  * Licensed under the Apache License, Version 2.0 (the "License");
 
 #include <vpp/app/stat_client.h>
 
-#include <vpp/api/vpe_msg_enum.h>
-
-#define vl_typedefs            /* define message structures */
-#include <vpp/api/vpe_all_api_h.h>
-#undef vl_typedefs
-
-#define vl_endianfun           /* define endian fcns */
-#include <vpp/api/vpe_all_api_h.h>
-#undef vl_endianfun
-
-/* instantiate all the print functions we know about */
-#define vl_print(handle, ...) fformat (handle, __VA_ARGS__)
-#define vl_printfun
-#include <vpp/api/vpe_all_api_h.h>
-#undef vl_printfun
-
 stat_client_main_t stat_client_main;
 
-static void vl_api_map_stats_segment_reply_t_handler
-  (vl_api_map_stats_segment_reply_t * mp)
+static int
+stat_segment_connect (stat_client_main_t * sm)
 {
-  stat_client_main_t *sm = &stat_client_main;
   ssvm_private_t *ssvmp = &sm->stat_segment;
   ssvm_shared_header_t *shared_header;
-  socket_client_main_t *scm = sm->socket_client_main;
-  int rv = ntohl (mp->retval);
-  int my_fd, retval;
-  clib_error_t *error;
-
-  if (rv != 0)
+  clib_socket_t s = { 0 };
+  clib_error_t *err;
+  int fd = -1, retval;
+
+  s.config = (char *) sm->socket_name;
+  s.flags = CLIB_SOCKET_F_IS_CLIENT | CLIB_SOCKET_F_SEQPACKET;
+  err = clib_socket_init (&s);
+  if (err)
     {
-      fformat (stderr, "ERROR mapping stats segment: %d", rv);
+      clib_error_report (err);
       exit (1);
     }
-
-  /*
-   * Check the socket for the magic fd
-   */
-  error = vl_sock_api_recv_fd_msg (scm->socket_fd, &my_fd, 5);
-  if (error)
+  err = clib_socket_recvmsg (&s, 0, 0, &fd, 1);
+  if (err)
     {
-      clib_error_report (error);
-      exit (1);
+      clib_error_report (err);
+      return -1;
     }
+  clib_socket_close (&s);
 
   memset (ssvmp, 0, sizeof (*ssvmp));
-  ssvmp->fd = my_fd;
+  ssvmp->fd = fd;
 
   /* Note: this closes memfd.fd */
   retval = ssvm_slave_init_memfd (ssvmp);
   if (retval)
     {
       clib_warning ("WARNING: segment map returned %d", retval);
-      exit (1);
+      return -1;
     }
 
   fformat (stdout, "Stat segment mapped OK...\n");
@@ -84,60 +66,6 @@ static void vl_api_map_stats_segment_reply_t_handler
   sm->stat_segment_lockp = (clib_spinlock_t *) (shared_header->opaque[0]);
   sm->segment_ready = 1;
 
-  /* No need to keep the socket API connection open */
-  close (sm->socket_client_main->socket_fd);
-}
-
-#define foreach_api_reply_msg \
-_(MAP_STATS_SEGMENT_REPLY, map_stats_segment_reply)
-
-static void
-vpp_api_hookup (void)
-{
-#define _(N,n)                                                  \
-    vl_msg_api_set_handlers(VL_API_##N, #n,                     \
-                           vl_api_##n##_t_handler,             \
-                           vl_noop_handler,                     \
-                           vl_api_##n##_t_endian,               \
-                           vl_api_##n##_t_print,                \
-                           sizeof(vl_api_##n##_t), 1);
-  foreach_api_reply_msg;
-#undef _
-}
-
-static int
-connect_to_vpp (stat_client_main_t * sm)
-{
-  int rv;
-  vl_api_map_stats_segment_t *mp;
-  api_main_t *am = &api_main;
-
-  sm->socket_client_main = &socket_client_main;
-
-  rv = vl_socket_client_connect ((char *) sm->socket_name,
-                                "stat_client",
-                                0 /* default socket rx, tx buffer */ );
-  if (rv)
-    {
-      fformat (stderr, "Error connecting to vpp...\n");
-      exit (1);
-    }
-
-  /* Hook up reply handler */
-  vpp_api_hookup ();
-
-  /* Map the stats segment */
-  mp = vl_socket_client_msg_alloc (sizeof (*mp));
-  mp->_vl_msg_id = ntohs (VL_API_MAP_STATS_SEGMENT);
-  mp->client_index = am->my_client_index;
-  mp->context = 0xdeaddabe;
-
-  /* Send the message */
-  vl_socket_client_write ();
-
-  /* Wait for a reply, process it.. */
-  vl_socket_client_read (5 /* timeout in seconds */ );
-
   return 0;
 }
 
@@ -399,24 +327,23 @@ stat_poll_loop (stat_client_main_t * sm)
     }
 }
 
-
 int
 main (int argc, char **argv)
 {
   unformat_input_t _argv, *a = &_argv;
   stat_client_main_t *sm = &stat_client_main;
-  u8 *socket_name;
+  u8 *stat_segment_name;
   int rv;
 
   clib_mem_init (0, 128 << 20);
 
   unformat_init_command_line (a, argv);
 
-  socket_name = (u8 *) API_SOCKET_FILE;
+  stat_segment_name = (u8 *) STAT_SEGMENT_SOCKET_FILE;
 
   while (unformat_check_input (a) != UNFORMAT_END_OF_INPUT)
     {
-      if (unformat (a, "socket-name %s", &socket_name))
+      if (unformat (a, "socket-name %s", &stat_segment_name))
        ;
       else
        {
@@ -425,14 +352,13 @@ main (int argc, char **argv)
        }
     }
 
-  sm->socket_name = socket_name;
-
-  rv = connect_to_vpp (sm);
+  sm->socket_name = stat_segment_name;
 
+  rv = stat_segment_connect (sm);
   if (rv)
     {
       fformat (stderr, "Couldn't connect to vpp, does %s exist?\n",
-              socket_name);
+              stat_segment_name);
       exit (1);
     }
 
index 87e5409..97bd3f9 100644 (file)
 #include <vlib/vlib.h>
 #include <vppinfra/socket.h>
 #include <svm/ssvm.h>
-#include <vlibapi/api.h>
-#include <vlibmemory/api.h>
-#include <vlibmemory/socket_api.h>
-#include <vlibmemory/socket_client.h>
 #include <vpp/stats/stats.h>
 
 typedef struct
@@ -50,9 +46,6 @@ typedef struct
   /* mapped stats segment object */
   ssvm_private_t stat_segment;
 
-  /* Socket client object */
-  socket_client_main_t *socket_client_main;
-
   /* Spinlock for the stats segment */
   clib_spinlock_t *stat_segment_lockp;
 
index bd1c3f6..72e03b0 100644 (file)
@@ -58,8 +58,6 @@ service {
   rpc want_udp_encap_stats
     returns want_udp_encap_stats_reply
     events vnet_udp_encap_counters;
-  rpc map_stats_segment
-    returns map_stats_segment_reply;
 };
 
 /** \brief Want Stats, enable/disable ALL stats updates
@@ -474,12 +472,6 @@ manual_print manual_endian define vnet_udp_encap_counters
   vl_api_udp_encap_counter_t c[count];
 };
 
-autoreply define map_stats_segment
-{
-  u32 client_index;
-  u32 context;
-}; 
-
 
 /*
  * Local Variables:
index 31cfc33..452871f 100644 (file)
@@ -65,8 +65,7 @@ _(VNET_IP6_NBR_COUNTERS, vnet_ip6_nbr_counters)                         \
 _(WANT_IP6_NBR_STATS, want_ip6_nbr_stats)                               \
 _(VNET_GET_SUMMARY_STATS, vnet_get_summary_stats)                       \
 _(STATS_GET_POLLER_DELAY, stats_get_poller_delay)                       \
-_(WANT_UDP_ENCAP_STATS, want_udp_encap_stats)                           \
-_(MAP_STATS_SEGMENT, map_stats_segment)
+_(WANT_UDP_ENCAP_STATS, want_udp_encap_stats)
 
 #define vl_msg_name_crc_list
 #include <vpp/stats/stats.api.h>
@@ -2258,14 +2257,74 @@ stats_set_poller_delay (u32 poller_delay_sec)
     }
 }
 
+/*
+ * Accept connection on the socket and exchange the fd for the shared
+ * memory segment.
+ */
+static clib_error_t *
+stats_socket_accept_ready (clib_file_t * uf)
+{
+  stats_main_t *sm = &stats_main;
+  ssvm_private_t *ssvmp = &sm->stat_segment;
+  clib_error_t *err;
+  clib_socket_t client = { 0 };
+
+  err = clib_socket_accept (sm->socket, &client);
+  if (err)
+    {
+      clib_error_report (err);
+      return err;
+    }
+
+  /* Send the fd across and close */
+  err = clib_socket_sendmsg (&client, 0, 0, &ssvmp->fd, 1);
+  if (err)
+    clib_error_report (err);
+  clib_socket_close (&client);
+
+  return 0;
+}
+
+static void
+stats_segment_socket_init (void)
+{
+  stats_main_t *sm = &stats_main;
+  clib_error_t *error;
+  clib_socket_t *s = clib_mem_alloc (sizeof (clib_socket_t));
+
+  s->config = (char *) sm->socket_name;
+  s->flags = CLIB_SOCKET_F_IS_SERVER | CLIB_SOCKET_F_SEQPACKET |
+    CLIB_SOCKET_F_ALLOW_GROUP_WRITE | CLIB_SOCKET_F_PASSCRED;
+  if ((error = clib_socket_init (s)))
+    {
+      clib_error_report (error);
+      return;
+    }
+
+  clib_file_t template = { 0 };
+  clib_file_main_t *fm = &file_main;
+  template.read_function = stats_socket_accept_ready;
+  template.file_descriptor = s->fd;
+  template.description =
+    format (0, "stats segment listener %s", STAT_SEGMENT_SOCKET_FILE);
+  clib_file_add (fm, &template);
+
+  sm->socket = s;
+}
+
 static clib_error_t *
 stats_config (vlib_main_t * vm, unformat_input_t * input)
 {
+  stats_main_t *sm = &stats_main;
   u32 sec;
 
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
-      if (unformat (input, "interval %u", &sec))
+      if (unformat (input, "socket-name %s", &sm->socket_name))
+       ;
+      else if (unformat (input, "default"))
+       sm->socket_name = format (0, "%s", STAT_SEGMENT_SOCKET_FILE);
+      else if (unformat (input, "interval %u", &sec))
        {
          int rv = stats_set_poller_delay (sec);
          if (rv)
@@ -2274,7 +2333,6 @@ stats_config (vlib_main_t * vm, unformat_input_t * input)
                                        "`stats_set_poller_delay' API call failed, rv=%d:%U",
                                        (int) rv, format_vnet_api_errno, rv);
            }
-         return 0;
        }
       else
        {
@@ -2282,6 +2340,10 @@ stats_config (vlib_main_t * vm, unformat_input_t * input)
                                    format_unformat_error, input);
        }
     }
+
+  if (sm->socket_name)
+    stats_segment_socket_init ();
+
   return 0;
 }
 
@@ -2989,50 +3051,6 @@ stats_memclnt_delete_callback (u32 client_index)
 #define vl_api_vnet_ip4_nbr_counters_t_print vl_noop_handler
 #define vl_api_vnet_ip6_nbr_counters_t_endian vl_noop_handler
 #define vl_api_vnet_ip6_nbr_counters_t_print vl_noop_handler
-#define vl_api_map_stats_segment_t_print vl_noop_handler
-
-static void
-vl_api_map_stats_segment_t_handler (vl_api_map_stats_segment_t * mp)
-{
-  vl_api_map_stats_segment_reply_t *rmp;
-  stats_main_t *sm = &stats_main;
-  ssvm_private_t *ssvmp = &sm->stat_segment;
-  vl_api_registration_t *regp;
-  api_main_t *am = &api_main;
-  clib_file_t *cf;
-  vl_api_shm_elem_config_t *config = 0;
-  vl_shmem_hdr_t *shmem_hdr;
-  int rv = 0;
-
-  regp = vl_api_client_index_to_registration (mp->client_index);
-  if (regp == 0)
-    {
-      clib_warning ("API client disconnected");
-      return;
-    }
-  if (regp->registration_type != REGISTRATION_TYPE_SOCKET_SERVER)
-    rv = VNET_API_ERROR_INVALID_REGISTRATION;
-
-  rmp = vl_msg_api_alloc (sizeof (*rmp));
-  rmp->_vl_msg_id = htons (VL_API_MAP_STATS_SEGMENT_REPLY);
-  rmp->context = mp->context;
-  rmp->retval = htonl (rv);
-
-  vl_api_send_msg (regp, (u8 *) rmp);
-
-  if (rv != 0)
-    return;
-
-  /*
-   * We need the reply message to make it out the back door
-   * before we send the magic fd message so force a flush
-   */
-  cf = vl_api_registration_file (regp);
-  cf->write_function (cf);
-
-  /* Send the magic "here's your sign (aka fd)" socket message */
-  vl_sock_api_send_fd_msg (cf->file_descriptor, ssvmp->fd);
-}
 
 static clib_error_t *
 stats_init (vlib_main_t * vm)
index 262304e..3b6f781 100644 (file)
@@ -29,6 +29,9 @@
 #include <svm/queue.h>
 #include <svm/ssvm.h>
 
+/* Default socket to exchange segment fd */
+#define STAT_SEGMENT_SOCKET_FILE "/run/vpp/stats.sock"
+
 typedef struct
 {
   volatile u32 lock;
@@ -162,6 +165,8 @@ typedef struct
   ssvm_private_t stat_segment;
   uword *counter_vector_by_name;
   clib_spinlock_t *stat_segment_lockp;
+  clib_socket_t *socket;
+  u8 *socket_name;
 
   /* Pointers to scalar stats maintained by the stat thread */
   f64 *input_rate_ptr;