hsa: custom proto vfts for vcl tests 30/32130/12
authorFlorin Coras <fcoras@cisco.com>
Tue, 27 Apr 2021 01:43:20 +0000 (18:43 -0700)
committerDamjan Marion <dmarion@me.com>
Tue, 27 Apr 2021 22:35:39 +0000 (22:35 +0000)
Define custom connect, listen, accept, close handlers for transport
protos under test.

Type: improvement

Signed-off-by: Florin Coras <fcoras@cisco.com>
Change-Id: Ifa260d05917256c590f29078f465ce47c576cbc3

src/plugins/hs_apps/CMakeLists.txt
src/plugins/hs_apps/vcl/vcl_test.h
src/plugins/hs_apps/vcl/vcl_test_client.c
src/plugins/hs_apps/vcl/vcl_test_protos.c [new file with mode: 0644]
src/plugins/hs_apps/vcl/vcl_test_server.c

index da86512..1f47482 100644 (file)
@@ -47,8 +47,6 @@ endif(VPP_BUILD_HS_SAPI_APPS)
 option(VPP_BUILD_VCL_TESTS "Build vcl tests." ON)
 if(VPP_BUILD_VCL_TESTS)
   foreach(test
-    vcl_test_server
-    vcl_test_client
     sock_test_server
     sock_test_client
   )
@@ -58,4 +56,17 @@ if(VPP_BUILD_VCL_TESTS)
       NO_INSTALL
     )
   endforeach()
+
+  foreach(test
+    vcl_test_server
+    vcl_test_client
+  )
+    add_vpp_executable(${test}
+      SOURCES
+      "vcl/${test}.c"
+      vcl/vcl_test_protos.c
+      LINK_LIBRARIES vppcom pthread
+      NO_INSTALL
+    )
+  endforeach()
 endif(VPP_BUILD_VCL_TESTS)
index 386e968..18e3c00 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2017-2021 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:
@@ -19,6 +19,7 @@
 #include <netdb.h>
 #include <errno.h>
 #include <stdlib.h>
+#include <stdio.h>
 #include <string.h>
 #include <vcl/vppcom.h>
 
@@ -121,14 +122,16 @@ typedef struct
   struct timespec stop;
 } vcl_test_stats_t;
 
-typedef struct
+typedef struct vcl_test_session
 {
   uint8_t is_alloc;
   uint8_t is_open;
   int fd;
+  int (*read) (struct vcl_test_session *ts, void *buf, uint32_t buflen);
+  int (*write) (struct vcl_test_session *ts, void *buf, uint32_t buflen);
   uint32_t txbuf_size;
-  char *txbuf;
   uint32_t rxbuf_size;
+  char *txbuf;
   char *rxbuf;
   vcl_test_cfg_t cfg;
   vcl_test_stats_t stats;
@@ -138,64 +141,45 @@ typedef struct
   vppcom_data_segment_t ds[2];
 } vcl_test_session_t;
 
-/*
- * TLS server cert and keys to be used for testing only
- */
-char vcl_test_crt_rsa[] =
-  "-----BEGIN CERTIFICATE-----\r\n"
-  "MIID5zCCAs+gAwIBAgIJALeMYCEHrTtJMA0GCSqGSIb3DQEBCwUAMIGJMQswCQYD\r\n"
-  "VQQGEwJVUzELMAkGA1UECAwCQ0ExETAPBgNVBAcMCFNhbiBKb3NlMQ4wDAYDVQQK\r\n"
-  "DAVDaXNjbzEOMAwGA1UECwwFZmQuaW8xFjAUBgNVBAMMDXRlc3R0bHMuZmQuaW8x\r\n"
-  "IjAgBgkqhkiG9w0BCQEWE3ZwcC1kZXZAbGlzdHMuZmQuaW8wHhcNMTgwMzA1MjEx\r\n"
-  "NTEyWhcNMjgwMzAyMjExNTEyWjCBiTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNB\r\n"
-  "MREwDwYDVQQHDAhTYW4gSm9zZTEOMAwGA1UECgwFQ2lzY28xDjAMBgNVBAsMBWZk\r\n"
-  "LmlvMRYwFAYDVQQDDA10ZXN0dGxzLmZkLmlvMSIwIAYJKoZIhvcNAQkBFhN2cHAt\r\n"
-  "ZGV2QGxpc3RzLmZkLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\r\n"
-  "4C1k8a1DuStgggqT4o09fP9sJ2dC54bxhS/Xk2VEfaIZ222WSo4X/syRVfVy9Yah\r\n"
-  "cpI1zJ/RDxaZSFhgA+nPZBrFMsrULkrdAOpOVj8eDEp9JuWdO2ODSoFnCvLxcYWB\r\n"
-  "Yc5kHryJpEaGJl1sFQSesnzMFty/59ta0stk0Fp8r5NhIjWvSovGzPo6Bhz+VS2c\r\n"
-  "ebIZh4x1t2hHaFcgm0qJoJ6DceReWCW8w+yOVovTolGGq+bpb2Hn7MnRSZ2K2NdL\r\n"
-  "+aLXpkZbS/AODP1FF2vTO1mYL290LO7/51vJmPXNKSDYMy5EvILr5/VqtjsFCwRL\r\n"
-  "Q4jcM/+GeHSAFWx4qIv0BwIDAQABo1AwTjAdBgNVHQ4EFgQUWa1SOB37xmT53tZQ\r\n"
-  "aXuLLhRI7U8wHwYDVR0jBBgwFoAUWa1SOB37xmT53tZQaXuLLhRI7U8wDAYDVR0T\r\n"
-  "BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAoUht13W4ya27NVzQuCMvqPWL3VM4\r\n"
-  "3xbPFk02FaGz/WupPu276zGlzJAZrbuDcQowwwU1Ni1Yygxl96s1c2M5rHDTrOKG\r\n"
-  "rK0hbkSFBo+i6I8u4HiiQ4rYmG0Hv6+sXn3of0HsbtDPGgWZoipPWDljPYEURu3e\r\n"
-  "3HRe/Dtsj9CakBoSDzs8ndWaBR+f4sM9Tk1cjD46Gq2T/qpSPXqKxEUXlzhdCAn4\r\n"
-  "twub17Bq2kykHpppCwPg5M+v30tHG/R2Go15MeFWbEJthFk3TZMjKL7UFs7fH+x2\r\n"
-  "wSonXb++jY+KmCb93C+soABBizE57g/KmiR2IxQ/LMjDik01RSUIaM0lLA==\r\n"
-  "-----END CERTIFICATE-----\r\n";
-uint32_t vcl_test_crt_rsa_len = sizeof (vcl_test_crt_rsa);
-
-char vcl_test_key_rsa[] =
-  "-----BEGIN PRIVATE KEY-----\r\n"
-  "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDgLWTxrUO5K2CC\r\n"
-  "CpPijT18/2wnZ0LnhvGFL9eTZUR9ohnbbZZKjhf+zJFV9XL1hqFykjXMn9EPFplI\r\n"
-  "WGAD6c9kGsUyytQuSt0A6k5WPx4MSn0m5Z07Y4NKgWcK8vFxhYFhzmQevImkRoYm\r\n"
-  "XWwVBJ6yfMwW3L/n21rSy2TQWnyvk2EiNa9Ki8bM+joGHP5VLZx5shmHjHW3aEdo\r\n"
-  "VyCbSomgnoNx5F5YJbzD7I5Wi9OiUYar5ulvYefsydFJnYrY10v5otemRltL8A4M\r\n"
-  "/UUXa9M7WZgvb3Qs7v/nW8mY9c0pINgzLkS8guvn9Wq2OwULBEtDiNwz/4Z4dIAV\r\n"
-  "bHioi/QHAgMBAAECggEBAMzGipP8+oT166U+NlJXRFifFVN1DvdhG9PWnOxGL+c3\r\n"
-  "ILmBBC08WQzmHshPemBvR6DZkA1H23cV5JTiLWrFtC00CvhXsLRMrE5+uWotI6yE\r\n"
-  "iofybMroHvD6/X5R510UX9hQ6MHu5ShLR5VZ9zXHz5MpTmB/60jG5dLx+jgcwBK8\r\n"
-  "LuGv2YB/WCUwT9QJ3YU2eaingnXtz/MrFbkbltrqlnBdlD+kTtw6Yac9y1XuuQXc\r\n"
-  "BPeulLNDuPolJVWbUvDBZrpt2dXTgz8ws1sv+wCNE0xwQJsqW4Nx3QkpibUL9RUr\r\n"
-  "CVbKlNfa9lopT6nGKlgX69R/uH35yh9AOsfasro6w0ECgYEA82UJ8u/+ORah+0sF\r\n"
-  "Q0FfW5MTdi7OAUHOz16pUsGlaEv0ERrjZxmAkHA/VRwpvDBpx4alCv0Hc39PFLIk\r\n"
-  "nhSsM2BEuBkTAs6/GaoNAiBtQVE/hN7awNRWVmlieS0go3Y3dzaE9IUMyj8sPOFT\r\n"
-  "5JdJ6BM69PHKCkY3dKdnnfpFEuECgYEA68mRpteunF1mdZgXs+WrN+uLlRrQR20F\r\n"
-  "ZyMYiUCH2Dtn26EzA2moy7FipIIrQcX/j+KhYNGM3e7MU4LymIO29E18mn8JODnH\r\n"
-  "sQOXzBTsf8A4yIVMkcuQD3bfb0JiUGYUPOidTp2N7IJA7+6Yc3vQOyb74lnKnJoO\r\n"
-  "gougPT2wS+cCgYAn7muzb6xFsXDhyW0Tm6YJYBfRS9yAWEuVufINobeBZPSl2cN1\r\n"
-  "Jrnw+HlrfTNbrJWuJmjtZJXUXQ6cVp2rUbjutNyRV4vG6iRwEXYQ40EJdkr1gZpi\r\n"
-  "CHQhuShuuPih2MNAy7EEbM+sXrDjTBR3bFqzuHPzu7dp+BshCFX3lRfAAQKBgGQt\r\n"
-  "K5i7IhCFDjb/+3IPLgOAK7mZvsvZ4eXD33TQ2eZgtut1PXtBtNl17/b85uv293Fm\r\n"
-  "VDISVcsk3eLNS8zIiT6afUoWlxAwXEs0v5WRfjl4radkGvgGiJpJYvyeM67877RB\r\n"
-  "EDSKc/X8ESLfOB44iGvZUEMG6zJFscx9DgN25iQZAoGAbyd+JEWwdVH9/K3IH1t2\r\n"
-  "PBkZX17kNWv+iVM1WyFjbe++vfKZCrOJiyiqhDeEqgrP3AuNMlaaduC3VRC3G5oV\r\n"
-  "Mj1tlhDWQ/qhvKdCKNdIVQYDE75nw+FRWV8yYkHAnXYW3tNoweDIwixE0hkPR1bc\r\n"
-  "oEjPLVNtx8SOj/M4rhaPT3I=\r\n" "-----END PRIVATE KEY-----\r\n";
-uint32_t vcl_test_key_rsa_len = sizeof (vcl_test_key_rsa);
+static __thread int __wrk_index = 0;
+
+static inline int
+vcl_test_worker_index (void)
+{
+  return __wrk_index;
+}
+
+typedef struct
+{
+  int (*init) (vcl_test_cfg_t *cfg);
+  int (*open) (vcl_test_session_t *ts, vppcom_endpt_t *endpt);
+  int (*listen) (vcl_test_session_t *ts, vppcom_endpt_t *endpt);
+  int (*accept) (int listen_fd, vcl_test_session_t *ts);
+  int (*close) (vcl_test_session_t *ts);
+} vcl_test_proto_vft_t;
+
+typedef struct
+{
+  vcl_test_session_t *qsessions;
+  uint32_t n_qsessions;
+  uint32_t n_sessions;
+} vcl_test_wrk_t;
+
+typedef struct
+{
+  const vcl_test_proto_vft_t *protos[VPPCOM_PROTO_DTLS + 1];
+  uint32_t ckpair_index;
+  vcl_test_cfg_t cfg;
+  vcl_test_wrk_t *wrk;
+} vcl_test_main_t;
+
+extern vcl_test_main_t vcl_test_main;
+
+#define VCL_TEST_REGISTER_PROTO(proto, vft)                                   \
+  static void __attribute__ ((constructor)) vcl_test_init_##proto (void)      \
+  {                                                                           \
+    vcl_test_main.protos[proto] = &vft;                                       \
+  }
 
 static inline void
 vcl_test_stats_accumulate (vcl_test_stats_t * accum, vcl_test_stats_t * incr)
