From 162ff5e4122572045ea7976c77ba3286fb05eeb5 Mon Sep 17 00:00:00 2001 From: Nathan Skrzypczak Date: Tue, 9 Nov 2021 18:18:21 +0100 Subject: [PATCH] interface: Add interface monitor cli This adds an interface CLI 'monitor interface ' that periodically reports rx/tx pps & bandwidth for a given interface. Type: feature Change-Id: Ia9d59b3443913520a52b38d7bda012190be6f167 Signed-off-by: Nathan Skrzypczak --- src/vnet/CMakeLists.txt | 1 + src/vnet/interface/monitor.c | 119 +++++++++++++++++++++++++++++++++++++++++++ src/vppinfra/format.h | 3 ++ src/vppinfra/std-formats.c | 18 +++++++ 4 files changed, 141 insertions(+) create mode 100644 src/vnet/interface/monitor.c diff --git a/src/vnet/CMakeLists.txt b/src/vnet/CMakeLists.txt index 5dd7cdb24ab..a8b13b62548 100644 --- a/src/vnet/CMakeLists.txt +++ b/src/vnet/CMakeLists.txt @@ -38,6 +38,7 @@ list(APPEND VNET_SOURCES interface/rx_queue.c interface/tx_queue.c interface/runtime.c + interface/monitor.c interface_stats.c misc.c ) diff --git a/src/vnet/interface/monitor.c b/src/vnet/interface/monitor.c new file mode 100644 index 00000000000..6d79154ae0a --- /dev/null +++ b/src/vnet/interface/monitor.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +static clib_error_t * +monitor_interface_command_fn (vlib_main_t *vm, unformat_input_t *input, + vlib_cli_command_t *cmd) +{ + const vnet_main_t *vnm = vnet_get_main (); + const vlib_combined_counter_main_t *counters = + vnm->interface_main.combined_sw_if_counters; + f64 refresh_interval = 1.0; + u32 refresh_count = ~0; + clib_error_t *error = 0; + vlib_counter_t vrx[2], vtx[2]; + f64 ts[2]; + u32 hw_if_index = ~0; + u8 spin = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "%U", unformat_vnet_hw_interface, vnm, + &hw_if_index)) + ; + else if (unformat (input, "interval %f", &refresh_interval)) + ; + else if (unformat (input, "count %u", &refresh_count)) + ; + else + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + goto done; + } + } + + if (hw_if_index == ~0) + { + error = clib_error_return (0, "no interface passed"); + goto done; + } + + vlib_get_combined_counter (counters + VNET_INTERFACE_COUNTER_RX, hw_if_index, + &vrx[spin]); + vlib_get_combined_counter (counters + VNET_INTERFACE_COUNTER_TX, hw_if_index, + &vtx[spin]); + ts[spin] = vlib_time_now (vm); + + while (refresh_count--) + { + f64 sleep_interval, tsd; + + while (((sleep_interval = + ts[spin] + refresh_interval - vlib_time_now (vm)) > 0.0)) + { + uword event_type, *event_data = 0; + vlib_process_wait_for_event_or_clock (vm, sleep_interval); + event_type = vlib_process_get_events (vm, &event_data); + switch (event_type) + { + case ~0: /* no events => timeout */ + break; + default: + /* someone pressed a key, abort */ + vlib_cli_output (vm, "Aborted due to a keypress."); + goto done; + } + vec_free (event_data); + } + spin ^= 1; + vlib_get_combined_counter (counters + VNET_INTERFACE_COUNTER_RX, + hw_if_index, &vrx[spin]); + vlib_get_combined_counter (counters + VNET_INTERFACE_COUNTER_TX, + hw_if_index, &vtx[spin]); + ts[spin] = vlib_time_now (vm); + + tsd = ts[spin] - ts[spin ^ 1]; + vlib_cli_output ( + vm, "rx: %Upps %Ubps tx: %Upps %Ubps%c", format_base10, + (u32) ((vrx[spin].packets - vrx[spin ^ 1].packets) / tsd), + format_base10, (u32) ((vrx[spin].bytes - vrx[spin ^ 1].bytes) / tsd), + format_base10, + (u32) ((vtx[spin].packets - vtx[spin ^ 1].packets) / tsd), + format_base10, (u32) ((vtx[spin].bytes - vtx[spin ^ 1].bytes) / tsd)); + } + +done: + return error; +} + +VLIB_CLI_COMMAND (monitor_interface_command, static) = { + .path = "monitor interface", + .short_help = + "monitor interface [interval ] [count ]", + .function = monitor_interface_command_fn, + .is_mp_safe = 1, +}; + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vppinfra/format.h b/src/vppinfra/format.h index cad9b0e0ef2..b70384c0e41 100644 --- a/src/vppinfra/format.h +++ b/src/vppinfra/format.h @@ -287,6 +287,9 @@ unformat_function_t unformat_eof; /* Parse memory size e.g. 100, 100k, 100m, 100g. */ unformat_function_t unformat_memory_size; +/* Format base 10 e.g. 100, 100K, 100M, 100G */ +u8 *format_base10 (u8 *s, va_list *va); + /* Unparse memory size e.g. 100, 100k, 100m, 100g. */ u8 *format_memory_size (u8 * s, va_list * va); diff --git a/src/vppinfra/std-formats.c b/src/vppinfra/std-formats.c index 1616001f9c5..1a150ead7bd 100644 --- a/src/vppinfra/std-formats.c +++ b/src/vppinfra/std-formats.c @@ -204,6 +204,24 @@ format_time_interval (u8 * s, va_list * args) return s; } +/* Format base 10 e.g. 100, 100K, 100M, 100G */ +__clib_export u8 * +format_base10 (u8 *s, va_list *va) +{ + uword size = va_arg (*va, uword); + + if (size < 1000) + s = format (s, "%d", size); + else if (size < 1000000) + s = format (s, "%.2fK", (f64) size / 1000.); + else if (size < 1000000000) + s = format (s, "%.2fM", (f64) size / 1000000.); + else + s = format (s, "%.2fG", (f64) size / 1000000000.); + + return s; +} + /* Unparse memory size e.g. 100, 100k, 100m, 100g. */ __clib_export u8 * format_memory_size (u8 * s, va_list * va) -- 2.16.6