/* SPDX-License-Identifier: Apache-2.0 * Copyright (c) 2023 Cisco Systems, Inc. */ #include #include #include #include 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 [driver ] " "[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 ", .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 ", .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 [port ] " "[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 [ | sw-if-index ]", .function = device_remove_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, };