| /* SPDX-License-Identifier: Apache-2.0 |
| * Copyright (c) 2023 Cisco Systems, Inc. |
| */ |
| |
| #include <vnet/vnet.h> |
| #include <vnet/dev/dev.h> |
| #include <vnet/dev/counters.h> |
| #include <vnet/dev/api.h> |
| |
| static clib_error_t * |
| device_attach_cmd_fn (vlib_main_t *vm, unformat_input_t *input, |
| vlib_cli_command_t *cmd) |
| { |
| vnet_dev_api_attach_args_t a = {}; |
| vnet_dev_rv_t rv; |
| |
| if (!unformat_user (input, unformat_c_string_array, a.device_id, |
| sizeof (a.device_id))) |
| return clib_error_return (0, "please specify valid device id"); |
| |
| while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) |
| { |
| if (!a.driver_name[0] && |
| unformat (input, "driver %U", unformat_c_string_array, a.driver_name, |
| sizeof (a.driver_name))) |
| ; |
| else if (!a.flags.n && |
| unformat (input, "flags %U", unformat_vnet_dev_flags, &a.flags)) |
| ; |
| else if (!a.args && unformat (input, "args %v", &a.args)) |
| ; |
| else |
| return clib_error_return (0, "unknown input `%U'", |
| format_unformat_error, input); |
| } |
| |
| rv = vnet_dev_api_attach (vm, &a); |
| |
| vec_free (a.args); |
| |
| if (rv != VNET_DEV_OK) |
| return clib_error_return (0, "unable to attach '%s': %U", a.device_id, |
| format_vnet_dev_rv, rv); |
| |
| return 0; |
| } |
| |
| VLIB_CLI_COMMAND (device_attach_cmd, static) = { |
| .path = "device attach", |
| .short_help = "device attach <device-id> [driver <name>] " |
| "[args <dev-args>]", |
| .function = device_attach_cmd_fn, |
| }; |
| |
| static clib_error_t * |
| device_detach_cmd_fn (vlib_main_t *vm, unformat_input_t *input, |
| vlib_cli_command_t *cmd) |
| { |
| vnet_dev_rv_t rv; |
| vnet_dev_device_id_t device_id = {}; |
| vnet_dev_t *dev; |
| |
| if (!unformat_user (input, unformat_c_string_array, device_id, |
| sizeof (device_id))) |
| return clib_error_return (0, "please specify valid device id"); |
| |
| dev = vnet_dev_by_id (device_id); |
| |
| if (dev) |
| { |
| vnet_dev_api_detach_args_t a = { .dev_index = dev->index }; |
| rv = vnet_dev_api_detach (vm, &a); |
| } |
| else |
| rv = VNET_DEV_ERR_UNKNOWN_DEVICE; |
| |
| if (rv != VNET_DEV_OK) |
| return clib_error_return (0, "unable to detach '%s': %U", device_id, |
| format_vnet_dev_rv, rv); |
| |
| return 0; |
| } |
| |
| VLIB_CLI_COMMAND (device_detach_cmd, static) = { |
| .path = "device detach", |
| .short_help = "device detach <device-id>", |
| .function = device_detach_cmd_fn, |
| .is_mp_safe = 1, |
| }; |
| |
| static clib_error_t * |
| device_reset_cmd_fn (vlib_main_t *vm, unformat_input_t *input, |
| vlib_cli_command_t *cmd) |
| { |
| vnet_dev_api_reset_args_t a = {}; |
| vnet_dev_rv_t rv; |
| |
| if (!unformat_user (input, unformat_c_string_array, a.device_id, |
| sizeof (a.device_id))) |
| return clib_error_return (0, "please specify valid device id"); |
| |
| rv = vnet_dev_api_reset (vm, &a); |
| |
| if (rv != VNET_DEV_OK) |
| return clib_error_return (0, "unable to reset '%s': %U", a.device_id, |
| format_vnet_dev_rv, rv); |
| |
| return 0; |
| } |
| |
| VLIB_CLI_COMMAND (device_reset_cmd, static) = { |
| .path = "device reset", |
| .short_help = "device reset <device-id>", |
| .function = device_reset_cmd_fn, |
| .is_mp_safe = 1, |
| }; |
| |
| static clib_error_t * |
| device_create_if_cmd_fn (vlib_main_t *vm, unformat_input_t *input, |
| vlib_cli_command_t *cmd) |
| { |
| vnet_dev_api_create_port_if_args_t a = {}; |
| vnet_dev_rv_t rv; |
| vnet_dev_device_id_t device_id = {}; |
| vnet_dev_t *dev = 0; |
| u32 n; |
| |
| if (unformat_user (input, unformat_c_string_array, device_id, |
| sizeof (device_id))) |
| dev = vnet_dev_by_id (device_id); |
| |
| if (!dev) |
| return clib_error_return (0, "please specify valid device id"); |
| |
| a.dev_index = dev->index; |
| |
| while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) |
| { |
| if (!a.intf_name[0] && |
| unformat (input, "if-name %U", unformat_c_string_array, a.intf_name, |
| sizeof (a.intf_name))) |
| ; |
| else if (!a.port_id && unformat (input, "port %u", &n)) |
| a.port_id = n; |
| else if (!a.flags.n && unformat (input, "flags %U", |
| unformat_vnet_dev_port_flags, &a.flags)) |
| ; |
| else if (!a.num_rx_queues && unformat (input, "num-rx-queues %u", &n)) |
| a.num_rx_queues = n; |
| else if (!a.num_tx_queues && unformat (input, "num-tx-queues %u", &n)) |
| a.num_tx_queues = n; |
| else if (!a.rx_queue_size && unformat (input, "rx-queues-size %u", &n)) |
| a.rx_queue_size = n; |
| else if (!a.tx_queue_size && unformat (input, "tx-queues-size %u", &n)) |
| a.tx_queue_size = n; |
| else if (!a.intf_name[0] && |
| unformat (input, "name %U", unformat_c_string_array, |
| &a.intf_name, sizeof (a.intf_name))) |
| ; |
| else if (!a.args && unformat (input, "args %v", &a.args)) |
| ; |
| else |
| return clib_error_return (0, "unknown input `%U'", |
| format_unformat_error, input); |
| } |
| |
| rv = vnet_dev_api_create_port_if (vm, &a); |
| |
| vec_free (a.args); |
| |
| if (rv != VNET_DEV_OK) |
| return clib_error_return (0, "unable to create_if '%s': %U", device_id, |
| format_vnet_dev_rv, rv); |
| |
| return 0; |
| } |
| |
| VLIB_CLI_COMMAND (device_create_if_cmd, static) = { |
| .path = "device create-interface", |
| .short_help = "device create-interface <device-id> [port <port-id>] " |
| "[args <iface-args>]", |
| .function = device_create_if_cmd_fn, |
| .is_mp_safe = 1, |
| }; |
| |
| static clib_error_t * |
| device_remove_if_cmd_fn (vlib_main_t *vm, unformat_input_t *input, |
| vlib_cli_command_t *cmd) |
| { |
| vnet_dev_api_remove_port_if_args_t a = { .sw_if_index = ~0 }; |
| vnet_main_t *vnm = vnet_get_main (); |
| vnet_dev_rv_t rv; |
| |
| while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) |
| { |
| if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, |
| &a.sw_if_index)) |
| ; |
| else if (unformat (input, "sw-if-index %u", &a.sw_if_index)) |
| ; |
| else |
| return clib_error_return (0, "unknown input `%U'", |
| format_unformat_error, input); |
| } |
| |
| if (a.sw_if_index == ~0) |
| return clib_error_return (0, "please specify existing interface name"); |
| |
| rv = vnet_dev_api_remove_port_if (vm, &a); |
| |
| if (rv != VNET_DEV_OK) |
| return clib_error_return (0, "unable to remove interface: %U", |
| format_vnet_dev_rv, rv); |
| |
| return 0; |
| } |
| |
| VLIB_CLI_COMMAND (device_remove_if_cmd, static) = { |
| .path = "device remove-interface", |
| .short_help = "device remove-interface [<interface-name> | sw-if-index <n>]", |
| .function = device_remove_if_cmd_fn, |
| .is_mp_safe = 1, |
| }; |
| |
| static clib_error_t * |
| device_create_sec_if_cmd_fn (vlib_main_t *vm, unformat_input_t *input, |
| vlib_cli_command_t *cmd) |
| { |
| vnet_dev_api_port_add_sec_if_args_t a = {}; |
| vnet_main_t *vnm = vnet_get_main (); |
| vnet_dev_rv_t rv; |
| |
| while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) |
| { |
| if (!a.intf_name[0] && |
| unformat (input, "if-name %U", unformat_c_string_array, a.intf_name, |
| sizeof (a.intf_name))) |
| ; |
| else if (unformat (input, "primary-if-name %U", |
| unformat_vnet_sw_interface, vnm, |
| &a.primary_sw_if_index)) |
| ; |
| else if (unformat (input, "primary-sw-if-index %u", |
| &a.primary_sw_if_index)) |
| ; |
| else if (!a.args && unformat (input, "args %v", &a.args)) |
| ; |
| else |
| return clib_error_return (0, "unknown input `%U'", |
| format_unformat_error, input); |
| } |
| |
| rv = vnet_dev_api_port_add_sec_if (vm, &a); |
| |
| vec_free (a.args); |
| |
| if (rv != VNET_DEV_OK) |
| return clib_error_return (0, "unable to create secondary interface: %U", |
| format_vnet_dev_rv, rv); |
| |
| return 0; |
| } |
| |
| VLIB_CLI_COMMAND (device_create_sec_if_cmd, static) = { |
| .path = "device create-secondary-interface", |
| .short_help = "device create-secondary-interface [<interface-name> | " |
| "sw-if-index <n>] id <n> [args <sec-if-args>]", |
| .function = device_create_sec_if_cmd_fn, |
| .is_mp_safe = 1, |
| }; |
| |
| static clib_error_t * |
| device_remove_sec_if_cmd_fn (vlib_main_t *vm, unformat_input_t *input, |
| vlib_cli_command_t *cmd) |
| { |
| vnet_dev_api_port_del_sec_if_args_t a = { .sw_if_index = ~0 }; |
| vnet_main_t *vnm = vnet_get_main (); |
| vnet_dev_rv_t rv; |
| |
| while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) |
| { |
| if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, |
| &a.sw_if_index)) |
| ; |
| else if (unformat (input, "sw-if-index %u", &a.sw_if_index)) |
| ; |
| else |
| return clib_error_return (0, "unknown input `%U'", |
| format_unformat_error, input); |
| } |
| |
| if (a.sw_if_index == ~0) |
| return clib_error_return ( |
| 0, "please specify existing secondary interface name"); |
| |
| rv = vnet_dev_api_port_del_sec_if (vm, &a); |
| |
| if (rv != VNET_DEV_OK) |
| return clib_error_return (0, "unable to remove secondary interface: %U", |
| format_vnet_dev_rv, rv); |
| |
| return 0; |
| } |
| |
| VLIB_CLI_COMMAND (device_remove_sec_if_cmd, static) = { |
| .path = "device remove-secondary-interface", |
| .short_help = |
| "device remove-secondary-interface [<interface-name> | sw-if-index <n>]", |
| .function = device_remove_sec_if_cmd_fn, |
| .is_mp_safe = 1, |
| }; |
| |
| static clib_error_t * |
| show_devices_cmd_fn (vlib_main_t *vm, unformat_input_t *input, |
| vlib_cli_command_t *cmd) |
| { |
| vnet_dev_main_t *dm = &vnet_dev_main; |
| vnet_dev_format_args_t fa = {}, *a = &fa; |
| |
| while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) |
| { |
| if (unformat (input, "counters")) |
| fa.counters = 1; |
| else if (unformat (input, "all")) |
| fa.show_zero_counters = 1; |
| else if (unformat (input, "debug")) |
| fa.debug = 1; |
| else |
| return clib_error_return (0, "unknown input `%U'", |
| format_unformat_error, input); |
| } |
| |
| pool_foreach_pointer (dev, dm->devices) |
| { |
| vlib_cli_output (vm, "device '%s':", dev->device_id); |
| vlib_cli_output (vm, " %U", format_vnet_dev_info, a, dev); |
| foreach_vnet_dev_port (p, dev) |
| { |
| vlib_cli_output (vm, " Port %u:", p->port_id); |
| vlib_cli_output (vm, " %U", format_vnet_dev_port_info, a, p); |
| if (fa.counters) |
| vlib_cli_output (vm, " %U", format_vnet_dev_counters, a, |
| p->counter_main); |
| |
| foreach_vnet_dev_port_rx_queue (q, p) |
| { |
| vlib_cli_output (vm, " RX queue %u:", q->queue_id); |
| vlib_cli_output (vm, " %U", format_vnet_dev_rx_queue_info, |
| a, q); |
| } |
| |
| foreach_vnet_dev_port_tx_queue (q, p) |
| { |
| vlib_cli_output (vm, " TX queue %u:", q->queue_id); |
| vlib_cli_output (vm, " %U", format_vnet_dev_tx_queue_info, |
| a, q); |
| } |
| } |
| } |
| return 0; |
| } |
| |
| VLIB_CLI_COMMAND (show_devices_cmd, static) = { |
| .path = "show device", |
| .short_help = "show device [counters]", |
| .function = show_devices_cmd_fn, |
| .is_mp_safe = 1, |
| }; |
| |
| static clib_error_t * |
| show_device_counters_cmd_fn (vlib_main_t *vm, unformat_input_t *input, |
| vlib_cli_command_t *cmd) |
| { |
| vnet_dev_main_t *dm = &vnet_dev_main; |
| vnet_dev_format_args_t fa = { .counters = 1 }; |
| |
| while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) |
| { |
| if (unformat (input, "all")) |
| fa.show_zero_counters = 1; |
| else |
| return clib_error_return (0, "unknown input `%U'", |
| format_unformat_error, input); |
| } |
| |
| pool_foreach_pointer (dev, dm->devices) |
| { |
| vlib_cli_output (vm, "device '%s':", dev->device_id); |
| foreach_vnet_dev_port (p, dev) |
| { |
| vlib_cli_output (vm, " Port %u:", p->port_id); |
| vlib_cli_output (vm, " %U", format_vnet_dev_counters, &fa, |
| p->counter_main); |
| |
| foreach_vnet_dev_port_rx_queue (q, p) |
| if (q->counter_main) |
| { |
| vlib_cli_output (vm, " RX queue %u:", q->queue_id); |
| vlib_cli_output (vm, " %U", format_vnet_dev_counters, &fa, |
| q->counter_main); |
| } |
| |
| foreach_vnet_dev_port_tx_queue (q, p) |
| if (q->counter_main) |
| { |
| vlib_cli_output (vm, " TX queue %u:", q->queue_id); |
| vlib_cli_output (vm, " %U", format_vnet_dev_counters, &fa, |
| q->counter_main); |
| } |
| } |
| } |
| return 0; |
| } |
| |
| VLIB_CLI_COMMAND (show_device_counters_cmd, static) = { |
| .path = "show device counters", |
| .short_help = "show device counters [all]", |
| .function = show_device_counters_cmd_fn, |
| .is_mp_safe = 1, |
| }; |