vcl svm: provide apps access to fifo chunks
[vpp.git] / src / plugins / hs_apps / vcl / vcl_test_server.c
index 62292ad..d55fef3 100644 (file)
@@ -38,7 +38,7 @@ typedef struct
   vcl_test_stats_t stats;
   vppcom_endpt_t endpt;
   uint8_t ip[16];
-  vppcom_data_segments_t ds;
+  vppcom_data_segment_t ds[2];
 } vcl_test_server_conn_t;
 
 typedef struct
@@ -180,7 +180,7 @@ vts_server_start_stop (vcl_test_server_worker_t * wrk,
          conn->stats.stop.tv_sec -= VCL_TEST_DELAY_DISCONNECT;
          if (conn->cfg.verbose)
            {
-             sprintf (buf, "SERVER (fd %d) RESULTS", tc->fd);
+             snprintf (buf, sizeof (buf), "SERVER (fd %d) RESULTS", tc->fd);
              vcl_test_stats_dump (buf, &tc->stats, 1 /* show_rx */ ,
                                   is_bi /* show tx */ , conn->cfg.verbose);
            }
@@ -246,12 +246,25 @@ vts_server_rx (vcl_test_server_conn_t * conn, int rx_bytes)
     }
 
   if (vsm->use_ds)
-    vppcom_session_free_segments (conn->fd, conn->ds);
+    vppcom_session_free_segments (conn->fd, rx_bytes);
 
   if (conn->stats.rx_bytes >= conn->cfg.total_bytes)
     clock_gettime (CLOCK_REALTIME, &conn->stats.stop);
 }
 
+static void
+vts_copy_ds (void *buf, vppcom_data_segment_t * ds, u32 max_bytes)
+{
+  uint32_t n_bytes = 0, ds_idx = 0;
+
+  while (n_bytes < max_bytes)
+    {
+      clib_memcpy_fast (buf + n_bytes, ds[ds_idx].data,
+                       clib_min (ds[ds_idx].len, max_bytes - n_bytes));
+      ds_idx += 1;
+    }
+}
+
 static void
 vts_server_echo (vcl_test_server_conn_t * conn, int rx_bytes)
 {
@@ -259,7 +272,7 @@ vts_server_echo (vcl_test_server_conn_t * conn, int rx_bytes)
   int tx_bytes, nbytes, pos;
 
   if (vsm->use_ds)
-    vppcom_data_segment_copy (conn->buf, conn->ds, rx_bytes);
+    vts_copy_ds (conn->buf, conn->ds, rx_bytes);
 
   /* If it looks vaguely like a string, make sure it's terminated */
   pos = rx_bytes < conn->buf_size ? rx_bytes : conn->buf_size - 1;
@@ -277,7 +290,7 @@ vts_server_echo (vcl_test_server_conn_t * conn, int rx_bytes)
 }
 
 static void
-vts_new_client (vcl_test_server_worker_t * wrk)
+vts_new_client (vcl_test_server_worker_t * wrk, int listen_fd)
 {
   vcl_test_server_conn_t *conn;
   struct epoll_event ev;
@@ -290,7 +303,7 @@ vts_new_client (vcl_test_server_worker_t * wrk)
       return;
     }
 
-  client_fd = vppcom_session_accept (wrk->listen_fd, &conn->endpt, 0);
+  client_fd = vppcom_session_accept (listen_fd, &conn->endpt, 0);
   if (client_fd < 0)
     {
       vterr ("vppcom_session_accept()", client_fd);
@@ -298,7 +311,8 @@ vts_new_client (vcl_test_server_worker_t * wrk)
     }
   conn->fd = client_fd;
 
-  vtinf ("Got a connection -- fd = %d (0x%08x)!", client_fd, client_fd);
+  vtinf ("Got a connection -- fd = %d (0x%08x) on listener fd = %d (0x%08x)",
+        client_fd, client_fd, listen_fd, listen_fd);
 
   ev.events = EPOLLIN;
   ev.data.u64 = conn - wrk->conn_pool;
@@ -320,6 +334,7 @@ print_usage_and_exit (void)
           "  -h               Print this message and exit.\n"
           "  -6               Use IPv6\n"
           "  -w <num>         Number of workers\n"
+          "  -p <PROTO>       Use <PROTO> transport layer\n"
           "  -D               Use UDP transport layer\n"
           "  -L               Use TLS transport layer\n");
   exit (1);