index 0033ae6..d87b4d3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2017-2021 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:
@@ -44,25 +44,23 @@ typedef struct
   vcl_test_client_worker_t *workers;
   vppcom_endpt_t server_endpt;
   uint32_t cfg_seq_num;
-  vcl_test_session_t quic_session;
   vcl_test_session_t ctrl_session;
   vcl_test_session_t *sessions;
   uint8_t dump_cfg;
   vcl_test_t post_test;
   uint8_t proto;
   uint32_t n_workers;
-  uint32_t ckpair_index;
   volatile int active_workers;
   struct sockaddr_storage server_addr;
 } vcl_test_client_main_t;
 
-static __thread int __wrk_index = 0;
-
 vcl_test_client_main_t vcl_client_main;
 
 #define vtc_min(a, b) (a < b ? a : b)
 #define vtc_max(a, b) (a > b ? a : b)
 
+vcl_test_main_t vcl_test_main;
+
 static int
 vtc_cfg_sync (vcl_test_session_t * ts)
 {
@@ -75,15 +73,14 @@ vtc_cfg_sync (vcl_test_session_t * ts)
       vtinf ("(fd %d): Sending config to server.", ts->fd);
       vcl_test_cfg_dump (&ts->cfg, 1 /* is_client */ );
     }
-  tx_bytes = vcl_test_write (ts, (uint8_t *) &ts->cfg, sizeof (ts->cfg));
+  tx_bytes = ts->write (ts, &ts->cfg, sizeof (ts->cfg));
   if (tx_bytes < 0)
     {
       vtwrn ("(fd %d): write test cfg failed (%d)!", ts->fd, tx_bytes);
       return tx_bytes;
     }
 
-  rx_bytes =
-    vcl_test_read (ts, (uint8_t *) ts->rxbuf, sizeof (vcl_test_cfg_t));
+  rx_bytes = ts->read (ts, ts->rxbuf, sizeof (vcl_test_cfg_t));
   if (rx_bytes < 0)
     return rx_bytes;
 
@@ -118,121 +115,16 @@ vtc_cfg_sync (vcl_test_session_t * ts)
   return 0;
 }
 
