summaryrefslogtreecommitdiffstats
path: root/src/plugins/hs_apps/vcl
diff options
context:
space:
mode:
authorNathan Skrzypczak <nathan.skrzypczak@gmail.com>2019-05-16 14:38:44 +0200
committerFlorin Coras <florin.coras@gmail.com>2019-07-18 18:19:05 +0000
commit9fd996275c745faec2843cf3a8b1d15d6f8c9dab (patch)
tree01bd59cd9deea4994a33bce8bb4a2a7d7fa5c283 /src/plugins/hs_apps/vcl
parentcef02be220eff4aa32ec7ff56b1e0a552faa1280 (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.h31
-rw-r--r--src/plugins/hs_apps/vcl/vcl_test_client.c209
-rw-r--r--src/plugins/hs_apps/vcl/vcl_test_server.c52
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;
}