@@ -371,13 +386,18 @@ vcl_test_server_process_opts (vcl_test_server_main_t * vsm, int argc,
   vsm->cfg.proto = VPPCOM_PROTO_TCP;
 
   opterr = 0;
-  while ((c = getopt (argc, argv, "6DLsw:")) != -1)
+  while ((c = getopt (argc, argv, "6DLsw:p:")) != -1)
     switch (c)
       {
       case '6':
        vsm->cfg.address_ip6 = 1;
        break;
 
+      case 'p':
+       if (vppcom_unformat_proto (&vsm->cfg.proto, optarg))
+         vtwrn ("Invalid vppcom protocol %s, defaulting to TCP", optarg);
+       break;
+
       case 'D':
        vsm->cfg.proto = VPPCOM_PROTO_UDP;
        break;
@@ -399,6 +419,10 @@ vcl_test_server_process_opts (vcl_test_server_main_t * vsm, int argc,
       case '?':
        switch (optopt)
          {
+         case 'w':
+         case 'p':
+           vtwrn ("Option `-%c' requires an argument.", optopt);
+           break;
          default:
            if (isprint (optopt))
              vtwrn ("Unknown option `-%c'.", optopt);
@@ -428,10 +452,24 @@ vcl_test_server_process_opts (vcl_test_server_main_t * vsm, int argc,
   vcl_test_init_endpoint_addr (vsm);
 }
 
+static void
+vts_clean_connected_listeners (vcl_test_server_worker_t * wrk,
+                              int listener_fd)
+{
+  if ((vppcom_session_n_accepted (listener_fd) == 0) &
+      vppcom_session_is_connectable_listener (listener_fd))
+    {
+      vtinf ("Connected Listener fd %x has no more sessions", listener_fd);
+      vppcom_session_close (listener_fd);
+      wrk->nfds--;
+    }
+}
+
 int
 vts_handle_cfg (vcl_test_server_worker_t * wrk, vcl_test_cfg_t * rx_cfg,
                vcl_test_server_conn_t * conn, int rx_bytes)
 {
+  int listener_fd;
   if (rx_cfg->verbose)
     {
       vtinf ("(fd %d): Received a cfg msg!", conn->fd);
@@ -469,9 +507,11 @@ vts_handle_cfg (vcl_test_server_worker_t * wrk, vcl_test_cfg_t * rx_cfg,
     case VCL_TEST_TYPE_EXIT:
       vtinf ("Session fd %d closing!", conn->fd);
       clock_gettime (CLOCK_REALTIME, &conn->stats.stop);
+      listener_fd = vppcom_session_listener (conn->fd);
       vppcom_session_close (conn->fd);
       conn_pool_free (conn);
       wrk->nfds--;
+      vts_clean_connected_listeners (wrk, listener_fd);
       break;
 
     default:
@@ -504,8 +544,13 @@ vts_worker_init (vcl_test_server_worker_t * wrk)
   if (wrk->listen_fd < 0)
     vtfail ("vppcom_session_create()", wrk->listen_fd);
 
+  if (vsm->cfg.proto == VPPCOM_PROTO_UDP)
+    {
+      vppcom_session_attr (wrk->listen_fd, VPPCOM_ATTR_SET_CONNECTED, 0, 0);
+    }
 
-  if (vsm->cfg.proto == VPPCOM_PROTO_TLS)
+  if (vsm->cfg.proto == VPPCOM_PROTO_TLS
+      || vsm->cfg.proto == VPPCOM_PROTO_QUIC)
     {
       vppcom_session_tls_add_cert (wrk->listen_fd, vcl_test_crt_rsa,
                                   vcl_test_crt_rsa_len);
@@ -558,7 +603,7 @@ vts_conn_read_config (vcl_test_server_conn_t * conn)
     {
       /* We could avoid the copy if the first segment is big enough but this
        * just simplifies things */
-      vppcom_data_segment_copy (conn->buf, conn->ds, sizeof (vcl_test_cfg_t));
+      vts_copy_ds (conn->buf, conn->ds, sizeof (vcl_test_cfg_t));
     }
   return (vcl_test_cfg_t *) conn->buf;
 }
@@ -590,7 +635,7 @@ vts_worker_loop (void *arg)
   vcl_test_server_main_t *vsm = &vcl_server_main;
   vcl_test_server_worker_t *wrk = arg;
   vcl_test_server_conn_t *conn;
-  int i, rx_bytes, num_ev;
+  int i, rx_bytes, num_ev, listener_fd;
   vcl_test_cfg_t *rx_cfg;
 
   if (wrk->wrk_index)
@@ -615,8 +660,11 @@ vts_worker_loop (void *arg)
          conn = &wrk->conn_pool[wrk->wait_events[i].data.u32];
          if (wrk->wait_events[i].events & (EPOLLHUP | EPOLLRDHUP))
            {
+             vtinf ("Closing session %d on HUP", conn->fd);
+             listener_fd = vppcom_session_listener (conn->fd);
              vppcom_session_close (conn->fd);
-             wrk->nfds -= 1;
+             wrk->nfds--;
+             vts_clean_connected_listeners (wrk, listener_fd);
              if (!wrk->nfds)
                {
                  vtinf ("All client connections closed\n");
@@ -626,7 +674,12 @@ vts_worker_loop (void *arg)
            }
          if (wrk->wait_events[i].data.u32 == ~0)
            {
-             vts_new_client (wrk);
+             vts_new_client (wrk, wrk->listen_fd);
+             continue;
+           }
+         else if (vppcom_session_is_connectable_listener (conn->fd))
+           {
+             vts_new_client (wrk, conn->fd);
              continue;
            }
 
@@ -652,7 +705,7 @@ vts_worker_loop (void *arg)
                  if (rx_cfg->magic == VCL_TEST_CFG_CTRL_MAGIC)
                    {
                      if (vsm->use_ds)
-                       vppcom_session_free_segments (conn->fd, conn->ds);
+                       vppcom_session_free_segments (conn->fd, rx_bytes);
                      vts_handle_cfg (wrk, rx_cfg, conn, rx_bytes);
                      if (!wrk->nfds)
                        {