diff options
Diffstat (limited to 'src/vnet/dev/handlers.c')
-rw-r--r-- | src/vnet/dev/handlers.c | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/src/vnet/dev/handlers.c b/src/vnet/dev/handlers.c new file mode 100644 index 00000000000..7e7347eb217 --- /dev/null +++ b/src/vnet/dev/handlers.c @@ -0,0 +1,225 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2023 Cisco Systems, Inc. + */ + +#include <vnet/vnet.h> +#include <vnet/ethernet/ethernet.h> +#include <vnet/dev/dev.h> +#include <vnet/dev/counters.h> +#include <vnet/dev/log.h> +#include <vnet/flow/flow.h> + +VLIB_REGISTER_LOG_CLASS (dev_log, static) = { + .class_name = "dev", + .subclass_name = "handler", +}; + +clib_error_t * +vnet_dev_port_set_max_frame_size (vnet_main_t *vnm, vnet_hw_interface_t *hw, + u32 frame_size) +{ + vlib_main_t *vm = vlib_get_main (); + vnet_dev_port_t *p = vnet_dev_get_port_from_dev_instance (hw->dev_instance); + vnet_dev_rv_t rv; + + vnet_dev_port_cfg_change_req_t req = { + .type = VNET_DEV_PORT_CFG_MAX_FRAME_SIZE, + .max_frame_size = frame_size, + }; + + log_debug (p->dev, "size %u", frame_size); + + rv = vnet_dev_port_cfg_change_req_validate (vm, p, &req); + if (rv == VNET_DEV_ERR_NO_CHANGE) + return 0; + + if (rv != VNET_DEV_OK) + return vnet_dev_port_err (vm, p, rv, + "new max frame size is not valid for port"); + + if ((rv = vnet_dev_process_port_cfg_change_req (vm, p, &req)) != VNET_DEV_OK) + return vnet_dev_port_err (vm, p, rv, + "device failed to change max frame size"); + + return 0; +} + +u32 +vnet_dev_port_eth_flag_change (vnet_main_t *vnm, vnet_hw_interface_t *hw, + u32 flags) +{ + vlib_main_t *vm = vlib_get_main (); + vnet_dev_port_t *p = vnet_dev_get_port_from_dev_instance (hw->dev_instance); + vnet_dev_rv_t rv; + + vnet_dev_port_cfg_change_req_t req = { + .type = VNET_DEV_PORT_CFG_PROMISC_MODE, + }; + + switch (flags) + { + case ETHERNET_INTERFACE_FLAG_DEFAULT_L3: + log_debug (p->dev, "promisc off"); + break; + case ETHERNET_INTERFACE_FLAG_ACCEPT_ALL: + log_debug (p->dev, "promisc on"); + req.promisc = 1; + break; + default: + return ~0; + } + + rv = vnet_dev_port_cfg_change_req_validate (vm, p, &req); + if (rv == VNET_DEV_ERR_NO_CHANGE) + return 0; + + if (rv != VNET_DEV_OK) + return ~0; + + rv = vnet_dev_process_port_cfg_change_req (vm, p, &req); + if (rv == VNET_DEV_OK || rv == VNET_DEV_ERR_NO_CHANGE) + return 0; + return ~0; +} + +clib_error_t * +vnet_dev_port_mac_change (vnet_hw_interface_t *hi, const u8 *old, + const u8 *new) +{ + vlib_main_t *vm = vlib_get_main (); + vnet_dev_port_t *p = vnet_dev_get_port_from_dev_instance (hi->dev_instance); + vnet_dev_rv_t rv; + + vnet_dev_port_cfg_change_req_t req = { + .type = VNET_DEV_PORT_CFG_CHANGE_PRIMARY_HW_ADDR, + }; + + vnet_dev_set_hw_addr_eth_mac (&req.addr, new); + + log_debug (p->dev, "new mac %U", format_vnet_dev_hw_addr, &req.addr); + + rv = vnet_dev_port_cfg_change_req_validate (vm, p, &req); + if (rv == VNET_DEV_ERR_NO_CHANGE) + return 0; + + if (rv != VNET_DEV_OK) + return vnet_dev_port_err (vm, p, rv, "hw address is not valid for port"); + + if ((rv = vnet_dev_process_port_cfg_change_req (vm, p, &req)) != VNET_DEV_OK) + return vnet_dev_port_err (vm, p, rv, "device failed to change hw address"); + + return 0; +} + +clib_error_t * +vnet_dev_add_del_mac_address (vnet_hw_interface_t *hi, const u8 *address, + u8 is_add) +{ + vlib_main_t *vm = vlib_get_main (); + vnet_dev_port_t *p = vnet_dev_get_port_from_dev_instance (hi->dev_instance); + vnet_dev_rv_t rv; + + vnet_dev_port_cfg_change_req_t req = { + .type = is_add ? VNET_DEV_PORT_CFG_ADD_SECONDARY_HW_ADDR : + VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR, + }; + + vnet_dev_set_hw_addr_eth_mac (&req.addr, address); + + log_debug (p->dev, "received (addr %U is_add %u", format_vnet_dev_hw_addr, + &req.addr, is_add); + + rv = vnet_dev_port_cfg_change_req_validate (vm, p, &req); + if (rv != VNET_DEV_OK) + return vnet_dev_port_err (vm, p, rv, + "provided secondary hw addresses cannot " + "be added/removed"); + + if ((rv = vnet_dev_process_port_cfg_change_req (vm, p, &req)) != VNET_DEV_OK) + return vnet_dev_port_err ( + vm, p, rv, "device failed to add/remove secondary hw address"); + + return 0; +} + +int +vnet_dev_flow_ops_fn (vnet_main_t *vnm, vnet_flow_dev_op_t op, + u32 dev_instance, u32 flow_index, uword *private_data) +{ + vnet_dev_port_t *p = vnet_dev_get_port_from_dev_instance (dev_instance); + log_warn (p->dev, "unsupported request for flow_ops received"); + return VNET_FLOW_ERROR_NOT_SUPPORTED; +} + +clib_error_t * +vnet_dev_interface_set_rss_queues (vnet_main_t *vnm, vnet_hw_interface_t *hi, + clib_bitmap_t *bitmap) +{ + vnet_dev_port_t *p = vnet_dev_get_port_from_dev_instance (hi->dev_instance); + log_warn (p->dev, "unsupported request for flow_ops received"); + return vnet_error (VNET_ERR_UNSUPPORTED, "not implemented"); +} + +void +vnet_dev_clear_hw_interface_counters (u32 instance) +{ + vnet_dev_port_t *port = vnet_dev_get_port_from_dev_instance (instance); + vlib_main_t *vm = vlib_get_main (); + + vnet_dev_process_call_port_op_no_rv (vm, port, vnet_dev_port_clear_counters); +} + +clib_error_t * +vnet_dev_rx_mode_change_fn (vnet_main_t *vnm, u32 hw_if_index, u32 qid, + vnet_hw_if_rx_mode mode) +{ + return clib_error_return (0, "not supported"); +} + +void +vnet_dev_set_interface_next_node (vnet_main_t *vnm, u32 hw_if_index, + u32 node_index) +{ + vlib_main_t *vm = vlib_get_main (); + vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index); + vnet_dev_port_t *port = + vnet_dev_get_port_from_dev_instance (hw->dev_instance); + int runtime_update = 0; + + if (node_index == ~0) + { + port->intf.redirect_to_node_next_index = 0; + if (port->intf.feature_arc == 0) + { + port->intf.rx_next_index = + vnet_dev_default_next_index_by_port_type[port->attr.type]; + runtime_update = 1; + } + port->intf.redirect_to_node = 0; + } + else + { + u16 next_index = vlib_node_add_next (vlib_get_main (), + port_rx_eth_node.index, node_index); + port->intf.redirect_to_node_next_index = next_index; + if (port->intf.feature_arc == 0) + { + port->intf.rx_next_index = next_index; + runtime_update = 1; + } + port->intf.redirect_to_node = 1; + } + port->intf.rx_next_index = + node_index == ~0 ? + vnet_dev_default_next_index_by_port_type[port->attr.type] : + node_index; + + if (runtime_update) + { + foreach_vnet_dev_port_rx_queue (rxq, port) + vnet_dev_rx_queue_rt_request ( + vm, rxq, (vnet_dev_rx_queue_rt_req_t){ .update_next_index = 1 }); + log_debug (port->dev, "runtime update requested due to chgange in " + "reditect-to-next configuration"); + } +} |