/* * Copyright (c) 2018 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 #include #include #include static format_function_t format_flow; uword unformat_ip_port_and_mask (unformat_input_t * input, va_list * args) { ip_port_and_mask_t *pm = va_arg (*args, ip_port_and_mask_t *); u32 port = 0, mask = 0; if (unformat (input, "any")) ; else if (unformat (input, "%u/%u", &port, &mask)) ; else if (unformat (input, "%u/0x%x", &port, &mask)) ; else if (unformat (input, "%u", &port)) mask = 0xffff; else return 0; if (port > 0xffff || mask > 0xffff) return 0; pm->port = port; pm->mask = mask; return 1; } u8 * format_ip_port_and_mask (u8 * s, va_list * args) { ip_port_and_mask_t *pm = va_arg (*args, ip_port_and_mask_t *); if (pm->port == 0 && pm->mask == 0) return format (s, "any"); if (pm->mask == 0xffff) return format (s, "%u", pm->port); return format (s, "%u/0x%x", pm->port, pm->mask); } u8 * format_flow_error (u8 * s, va_list * args) { int error = va_arg (*args, int); if (error == 0) return format (s, "no error"); #define _(v,n,str) if (error == v) return format (s, #str); foreach_flow_error; #undef _ return format (s, "unknown error (%d)", error); } u8 * format_flow_actions (u8 * s, va_list * args) { u32 actions = va_arg (*args, u32); u8 *t = 0; #define _(a, b, c) if (actions & (1 << a)) \ t = format (t, "%s%s", t ? " ":"", c); foreach_flow_action #undef _ s = format (s, "%v", t); vec_free (t); return s; } u8 * format_flow_enabled_hw (u8 * s, va_list * args) { u32 flow_index = va_arg (*args, u32); vnet_flow_t *f = vnet_get_flow (flow_index); if (f == 0) return format (s, "not found"); u8 *t = 0; u32 hw_if_index; uword private_data; vnet_main_t *vnm = vnet_get_main (); /* *INDENT-OFF* */ hash_foreach (hw_if_index, private_data, f->private_data, ({ t = format (t, "%s%U", t ? ", " : "", format_vnet_hw_if_index_name, vnm, hw_if_index); })); /* *INDENT-ON* */ s = format (s, "%v", t); vec_free (t); return s; } static const char *flow_type_strings[] = { 0, #define _(a,b,c) c, foreach_flow_type #undef _ }; static clib_error_t * show_flow_entry (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd_arg) { vnet_main_t *vnm = vnet_get_main (); vnet_flow_main_t *fm = &flow_main; unformat_input_t _line_input, *line_input = &_line_input; vnet_hw_interface_t *hi; vnet_device_class_t *dev_class; vnet_flow_t *f; uword private_data; u32 index = ~0, hw_if_index; if (!unformat_user (input, unformat_line_input, line_input)) goto no_args; while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { if (unformat (line_input, "index %u", &index)) ; else return clib_error_return (0, "parse error: '%U'", format_unformat_error, line_input); } unformat_free (line_input); if (index != ~0) { if ((f = vnet_get_flow (index)) == 0) return clib_error_return (0, "no such flow"); vlib_cli_output (vm, "%-10s: %u", "index", f->index); vlib_cli_output (vm, "%-10s: %s", "type", flow_type_strings[f->type]); vlib_cli_output (vm, "%-10s: %U", "match", format_flow, f); /* *INDENT-OFF* */ hash_foreach (hw_if_index, private_data, f->private_data, ({ hi = vnet_get_hw_interface (vnm, hw_if_index); dev_class = vnet_get_device_class (vnm, hi->dev_class_index); vlib_cli_output (vm, "interface %U\n", format_vnet_hw_if_index_name, vnm, hw_if_index); if (dev_class->format_flow) vlib_cli_output (vm, " %U\n", dev_class->format_flow, hi->dev_instance, f->index, private_data); })); /* *INDENT-ON* */ return 0; } no_args: /* *INDENT-OFF* */ pool_foreach (f, fm->global_flow_pool, { vlib_cli_output (vm, "%U\n", format_flow, f); }); /* *INDENT-ON* */ return 0; } /* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_flow_entry_command, static) = { .path = "show flow entry", .short_help = "show flow entry [index ]", .function = show_flow_entry, }; /* *INDENT-ON* */ static clib_error_t * show_flow_ranges (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd_arg) { vnet_flow_main_t *fm = &flow_main; vnet_flow_range_t *r = 0; vlib_cli_output (vm, "%8s %8s %s", "Start", "Count", "Owner"); /* *INDENT-OFF* */ vec_foreach (r, fm->ranges) { vlib_cli_output (vm, "%8u %8u %s", r->start, r->count, r->owner); }; /* *INDENT-ON* */ return 0; } /* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_flow_ranges_command, static) = { .path = "show flow ranges", .short_help = "show flow ranges", .function = show_flow_ranges, }; /* *INDENT-ON* */ static clib_error_t * show_flow_interface (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd_arg) { vnet_main_t *vnm = vnet_get_main (); vnet_hw_interface_t *hi; vnet_device_class_t *dev_class; unformat_input_t _line_input, *line_input = &_line_input; u32 hw_if_index = ~0; if (unformat_user (input, unformat_line_input, line_input)) { while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { if (unformat (line_input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index)) ; else return clib_error_return (0, "parse error: '%U'", format_unformat_error, line_input); } unformat_free (line_input); } if (hw_if_index == ~0) return clib_error_return (0, "please specify interface"); hi = vnet_get_hw_interface (vnm, hw_if_index); dev_class = vnet_get_device_class (vnm, hi->dev_class_index); if (dev_class->format_flow == 0) return clib_error_return (0, "not supported"); vlib_cli_output (vm, "%U", dev_class->format_flow, hi->dev_instance, ~0, 0); return 0; } /* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_flow_interface_command, static) = { .path = "show flow interface", .short_help = "show flow interface ", .function = show_flow_interface, }; /* *INDENT-ON* */ static clib_error_t * test_flow (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd_arg) { vnet_flow_t flow; vnet_main_t *vnm = vnet_get_main (); unformat_input_t _line_input, *line_input = &_line_input; enum { FLOW_UNKNOWN_ACTION, FLOW_ADD, FLOW_DEL, FLOW_ENABLE, FLOW_DISABLE } action = FLOW_UNKNOWN_ACTION; u32 hw_if_index = ~0, flow_index = ~0; int rv; u32 prot = 0, teid = 0; vnet_flow_type_t type = VNET_FLOW_TYPE_IP4_N_TUPLE; bool is_gtpc_set = false; bool is_gtpu_set = false; vnet_flow_type_t outer_type = VNET_FLOW_TYPE_UNKNOWN; vnet_flow_type_t inner_type = VNET_FLOW_TYPE_UNKNOWN; bool outer_ip4_set = false, inner_ip4_set = false; bool outer_ip6_set = false, inner_ip6_set = false; ip4_address_and_mask_t ip4s = { }; ip4_address_and_mask_t ip4d = { }; ip4_address_and_mask_t inner_ip4s = { }; ip4_address_and_mask_t inner_ip4d = { }; ip6_address_and_mask_t ip6s = { }; ip6_address_and_mask_t ip6d = { }; ip6_address_and_mask_t inner_ip6s = { }; ip6_address_and_mask_t inner_ip6d = { }; ip_port_and_mask_t sport = { }; ip_port_and_mask_t dport = { }; u16 eth_type; bool ethernet_set = false; clib_memset (&flow, 0, sizeof (vnet_flow_t)); flow.index = ~0; flow.actions = 0; flow.ip4_n_tuple.protocol = ~0; if (!unformat_user (input, unformat_line_input, line_input)) return 0; while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { if (unformat (line_input, "add")) action = FLOW_ADD; else if (unformat (line_input, "del
.. _cpuusage:

**************
CPU Load/Usage
**************

There are various commands and tools that can help users see FD.io VPP CPU and memory usage at runtime.

Linux top/htop
==============

The Linux top and htop are decent tools to look at FD.io VPP cpu and memory usage, but they will only show
preallocated memory and total CPU usage. These commands can be useful to show which cores VPP is running on.

This is an example of VPP instance that is running on cores 8 and 9. For this output type **top** and then
type **1** when the tool starts.

.. code-block:: console

    $ top

    top - 11:04:04 up 35 days,  3:16,  5 users,  load average: 2.33, 2.23, 2.16
    Tasks: 435 total,   2 running, 432 sleeping,   1 stopped,   0 zombie
    %Cpu0  :  1.0 us,  0.7 sy,  0.0 ni, 98.0 id,  0.0 wa,  0.0 hi,  0.3 si,  0.0 st
    %Cpu1  :  2.0 us,  0.3 sy,  0.0 ni, 97.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu2  :  0.7 us,  1.0 sy,  0.0 ni, 98.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu3  :  1.7 us,  0.7 sy,  0.0 ni, 97.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu4  :  2.0 us,  0.7 sy,  0.0 ni, 97.4 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu5  :  3.0 us,  0.3 sy,  0.0 ni, 96.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu6  :  2.3 us,  0.7 sy,  0.0 ni, 97.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu7  :  2.6 us,  0.3 sy,  0.0 ni, 97.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu8  : 96.0 us,  0.3 sy,