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)
es->bytes_to_send -= rv;
es->bytes_sent += rv;
- if (EC_DBG)
+ if (ecm->cfg.verbose)
{
ELOG_TYPE_DECLARE (e) =
{
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 =
if (n_read > 0)
{
- if (EC_DBG)
+ if (ecm->cfg.verbose)
{
ELOG_TYPE_DECLARE (e) =
{
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;
}
}
ecm->prev_conns = vec_len (conns_this_batch);
if (ecm->repeats == 500000)
{
- clib_warning ("stuck clients");
+ ec_err ("stuck clients");
}
}
else
}
else
{
- clib_warning ("session AWOL?");
+ ec_err ("session AWOL?");
vec_delete (conns_this_batch, 1, i);
}
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;
ec_init (vlib_main_t *vm)
{
ec_main_t *ecm = &ec_main;
- vlib_thread_main_t *vtm = vlib_get_thread_main ();
ec_worker_t *wrk;
u32 num_threads;
int i;
for (i = 0; i < vec_len (ecm->connect_test_data); i++)
ecm->connect_test_data[i] = i & 0xff;
- num_threads = 1 /* main thread */ + vtm->n_threads;
- vec_validate (ecm->wrk, num_threads);
+ num_threads = 1 /* main thread */ + vlib_num_workers ();
+ vec_validate (ecm->wrk, num_threads - 1);
vec_foreach (wrk, ecm->wrk)
{
vec_validate (wrk->rx_buf, vec_len (ecm->connect_test_data) - 1);
vlib_worker_thread_barrier_sync (vm);
vnet_session_enable_disable (vm, 1 /* turn on session and transports */);
- vlib_worker_thread_barrier_release (vm);
/* Turn on the builtin client input nodes */
- for (i = 0; i < vtm->n_vlib_mains; i++)
- vlib_node_set_state (vlib_get_main_by_index (i), echo_clients_node.index,
+ foreach_vlib_main ()
+ vlib_node_set_state (this_vlib_main, echo_clients_node.index,
VLIB_NODE_STATE_POLLING);
+ vlib_worker_thread_barrier_release (vm);
+
return 0;
}
{
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;
}
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;
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 ()
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;
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;
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);
/*
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;
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;
{
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);
vnet_disconnect_session (a);
}
+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_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);
receive_data_chunk (wrk, es);
if (svm_fifo_max_dequeue_cons (s->rx_fifo))
- {
- if (svm_fifo_set_event (s->rx_fifo))
- session_send_io_evt_to_thread (s->rx_fifo, SESSION_IO_EVT_BUILTIN_RX);
- }
+ session_enqueue_notify (s);
+
return 0;
}
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;
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,
;
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))
;
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
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);
}
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 ();
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;
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;
}
/*
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);
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;
}
/*
{
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),
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);
.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,
};