aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/hs_apps/echo_client.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/hs_apps/echo_client.c')
-rw-r--r--src/plugins/hs_apps/echo_client.c372
1 files changed, 304 insertions, 68 deletions
diff --git a/src/plugins/hs_apps/echo_client.c b/src/plugins/hs_apps/echo_client.c
index d449045cf6a..344f4af81c6 100644
--- a/src/plugins/hs_apps/echo_client.c
+++ b/src/plugins/hs_apps/echo_client.c
@@ -19,10 +19,17 @@
static ec_main_t ec_main;
-#define EC_DBG (0)
-#define DBG(_fmt, _args...) \
- if (EC_DBG) \
- clib_warning (_fmt, ##_args)
+#define ec_err(_fmt, _args...) clib_warning (_fmt, ##_args);
+
+#define ec_dbg(_fmt, _args...) \
+ do \
+ { \
+ if (ec_main.cfg.verbose) \
+ ec_err (_fmt, ##_args); \
+ } \
+ while (0)
+
+#define ec_cli(_fmt, _args...) vlib_cli_output (vm, _fmt, ##_args)
static void
signal_evt_to_cli_i (void *codep)
@@ -143,7 +150,7 @@ send_data_chunk (ec_main_t *ecm, ec_session_t *es)
es->bytes_to_send -= rv;
es->bytes_sent += rv;
- if (EC_DBG)
+ if (ecm->cfg.verbose)
{
ELOG_TYPE_DECLARE (e) =
{
@@ -169,7 +176,7 @@ receive_data_chunk (ec_worker_t *wrk, ec_session_t *es)
svm_fifo_t *rx_fifo = es->data.rx_fifo;
int n_read, i;
- if (ecm->test_bytes)
+ if (ecm->cfg.test_bytes)
{
if (!ecm->is_dgram)
n_read =
@@ -186,7 +193,7 @@ receive_data_chunk (ec_worker_t *wrk, ec_session_t *es)
if (n_read > 0)
{
- if (EC_DBG)
+ if (ecm->cfg.verbose)
{
ELOG_TYPE_DECLARE (e) =
{
@@ -201,15 +208,15 @@ receive_data_chunk (ec_worker_t *wrk, ec_session_t *es)
ed->data[0] = n_read;
}
- if (ecm->test_bytes)
+ if (ecm->cfg.test_bytes)
{
for (i = 0; i < n_read; i++)
{
if (wrk->rx_buf[i] != ((es->bytes_received + i) & 0xff))
{
- clib_warning ("read %d error at byte %lld, 0x%x not 0x%x",
- n_read, es->bytes_received + i, wrk->rx_buf[i],
- ((es->bytes_received + i) & 0xff));
+ ec_err ("read %d error at byte %lld, 0x%x not 0x%x", n_read,
+ es->bytes_received + i, wrk->rx_buf[i],
+ ((es->bytes_received + i) & 0xff));
ecm->test_failed = 1;
}
}
@@ -265,7 +272,7 @@ ec_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
ecm->prev_conns = vec_len (conns_this_batch);
if (ecm->repeats == 500000)
{
- clib_warning ("stuck clients");
+ ec_err ("stuck clients");
}
}
else
@@ -313,7 +320,7 @@ ec_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
}
else
{
- clib_warning ("session AWOL?");
+ ec_err ("session AWOL?");
vec_delete (conns_this_batch, 1, i);
}
@@ -340,16 +347,15 @@ VLIB_REGISTER_NODE (echo_clients_node) = {
static void
ec_reset_runtime_config (ec_main_t *ecm)
{
+ hs_test_cfg_init (&ecm->cfg);
ecm->n_clients = 1;
ecm->quic_streams = 1;
ecm->bytes_to_send = 8192;
- ecm->no_return = 0;
+ ecm->echo_bytes = 0;
ecm->fifo_size = 64 << 10;
ecm->connections_per_batch = 1000;
ecm->private_segment_count = 0;
ecm->private_segment_size = 256 << 20;
- ecm->no_output = 0;
- ecm->test_bytes = 0;
ecm->test_failed = 0;
ecm->tls_engine = CRYPTO_ENGINE_OPENSSL;
ecm->no_copy = 0;
@@ -480,39 +486,71 @@ quic_ec_qsession_connected_callback (u32 app_index, u32 api_context,
{
session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
ec_main_t *ecm = &ec_main;
- vnet_connect_args_t *a = 0;
- session_handle_t handle;
+ vnet_connect_args_t _a, *a = &_a;
u32 stream_n;
int rv;
- DBG ("QUIC Connection handle %d", session_handle (s));
+ ec_dbg ("QUIC Connection handle %d", session_handle (s));
- vec_validate (a, 1);
a->uri = (char *) ecm->connect_uri;
if (parse_uri (a->uri, &sep))
return -1;
- sep.parent_handle = handle = session_handle (s);
+ sep.parent_handle = session_handle (s);
for (stream_n = 0; stream_n < ecm->quic_streams; stream_n++)
{
clib_memset (a, 0, sizeof (*a));
a->app_index = ecm->app_index;
- a->api_context = -1 - api_context;
+ a->api_context = -2 - api_context;
clib_memcpy (&a->sep_ext, &sep, sizeof (sep));
- DBG ("QUIC opening stream %d", stream_n);
+ ec_dbg ("QUIC opening stream %d", stream_n);
if ((rv = vnet_connect (a)))
{
clib_error ("Stream session %d opening failed: %d", stream_n, rv);
return -1;
}
- DBG ("QUIC stream %d connected", stream_n);
+ ec_dbg ("QUIC stream %d connected", stream_n);
}
- /*
- * 's' is no longer valid, its underlying pool could have been moved in
- * vnet_connect()
- */
- vec_free (a);
+ return 0;
+}
+
+static int
+ec_ctrl_send (hs_test_cmd_t cmd)
+{
+ ec_main_t *ecm = &ec_main;
+ session_t *s;
+ int rv;
+
+ ecm->cfg.cmd = cmd;
+ if (ecm->ctrl_session_handle == SESSION_INVALID_HANDLE)
+ {
+ ec_dbg ("ctrl session went away");
+ return -1;
+ }
+
+ s = session_get_from_handle_if_valid (ecm->ctrl_session_handle);
+
+ ec_dbg ("sending test paramters to the server..");
+ if (ecm->cfg.verbose)
+ hs_test_cfg_dump (&ecm->cfg, 1);
+
+ rv = svm_fifo_enqueue (s->tx_fifo, sizeof (ecm->cfg), (u8 *) &ecm->cfg);
+ ASSERT (rv == sizeof (ecm->cfg));
+ session_send_io_evt_to_thread (s->tx_fifo, SESSION_IO_EVT_TX);
+ return 0;
+}
+
+static int
+ec_ctrl_session_connected_callback (session_t *s)
+{
+ ec_main_t *ecm = &ec_main;
+
+ s->opaque = HS_CTRL_HANDLE;
+ ecm->ctrl_session_handle = session_handle (s);
+
+ /* send test parameters to the server */
+ ec_ctrl_send (HS_TEST_CMD_SYNC);
return 0;
}
@@ -525,12 +563,15 @@ quic_ec_session_connected_callback (u32 app_index, u32 api_context,
ec_worker_t *wrk;
u32 thread_index;
+ if (PREDICT_FALSE (api_context == HS_CTRL_HANDLE))
+ return ec_ctrl_session_connected_callback (s);
+
if (PREDICT_FALSE (ecm->run_test != EC_STARTING))
return -1;
if (err)
{
- clib_warning ("connection %d failed!", api_context);
+ ec_err ("connection %d failed!", api_context);
ecm->run_test = EC_EXITING;
signal_evt_to_cli (EC_CLI_CONNECTS_FAILED);
return 0;
@@ -539,7 +580,7 @@ quic_ec_session_connected_callback (u32 app_index, u32 api_context,
if (s->listener_handle == SESSION_INVALID_HANDLE)
return quic_ec_qsession_connected_callback (app_index, api_context, s,
err);
- DBG ("STREAM Connection callback %d", api_context);
+ ec_dbg ("STREAM Connection callback %d", api_context);
thread_index = s->thread_index;
ASSERT (thread_index == vlib_get_thread_index ()
@@ -553,7 +594,7 @@ quic_ec_session_connected_callback (u32 app_index, u32 api_context,
es = ec_session_alloc (wrk);
es->bytes_to_send = ecm->bytes_to_send;
- es->bytes_to_receive = ecm->no_return ? 0ULL : ecm->bytes_to_send;
+ es->bytes_to_receive = ecm->echo_bytes ? ecm->bytes_to_send : 0ULL;
es->data.rx_fifo = s->rx_fifo;
es->data.rx_fifo->shr->client_session_index = es->data.session_index;
es->data.tx_fifo = s->tx_fifo;
@@ -597,7 +638,8 @@ ec_session_connected_callback (u32 app_index, u32 api_context, session_t *s,
if (err)
{
- clib_warning ("connection %d failed!", api_context);
+ ec_err ("connection %d failed! %U", api_context, format_session_error,
+ err);
ecm->run_test = EC_EXITING;
signal_evt_to_cli (EC_CLI_CONNECTS_FAILED);
return 0;
@@ -607,6 +649,9 @@ ec_session_connected_callback (u32 app_index, u32 api_context, session_t *s,
ASSERT (thread_index == vlib_get_thread_index ()
|| session_transport_service_type (s) == TRANSPORT_SERVICE_CL);
+ if (PREDICT_FALSE (api_context == HS_CTRL_HANDLE))
+ return ec_ctrl_session_connected_callback (s);
+
wrk = ec_worker_get (thread_index);
/*
@@ -615,7 +660,7 @@ ec_session_connected_callback (u32 app_index, u32 api_context, session_t *s,
es = ec_session_alloc (wrk);
es->bytes_to_send = ecm->bytes_to_send;
- es->bytes_to_receive = ecm->no_return ? 0ULL : ecm->bytes_to_send;
+ es->bytes_to_receive = ecm->echo_bytes ? ecm->bytes_to_send : 0ULL;
es->data.rx_fifo = s->rx_fifo;
es->data.rx_fifo->shr->client_session_index = es->data.session_index;
es->data.tx_fifo = s->tx_fifo;
@@ -652,7 +697,7 @@ ec_session_reset_callback (session_t *s)
vnet_disconnect_args_t _a = { 0 }, *a = &_a;
if (s->session_state == SESSION_STATE_READY)
- clib_warning ("Reset active connection %U", format_session, s, 2);
+ ec_err ("Reset active connection %U", format_session, s, 2);
a->handle = session_handle (s);
a->app_index = ecm->app_index;
@@ -671,6 +716,13 @@ ec_session_disconnect_callback (session_t *s)
{
ec_main_t *ecm = &ec_main;
vnet_disconnect_args_t _a = { 0 }, *a = &_a;
+
+ if (session_handle (s) == ecm->ctrl_session_handle)
+ {
+ ec_dbg ("ctrl session disconnect");
+ ecm->ctrl_session_handle = SESSION_INVALID_HANDLE;
+ }
+
a->handle = session_handle (s);
a->app_index = ecm->app_index;
vnet_disconnect_session (a);
@@ -688,12 +740,77 @@ ec_session_disconnect (session_t *s)
}
static int
+ec_ctrl_session_rx_callback (session_t *s)
+{
+ ec_main_t *ecm = &ec_main;
+ int rx_bytes;
+ hs_test_cfg_t cfg = { 0 };
+
+ rx_bytes = svm_fifo_dequeue (s->rx_fifo, sizeof (cfg), (u8 *) &cfg);
+ if (rx_bytes != sizeof (cfg))
+ {
+ ec_err ("invalid cfg length %d (expected %d)", rx_bytes, sizeof (cfg));
+ signal_evt_to_cli (EC_CLI_CONNECTS_FAILED);
+ return -1;
+ }
+
+ ec_dbg ("control message received:");
+ if (ecm->cfg.verbose)
+ hs_test_cfg_dump (&cfg, 1);
+
+ switch (cfg.cmd)
+ {
+ case HS_TEST_CMD_SYNC:
+ switch (ecm->run_test)
+ {
+ case EC_STARTING:
+ if (!hs_test_cfg_verify (&cfg, &ecm->cfg))
+ {
+ ec_err ("invalid config received from server!");
+ signal_evt_to_cli (EC_CLI_CONNECTS_FAILED);
+ return -1;
+ }
+ signal_evt_to_cli (EC_CLI_CFG_SYNC);
+ break;
+
+ case EC_RUNNING:
+ ec_dbg ("test running..");
+ break;
+
+ case EC_EXITING:
+ /* post test sync */
+ signal_evt_to_cli (EC_CLI_CFG_SYNC);
+ break;
+
+ default:
+ ec_err ("unexpected test state! %d", ecm->run_test);
+ break;
+ }
+ break;
+ case HS_TEST_CMD_START:
+ signal_evt_to_cli (EC_CLI_START);
+ break;
+ case HS_TEST_CMD_STOP:
+ signal_evt_to_cli (EC_CLI_STOP);
+ break;
+ default:
+ ec_err ("unexpected cmd! %d", cfg.cmd);
+ break;
+ }
+
+ return 0;
+}
+
+static int
ec_session_rx_callback (session_t *s)
{
ec_main_t *ecm = &ec_main;
ec_worker_t *wrk;
ec_session_t *es;
+ if (PREDICT_FALSE (s->opaque == HS_CTRL_HANDLE))
+ return ec_ctrl_session_rx_callback (s);
+
if (PREDICT_FALSE (ecm->run_test != EC_RUNNING))
{
ec_session_disconnect (s);
@@ -859,7 +976,7 @@ ec_connect_rpc (void *args)
if (rv)
{
- clib_warning ("connect returned: %U", format_session_error, rv);
+ ec_err ("connect returned: %U", format_session_error, rv);
ecm->run_test = EC_EXITING;
signal_evt_to_cli (EC_CLI_CONNECTS_FAILED);
break;
@@ -881,9 +998,89 @@ ec_program_connects (void)
0);
}
-#define ec_cli(_fmt, _args...) \
- if (!ecm->no_output) \
- vlib_cli_output (vm, _fmt, ##_args)
+static clib_error_t *
+ec_ctrl_connect_rpc ()
+{
+ session_error_t rv;
+ ec_main_t *ecm = &ec_main;
+ vnet_connect_args_t _a = {}, *a = &_a;
+
+ a->api_context = HS_CTRL_HANDLE;
+ ecm->cfg.cmd = HS_TEST_CMD_SYNC;
+ clib_memcpy (&a->sep_ext, &ecm->connect_sep, sizeof (ecm->connect_sep));
+ a->sep_ext.transport_proto = TRANSPORT_PROTO_TCP;
+ a->app_index = ecm->app_index;
+
+ rv = vnet_connect (a);
+ if (rv)
+ {
+ ec_err ("ctrl connect returned: %U", format_session_error, rv);
+ ecm->run_test = EC_EXITING;
+ signal_evt_to_cli (EC_CLI_CONNECTS_FAILED);
+ }
+ return 0;
+}
+
+static void
+ec_ctrl_connect (void)
+{
+ session_send_rpc_evt_to_thread_force (transport_cl_thread (),
+ ec_ctrl_connect_rpc, 0);
+}
+
+static void
+ec_ctrl_session_disconnect ()
+{
+ ec_main_t *ecm = &ec_main;
+ vnet_disconnect_args_t _a, *a = &_a;
+ session_error_t err;
+
+ a->handle = ecm->ctrl_session_handle;
+ a->app_index = ecm->app_index;
+ err = vnet_disconnect_session (a);
+ if (err)
+ ec_err ("vnet_disconnect_session: %U", format_session_error, err);
+}
+
+static int
+ec_ctrl_test_sync ()
+{
+ ec_main_t *ecm = &ec_main;
+ ecm->cfg.test = HS_TEST_TYPE_ECHO;
+ return ec_ctrl_send (HS_TEST_CMD_SYNC);
+}
+
+static int
+ec_ctrl_test_start ()
+{
+ return ec_ctrl_send (HS_TEST_CMD_START);
+}
+
+static int
+ec_ctrl_test_stop ()
+{
+ return ec_ctrl_send (HS_TEST_CMD_STOP);
+}
+
+#define ec_wait_for_signal(_sig) \
+ vlib_process_wait_for_event_or_clock (vm, ecm->syn_timeout); \
+ event_type = vlib_process_get_events (vm, &event_data); \
+ switch (event_type) \
+ { \
+ case ~0: \
+ ec_cli ("Timeout while waiting for " #_sig); \
+ error = \
+ clib_error_return (0, "failed: timeout while waiting for " #_sig); \
+ goto cleanup; \
+ case _sig: \
+ break; \
+ default: \
+ ec_cli ("unexpected event while waiting for " #_sig ": %d", \
+ event_type); \
+ error = \
+ clib_error_return (0, "failed: unexpected event: %d", event_type); \
+ goto cleanup; \
+ }
static clib_error_t *
ec_command_fn (vlib_main_t *vm, unformat_input_t *input,
@@ -932,10 +1129,11 @@ ec_command_fn (vlib_main_t *vm, unformat_input_t *input,
;
else if (unformat (line_input, "syn-timeout %f", &ecm->syn_timeout))
;
- else if (unformat (line_input, "no-return"))
- ecm->no_return = 1;
- else if (unformat (line_input, "fifo-size %d", &ecm->fifo_size))
- ecm->fifo_size <<= 10;
+ else if (unformat (line_input, "echo-bytes"))
+ ecm->echo_bytes = 1;
+ else if (unformat (line_input, "fifo-size %U", unformat_memory_size,
+ &ecm->fifo_size))
+ ;
else if (unformat (line_input, "private-segment-count %d",
&ecm->private_segment_count))
;
@@ -960,10 +1158,10 @@ ec_command_fn (vlib_main_t *vm, unformat_input_t *input,
ecm->attach_flags = APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
else if (unformat (line_input, "secret %lu", &ecm->appns_secret))
;
- else if (unformat (line_input, "no-output"))
- ecm->no_output = 1;
+ else if (unformat (line_input, "verbose"))
+ ecm->cfg.verbose = 1;
else if (unformat (line_input, "test-bytes"))
- ecm->test_bytes = 1;
+ ecm->cfg.test_bytes = 1;
else if (unformat (line_input, "tls-engine %d", &ecm->tls_engine))
;
else
@@ -976,11 +1174,12 @@ ec_command_fn (vlib_main_t *vm, unformat_input_t *input,
parse_config:
- ecm->expected_connections = ecm->n_clients * ecm->quic_streams;
+ ecm->cfg.num_test_sessions = ecm->expected_connections =
+ ecm->n_clients * ecm->quic_streams;
if (!ecm->connect_uri)
{
- clib_warning ("No uri provided. Using default: %s", default_uri);
+ ec_cli ("No uri provided. Using default: %s", default_uri);
ecm->connect_uri = format (0, "%s%c", default_uri, 0);
}
@@ -1001,10 +1200,28 @@ parse_config:
goto cleanup;
}
+ if (ecm->echo_bytes)
+ ecm->cfg.test = HS_TEST_TYPE_BI;
+ else
+ ecm->cfg.test = HS_TEST_TYPE_UNI;
+
+ ec_ctrl_connect ();
+ ec_wait_for_signal (EC_CLI_CFG_SYNC);
+
+ if (ec_ctrl_test_start () < 0)
+ {
+ ec_cli ("failed to send start command");
+ goto cleanup;
+ }
+ ec_wait_for_signal (EC_CLI_START);
+
/*
* Start. Fire off connect requests
*/
+ /* update data port */
+ ecm->connect_sep.port = hs_make_data_port (ecm->connect_sep.port);
+
ecm->syn_start_time = vlib_time_now (vm);
ec_program_connects ();
@@ -1021,7 +1238,7 @@ parse_config:
ecm->ready_connections);
error = clib_error_return (0, "failed: syn timeout with %d sessions",
ecm->ready_connections);
- goto cleanup;
+ goto stop_test;
case EC_CLI_CONNECTS_DONE:
delta = vlib_time_now (vm) - ecm->syn_start_time;
@@ -1032,13 +1249,13 @@ parse_config:
case EC_CLI_CONNECTS_FAILED:
error = clib_error_return (0, "failed: connect returned");
- goto cleanup;
+ goto stop_test;
default:
- ec_cli ("unexpected event(1): %d", event_type);
- error = clib_error_return (0, "failed: unexpected event(1): %d",
- event_type);
- goto cleanup;
+ ec_cli ("unexpected event(2): %d", event_type);
+ error =
+ clib_error_return (0, "failed: unexpected event(2): %d", event_type);
+ goto stop_test;
}
/*
@@ -1055,7 +1272,7 @@ parse_config:
vlib_time_now (ecm->vlib_main), ecm->ready_connections);
error = clib_error_return (0, "failed: timeout with %d sessions",
ecm->ready_connections);
- goto cleanup;
+ goto stop_test;
case EC_CLI_TEST_DONE:
ecm->test_end_time = vlib_time_now (vm);
@@ -1063,10 +1280,10 @@ parse_config:
break;
default:
- ec_cli ("unexpected event(2): %d", event_type);
- error = clib_error_return (0, "failed: unexpected event(2): %d",
- event_type);
- goto cleanup;
+ ec_cli ("unexpected event(3): %d", event_type);
+ error =
+ clib_error_return (0, "failed: unexpected event(3): %d", event_type);
+ goto stop_test;
}
/*
@@ -1077,11 +1294,11 @@ parse_config:
{
ec_cli ("zero delta-t?");
error = clib_error_return (0, "failed: zero delta-t");
- goto cleanup;
+ goto stop_test;
}
- total_bytes = (ecm->no_return ? ecm->tx_total : ecm->rx_total);
- transfer_type = ecm->no_return ? "half-duplex" : "full-duplex";
+ total_bytes = (ecm->echo_bytes ? ecm->rx_total : ecm->tx_total);
+ transfer_type = ecm->echo_bytes ? "full-duplex" : "half-duplex";
ec_cli ("%lld bytes (%lld mbytes, %lld gbytes) in %.2f seconds", total_bytes,
total_bytes / (1ULL << 20), total_bytes / (1ULL << 30), delta);
ec_cli ("%.2f bytes/second %s", ((f64) total_bytes) / (delta),
@@ -1089,14 +1306,33 @@ parse_config:
ec_cli ("%.4f gbit/second %s", (((f64) total_bytes * 8.0) / delta / 1e9),
transfer_type);
- if (ecm->test_bytes && ecm->test_failed)
+ if (ecm->cfg.test_bytes && ecm->test_failed)
error = clib_error_return (0, "failed: test bytes");
+stop_test:
+ ecm->run_test = EC_EXITING;
+
+ /* send stop test command to the server */
+ if (ec_ctrl_test_stop () < 0)
+ {
+ ec_cli ("failed to send stop command");
+ goto cleanup;
+ }
+ ec_wait_for_signal (EC_CLI_STOP);
+
+ /* post test sync */
+ if (ec_ctrl_test_sync () < 0)
+ {
+ ec_cli ("failed to send post sync command");
+ goto cleanup;
+ }
+ ec_wait_for_signal (EC_CLI_CFG_SYNC);
+
+ /* disconnect control session */
+ ec_ctrl_session_disconnect ();
+
cleanup:
- /*
- * Cleanup
- */
ecm->run_test = EC_EXITING;
vlib_process_wait_for_event_or_clock (vm, 10e-3);
@@ -1121,10 +1357,10 @@ VLIB_CLI_COMMAND (ec_command, static) = {
.path = "test echo clients",
.short_help =
"test echo clients [nclients %d][[m|g]bytes <bytes>]"
- "[test-timeout <time>][syn-timeout <time>][no-return][fifo-size <size>]"
+ "[test-timeout <time>][syn-timeout <time>][echo-bytes][fifo-size <size>]"
"[private-segment-count <count>][private-segment-size <bytes>[m|g]]"
"[preallocate-fifos][preallocate-sessions][client-batch <batch-size>]"
- "[uri <tcp://ip/port>][test-bytes][no-output]",
+ "[uri <tcp://ip/port>][test-bytes][verbose]",
.function = ec_command_fn,
.is_mp_safe = 1,
};