diff options
-rw-r--r-- | src/plugins/hs_apps/CMakeLists.txt | 15 | ||||
-rw-r--r-- | src/plugins/hs_apps/vcl/vcl_test.h | 106 | ||||
-rw-r--r-- | src/plugins/hs_apps/vcl/vcl_test_client.c | 228 | ||||
-rw-r--r-- | src/plugins/hs_apps/vcl/vcl_test_protos.c | 674 | ||||
-rw-r--r-- | src/plugins/hs_apps/vcl/vcl_test_server.c | 127 |
5 files changed, 836 insertions, 314 deletions
diff --git a/src/plugins/hs_apps/CMakeLists.txt b/src/plugins/hs_apps/CMakeLists.txt index da86512f99f..1f474828b15 100644 --- a/src/plugins/hs_apps/CMakeLists.txt +++ b/src/plugins/hs_apps/CMakeLists.txt @@ -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) diff --git a/src/plugins/hs_apps/vcl/vcl_test.h b/src/plugins/hs_apps/vcl/vcl_test.h index 386e9686ef2..18e3c00f487 100644 --- a/src/plugins/hs_apps/vcl/vcl_test.h +++ b/src/plugins/hs_apps/vcl/vcl_test.h @@ -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) diff --git a/src/plugins/hs_apps/vcl/vcl_test_client.c b/src/plugins/hs_apps/vcl/vcl_test_client.c index 0033ae6a30d..d87b4d3d3f6 100644 --- a/src/plugins/hs_apps/vcl/vcl_test_client.c +++ b/src/plugins/hs_apps/vcl/vcl_test_client.c @@ -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; @@ -119,120 +116,15 @@ vtc_cfg_sync (vcl_test_session_t * ts) } 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 index 00000000000..d2388224d12 --- /dev/null +++ b/src/plugins/hs_apps/vcl/vcl_test_protos.c @@ -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: + */ diff --git a/src/plugins/hs_apps/vcl/vcl_test_server.c b/src/plugins/hs_apps/vcl/vcl_test_server.c index b8fa1b7c600..ab0c6014620 100644 --- a/src/plugins/hs_apps/vcl/vcl_test_server.c +++ b/src/plugins/hs_apps/vcl/vcl_test_server.c @@ -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]); |