-static int
-vtc_quic_connect_test_sessions (vcl_test_client_worker_t * wrk)
-{
-  vcl_test_client_main_t *vcm = &vcl_client_main;
-  vcl_test_session_t *ts, *tq;
-  uint32_t i, flags, flen;
-  int rv;
-
-  if (wrk->cfg.num_test_sessions < 1 || wrk->cfg.num_test_sessions_perq < 1)
-    {
-      errno = EINVAL;
-      return -1;
-    }
-
-  if (wrk->n_sessions >= wrk->cfg.num_test_sessions)
-    goto done;
-
-  /* Connect Qsessions */
-
-  if (wrk->n_qsessions)
-    wrk->qsessions =
-      realloc (wrk->qsessions,
-              wrk->cfg.num_test_qsessions * sizeof (vcl_test_session_t));
-  else
-    wrk->qsessions =
-      calloc (wrk->cfg.num_test_qsessions, sizeof (vcl_test_session_t));
-
-  if (!wrk->qsessions)
-    {
-      vterr ("failed to alloc Qsessions", -errno);
-      return errno;
-    }
-
-
-  for (i = 0; i < wrk->cfg.num_test_qsessions; i++)
-    {
-      tq = &wrk->qsessions[i];
-      tq->fd = vppcom_session_create (vcm->proto, 0 /* is_nonblocking */ );
-      tq->session_index = i;
-      if (tq->fd < 0)
-       {
-         vterr ("vppcom_session_create()", tq->fd);
-         return tq->fd;
-       }
-
-      /* Connect is blocking */
-      rv = vppcom_session_connect (tq->fd, &vcm->server_endpt);
-      if (rv < 0)
-       {
-         vterr ("vppcom_session_connect()", rv);
-         return rv;
-       }
-      flags = O_NONBLOCK;
-      flen = sizeof (flags);
-      vppcom_session_attr (tq->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
-      vtinf ("Test Qsession %d (fd %d) connected.", i, tq->fd);
-    }
-  wrk->n_qsessions = wrk->cfg.num_test_qsessions;
-
-  /* Connect Stream sessions */
-
-  if (wrk->n_sessions)
-    wrk->sessions =
-      realloc (wrk->sessions,
-              wrk->cfg.num_test_sessions * sizeof (vcl_test_session_t));
-  else
-    wrk->sessions =
-      calloc (wrk->cfg.num_test_sessions, sizeof (vcl_test_session_t));
-
-  if (!wrk->sessions)
-    {
-      vterr ("failed to alloc sessions", -errno);
-      return errno;
-    }
-
-  for (i = 0; i < wrk->cfg.num_test_sessions; i++)
-    {
-      tq = &wrk->qsessions[i / wrk->cfg.num_test_sessions_perq];
-      ts = &wrk->sessions[i];
-      ts->fd = vppcom_session_create (vcm->proto, 1 /* is_nonblocking */ );
-      ts->session_index = i;
-      if (ts->fd < 0)
-       {
-         vterr ("vppcom_session_create()", ts->fd);
-         return ts->fd;
-       }
-
-      rv = vppcom_session_stream_connect (ts->fd, tq->fd);
-      if (rv < 0)
-       {
-         vterr ("vppcom_session_stream_connect()", rv);
-         return rv;
-       }
-
-      vtinf ("Test session %d (fd %d) connected.", i, ts->fd);
-    }
-  wrk->n_sessions = wrk->cfg.num_test_sessions;
-
-done:
-  vtinf ("All test sessions (%d) connected!", wrk->cfg.num_test_sessions);
-  return 0;
-}
-
 static int
 vtc_connect_test_sessions (vcl_test_client_worker_t * wrk)
 {
   vcl_test_client_main_t *vcm = &vcl_client_main;
+  vcl_test_main_t *vt = &vcl_test_main;
+  const vcl_test_proto_vft_t *tp;
   vcl_test_session_t *ts;
   uint32_t n_test_sessions;
-  uint32_t flags, flen;
   int i, rv;
 
-  if (vcm->proto == VPPCOM_PROTO_QUIC)
-    return vtc_quic_connect_test_sessions (wrk);
-
   n_test_sessions = wrk->cfg.num_test_sessions;
   if (n_test_sessions < 1)
     {
@@ -255,34 +147,15 @@ vtc_connect_test_sessions (vcl_test_client_worker_t * wrk)
       return errno;
     }
 
+  tp = vt->protos[vcm->proto];
+
   for (i = 0; i < n_test_sessions; i++)
     {
       ts = &wrk->sessions[i];
-      ts->fd = vppcom_session_create (vcm->proto, 0 /* is_nonblocking */ );
-      if (ts->fd < 0)
-       {
-         vterr ("vppcom_session_create()", ts->fd);
-         return ts->fd;
-       }
-
-      if (vcm->proto == VPPCOM_PROTO_TLS || vcm->proto == VPPCOM_PROTO_DTLS)
-       {
-         uint32_t ckp_len = sizeof (vcm->ckpair_index);
-         vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_CKPAIR,
-                              &vcm->ckpair_index, &ckp_len);
-       }
-
-      /* Connect is blocking */
-      rv = vppcom_session_connect (ts->fd, &vcm->server_endpt);
+      ts->session_index = i;
+      rv = tp->open (&wrk->sessions[i], &vcm->server_endpt);
       if (rv < 0)
-       {
-         vterr ("vppcom_session_connect()", rv);
-         return rv;
-       }
-      flags = O_NONBLOCK;
-      flen = sizeof (flags);
-      vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
-      vtinf ("Test session %d (fd %d) connected.", i, ts->fd);
+       return rv;
     }
   wrk->n_sessions = n_test_sessions;
 
@@ -476,14 +349,13 @@ vtc_worker_loop (void *arg)
          if (FD_ISSET (vppcom_session_index (ts->fd), rfdset)
              && ts->stats.rx_bytes < ts->cfg.total_bytes)
            {
-             (void) vcl_test_read (ts, (uint8_t *) ts->rxbuf, ts->rxbuf_size);
+             (void) ts->read (ts, ts->rxbuf, ts->rxbuf_size);
            }
 
          if (FD_ISSET (vppcom_session_index (ts->fd), wfdset)
              && ts->stats.tx_bytes < ts->cfg.total_bytes)
            {
-             rv =
-               vcl_test_write (ts, (uint8_t *) ts->txbuf, ts->cfg.txbuf_size);
+             rv = ts->write (ts, ts->txbuf, ts->cfg.txbuf_size);
              if (rv < 0)
                {
                  vtwrn ("vppcom_test_write (%d) failed -- aborting test",
@@ -501,8 +373,7 @@ vtc_worker_loop (void *arg)
     }
 exit:
   vtinf ("Worker %d done ...", wrk->wrk_index);
-  if (wrk->cfg.test != VCL_TEST_TYPE_ECHO)
-    vtc_accumulate_stats (wrk, ctrl);
+  vtc_accumulate_stats (wrk, ctrl);
   sleep (VCL_TEST_DELAY_DISCONNECT);
   vtc_worker_sessions_exit (wrk);
   if (wrk->wrk_index)
@@ -558,14 +429,14 @@ vtc_echo_client (vcl_test_client_main_t * vcm)
   cfg->total_bytes = strlen (ctrl->txbuf) + 1;
   memset (&ctrl->stats, 0, sizeof (ctrl->stats));
 
-  rv = vcl_test_write (ctrl, (uint8_t *) ctrl->txbuf, cfg->total_bytes);
+  rv = ctrl->write (ctrl, ctrl->txbuf, cfg->total_bytes);
   if (rv < 0)
     {
       vtwrn ("vppcom_test_write (%d) failed ", ctrl->fd);
       return;
     }
 
-  (void) vcl_test_read (ctrl, (uint8_t *) ctrl->rxbuf, ctrl->rxbuf_size);
+  (void) ctrl->read (ctrl, ctrl->rxbuf, ctrl->rxbuf_size);
 }
 
 static void
@@ -1059,12 +930,50 @@ vtc_ctrl_session_exit (void)
   sleep (1);
 }
 
+static int
+vtc_ctrl_session_init (vcl_test_client_main_t *vcm, vcl_test_session_t *ctrl)
+{
+  int rv;
+
+  ctrl->fd = vppcom_session_create (VPPCOM_PROTO_TCP, 0 /* is_nonblocking */);
+  if (ctrl->fd < 0)
+    {
+      vterr ("vppcom_session_create()", ctrl->fd);
+      return ctrl->fd;
+    }
+
+  vtinf ("Connecting to server...");
+  rv = vppcom_session_connect (ctrl->fd, &vcm->server_endpt);
+  if (rv)
+    {
+      vterr ("vppcom_session_connect()", rv);
+      return rv;
+    }
+  vtinf ("Control session (fd %d) connected.", ctrl->fd);
+
+  ctrl->read = vcl_test_read;
+  ctrl->write = vcl_test_write;
+
+  ctrl->cfg.cmd = VCL_TEST_CMD_SYNC;
+  rv = vtc_cfg_sync (ctrl);
+  if (rv)
+    {
+      vterr ("vtc_cfg_sync()", rv);
+      return rv;
+    }
+
+  ctrl->cfg.ctrl_handle = ((vcl_test_cfg_t *) ctrl->rxbuf)->ctrl_handle;
+  memset (&ctrl->stats, 0, sizeof (ctrl->stats));
+
+  return 0;
+}
+
 int
 main (int argc, char **argv)
 {
   vcl_test_client_main_t *vcm = &vcl_client_main;
   vcl_test_session_t *ctrl = &vcm->ctrl_session;
-  vcl_test_session_t *quic_session = &vcm->quic_session;
+  vcl_test_main_t *vt = &vcl_test_main;
   int rv;
 
   vcm->n_workers = 1;
@@ -1073,27 +982,18 @@ main (int argc, char **argv)
   vtc_process_opts (vcm, argc, argv);
 
   vcm->workers = calloc (vcm->n_workers, sizeof (vcl_test_client_worker_t));
+  vt->wrk = calloc (vcm->n_workers, sizeof (vcl_test_wrk_t));
+
   rv = vppcom_app_create ("vcl_test_client");
   if (rv < 0)
     vtfail ("vppcom_app_create()", rv);
 
-  ctrl->fd = vppcom_session_create (VPPCOM_PROTO_TCP, 0 /* is_nonblocking */);
-  if (ctrl->fd < 0)
-    vtfail ("vppcom_session_create()", ctrl->fd);
-
-  vtinf ("Connecting to server...");
-  rv = vppcom_session_connect (ctrl->fd, &vcm->server_endpt);
-  if (rv)
-    vtfail ("vppcom_session_connect()", rv);
-  vtinf ("Control session (fd %d) connected.", ctrl->fd);
-
-  ctrl->cfg.cmd = VCL_TEST_CMD_SYNC;
-  rv = vtc_cfg_sync (ctrl);
-  if (rv)
-    vtfail ("vtc_cfg_sync()", rv);
+  /* Protos like tls/dtls/quic need init */
+  if (vt->protos[vcm->proto]->init)
+    vt->protos[vcm->proto]->init (&ctrl->cfg);
 
-  ctrl->cfg.ctrl_handle = ((vcl_test_cfg_t *) ctrl->rxbuf)->ctrl_handle;
-  memset (&ctrl->stats, 0, sizeof (ctrl->stats));
+  if ((rv = vtc_ctrl_session_init (vcm, ctrl)))
+    vtfail ("vppcom_session_create() ctrl session", rv);
 
   /* Update ctrl port to data port */
   vcm->server_endpt.port += 1;
@@ -1157,8 +1057,6 @@ main (int argc, char **argv)
     }
 
   vtc_ctrl_session_exit ();
-  if (quic_session)
-    vppcom_session_close (quic_session->fd);
   vppcom_app_destroy ();
   free (vcm->workers);
   return 0;
diff --git a/src/plugins/hs_apps/vcl/vcl_test_protos.c b/src/plugins/hs_apps/vcl/vcl_test_protos.c
new file mode 100644 (file)
index 0000000..d238822
--- /dev/null
@@ -0,0 +1,674 @@
+/*
+ * Copyright (c) 2021 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 <hs_apps/vcl/vcl_test.h>
+
+static int
+vt_tcp_connect (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
+{
+  uint32_t flags, flen;
+  int rv;
+
+  ts->fd = vppcom_session_create (VPPCOM_PROTO_TCP, 0 /* is_nonblocking */);
+  if (ts->fd < 0)
+    {
+      vterr ("vppcom_session_create()", ts->fd);
+      return ts->fd;
+    }
+
+  /* Connect is blocking */
+  rv = vppcom_session_connect (ts->fd, endpt);
+  if (rv < 0)
+    {
+      vterr ("vppcom_session_connect()", rv);
+      return rv;
+    }
+
+  ts->read = vcl_test_read;
+  ts->write = vcl_test_write;
+  flags = O_NONBLOCK;
+  flen = sizeof (flags);
+  vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
+  vtinf ("Test session %d (fd %d) connected.", ts->session_index, ts->fd);
+
+  return 0;
+}
+
+static int
+vt_tcp_listen (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
+{
+  int rv;
+
+  ts->fd = vppcom_session_create (VPPCOM_PROTO_TCP, 0 /* is_nonblocking */);
+  if (ts->fd < 0)
+    {
+      vterr ("vppcom_session_create()", ts->fd);
+      return ts->fd;
+    }
+
+  rv = vppcom_session_bind (ts->fd, endpt);
+  if (rv < 0)
+    {
+      vterr ("vppcom_session_bind()", rv);
+      return rv;
+    }
+
+  rv = vppcom_session_listen (ts->fd, 10);
+  if (rv < 0)
+    {
+      vterr ("vppcom_session_listen()", rv);
+      return rv;
+    }
+
+  return 0;
+}
+
+static int
+vt_tcp_accept (int listen_fd, vcl_test_session_t *ts)
+{
+  int client_fd;
+
+  client_fd = vppcom_session_accept (listen_fd, &ts->endpt, 0);
+  if (client_fd < 0)
+    {
+      vterr ("vppcom_session_accept()", client_fd);
+      return client_fd;
+    }
+  ts->fd = client_fd;
+  ts->is_open = 1;
+  ts->read = vcl_test_read;
+  ts->write = vcl_test_write;
+
+  return 0;
+}
+
+static const vcl_test_proto_vft_t vcl_test_tcp = {
+  .open = vt_tcp_connect,
+  .listen = vt_tcp_listen,
+  .accept = vt_tcp_accept,
+};
+
+VCL_TEST_REGISTER_PROTO (VPPCOM_PROTO_TCP, vcl_test_tcp);
+
+static int
+vt_udp_connect (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
+{
+  uint32_t flags, flen;
+  int rv;
+
+  ts->fd = vppcom_session_create (VPPCOM_PROTO_UDP, 0 /* is_nonblocking */);
+  if (ts->fd < 0)
+    {
+      vterr ("vppcom_session_create()", ts->fd);
+      return ts->fd;
+    }
+
+  /* Connect is blocking */
+  rv = vppcom_session_connect (ts->fd, endpt);
+  if (rv < 0)
+    {
+      vterr ("vppcom_session_connect()", rv);
+      return rv;
+    }
+
+  ts->read = vcl_test_read;
+  ts->write = vcl_test_write;
+  flags = O_NONBLOCK;
+  flen = sizeof (flags);
+  vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
+  vtinf ("Test session %d (fd %d) connected.", ts->session_index, ts->fd);
+
+  return 0;
+}
+
+static int
+vt_udp_listen (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
+{
+  int rv;
+
+  ts->fd = vppcom_session_create (VPPCOM_PROTO_UDP, 0 /* is_nonblocking */);
+  if (ts->fd < 0)
+    {
+      vterr ("vppcom_session_create()", ts->fd);
+      return ts->fd;
+    }
+
+  vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_CONNECTED, 0, 0);
+
+  /* Listen is implicit */
+  rv = vppcom_session_bind (ts->fd, endpt);
+  if (rv < 0)
+    {
+      vterr ("vppcom_session_bind()", rv);
+      return rv;
+    }
+
+  return 0;
+}
+
+static int
+vt_udp_accept (int listen_fd, vcl_test_session_t *ts)
+{
+  int client_fd;
+
+  client_fd = vppcom_session_accept (listen_fd, &ts->endpt, 0);
+  if (client_fd < 0)
+    {
+      vterr ("vppcom_session_accept()", client_fd);
+      return client_fd;
+    }
+  ts->fd = client_fd;
+  ts->is_open = 1;
+  ts->read = vcl_test_read;
+  ts->write = vcl_test_write;
+
+  return 0;
+}
+
+static const vcl_test_proto_vft_t vcl_test_udp = {
+  .open = vt_udp_connect,
+  .listen = vt_udp_listen,
+  .accept = vt_udp_accept,
+};
+
+VCL_TEST_REGISTER_PROTO (VPPCOM_PROTO_UDP, vcl_test_udp);
+
+/*
+ * TLS server cert and keys to be used for testing only
+ */
+static char vcl_test_crt_rsa[] =
+  "-----BEGIN CERTIFICATE-----\r\n"
+  "MIID5zCCAs+gAwIBAgIJALeMYCEHrTtJMA0GCSqGSIb3DQEBCwUAMIGJMQswCQYD\r\n"
+  "VQQGEwJVUzELMAkGA1UECAwCQ0ExETAPBgNVBAcMCFNhbiBKb3NlMQ4wDAYDVQQK\r\n"
+  "DAVDaXNjbzEOMAwGA1UECwwFZmQuaW8xFjAUBgNVBAMMDXRlc3R0bHMuZmQuaW8x\r\n"
+  "IjAgBgkqhkiG9w0BCQEWE3ZwcC1kZXZAbGlzdHMuZmQuaW8wHhcNMTgwMzA1MjEx\r\n"
+  "NTEyWhcNMjgwMzAyMjExNTEyWjCBiTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNB\r\n"
+  "MREwDwYDVQQHDAhTYW4gSm9zZTEOMAwGA1UECgwFQ2lzY28xDjAMBgNVBAsMBWZk\r\n"
+  "LmlvMRYwFAYDVQQDDA10ZXN0dGxzLmZkLmlvMSIwIAYJKoZIhvcNAQkBFhN2cHAt\r\n"
+  "ZGV2QGxpc3RzLmZkLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\r\n"
+  "4C1k8a1DuStgggqT4o09fP9sJ2dC54bxhS/Xk2VEfaIZ222WSo4X/syRVfVy9Yah\r\n"
+  "cpI1zJ/RDxaZSFhgA+nPZBrFMsrULkrdAOpOVj8eDEp9JuWdO2ODSoFnCvLxcYWB\r\n"
+  "Yc5kHryJpEaGJl1sFQSesnzMFty/59ta0stk0Fp8r5NhIjWvSovGzPo6Bhz+VS2c\r\n"
+  "ebIZh4x1t2hHaFcgm0qJoJ6DceReWCW8w+yOVovTolGGq+bpb2Hn7MnRSZ2K2NdL\r\n"
+  "+aLXpkZbS/AODP1FF2vTO1mYL290LO7/51vJmPXNKSDYMy5EvILr5/VqtjsFCwRL\r\n"
+  "Q4jcM/+GeHSAFWx4qIv0BwIDAQABo1AwTjAdBgNVHQ4EFgQUWa1SOB37xmT53tZQ\r\n"
+  "aXuLLhRI7U8wHwYDVR0jBBgwFoAUWa1SOB37xmT53tZQaXuLLhRI7U8wDAYDVR0T\r\n"
+  "BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAoUht13W4ya27NVzQuCMvqPWL3VM4\r\n"
+  "3xbPFk02FaGz/WupPu276zGlzJAZrbuDcQowwwU1Ni1Yygxl96s1c2M5rHDTrOKG\r\n"
+  "rK0hbkSFBo+i6I8u4HiiQ4rYmG0Hv6+sXn3of0HsbtDPGgWZoipPWDljPYEURu3e\r\n"
+  "3HRe/Dtsj9CakBoSDzs8ndWaBR+f4sM9Tk1cjD46Gq2T/qpSPXqKxEUXlzhdCAn4\r\n"
+  "twub17Bq2kykHpppCwPg5M+v30tHG/R2Go15MeFWbEJthFk3TZMjKL7UFs7fH+x2\r\n"
+  "wSonXb++jY+KmCb93C+soABBizE57g/KmiR2IxQ/LMjDik01RSUIaM0lLA==\r\n"
+  "-----END CERTIFICATE-----\r\n";
+static uint32_t vcl_test_crt_rsa_len = sizeof (vcl_test_crt_rsa);
+
+static char vcl_test_key_rsa[] =
+  "-----BEGIN PRIVATE KEY-----\r\n"
+  "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDgLWTxrUO5K2CC\r\n"
+  "CpPijT18/2wnZ0LnhvGFL9eTZUR9ohnbbZZKjhf+zJFV9XL1hqFykjXMn9EPFplI\r\n"
+  "WGAD6c9kGsUyytQuSt0A6k5WPx4MSn0m5Z07Y4NKgWcK8vFxhYFhzmQevImkRoYm\r\n"
+  "XWwVBJ6yfMwW3L/n21rSy2TQWnyvk2EiNa9Ki8bM+joGHP5VLZx5shmHjHW3aEdo\r\n"
+  "VyCbSomgnoNx5F5YJbzD7I5Wi9OiUYar5ulvYefsydFJnYrY10v5otemRltL8A4M\r\n"
+  "/UUXa9M7WZgvb3Qs7v/nW8mY9c0pINgzLkS8guvn9Wq2OwULBEtDiNwz/4Z4dIAV\r\n"
+  "bHioi/QHAgMBAAECggEBAMzGipP8+oT166U+NlJXRFifFVN1DvdhG9PWnOxGL+c3\r\n"
+  "ILmBBC08WQzmHshPemBvR6DZkA1H23cV5JTiLWrFtC00CvhXsLRMrE5+uWotI6yE\r\n"
+  "iofybMroHvD6/X5R510UX9hQ6MHu5ShLR5VZ9zXHz5MpTmB/60jG5dLx+jgcwBK8\r\n"
+  "LuGv2YB/WCUwT9QJ3YU2eaingnXtz/MrFbkbltrqlnBdlD+kTtw6Yac9y1XuuQXc\r\n"
+  "BPeulLNDuPolJVWbUvDBZrpt2dXTgz8ws1sv+wCNE0xwQJsqW4Nx3QkpibUL9RUr\r\n"
+  "CVbKlNfa9lopT6nGKlgX69R/uH35yh9AOsfasro6w0ECgYEA82UJ8u/+ORah+0sF\r\n"
+  "Q0FfW5MTdi7OAUHOz16pUsGlaEv0ERrjZxmAkHA/VRwpvDBpx4alCv0Hc39PFLIk\r\n"
+  "nhSsM2BEuBkTAs6/GaoNAiBtQVE/hN7awNRWVmlieS0go3Y3dzaE9IUMyj8sPOFT\r\n"
+  "5JdJ6BM69PHKCkY3dKdnnfpFEuECgYEA68mRpteunF1mdZgXs+WrN+uLlRrQR20F\r\n"
+  "ZyMYiUCH2Dtn26EzA2moy7FipIIrQcX/j+KhYNGM3e7MU4LymIO29E18mn8JODnH\r\n"
+  "sQOXzBTsf8A4yIVMkcuQD3bfb0JiUGYUPOidTp2N7IJA7+6Yc3vQOyb74lnKnJoO\r\n"
+  "gougPT2wS+cCgYAn7muzb6xFsXDhyW0Tm6YJYBfRS9yAWEuVufINobeBZPSl2cN1\r\n"
+  "Jrnw+HlrfTNbrJWuJmjtZJXUXQ6cVp2rUbjutNyRV4vG6iRwEXYQ40EJdkr1gZpi\r\n"
+  "CHQhuShuuPih2MNAy7EEbM+sXrDjTBR3bFqzuHPzu7dp+BshCFX3lRfAAQKBgGQt\r\n"
+  "K5i7IhCFDjb/+3IPLgOAK7mZvsvZ4eXD33TQ2eZgtut1PXtBtNl17/b85uv293Fm\r\n"
+  "VDISVcsk3eLNS8zIiT6afUoWlxAwXEs0v5WRfjl4radkGvgGiJpJYvyeM67877RB\r\n"
+  "EDSKc/X8ESLfOB44iGvZUEMG6zJFscx9DgN25iQZAoGAbyd+JEWwdVH9/K3IH1t2\r\n"
+  "PBkZX17kNWv+iVM1WyFjbe++vfKZCrOJiyiqhDeEqgrP3AuNMlaaduC3VRC3G5oV\r\n"
+  "Mj1tlhDWQ/qhvKdCKNdIVQYDE75nw+FRWV8yYkHAnXYW3tNoweDIwixE0hkPR1bc\r\n"
+  "oEjPLVNtx8SOj/M4rhaPT3I=\r\n"
+  "-----END PRIVATE KEY-----\r\n";
+static uint32_t vcl_test_key_rsa_len = sizeof (vcl_test_key_rsa);
+
+static int
+vt_add_cert_key_pair ()
+{
+  vcl_test_main_t *vt = &vcl_test_main;
+  vppcom_cert_key_pair_t ckpair;
+  int ckp_index;
+
+  vtinf ("Adding tls certs ...");
+
+  ckpair.cert = vcl_test_crt_rsa;
+  ckpair.key = vcl_test_key_rsa;
+  ckpair.cert_len = vcl_test_crt_rsa_len;
+  ckpair.key_len = vcl_test_key_rsa_len;
+  ckp_index = vppcom_add_cert_key_pair (&ckpair);
+  if (ckp_index < 0)
+    {
+      vterr ("vppcom_add_cert_key_pair()", ckp_index);
+      return ckp_index;
+    }
+
+  vt->ckpair_index = ckp_index;
+  return 0;
+}
+
+static int
+vt_tls_init (vcl_test_cfg_t *cfg)
+{
+  return vt_add_cert_key_pair ();
+}
+
+static int
+vt_tls_connect (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
+{
+  vcl_test_main_t *vt = &vcl_test_main;
+  uint32_t flags, flen;
+  int rv;
+
+  ts->fd = vppcom_session_create (VPPCOM_PROTO_TLS, 0 /* is_nonblocking */);
+  if (ts->fd < 0)
+    {
+      vterr ("vppcom_session_create()", ts->fd);
+      return ts->fd;
+    }
+
+  uint32_t ckp_len = sizeof (vt->ckpair_index);
+  vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_CKPAIR, &vt->ckpair_index,
+                      &ckp_len);
+
+  /* Connect is blocking */
+  rv = vppcom_session_connect (ts->fd, endpt);
+  if (rv < 0)
+    {
+      vterr ("vppcom_session_connect()", rv);
+      return rv;
+    }
+
+  ts->read = vcl_test_read;
+  ts->write = vcl_test_write;
+  flags = O_NONBLOCK;
+  flen = sizeof (flags);
+  vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
+  vtinf ("Test session %d (fd %d) connected.", ts->session_index, ts->fd);
+
+  return 0;
+}
+
+static int
+vt_tls_listen (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
+{
+  vcl_test_main_t *vt = &vcl_test_main;
+  uint32_t ckp_len;
+  int rv;
+
+  ts->fd = vppcom_session_create (VPPCOM_PROTO_TLS, 0 /* is_nonblocking */);
+  if (ts->fd < 0)
+    {
+      vterr ("vppcom_session_create()", ts->fd);
+      return ts->fd;
+    }
+
+  ckp_len = sizeof (vt->ckpair_index);
+  vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_CKPAIR, &vt->ckpair_index,
+                      &ckp_len);
+
+  rv = vppcom_session_bind (ts->fd, endpt);
+  if (rv < 0)
+    {
+      vterr ("vppcom_session_bind()", rv);
+      return rv;
+    }
+
+  rv = vppcom_session_listen (ts->fd, 10);
+  if (rv < 0)
+    {
+      vterr ("vppcom_session_listen()", rv);
+      return rv;
+    }
+
+  return 0;
+}
+
+static int
+vt_tls_accept (int listen_fd, vcl_test_session_t *ts)
+{
+  int client_fd;
+
+  client_fd = vppcom_session_accept (listen_fd, &ts->endpt, 0);
+  if (client_fd < 0)
+    {
+      vterr ("vppcom_session_accept()", client_fd);
+      return client_fd;
+    }
+  ts->fd = client_fd;
+  ts->is_open = 1;
+  ts->read = vcl_test_read;
+  ts->write = vcl_test_write;
+
+  return 0;
+}
+
+static const vcl_test_proto_vft_t vcl_test_tls = {
+  .init = vt_tls_init,
+  .open = vt_tls_connect,
+  .listen = vt_tls_listen,
+  .accept = vt_tls_accept,
+};
+
+VCL_TEST_REGISTER_PROTO (VPPCOM_PROTO_TLS, vcl_test_tls);
+
+static int
+vt_dtls_init (vcl_test_cfg_t *cfg)
+{
+  return vt_add_cert_key_pair ();
+}
+
+static int
+vt_dtls_connect (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
+{
+  vcl_test_main_t *vt = &vcl_test_main;
+  uint32_t flags, flen;
+  int rv;
+
+  ts->fd = vppcom_session_create (VPPCOM_PROTO_DTLS, 0 /* is_nonblocking */);
+  if (ts->fd < 0)
+    {
+      vterr ("vppcom_session_create()", ts->fd);
+      return ts->fd;
+    }
+
+  uint32_t ckp_len = sizeof (vt->ckpair_index);
+  vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_CKPAIR, &vt->ckpair_index,
+                      &ckp_len);
+
+  /* Connect is blocking */
+  rv = vppcom_session_connect (ts->fd, endpt);
+  if (rv < 0)
+    {
+      vterr ("vppcom_session_connect()", rv);
+      return rv;
+    }
+
+  ts->read = vcl_test_read;
+  ts->write = vcl_test_write;
+  flags = O_NONBLOCK;
+  flen = sizeof (flags);
+  vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
+  vtinf ("Test session %d (fd %d) connected.", ts->session_index, ts->fd);
+
+  return 0;
+}
+
+static int
+vt_dtls_listen (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
+{
+  vcl_test_main_t *vt = &vcl_test_main;
+  uint32_t ckp_len;
+  int rv;
+
+  ts->fd = vppcom_session_create (VPPCOM_PROTO_DTLS, 0 /* is_nonblocking */);
+  if (ts->fd < 0)
+    {
+      vterr ("vppcom_session_create()", ts->fd);
+      return ts->fd;
+    }
+
+  ckp_len = sizeof (vt->ckpair_index);
+  vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_CKPAIR, &vt->ckpair_index,
+                      &ckp_len);
+
+  rv = vppcom_session_bind (ts->fd, endpt);
+  if (rv < 0)
+    {
+      vterr ("vppcom_session_bind()", rv);
+      return rv;
+    }
+
+  rv = vppcom_session_listen (ts->fd, 10);
+  if (rv < 0)
+    {
+      vterr ("vppcom_session_listen()", rv);
+      return rv;
+    }
+
+  return 0;
+}
+
+static int
+vt_dtls_accept (int listen_fd, vcl_test_session_t *ts)
+{
+  int client_fd;
+
+  client_fd = vppcom_session_accept (listen_fd, &ts->endpt, 0);
+  if (client_fd < 0)
+    {
+      vterr ("vppcom_session_accept()", client_fd);
+      return client_fd;
+    }
+  ts->fd = client_fd;
+  ts->is_open = 1;
+  ts->read = vcl_test_read;
+  ts->write = vcl_test_write;
+
+  return 0;
+}
+
+static const vcl_test_proto_vft_t vcl_test_dtls = {
+  .init = vt_dtls_init,
+  .open = vt_dtls_connect,
+  .listen = vt_dtls_listen,
+  .accept = vt_dtls_accept,
+};
+
+VCL_TEST_REGISTER_PROTO (VPPCOM_PROTO_DTLS, vcl_test_dtls);
+
+static int
+vt_quic_init (vcl_test_cfg_t *cfg)
+{
+  vcl_test_main_t *vt = &vcl_test_main;
+
+  if (cfg)
+    vt->cfg = *cfg;
+
+  return vt_add_cert_key_pair ();
+}
+
+static int
+vt_quic_maybe_init_wrk (vcl_test_main_t *vt, vcl_test_wrk_t *wrk,
+                       vppcom_endpt_t *endpt)
+{
+  uint32_t size, i, flags, flen;
+  vcl_test_session_t *tq;
+  int rv;
+
+  /* Test already initialized */
+  if (wrk->n_qsessions == vt->cfg.num_test_qsessions)
+    return 0;
+
+  /* Make sure pool is large enough */
+  if (!wrk->qsessions)
+    {
+      wrk->qsessions =
+       calloc (vt->cfg.num_test_qsessions, sizeof (vcl_test_session_t));
+    }
+  else
+    {
+      size = vt->cfg.num_test_qsessions * sizeof (vcl_test_session_t);
+      wrk->qsessions = realloc (wrk->qsessions, size);
+    }
+
+  if (!wrk->qsessions)
+    {
+      vterr ("failed to alloc Qsessions", -errno);
+      return errno;
+    }
+
+  for (i = 0; i < vt->cfg.num_test_qsessions; i++)
+    {
+      tq = &wrk->qsessions[i];
+      tq->fd =
+       vppcom_session_create (VPPCOM_PROTO_QUIC, 0 /* is_nonblocking */);
+      tq->session_index = i;
+      if (tq->fd < 0)
+       {
+         vterr ("vppcom_session_create()", tq->fd);
+         return tq->fd;
+       }
+
+      /* Connect is blocking */
+      rv = vppcom_session_connect (tq->fd, endpt);
+      if (rv < 0)
+       {
+         vterr ("vppcom_session_connect()", rv);
+         return rv;
+       }
+      flags = O_NONBLOCK;
+      flen = sizeof (flags);
+      vppcom_session_attr (tq->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
+      vtinf ("Test Qsession %d (fd %d) connected.", i, tq->fd);
+    }
+  wrk->n_qsessions = vt->cfg.num_test_qsessions;
+
+  return 0;
+}
+
+static int
+vt_quic_connect (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
+{
+  vcl_test_main_t *vt = &vcl_test_main;
+  vcl_test_session_t *tq;
+  vcl_test_wrk_t *wrk;
+  uint32_t wrk_index;
+  int rv;
+
+  wrk_index = vcl_test_worker_index ();
+  wrk = &vt->wrk[wrk_index];
+
+  /* Make sure qsessions are initialized */
+  vt_quic_maybe_init_wrk (vt, wrk, endpt);
+
+  ts->fd = vppcom_session_create (VPPCOM_PROTO_QUIC, 1 /* is_nonblocking */);
+  if (ts->fd < 0)
+    {
+      vterr ("vppcom_session_create()", ts->fd);
+      return ts->fd;
+    }
+
+  /* Choose qession to use for stream */
+  tq = &wrk->qsessions[ts->session_index / vt->cfg.num_test_sessions_perq];
+
+  rv = vppcom_session_stream_connect (ts->fd, tq->fd);
+  if (rv < 0)
+    {
+      vterr ("vppcom_session_stream_connect()", rv);
+      return rv;
+    }
+
+  vtinf ("Test session %d (fd %d) connected.", ts->session_index, ts->fd);
+
+  return 0;
+}
+
+static int
+vt_quic_listen (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
+{
+  vcl_test_main_t *vt = &vcl_test_main;
+  uint32_t ckp_len;
+  int rv;
+
+  ts->fd = vppcom_session_create (VPPCOM_PROTO_QUIC, 0 /* is_nonblocking */);
+  if (ts->fd < 0)
+    {
+      vterr ("vppcom_session_create()", ts->fd);
+      return ts->fd;
+    }
+
+  ckp_len = sizeof (vt->ckpair_index);
+  vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_CKPAIR, &vt->ckpair_index,
+                      &ckp_len);
+
+  rv = vppcom_session_bind (ts->fd, endpt);
+  if (rv < 0)
+    {
+      vterr ("vppcom_session_bind()", rv);
+      return rv;
+    }
+
+  rv = vppcom_session_listen (ts->fd, 10);
+  if (rv < 0)
+    {
+      vterr ("vppcom_session_listen()", rv);
+      return rv;
+    }
+
+  return 0;
+}
+
+static int
+vt_quic_accept (int listen_fd, vcl_test_session_t *ts)
+{
+  int client_fd;
+
+  client_fd = vppcom_session_accept (listen_fd, &ts->endpt, 0);
+  if (client_fd < 0)
+    {
+      vterr ("vppcom_session_accept()", client_fd);
+      return client_fd;
+    }
+  ts->fd = client_fd;
+  ts->is_open = 1;
+  ts->read = vcl_test_read;
+  ts->write = vcl_test_write;
+
+  return 0;
+}
+
+static int
+vt_quic_close (vcl_test_session_t *ts)
+{
+  int listener_fd = vppcom_session_listener (ts->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);
+    }
+
+  return 0;
+}
+
+static const vcl_test_proto_vft_t vcl_test_quic = {
+  .init = vt_quic_init,
+  .open = vt_quic_connect,
+  .listen = vt_quic_listen,
+  .accept = vt_quic_accept,
+  .close = vt_quic_close,
+};
+
+VCL_TEST_REGISTER_PROTO (VPPCOM_PROTO_QUIC, vcl_test_quic);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index b8fa1b7..ab0c601 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2017-2021 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:
@@ -40,7 +40,7 @@ typedef struct
 typedef struct
 {
   uint32_t wrk_index;
-  int listen_fd;
+  vcl_test_session_t listener;
   int epfd;
   struct epoll_event wait_events[VCL_TEST_CFG_MAX_EPOLL_EVENTS];
   size_t conn_pool_size;
@@ -53,7 +53,6 @@ typedef struct
 {
   vcl_test_server_cfg_t cfg;
   vcl_test_server_worker_t *workers;
-
   vcl_test_session_t *ctrl;
   int ctrl_listen_fd;
   struct sockaddr_storage servaddr;
@@ -62,7 +61,7 @@ typedef struct
   u8 use_ds;
 } vcl_test_server_main_t;
 
-static __thread int __wrk_index = 0;
+vcl_test_main_t vcl_test_main;
 
 static vcl_test_server_main_t vcl_server_main;
 
@@ -107,6 +106,7 @@ again:
        {
          wrk->conn_pool[i].endpt.ip = wrk->conn_pool[i].ip;
          wrk->conn_pool[i].is_alloc = 1;
+         wrk->conn_pool[i].session_index = i;
          return (&wrk->conn_pool[i]);
        }
     }
@@ -147,8 +147,15 @@ sync_config_and_reply (vcl_test_session_t *conn, vcl_test_cfg_t *rx_cfg)
 static void
 vts_session_close (vcl_test_session_t *conn)
 {
+  vcl_test_server_main_t *vsm = &vcl_server_main;
+  vcl_test_main_t *vt = &vcl_test_main;
+
   if (!conn->is_open)
     return;
+
+  if (vt->protos[vsm->cfg.proto]->close)
+    vt->protos[vsm->cfg.proto]->close (conn);
+
   vppcom_session_close (conn->fd);
   conn->is_open = 0;
 }
@@ -293,7 +300,7 @@ vts_server_echo (vcl_test_session_t *conn, int rx_bytes)
     vtinf ("(fd %d): Echoing back", conn->fd);
 
   nbytes = strlen ((const char *) conn->rxbuf) + 1;
-  tx_bytes = vcl_test_write (conn, conn->rxbuf, nbytes);
+  tx_bytes = conn->write (conn, conn->rxbuf, nbytes);
   if (tx_bytes >= 0)
     vtinf ("(fd %d): TX (%d bytes) - '%s'", conn->fd, tx_bytes, conn->rxbuf);
 }
@@ -301,9 +308,11 @@ vts_server_echo (vcl_test_session_t *conn, int rx_bytes)
 static vcl_test_session_t *
 vts_accept_client (vcl_test_server_worker_t *wrk, int listen_fd)
 {
+  vcl_test_server_main_t *vsm = &vcl_server_main;
+  const vcl_test_proto_vft_t *tp;
   vcl_test_session_t *conn;
   struct epoll_event ev;
-  int rv, client_fd;
+  int rv;
 
   conn = conn_pool_alloc (wrk);
   if (!conn)
@@ -312,21 +321,16 @@ vts_accept_client (vcl_test_server_worker_t *wrk, int listen_fd)
       return 0;
     }
 
-  client_fd = vppcom_session_accept (listen_fd, &conn->endpt, 0);
-  if (client_fd < 0)
-    {
-      vterr ("vppcom_session_accept()", client_fd);
-      return 0;
-    }
-  conn->fd = client_fd;
-  conn->is_open = 1;
+  tp = vcl_test_main.protos[vsm->cfg.proto];
+  if (tp->accept (listen_fd, conn))
+    return 0;
 
   vtinf ("Got a connection -- fd = %d (0x%08x) on listener fd = %d (0x%08x)",
-        client_fd, client_fd, listen_fd, listen_fd);
+        conn->fd, conn->fd, listen_fd, listen_fd);
 
   ev.events = EPOLLIN;
   ev.data.u64 = conn - wrk->conn_pool;
-  rv = vppcom_epoll_ctl (wrk->epfd, EPOLL_CTL_ADD, client_fd, &ev);
+  rv = vppcom_epoll_ctl (wrk->epfd, EPOLL_CTL_ADD, conn->fd, &ev);
   if (rv < 0)
     {
       vterr ("vppcom_epoll_ctl()", rv);
@@ -464,24 +468,10 @@ 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_ctrl_cfg (vcl_test_server_worker_t *wrk, vcl_test_cfg_t *rx_cfg,
                     vcl_test_session_t *conn, int rx_bytes)
 {
-  int listener_fd;
   if (rx_cfg->verbose)
     {
       vtinf ("(fd %d): Received a cfg msg!", conn->fd);
@@ -499,7 +489,7 @@ vts_handle_ctrl_cfg (vcl_test_server_worker_t *wrk, vcl_test_cfg_t *rx_cfg,
          vtinf ("(fd %d): Replying to cfg msg", conn->fd);
          vcl_test_cfg_dump (rx_cfg, 0 /* is_client */ );
        }
-      vcl_test_write (conn, &conn->cfg, sizeof (conn->cfg));
+      conn->write (conn, &conn->cfg, sizeof (conn->cfg));
       return -1;
     }
 
@@ -517,8 +507,6 @@ vts_handle_ctrl_cfg (vcl_test_server_worker_t *wrk, vcl_test_cfg_t *rx_cfg,
 
     case VCL_TEST_TYPE_EXIT:
       vtinf ("Ctrl session fd %d closing!", conn->fd);
-      listener_fd = vppcom_session_listener (conn->fd);
-      vts_clean_connected_listeners (wrk, listener_fd);
       vts_session_cleanup (conn);
       wrk->nfds--;
       if (wrk->nfds)
@@ -538,6 +526,8 @@ static void
 vts_worker_init (vcl_test_server_worker_t * wrk)
 {
   vcl_test_server_main_t *vsm = &vcl_server_main;
+  vcl_test_main_t *vt = &vcl_test_main;
+  const vcl_test_proto_vft_t *tp;
   struct epoll_event listen_ev;
   int rv;
 
@@ -550,48 +540,9 @@ vts_worker_init (vcl_test_server_worker_t * wrk)
     if (vppcom_worker_register ())
       vtfail ("vppcom_worker_register()", 1);
 
-  wrk->listen_fd = vppcom_session_create (vsm->cfg.proto,
-                                         0 /* is_nonblocking */ );
-  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 ||
-      vsm->cfg.proto == VPPCOM_PROTO_QUIC ||
-      vsm->cfg.proto == VPPCOM_PROTO_DTLS)
-    {
-      vppcom_cert_key_pair_t ckpair;
-      uint32_t ckp_len;
-      int ckp_index;
-
-      vtinf ("Adding tls certs ...");
-      ckpair.cert = vcl_test_crt_rsa;
-      ckpair.key = vcl_test_key_rsa;
-      ckpair.cert_len = vcl_test_crt_rsa_len;
-      ckpair.key_len = vcl_test_key_rsa_len;
-      ckp_index = vppcom_add_cert_key_pair (&ckpair);
-      if (ckp_index < 0)
-       vtfail ("vppcom_add_cert_key_pair()", ckp_index);
-
-      ckp_len = sizeof (ckp_index);
-      vppcom_session_attr (wrk->listen_fd, VPPCOM_ATTR_SET_CKPAIR, &ckp_index,
-                          &ckp_len);
-    }
-
-  rv = vppcom_session_bind (wrk->listen_fd, &vsm->cfg.endpt);
-  if (rv < 0)
-    vtfail ("vppcom_session_bind()", rv);
-
-  if (!(vsm->cfg.proto == VPPCOM_PROTO_UDP))
-    {
-      rv = vppcom_session_listen (wrk->listen_fd, 10);
-      if (rv < 0)
-       vtfail ("vppcom_session_listen()", rv);
-    }
+  tp = vt->protos[vsm->cfg.proto];
+  if ((rv = tp->listen (&wrk->listener, &vsm->cfg.endpt)))
+    vtfail ("proto listen", rv);
 
   /* First worker already has epoll fd */
   if (wrk->wrk_index)
@@ -603,13 +554,14 @@ vts_worker_init (vcl_test_server_worker_t * wrk)
 
   listen_ev.events = EPOLLIN;
   listen_ev.data.u32 = VCL_TEST_DATA_LISTENER;
-  rv = vppcom_epoll_ctl (wrk->epfd, EPOLL_CTL_ADD, wrk->listen_fd,
-                        &listen_ev);
+  rv =
+    vppcom_epoll_ctl (wrk->epfd, EPOLL_CTL_ADD, wrk->listener.fd, &listen_ev);
   if (rv < 0)
     vtfail ("vppcom_epoll_ctl", rv);
 
   vsm->active_workers += 1;
-  vtinf ("Waiting for a client to connect on port %d ...", vsm->cfg.port);
+  vtinf ("Waiting for client data connections on port %d ...",
+        ntohs (vsm->cfg.endpt.port));
 }
 
 static inline int
@@ -619,7 +571,7 @@ vts_conn_read (vcl_test_session_t *conn)
   if (vsm->use_ds)
     return vcl_test_read_ds (conn);
   else
-    return vcl_test_read (conn, conn->rxbuf, conn->rxbuf_size);
+    return conn->read (conn, conn->rxbuf, conn->rxbuf_size);
 }
 
 static void *
@@ -628,7 +580,7 @@ vts_worker_loop (void *arg)
   vcl_test_server_main_t *vsm = &vcl_server_main;
   vcl_test_server_worker_t *wrk = arg;
   vcl_test_session_t *conn;
-  int i, rx_bytes, num_ev, listener_fd;
+  int i, rx_bytes, num_ev;
   vcl_test_cfg_t *rx_cfg;
 
   if (wrk->wrk_index)
@@ -656,8 +608,6 @@ vts_worker_loop (void *arg)
           */
          if (wrk->wait_events[i].events & (EPOLLHUP | EPOLLRDHUP))
            {
-             listener_fd = vppcom_session_listener (conn->fd);
-             vts_clean_connected_listeners (wrk, listener_fd);
              vts_session_close (conn);
              wrk->nfds--;
              if (!wrk->nfds)
@@ -684,7 +634,7 @@ vts_worker_loop (void *arg)
            }
          if (wrk->wait_events[i].data.u32 == VCL_TEST_DATA_LISTENER)
            {
-             conn = vts_accept_client (wrk, wrk->listen_fd);
+             conn = vts_accept_client (wrk, wrk->listener.fd);
              conn->cfg = vsm->ctrl->cfg;
              continue;
            }
@@ -700,7 +650,7 @@ vts_worker_loop (void *arg)
 
          if (!wrk->wrk_index && conn->fd == vsm->ctrl->fd)
            {
-             rx_bytes = vcl_test_read (conn, conn->rxbuf, conn->rxbuf_size);
+             rx_bytes = conn->read (conn, conn->rxbuf, conn->rxbuf_size);
              rx_cfg = (vcl_test_cfg_t *) conn->rxbuf;
              if (rx_cfg->magic == VCL_TEST_CFG_CTRL_MAGIC)
                {
@@ -759,7 +709,7 @@ fail:
   vsm->worker_fails -= 1;
 
 done:
-  vppcom_session_close (wrk->listen_fd);
+  vppcom_session_close (wrk->listener.fd);
   if (wrk->conn_pool)
     free (wrk->conn_pool);
   vsm->active_workers -= 1;
@@ -799,13 +749,14 @@ vts_ctrl_session_init (vcl_test_server_worker_t *wrk)
   if (rv < 0)
     vtfail ("vppcom_epoll_ctl", rv);
 
-  vtinf ("Waiting for a client to connect on port %d ...", vsm->cfg.port);
+  vtinf ("Waiting for client ctrl connection on port %d ...", vsm->cfg.port);
 }
 
 int
 main (int argc, char **argv)
 {
   vcl_test_server_main_t *vsm = &vcl_server_main;
+  vcl_test_main_t *vt = &vcl_test_main;
   int rv, i;
 
   clib_mem_init_thread_safe (0, 64 << 20);
@@ -818,6 +769,10 @@ main (int argc, char **argv)
   if (rv)
     vtfail ("vppcom_app_create()", rv);
 
+  /* Protos like tls/dtls/quic need init */
+  if (vt->protos[vsm->cfg.proto]->init)
+    vt->protos[vsm->cfg.proto]->init (0);
+
   vsm->workers = calloc (vsm->cfg.workers, sizeof (*vsm->workers));
   vts_ctrl_session_init (&vsm->workers[0]);