diff options
author | Nathan Skrzypczak <nathan.skrzypczak@gmail.com> | 2019-05-16 14:38:44 +0200 |
---|---|---|
committer | Florin Coras <florin.coras@gmail.com> | 2019-07-18 18:19:05 +0000 |
commit | 9fd996275c745faec2843cf3a8b1d15d6f8c9dab (patch) | |
tree | 01bd59cd9deea4994a33bce8bb4a2a7d7fa5c283 /src/plugins/hs_apps/vcl | |
parent | cef02be220eff4aa32ec7ff56b1e0a552faa1280 (diff) |
vcl: add QUIC support
Type: feature
* Adds the concept of a "connectable listener" : a session that
can be both connected and accepted on.
* vppcom_session_is_connectable_listener (fd) that tells if the fd
is a connectable listener
* vppcom_session_listener (fd) that gives you the listener's fd
that accepted the session (if any)
* vppcom_session_n_accepted (fd) that gives the number
of sessions a listener accepted.
Change-Id: Id89d67d8339fb15a7cf7e00a9c5448175eca04fc
Signed-off-by: Nathan Skrzypczak <nathan.skrzypczak@gmail.com>
Diffstat (limited to 'src/plugins/hs_apps/vcl')
-rw-r--r-- | src/plugins/hs_apps/vcl/vcl_test.h | 31 | ||||
-rw-r--r-- | src/plugins/hs_apps/vcl/vcl_test_client.c | 209 | ||||
-rw-r--r-- | src/plugins/hs_apps/vcl/vcl_test_server.c | 52 |
3 files changed, 223 insertions, 69 deletions
diff --git a/src/plugins/hs_apps/vcl/vcl_test.h b/src/plugins/hs_apps/vcl/vcl_test.h index ab05f7ae9cf..7586e29749a 100644 --- a/src/plugins/hs_apps/vcl/vcl_test.h +++ b/src/plugins/hs_apps/vcl/vcl_test.h @@ -86,10 +86,11 @@ typedef struct __attribute__ ((packed)) uint32_t test; uint32_t ctrl_handle; uint32_t num_test_sessions; + uint32_t num_test_sessions_perq; + uint32_t num_test_qsessions; uint32_t verbose; uint32_t address_ip6; uint32_t transport_udp; - uint32_t transport_tls; uint64_t rxbuf_size; uint64_t txbuf_size; uint64_t num_writes; @@ -119,6 +120,7 @@ typedef struct char *rxbuf; vcl_test_cfg_t cfg; vcl_test_stats_t stats; + int session_index; } vcl_test_session_t; @@ -201,6 +203,7 @@ vcl_test_cfg_init (vcl_test_cfg_t * cfg) cfg->test = VCL_TEST_TYPE_NONE; cfg->ctrl_handle = ~0; cfg->num_test_sessions = 1; + cfg->num_test_sessions_perq = 1; cfg->verbose = 0; cfg->rxbuf_size = VCL_TEST_CFG_RXBUF_SIZE_DEF; cfg->num_writes = VCL_TEST_CFG_NUM_WRITES_DEF; @@ -491,28 +494,16 @@ vcl_test_write (int fd, uint8_t * buf, uint32_t nbytes, if (rv < 0) { errno = -rv; - rv = -1; - } - if (rv < 0) - { - if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) - { - if (stats) - stats->tx_eagain++; - break; - } - else - break; + if ((errno == EAGAIN || errno == EWOULDBLOCK) && stats) + stats->tx_eagain++; + break; } tx_bytes += rv; - if (tx_bytes != nbytes) - { - nbytes_left = nbytes_left - rv; - buf += rv; - if (stats) - stats->tx_incomp++; - } + nbytes_left = nbytes_left - rv; + buf += rv; + if (stats) + stats->tx_incomp++; } while (tx_bytes != nbytes); diff --git a/src/plugins/hs_apps/vcl/vcl_test_client.c b/src/plugins/hs_apps/vcl/vcl_test_client.c index 1ead146aef5..b9bdd6eed55 100644 --- a/src/plugins/hs_apps/vcl/vcl_test_client.c +++ b/src/plugins/hs_apps/vcl/vcl_test_client.c @@ -28,7 +28,9 @@ typedef struct { vcl_test_session_t *sessions; + vcl_test_session_t *qsessions; uint32_t n_sessions; + uint32_t n_qsessions; uint32_t wrk_index; fd_set wr_fdset; fd_set rd_fdset; @@ -42,11 +44,12 @@ 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; - uint32_t proto; + uint8_t proto; uint32_t n_workers; volatile int active_workers; struct sockaddr_storage server_addr; @@ -116,6 +119,105 @@ 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; + 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, 1 /* is_nonblocking */ ); + tq->session_index = i; + if (tq->fd < 0) + { + vterr ("vppcom_session_create()", tq->fd); + return tq->fd; + } + + rv = vppcom_session_connect (tq->fd, &vcm->server_endpt); + if (rv < 0) + { + vterr ("vppcom_session_connect()", rv); + return rv; + } + 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; @@ -123,6 +225,9 @@ vtc_connect_test_sessions (vcl_test_client_worker_t * wrk) uint32_t n_test_sessions; 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) { @@ -314,6 +419,7 @@ vtc_worker_sessions_exit (vcl_test_client_worker_t * wrk) (void) vcl_test_write (ts->fd, (uint8_t *) & ts->cfg, sizeof (ts->cfg), &ts->stats, verbose); } + wrk->n_sessions = 0; } @@ -387,7 +493,6 @@ vtc_worker_loop (void *arg) goto exit; } } - if ((!check_rx && ts->stats.tx_bytes >= ts->cfg.total_bytes) || (check_rx && ts->stats.rx_bytes >= ts->cfg.total_bytes)) { @@ -710,6 +815,7 @@ print_usage_and_exit (void) " -c Print test config before test.\n" " -w <dir> Write test results to <dir>.\n" " -X Exit after running test.\n" + " -p <proto> Use <proto> transport layer\n" " -D Use UDP transport layer\n" " -L Use TLS transport layer\n" " -E Run Echo test.\n" @@ -718,7 +824,10 @@ print_usage_and_exit (void) " -T <txbuf-size> Test Cfg: tx buffer size.\n" " -U Run Uni-directional test.\n" " -B Run Bi-directional test.\n" - " -V Verbose mode.\n"); + " -V Verbose mode.\n" + " -I <N> Use N sessions.\n" + " -s <N> Use N sessions.\n" + " -q <n> QUIC : use N Ssessions on top of n Qsessions\n"); exit (1); } @@ -729,13 +838,14 @@ vtc_process_opts (vcl_test_client_main_t * vcm, int argc, char **argv) int c, v; opterr = 0; - while ((c = getopt (argc, argv, "chn:w:XE:I:N:R:T:UBV6DL")) != -1) + while ((c = getopt (argc, argv, "chnp:w:XE:I:N:R:T:UBV6DLs:q:")) != -1) switch (c) { case 'c': vcm->dump_cfg = 1; break; + case 'I': /* deprecated */ case 's': if (sscanf (optarg, "0x%x", &ctrl->cfg.num_test_sessions) != 1) if (sscanf (optarg, "%u", &ctrl->cfg.num_test_sessions) != 1) @@ -744,11 +854,30 @@ vtc_process_opts (vcl_test_client_main_t * vcm, int argc, char **argv) print_usage_and_exit (); } if (!ctrl->cfg.num_test_sessions || - (ctrl->cfg.num_test_sessions > FD_SETSIZE)) + (ctrl->cfg.num_test_sessions > VCL_TEST_CFG_MAX_TEST_SESS)) { vtwrn ("Invalid number of sessions (%d) specified for option -%c!" "\n Valid range is 1 - %d", - ctrl->cfg.num_test_sessions, c, FD_SETSIZE); + ctrl->cfg.num_test_sessions, c, + VCL_TEST_CFG_MAX_TEST_SESS); + print_usage_and_exit (); + } + break; + + case 'q': + if (sscanf (optarg, "0x%x", &ctrl->cfg.num_test_sessions_perq) != 1) + if (sscanf (optarg, "%u", &ctrl->cfg.num_test_sessions_perq) != 1) + { + vtwrn ("Invalid value for option -%c!", c); + print_usage_and_exit (); + } + if (!ctrl->cfg.num_test_sessions_perq || + (ctrl->cfg.num_test_sessions_perq > VCL_TEST_CFG_MAX_TEST_SESS)) + { + vtwrn ("Invalid number of Stream sessions (%d) per Qsession" + "for option -%c!\nValid range is 1 - %d", + ctrl->cfg.num_test_sessions_perq, c, + VCL_TEST_CFG_MAX_TEST_SESS); print_usage_and_exit (); } break; @@ -778,21 +907,6 @@ vtc_process_opts (vcl_test_client_main_t * vcm, int argc, char **argv) ctrl->cfg.test = VCL_TEST_TYPE_ECHO; break; - case 'I': - if (sscanf (optarg, "0x%x", &ctrl->cfg.num_test_sessions) != 1) - if (sscanf (optarg, "%d", &ctrl->cfg.num_test_sessions) != 1) - { - vtwrn ("Invalid value for option -%c!", c); - print_usage_and_exit (); - } - if (ctrl->cfg.num_test_sessions > VCL_TEST_CFG_MAX_TEST_SESS) - { - vtwrn ("value greater than max number test sessions (%d)!", - VCL_TEST_CFG_MAX_TEST_SESS); - print_usage_and_exit (); - } - break; - case 'N': if (sscanf (optarg, "0x%lx", &ctrl->cfg.num_writes) != 1) if (sscanf (optarg, "%ld", &ctrl->cfg.num_writes) != 1) @@ -866,23 +980,30 @@ vtc_process_opts (vcl_test_client_main_t * vcm, int argc, char **argv) ctrl->cfg.address_ip6 = 1; break; - case 'D': - ctrl->cfg.transport_udp = 1; + case 'p': + if (vppcom_unformat_proto (&vcm->proto, optarg)) + vtwrn ("Invalid vppcom protocol %s, defaulting to TCP", optarg); break; - case 'L': - ctrl->cfg.transport_tls = 1; + case 'D': /* deprecated */ + vcm->proto = VPPCOM_PROTO_UDP; + break; + + case 'L': /* deprecated */ + vcm->proto = VPPCOM_PROTO_TLS; break; case '?': switch (optopt) { case 'E': - case 'I': + case 'I': /* deprecated */ case 'N': case 'R': case 'T': case 'w': + case 'p': + case 'q': vtwrn ("Option -%c requires an argument.", optopt); break; @@ -904,18 +1025,9 @@ vtc_process_opts (vcl_test_client_main_t * vcm, int argc, char **argv) print_usage_and_exit (); } - if (ctrl->cfg.transport_udp) - { - vcm->proto = VPPCOM_PROTO_UDP; - } - else if (ctrl->cfg.transport_tls) - { - vcm->proto = VPPCOM_PROTO_TLS; - } - else - { - vcm->proto = VPPCOM_PROTO_TCP; - } + ctrl->cfg.num_test_qsessions = vcm->proto != VPPCOM_PROTO_QUIC ? 0 : + (ctrl->cfg.num_test_sessions + ctrl->cfg.num_test_sessions_perq - 1) / + ctrl->cfg.num_test_sessions_perq; memset (&vcm->server_addr, 0, sizeof (vcm->server_addr)); if (ctrl->cfg.address_ip6) @@ -985,6 +1097,7 @@ 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; int rv; vcm->n_workers = 1; @@ -1001,7 +1114,7 @@ main (int argc, char **argv) if (ctrl->fd < 0) vtfail ("vppcom_session_create()", ctrl->fd); - if (vcm->proto == VPPCOM_PROTO_TLS) + if (vcm->proto == VPPCOM_PROTO_TLS || vcm->proto == VPPCOM_PROTO_QUIC) { vtinf ("Adding tls certs ..."); vppcom_session_tls_add_cert (ctrl->fd, vcl_test_crt_rsa, @@ -1011,7 +1124,20 @@ main (int argc, char **argv) } vtinf ("Connecting to server..."); - rv = vppcom_session_connect (ctrl->fd, &vcm->server_endpt); + if (vcm->proto == VPPCOM_PROTO_QUIC) + { + quic_session->fd = vppcom_session_create (vcm->proto, + 0 /* is_nonblocking */ ); + if (quic_session->fd < 0) + vtfail ("vppcom_session_create()", quic_session->fd); + rv = vppcom_session_connect (quic_session->fd, &vcm->server_endpt); + if (rv) + vtfail ("vppcom_session_connect()", rv); + vtinf ("Connecting to stream..."); + rv = vppcom_session_stream_connect (ctrl->fd, quic_session->fd); + } + else + rv = vppcom_session_connect (ctrl->fd, &vcm->server_endpt); if (rv) vtfail ("vppcom_session_connect()", rv); vtinf ("Control session (fd %d) connected.", ctrl->fd); @@ -1082,7 +1208,8 @@ main (int argc, char **argv) } vtc_ctrl_session_exit (); - vppcom_session_close (ctrl->fd); + 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_server.c b/src/plugins/hs_apps/vcl/vcl_test_server.c index 62292adae5f..be225fa8c9e 100644 --- a/src/plugins/hs_apps/vcl/vcl_test_server.c +++ b/src/plugins/hs_apps/vcl/vcl_test_server.c @@ -277,7 +277,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 +290,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 +298,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 +321,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 +373,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 +406,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 +439,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 +494,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: @@ -505,7 +532,8 @@ vts_worker_init (vcl_test_server_worker_t * wrk) vtfail ("vppcom_session_create()", wrk->listen_fd); - 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); @@ -590,7 +618,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 +643,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 +657,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; } |