diff options
author | Florin Coras <fcoras@cisco.com> | 2019-08-31 09:45:13 -0700 |
---|---|---|
committer | Florin Coras <fcoras@cisco.com> | 2019-09-04 10:38:49 -0700 |
commit | 5bb23ecd098eac639641e2b3d62eb8744e0efef0 (patch) | |
tree | 6a9a4e77ea11641c51b381af7019e409e3f013cf /src/vnet/session/session_cli.c | |
parent | 8b4114e52f69b9292efb282e49ed4d90699ceeb8 (diff) |
session: improve cli
Type: feature
Allow session cli filtering based on thread index, transport protocol,
session state and range of session pool indices. For instance
show session thread 1 proto tcp state ready range 0 20 verbose
Shows the session ids for the first 20 tcp sessions in thread 1 that are
in ready state.
To avoid excessive output that could reasult in the worker barrier being
held by the main thread for long periods of time, the session cli will
only output:
- session ids (verbose == 1) for a maximum of 50 sessions / worker
- verbose > 1 details for a maximum of 10 sessions
Change-Id: I2cfb351b548e2e0a1d5b4345810be613e2917d17
Signed-off-by: Florin Coras <fcoras@cisco.com>
Diffstat (limited to 'src/vnet/session/session_cli.c')
-rwxr-xr-x | src/vnet/session/session_cli.c | 341 |
1 files changed, 284 insertions, 57 deletions
diff --git a/src/vnet/session/session_cli.c b/src/vnet/session/session_cli.c index fd598f45d3e..d8aedd64e23 100755 --- a/src/vnet/session/session_cli.c +++ b/src/vnet/session/session_cli.c @@ -162,6 +162,27 @@ unformat_stream_session_id (unformat_input_t * input, va_list * args) } uword +unformat_session_state (unformat_input_t * input, va_list * args) +{ + session_state_t *state = va_arg (*args, session_state_t *); + u8 *state_vec = 0; + int rv = 0; + +#define _(sym, str) \ + if (unformat (input, str)) \ + { \ + *state = SESSION_STATE_ ## sym; \ + rv = 1; \ + goto done; \ + } + foreach_session_state +#undef _ +done: + vec_free (state_vec); + return rv; +} + +uword unformat_session (unformat_input_t * input, va_list * args) { session_t **result = va_arg (*args, session_t **); @@ -227,42 +248,270 @@ unformat_transport_connection (unformat_input_t * input, va_list * args) return 0; } +static void +session_cli_show_all_sessions (vlib_main_t * vm, int verbose) +{ + session_main_t *smm = &session_main; + u32 n_closed = 0, thread_index; + session_t *pool, *s; + + for (thread_index = 0; thread_index < vec_len (smm->wrk); thread_index++) + { + pool = smm->wrk[thread_index].sessions; + + if (!pool_elts (pool)) + { + vlib_cli_output (vm, "Thread %d: no sessions", thread_index); + continue; + } + + if (!verbose) + { + vlib_cli_output (vm, "Thread %d: %d sessions", thread_index, + pool_elts (pool)); + continue; + } + + if (pool_elts (pool) > 50) + { + vlib_cli_output (vm, "Thread %u: %d sessions. Verbose output " + "suppressed. For more details use filters.", + thread_index, pool_elts (pool)); + continue; + } + + if (verbose == 1) + vlib_cli_output (vm, "%s%-50s%-15s%-10s%-10s", + thread_index ? "\n" : "", + "Connection", "State", "Rx-f", "Tx-f"); + + /* *INDENT-OFF* */ + pool_foreach(s, pool, ({ + if (s->session_state >= SESSION_STATE_TRANSPORT_DELETED) + { + n_closed += 1; + continue; + } + vlib_cli_output (vm, "%U", format_session, s, verbose); + })); + /* *INDENT-ON* */ + + if (!n_closed) + vlib_cli_output (vm, "Thread %d: active sessions %u", thread_index, + pool_elts (pool) - n_closed); + else + vlib_cli_output (vm, "Thread %d: active sessions %u closed %u", + thread_index, pool_elts (pool) - n_closed, n_closed); + } +} + +static int +session_cli_filter_check (session_t * s, session_state_t * states, + transport_proto_t tp) +{ + if (states) + { + session_state_t *state; + vec_foreach (state, states) if (s->session_state == *state) + goto check_transport; + return 0; + } + +check_transport: + + if (tp != TRANSPORT_N_PROTO && session_get_transport_proto (s) != tp) + return 0; + + return 1; +} + +static void +session_cli_show_session_filter (vlib_main_t * vm, u32 thread_index, + u32 start, u32 end, session_state_t * states, + transport_proto_t tp, int verbose) +{ + u8 output_suppressed = 0; + session_worker_t *wrk; + session_t *pool, *s; + u32 count = 0, max_index; + int i; + + wrk = session_main_get_worker_if_valid (thread_index); + if (!wrk) + { + vlib_cli_output (vm, "invalid thread index %u", thread_index); + return; + } + + pool = wrk->sessions; + + if (tp == TRANSPORT_N_PROTO && states == 0 && !verbose + && (start == 0 && end == ~0)) + { + vlib_cli_output (vm, "Thread %d: %u sessions", thread_index, + pool_elts (pool)); + return; + } + + max_index = pool_elts (pool) ? pool_elts (pool) - 1 : 0; + for (i = start; i <= clib_min (end, max_index); i++) + { + if (pool_is_free_index (pool, i)) + continue; + + s = pool_elt_at_index (pool, i); + + if (session_cli_filter_check (s, states, tp)) + { + count += 1; + if (verbose) + { + if (count > 50 || (verbose > 1 && count > 10)) + { + output_suppressed = 1; + continue; + } + if (s->session_state < SESSION_STATE_TRANSPORT_DELETED) + vlib_cli_output (vm, "%U", format_session, s, verbose); + } + } + } + + if (!output_suppressed) + vlib_cli_output (vm, "Thread %d: %u sessions matched filter", + thread_index, count); + else + vlib_cli_output (vm, "Thread %d: %u sessions matched filter. Not all" + " shown. Use finer grained filter.", thread_index, + count); +} + +static void +session_cli_print_transport_protos (vlib_main_t * vm) +{ +#define _(sym, str, sstr) vlib_cli_output (vm, str); + foreach_transport_proto +#undef _ +} + +static void +session_cli_print_session_states (vlib_main_t * vm) +{ +#define _(sym, str) vlib_cli_output (vm, str); + foreach_session_state +#undef _ +} + static clib_error_t * show_session_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { - u8 one_session = 0, do_listeners = 0, sst, do_elog = 0; + u8 one_session = 0, do_listeners = 0, sst, do_elog = 0, do_filter = 0; + u32 track_index, thread_index = 0, start = 0, end = ~0, session_index; + unformat_input_t _line_input, *line_input = &_line_input; + transport_proto_t transport_proto = TRANSPORT_N_PROTO; + session_state_t state = SESSION_N_STATES, *states = 0; session_main_t *smm = &session_main; - u32 transport_proto = ~0, track_index; - session_t *pool, *s; - transport_connection_t *tc; + clib_error_t *error = 0; app_worker_t *app_wrk; - int verbose = 0, i; + u32 transport_index; const u8 *app_name; + int verbose = 0; + session_t *s; - if (!smm->is_enabled) + session_cli_return_if_not_enabled (); + + if (!unformat_user (input, unformat_line_input, line_input)) { - return clib_error_return (0, "session layer is not enabled"); + session_cli_show_all_sessions (vm, 0); + return 0; } - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { - if (unformat (input, "verbose %d", &verbose)) + if (unformat (line_input, "verbose %d", &verbose)) ; - else if (unformat (input, "verbose")) + else if (unformat (line_input, "verbose")) verbose = 1; - else if (unformat (input, "listeners %U", unformat_transport_proto, + else if (unformat (line_input, "listeners %U", unformat_transport_proto, &transport_proto)) do_listeners = 1; - else if (unformat (input, "%U", unformat_session, &s)) + else if (unformat (line_input, "%U", unformat_session, &s)) { one_session = 1; } - else if (unformat (input, "elog")) + else if (unformat (line_input, "thread %u index %u", &thread_index, + &session_index)) + { + s = session_get_if_valid (session_index, thread_index); + if (!s) + { + vlib_cli_output (vm, "session is not allocated"); + goto done; + } + one_session = 1; + } + else if (unformat (line_input, "thread %u", &thread_index)) + { + do_filter = 1; + } + else + if (unformat (line_input, "state %U", unformat_session_state, &state)) + { + vec_add1 (states, state); + do_filter = 1; + } + else if (unformat (line_input, "proto %U index %u", + unformat_transport_proto, &transport_proto, + &transport_index)) + { + transport_connection_t *tc; + tc = transport_get_connection (transport_proto, transport_index, + thread_index); + if (!tc) + { + vlib_cli_output (vm, "transport connection %u thread %u is not" + " allocated", transport_index, thread_index); + goto done; + } + s = session_get_if_valid (tc->s_index, thread_index); + if (!s) + { + vlib_cli_output (vm, "session for transport connection %u " + "thread %u does not exist", transport_index, + thread_index); + goto done; + } + one_session = 1; + } + else if (unformat (line_input, "proto %U", unformat_transport_proto, + &transport_proto)) + do_filter = 1; + else if (unformat (line_input, "range %u %u", &start, &end)) + do_filter = 1; + else if (unformat (line_input, "range %u", &start)) + { + end = start + 50; + do_filter = 1; + } + else if (unformat (line_input, "elog")) do_elog = 1; + else if (unformat (line_input, "protos")) + { + session_cli_print_transport_protos (vm); + goto done; + } + else if (unformat (line_input, "states")) + { + session_cli_print_session_states (vm); + goto done; + } else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } if (one_session) @@ -271,6 +520,7 @@ show_session_command_fn (vlib_main_t * vm, unformat_input_t * input, if (do_elog && s->session_state != SESSION_STATE_LISTENING) { elog_main_t *em = &vm->elog_main; + transport_connection_t *tc; f64 dt; tc = session_get_transport (s); @@ -283,7 +533,7 @@ show_session_command_fn (vlib_main_t * vm, unformat_input_t * input, } vlib_cli_output (vm, "%v", str); vec_free (str); - return 0; + goto done; } if (do_listeners) @@ -301,53 +551,28 @@ show_session_command_fn (vlib_main_t * vm, unformat_input_t * input, app_name); })); /* *INDENT-ON* */ - return 0; + goto done; } - for (i = 0; i < vec_len (smm->wrk); i++) + if (do_filter) { - u32 once_per_pool = 1, n_closed = 0; - - pool = smm->wrk[i].sessions; - if (!pool_elts (pool)) - { - vlib_cli_output (vm, "Thread %d: no sessions", i); - continue; - } - - if (!verbose) - { - vlib_cli_output (vm, "Thread %d: %d sessions", i, pool_elts (pool)); - continue; - } - - if (once_per_pool && verbose == 1) + if (end < start) { - vlib_cli_output (vm, "%s%-50s%-15s%-10s%-10s", i ? "\n" : "", - "Connection", "State", "Rx-f", "Tx-f"); - once_per_pool = 0; + error = clib_error_return (0, "invalid range start: %u end: %u", + start, end); + goto done; } - - /* *INDENT-OFF* */ - pool_foreach (s, pool, ({ - if (s->session_state >= SESSION_STATE_TRANSPORT_DELETED) - { - n_closed += 1; - continue; - } - vlib_cli_output (vm, "%U", format_session, s, verbose); - })); - /* *INDENT-ON* */ - - if (!n_closed) - vlib_cli_output (vm, "Thread %d: active sessions %u", i, - pool_elts (pool) - n_closed); - else - vlib_cli_output (vm, "Thread %d: active sessions %u closed %u", i, - pool_elts (pool) - n_closed, n_closed); + session_cli_show_session_filter (vm, thread_index, start, end, states, + transport_proto, verbose); + goto done; } - return 0; + session_cli_show_all_sessions (vm, verbose); + +done: + unformat_free (line_input); + vec_free (states); + return error; } /* *INDENT-OFF* */ @@ -355,7 +580,9 @@ VLIB_CLI_COMMAND (vlib_cli_show_session_command) = { .path = "show session", .short_help = "show session [verbose [n]] [listeners <proto>] " - "[<session-id> [elog]]", + "[<session-id> [elog]] [thread <n> [index <n>] " + "[proto <proto>] [state <state>] [range <min> [<max>]] " + "[protos] [states] ", .function = show_session_command_fn, }; /* *INDENT-ON* */ |