diff options
Diffstat (limited to 'src/plugins/hs_apps/echo_client.c')
-rw-r--r-- | src/plugins/hs_apps/echo_client.c | 372 |
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, }; |