diff options
author | Damjan Marion <damarion@cisco.com> | 2024-10-08 20:50:56 +0200 |
---|---|---|
committer | Damjan Marion <damjan.marion@gmail.com> | 2024-11-07 16:49:49 +0100 |
commit | 61e287b9f895fa7cd9809ec74e44efee780a5aad (patch) | |
tree | 2a1f6e6f038062940d9b04dce480ed07394c9407 | |
parent | de020ab4788d75e70f0cfea4c21f09a4716be161 (diff) |
dev: secondary interfaces support
Type: feature
Change-Id: I6cc4340431b8273022955fca1600061a722e3ace
Signed-off-by: Damjan Marion <damarion@cisco.com>
-rw-r--r-- | src/vnet/dev/api.c | 97 | ||||
-rw-r--r-- | src/vnet/dev/api.h | 23 | ||||
-rw-r--r-- | src/vnet/dev/cli.c | 88 | ||||
-rw-r--r-- | src/vnet/dev/dev.c | 48 | ||||
-rw-r--r-- | src/vnet/dev/dev.h | 124 | ||||
-rw-r--r-- | src/vnet/dev/dev_funcs.h | 98 | ||||
-rw-r--r-- | src/vnet/dev/errors.h | 3 | ||||
-rw-r--r-- | src/vnet/dev/format.c | 30 | ||||
-rw-r--r-- | src/vnet/dev/handlers.c | 82 | ||||
-rw-r--r-- | src/vnet/dev/port.c | 345 | ||||
-rw-r--r-- | src/vnet/dev/queue.c | 10 |
11 files changed, 765 insertions, 183 deletions
diff --git a/src/vnet/dev/api.c b/src/vnet/dev/api.c index 48ceccf3b6c..d968f66c316 100644 --- a/src/vnet/dev/api.c +++ b/src/vnet/dev/api.c @@ -156,6 +156,7 @@ vnet_dev_api_create_port_if (vlib_main_t *vm, { vnet_dev_t *dev = vnet_dev_by_index (args->dev_index); vnet_dev_port_t *port = 0; + vnet_dev_port_if_create_args_t a = {}; u16 n_threads = vlib_get_n_threads (); int default_is_intr_mode; vnet_dev_rv_t rv; @@ -181,7 +182,7 @@ vnet_dev_api_create_port_if (vlib_main_t *vm, if (!port) return VNET_DEV_ERR_INVALID_DEVICE_ID; - if (port->interface_created) + if (port->interfaces) return VNET_DEV_ERR_ALREADY_EXISTS; if (args->args) @@ -202,47 +203,82 @@ vnet_dev_api_create_port_if (vlib_main_t *vm, { if (args->num_rx_queues > port->attr.max_rx_queues) return VNET_DEV_ERR_INVALID_NUM_RX_QUEUES; - port->intf.num_rx_queues = args->num_rx_queues; + a.num_rx_queues = args->num_rx_queues; } else - port->intf.num_rx_queues = clib_min (port->attr.max_tx_queues, 1); + a.num_rx_queues = clib_min (port->attr.max_tx_queues, 1); if (args->num_tx_queues) { if (args->num_tx_queues > port->attr.max_tx_queues) return VNET_DEV_ERR_INVALID_NUM_TX_QUEUES; - port->intf.num_tx_queues = args->num_tx_queues; + a.num_tx_queues = args->num_tx_queues; } else - port->intf.num_tx_queues = clib_min (port->attr.max_tx_queues, n_threads); + a.num_tx_queues = clib_min (port->attr.max_tx_queues, n_threads); if (args->rx_queue_size) { if (!_vnet_dev_queue_size_validate (args->rx_queue_size, port->rx_queue_config)) return VNET_DEV_ERR_INVALID_RX_QUEUE_SIZE; - port->intf.rxq_sz = args->rx_queue_size; + a.rxq_sz = args->rx_queue_size; } else - port->intf.rxq_sz = port->rx_queue_config.default_size; + a.rxq_sz = port->rx_queue_config.default_size; if (args->tx_queue_size) { if (!_vnet_dev_queue_size_validate (args->tx_queue_size, port->tx_queue_config)) return VNET_DEV_ERR_INVALID_TX_QUEUE_SIZE; - port->intf.txq_sz = args->tx_queue_size; + a.txq_sz = args->tx_queue_size; } else - port->intf.txq_sz = port->tx_queue_config.default_size; + a.txq_sz = port->tx_queue_config.default_size; - clib_memcpy (port->intf.name, args->intf_name, sizeof (port->intf.name)); - port->intf.default_is_intr_mode = default_is_intr_mode; - port->intf.consistent_qp = - (args->flags.n & VNET_DEV_PORT_F_CONSISTENT_QP) != 0; + clib_memcpy (a.name, args->intf_name, sizeof (a.name)); + a.default_is_intr_mode = default_is_intr_mode; + a.consistent_qp = (args->flags.n & VNET_DEV_PORT_F_CONSISTENT_QP) != 0; - rv = vnet_dev_process_call_port_op (vm, port, vnet_dev_port_if_create); - args->sw_if_index = (rv == VNET_DEV_OK) ? port->intf.sw_if_index : ~0; + rv = vnet_dev_process_call_port_op_with_ptr (vm, port, + vnet_dev_port_if_create, &a); + args->sw_if_index = (rv == VNET_DEV_OK) ? a.sw_if_index : ~0; + + return rv; +} + +vnet_dev_rv_t +vnet_dev_api_port_add_sec_if (vlib_main_t *vm, + vnet_dev_api_port_add_sec_if_args_t *args) +{ + vnet_dev_port_t *port = 0; + vnet_dev_t *dev = 0; + vnet_dev_port_sec_if_create_args_t a = {}; + vnet_dev_rv_t rv = VNET_DEV_OK; + + port = vnet_dev_get_port_from_sw_if_index (args->primary_sw_if_index); + if (port == 0) + return VNET_DEV_ERR_NOT_FOUND; + + log_debug (dev, + "create_port_if: primary_sw_if_index %u intf_name '%s' " + "args '%v'", + args->primary_sw_if_index, args->intf_name, args->args); + + if (port->interfaces == 0) + return VNET_DEV_ERR_PRIMARY_INTERFACE_MISSING; + + clib_memcpy (a.name, args->intf_name, sizeof (a.name)); + a.args = args->args; + + rv = vnet_dev_process_call_port_op_with_ptr (vm, port, + vnet_dev_port_add_sec_if, &a); + + if (rv != VNET_DEV_OK) + args->sw_if_index = ~0; + else + args->sw_if_index = a.sw_if_index; return rv; } @@ -251,9 +287,23 @@ vnet_dev_rv_t vnet_dev_api_remove_port_if (vlib_main_t *vm, vnet_dev_api_remove_port_if_args_t *args) { + vnet_dev_port_t *port; + + port = vnet_dev_get_port_from_sw_if_index (args->sw_if_index); + + if (port == 0) + return VNET_DEV_ERR_UNKNOWN_INTERFACE; + + return vnet_dev_process_call_port_op (vm, port, vnet_dev_port_if_remove); +} + +vnet_dev_rv_t +vnet_dev_api_port_del_sec_if (vlib_main_t *vm, + vnet_dev_api_port_del_sec_if_args_t *args) +{ vnet_dev_main_t *dm = &vnet_dev_main; vnet_main_t *vnm = vnet_get_main (); - vnet_sw_interface_t *si; + vnet_sw_interface_t *si, *sup_si; vnet_hw_interface_t *hi; vnet_dev_port_t *port; @@ -261,7 +311,14 @@ vnet_dev_api_remove_port_if (vlib_main_t *vm, if (!si) return VNET_DEV_ERR_UNKNOWN_INTERFACE; - hi = vnet_get_hw_interface_or_null (vnm, si->hw_if_index); + if (si->sup_sw_if_index == si->sw_if_index) + return VNET_DEV_ERR_UNKNOWN_INTERFACE; + + sup_si = vnet_get_sw_interface_or_null (vnm, si->sup_sw_if_index); + if (!sup_si) + return VNET_DEV_ERR_UNKNOWN_INTERFACE; + + hi = vnet_get_hw_interface_or_null (vnm, sup_si->hw_if_index); if (!hi) return VNET_DEV_ERR_UNKNOWN_INTERFACE; @@ -270,8 +327,10 @@ vnet_dev_api_remove_port_if (vlib_main_t *vm, port = vnet_dev_get_port_from_dev_instance (hi->dev_instance); - if (port->intf.hw_if_index != si->hw_if_index) + if (port->interfaces->primary_interface.hw_if_index != si->hw_if_index) return VNET_DEV_ERR_UNKNOWN_INTERFACE; - return vnet_dev_process_call_port_op (vm, port, vnet_dev_port_if_remove); + return vnet_dev_process_call_port_op_with_ptr ( + vm, port, vnet_dev_port_del_sec_if, + &(vnet_dev_port_del_sec_if_args_t){ .sw_if_index = args->sw_if_index }); } diff --git a/src/vnet/dev/api.h b/src/vnet/dev/api.h index 1b7bf27d62a..3e552e4326e 100644 --- a/src/vnet/dev/api.h +++ b/src/vnet/dev/api.h @@ -65,4 +65,27 @@ vnet_dev_rv_t vnet_dev_api_remove_port_if (vlib_main_t *, vnet_dev_api_remove_port_if_args_t *); +typedef struct +{ + u32 primary_sw_if_index; + vnet_dev_if_name_t intf_name; + u8 *args; + + /* return */ + u32 sw_if_index; +} vnet_dev_api_port_add_sec_if_args_t; + +vnet_dev_rv_t +vnet_dev_api_port_add_sec_if (vlib_main_t *, + vnet_dev_api_port_add_sec_if_args_t *); + +typedef struct +{ + u32 sw_if_index; +} vnet_dev_api_port_del_sec_if_args_t; + +vnet_dev_rv_t +vnet_dev_api_port_del_sec_if (vlib_main_t *, + vnet_dev_api_port_del_sec_if_args_t *); + #endif /* _VNET_DEV_API_H_ */ diff --git a/src/vnet/dev/cli.c b/src/vnet/dev/cli.c index 608abcfd989..6002a2f0dee 100644 --- a/src/vnet/dev/cli.c +++ b/src/vnet/dev/cli.c @@ -223,6 +223,94 @@ VLIB_CLI_COMMAND (device_remove_if_cmd, static) = { }; 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) { diff --git a/src/vnet/dev/dev.c b/src/vnet/dev/dev.c index e04fa161ce2..7954707dd32 100644 --- a/src/vnet/dev/dev.c +++ b/src/vnet/dev/dev.c @@ -130,7 +130,7 @@ vnet_dev_deinit (vlib_main_t *vm, vnet_dev_t *dev) vnet_dev_validate (vm, dev); foreach_vnet_dev_port (p, dev) - ASSERT (p->interface_created == 0); + ASSERT (p->interfaces == 0); if (dev->ops.deinit) dev->ops.deinit (vm, dev); @@ -188,7 +188,7 @@ void vnet_dev_detach (vlib_main_t *vm, vnet_dev_t *dev) { foreach_vnet_dev_port (p, dev) - if (p->interface_created) + if (p->interfaces) vnet_dev_port_if_remove (vm, p); vnet_dev_deinit (vm, dev); vnet_dev_free (vm, dev); @@ -260,6 +260,8 @@ vnet_dev_feature_update_cb (u32 sw_if_index, u8 arc_index, u8 is_enable, vnet_feature_config_main_t *cm; vnet_dev_main_t *vdm = &vnet_dev_main; vnet_dev_port_t *port; + vnet_dev_port_interface_t *intf; + vnet_dev_instance_t *di; vnet_hw_interface_t *hw; u32 current_config_index = ~0; u32 next_index = ~0; @@ -269,9 +271,18 @@ vnet_dev_feature_update_cb (u32 sw_if_index, u8 arc_index, u8 is_enable, return; hw = vnet_get_sup_hw_interface (vnm, sw_if_index); - port = vnet_dev_get_port_from_dev_instance (hw->dev_instance); + di = vnet_dev_get_dev_instance (hw->dev_instance); - if (port == 0 || port->intf.sw_if_index != sw_if_index) + if (!di) + return; + + intf = di->is_primary_if ? + vnet_dev_port_get_primary_if (di->port) : + vnet_dev_port_get_sec_if_by_index (di->port, di->sec_if_index); + + port = di->port; + + if (port == 0 || intf->sw_if_index != sw_if_index) return; if (vnet_have_features (arc_index, sw_if_index)) @@ -281,28 +292,27 @@ vnet_dev_feature_update_cb (u32 sw_if_index, u8 arc_index, u8 is_enable, vec_elt (cm->config_index_by_sw_if_index, sw_if_index); vnet_get_config_data (&cm->config_main, ¤t_config_index, &next_index, 0); - if (port->intf.feature_arc == 0 || - port->intf.rx_next_index != next_index || - port->intf.current_config_index != current_config_index) + if (intf->feature_arc == 0 || intf->rx_next_index != next_index || + intf->current_config_index != current_config_index) { - port->intf.current_config_index = current_config_index; - port->intf.rx_next_index = next_index; - port->intf.feature_arc_index = arc_index; - port->intf.feature_arc = 1; + intf->current_config_index = current_config_index; + intf->rx_next_index = next_index; + intf->feature_arc_index = arc_index; + intf->feature_arc = 1; update_runtime = 1; } } else { - if (port->intf.feature_arc) + if (intf->feature_arc) { - port->intf.current_config_index = 0; - port->intf.rx_next_index = - port->intf.redirect_to_node ? - port->intf.redirect_to_node_next_index : - vnet_dev_default_next_index_by_port_type[port->attr.type]; - port->intf.feature_arc_index = 0; - port->intf.feature_arc = 0; + intf->current_config_index = 0; + intf->rx_next_index = + intf->redirect_to_node ? + intf->redirect_to_node_next_index : + vnet_dev_default_next_index_by_port_type[port->attr.type]; + intf->feature_arc_index = 0; + intf->feature_arc = 0; update_runtime = 1; } } diff --git a/src/vnet/dev/dev.h b/src/vnet/dev/dev.h index 76ff4f55b71..f3f7563317e 100644 --- a/src/vnet/dev/dev.h +++ b/src/vnet/dev/dev.h @@ -29,7 +29,8 @@ typedef enum _ (interrupt_mode) \ _ (rss) \ _ (change_max_rx_frame_size) \ - _ (mac_filter) + _ (mac_filter) \ + _ (secondary_interfaces) #define foreach_vnet_dev_port_rx_offloads _ (ip4_cksum) @@ -253,6 +254,8 @@ typedef struct vnet_dev_port_op_no_rv_t *deinit; vnet_dev_port_op_no_rv_t *free; vnet_dev_port_op_no_rv_t *clear_counters; + vnet_dev_port_op_with_ptr_t *add_sec_if; + vnet_dev_port_op_with_ptr_t *del_sec_if; format_function_t *format_status; format_function_t *format_flow; } vnet_dev_port_ops_t; @@ -269,30 +272,41 @@ typedef union u8 as_number; } vnet_dev_rx_queue_rt_req_t; +typedef struct +{ + vlib_buffer_template_t buffer_template; + u32 sw_if_index; + u16 next_index; + u16 sec_if_index; +} vnet_dev_rx_queue_if_rt_data_t; + typedef struct vnet_dev_rx_queue { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); vnet_dev_port_t *port; u16 rx_thread_index; u16 index; - vnet_dev_counter_main_t *counter_main; - CLIB_CACHE_LINE_ALIGN_MARK (runtime0); - vnet_dev_rx_queue_t *next_on_thread; + u16 size; u8 interrupt_mode : 1; u8 enabled : 1; u8 started : 1; u8 suspended : 1; - vnet_dev_queue_id_t queue_id; - u16 size; - u16 next_index; vnet_dev_rx_queue_rt_req_t runtime_request; + vnet_dev_counter_main_t *counter_main; + vnet_dev_rx_queue_t *next_on_thread; + vnet_dev_queue_id_t queue_id; + vnet_dev_rx_queue_if_rt_data_t **sec_if_rt_data; CLIB_CACHE_LINE_ALIGN_MARK (runtime1); - vlib_buffer_template_t buffer_template; + vnet_dev_rx_queue_if_rt_data_t if_rt_data; CLIB_CACHE_LINE_ALIGN_MARK (driver_data); u8 data[]; } vnet_dev_rx_queue_t; +#if CLIB_CACHE_LINE_BYTES > 64 +STATIC_ASSERT_SIZEOF (vnet_dev_rx_queue_t, 2 * CLIB_CACHE_LINE_BYTES); +#else STATIC_ASSERT_SIZEOF (vnet_dev_rx_queue_t, 3 * CLIB_CACHE_LINE_BYTES); +#endif typedef struct vnet_dev_tx_queue { @@ -314,6 +328,38 @@ typedef struct vnet_dev_tx_queue STATIC_ASSERT_SIZEOF (vnet_dev_tx_queue_t, 2 * CLIB_CACHE_LINE_BYTES); +typedef struct +{ + vnet_dev_if_name_t name; + u8 interface_created : 1; + u8 feature_arc : 1; + u8 redirect_to_node : 1; + u8 feature_arc_index; + u16 rx_next_index; + u32 index; + u32 sw_if_index; + u32 hw_if_index; + u32 dev_instance; + u32 tx_node_index; + u32 next_index; + u32 current_config_index; + u16 redirect_to_node_next_index; + u32 user_data; + vnet_dev_arg_t *args; +} vnet_dev_port_interface_t; + +typedef struct +{ + u32 rx_node_index; + u8 default_is_intr_mode : 1; + u16 num_rx_queues; + u16 num_tx_queues; + u16 txq_sz; + u16 rxq_sz; + vnet_dev_port_interface_t primary_interface; + vnet_dev_port_interface_t **secondary_interfaces; +} vnet_dev_port_interfaces_t; + typedef struct vnet_dev_port { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); @@ -324,7 +370,6 @@ typedef struct vnet_dev_port u8 started : 1; u8 link_up : 1; u8 promisc : 1; - u8 interface_created : 1; u8 rx_node_assigned : 1; vnet_dev_counter_main_t *counter_main; vnet_dev_queue_config_t rx_queue_config; @@ -339,32 +384,12 @@ typedef struct vnet_dev_port vnet_dev_tx_queue_t **tx_queues; vnet_dev_port_ops_t port_ops; vnet_dev_arg_t *args; + vnet_dev_arg_t *sec_if_args; vnet_dev_rx_queue_ops_t rx_queue_ops; vnet_dev_tx_queue_ops_t tx_queue_ops; vnet_dev_node_t rx_node; vnet_dev_node_t tx_node; - - struct - { - vnet_dev_if_name_t name; - u32 dev_instance; - u32 rx_node_index; - u32 current_config_index; - u16 rx_next_index; - u16 redirect_to_node_next_index; - u8 feature_arc_index; - u8 feature_arc : 1; - u8 redirect_to_node : 1; - u8 default_is_intr_mode : 1; - u8 consistent_qp : 1; - u32 tx_node_index; - u32 hw_if_index; - u32 sw_if_index; - u16 num_rx_queues; - u16 num_tx_queues; - u16 txq_sz; - u16 rxq_sz; - } intf; + vnet_dev_port_interfaces_t *interfaces; CLIB_CACHE_LINE_ALIGN_MARK (data0); u8 data[]; @@ -463,6 +488,8 @@ typedef struct typedef struct { vnet_dev_port_t *port; + u32 sec_if_index; + u8 is_primary_if : 1; } vnet_dev_instance_t; typedef struct @@ -493,6 +520,7 @@ typedef struct vnet_dev_port_attr_t attr; vnet_dev_port_ops_t ops; vnet_dev_arg_t *args; + vnet_dev_arg_t *sec_if_args; u16 data_size; void *initial_data; } port; @@ -578,12 +606,44 @@ void vnet_dev_clear_hw_interface_counters (u32); void vnet_dev_set_interface_next_node (vnet_main_t *, u32, u32); /* port.c */ + +typedef struct +{ + vnet_dev_if_name_t name; + u16 num_rx_queues; + u16 num_tx_queues; + u16 rxq_sz; + u16 txq_sz; + u8 default_is_intr_mode : 1; + u8 consistent_qp : 1; + + /* return */ + u32 sw_if_index; +} vnet_dev_port_if_create_args_t; + +typedef struct +{ + vnet_dev_if_name_t name; + u8 *args; + + /* return */ + u32 sw_if_index; +} vnet_dev_port_sec_if_create_args_t; + +typedef struct +{ + u32 sw_if_index; +} vnet_dev_port_del_sec_if_args_t; + vnet_dev_port_op_t vnet_dev_port_start; vnet_dev_port_op_t vnet_dev_port_start_all_rx_queues; vnet_dev_port_op_t vnet_dev_port_start_all_tx_queues; vnet_dev_port_op_no_rv_t vnet_dev_port_stop; vnet_dev_port_op_no_rv_t vnet_dev_port_deinit; vnet_dev_port_op_no_rv_t vnet_dev_port_free; +vnet_dev_port_op_with_ptr_t vnet_dev_port_add_sec_if; +vnet_dev_port_op_with_ptr_t vnet_dev_port_del_sec_if; + void vnet_dev_port_add_counters (vlib_main_t *, vnet_dev_port_t *, vnet_dev_counter_t *, u16); vnet_dev_port_op_no_rv_t vnet_dev_port_free_counters; @@ -596,7 +656,7 @@ vnet_dev_port_cfg_change_req_validate (vlib_main_t *, vnet_dev_port_t *, vnet_dev_port_cfg_change_req_t *); vnet_dev_rv_t vnet_dev_port_cfg_change (vlib_main_t *, vnet_dev_port_t *, vnet_dev_port_cfg_change_req_t *); -vnet_dev_port_op_t vnet_dev_port_if_create; +vnet_dev_port_op_with_ptr_t vnet_dev_port_if_create; vnet_dev_port_op_t vnet_dev_port_if_remove; /* queue.c */ diff --git a/src/vnet/dev/dev_funcs.h b/src/vnet/dev/dev_funcs.h index 0531b17a009..f47344b0cea 100644 --- a/src/vnet/dev/dev_funcs.h +++ b/src/vnet/dev/dev_funcs.h @@ -60,6 +60,18 @@ vnet_dev_get_dev_instance (u32 dev_instance) return pool_elt_at_index (dm->dev_instances, dev_instance); } +static_always_inline vnet_dev_port_interface_t * +vnet_dev_port_get_primary_if (vnet_dev_port_t *p) +{ + return &p->interfaces->primary_interface; +} + +static_always_inline vnet_dev_port_interface_t * +vnet_dev_port_get_sec_if_by_index (vnet_dev_port_t *p, u32 index) +{ + return *pool_elt_at_index (p->interfaces->secondary_interfaces, index); +} + static_always_inline vnet_dev_port_t * vnet_dev_get_port_from_dev_instance (u32 dev_instance) { @@ -76,7 +88,8 @@ vnet_dev_get_port_from_hw_if_index (u32 hw_if_index) hw = vnet_get_hw_interface (vnet_get_main (), hw_if_index); port = vnet_dev_get_port_from_dev_instance (hw->dev_instance); - if (!port || port->intf.hw_if_index != hw_if_index) + if (!port || !port->interfaces || + port->interfaces->primary_interface.hw_if_index != hw_if_index) return 0; return port; @@ -85,19 +98,32 @@ vnet_dev_get_port_from_hw_if_index (u32 hw_if_index) static_always_inline u32 vnet_dev_get_rx_queue_if_sw_if_index (vnet_dev_rx_queue_t *rxq) { - return rxq->port->intf.sw_if_index; + return rxq->port->interfaces->primary_interface.sw_if_index; } static_always_inline u32 vnet_dev_get_rx_queue_if_hw_if_index (vnet_dev_rx_queue_t *rxq) { - return rxq->port->intf.hw_if_index; + return rxq->port->interfaces->primary_interface.hw_if_index; } static_always_inline u32 vnet_dev_get_port_rx_node_index (vnet_dev_port_t *port) { - return port->intf.rx_node_index; + return port->interfaces->rx_node_index; +} + +static_always_inline vnet_dev_port_t * +vnet_dev_get_port_from_sw_if_index (u32 sw_if_index) +{ + vnet_main_t *vnm = vnet_get_main (); + vnet_sw_interface_t *si; + + si = vnet_get_sw_interface_or_null (vnm, sw_if_index); + if (!si) + return 0; + + return vnet_dev_get_port_from_hw_if_index (si->hw_if_index); } static_always_inline vnet_dev_t * @@ -219,22 +245,49 @@ vnet_dev_tx_queue_unlock_if_needed (vnet_dev_tx_queue_t *txq) __atomic_store_n (&txq->lock, 0, __ATOMIC_RELEASE); } +static_always_inline vnet_dev_rx_queue_if_rt_data_t * +vnet_dev_get_rx_queue_if_rt_data (vnet_dev_rx_queue_t *rxq) +{ + return &rxq->if_rt_data; +} + +static_always_inline vnet_dev_rx_queue_if_rt_data_t * +vnet_dev_get_rx_queue_sec_if_rt_data (vnet_dev_rx_queue_t *rxq, + u32 sec_if_index) +{ + return rxq->sec_if_rt_data[sec_if_index]; +} + static_always_inline vlib_buffer_template_t vnet_dev_get_rx_queue_if_buffer_template (vnet_dev_rx_queue_t *rxq) { - return rxq->buffer_template; + return rxq->if_rt_data.buffer_template; +} + +static_always_inline vlib_buffer_template_t +vnet_dev_get_rx_queue_sec_if_buffer_template (vnet_dev_rx_queue_t *rxq, + u32 sec_if_index) +{ + return rxq->sec_if_rt_data[sec_if_index]->buffer_template; } static_always_inline u16 vnet_dev_get_rx_queue_if_next_index (vnet_dev_rx_queue_t *rxq) { - return rxq->next_index; + return rxq->if_rt_data.next_index; +} + +static_always_inline u16 +vnet_dev_get_rx_queue_sec_if_next_index (vnet_dev_rx_queue_t *rxq, + u32 sec_if_index) +{ + return rxq->sec_if_rt_data[sec_if_index]->next_index; } static_always_inline u8 vnet_dev_get_rx_queue_buffer_pool_index (vnet_dev_rx_queue_t *rxq) { - return rxq->buffer_template.buffer_pool_index; + return rxq->if_rt_data.buffer_template.buffer_pool_index; } static_always_inline u32 @@ -269,8 +322,8 @@ static_always_inline vnet_dev_rx_queue_t * foreach_vnet_dev_rx_queue_runtime_helper (vlib_node_runtime_t *node, vnet_dev_rx_queue_t *rxq) { - vnet_dev_port_t *port; vnet_dev_rx_queue_rt_req_t req; + vnet_dev_port_interfaces_t *ifs; if (rxq == 0) rxq = vnet_dev_get_rx_node_runtime (node)->first_rx_queue; @@ -287,15 +340,34 @@ foreach_vnet_dev_rx_queue_runtime_helper (vlib_node_runtime_t *node, req.as_number = __atomic_exchange_n (&rxq->runtime_request.as_number, 0, __ATOMIC_ACQUIRE); - port = rxq->port; + ifs = rxq->port->interfaces; if (req.update_next_index) - rxq->next_index = port->intf.rx_next_index; + { + vnet_dev_port_interface_t **si = + rxq->port->interfaces->secondary_interfaces; + rxq->if_rt_data.next_index = ifs->primary_interface.rx_next_index; + vec_foreach_pointer (rtd, rxq->sec_if_rt_data) + if (rtd) + rtd->next_index = si[rtd->sec_if_index]->next_index; + } if (req.update_feature_arc) { - vlib_buffer_template_t *bt = &rxq->buffer_template; - bt->current_config_index = port->intf.current_config_index; - vnet_buffer (bt)->feature_arc_index = port->intf.feature_arc_index; + vnet_dev_port_interface_t **si = + rxq->port->interfaces->secondary_interfaces; + vlib_buffer_template_t *bt = &rxq->if_rt_data.buffer_template; + bt->current_config_index = ifs->primary_interface.current_config_index; + vnet_buffer (bt)->feature_arc_index = + ifs->primary_interface.feature_arc_index; + vec_foreach_pointer (rtd, rxq->sec_if_rt_data) + if (rtd) + { + vlib_buffer_template_t *bt = &rtd->buffer_template; + bt->current_config_index = + si[rtd->sec_if_index]->current_config_index; + vnet_buffer (bt)->feature_arc_index = + si[rtd->sec_if_index]->feature_arc_index; + } } if (req.suspend_on) diff --git a/src/vnet/dev/errors.h b/src/vnet/dev/errors.h index 6ececad12ec..243b10e698e 100644 --- a/src/vnet/dev/errors.h +++ b/src/vnet/dev/errors.h @@ -37,9 +37,12 @@ _ (TIMEOUT, "timeout") \ _ (UNKNOWN_DEVICE, "unknown device") \ _ (UNKNOWN_INTERFACE, "unknown interface") \ + _ (NOT_PRIMARY_INTERFACE, "not primary interface") \ + _ (PRIMARY_INTERFACE_MISSING, "primary interface missing") \ _ (UNSUPPORTED_CONFIG, "unsupported config") \ _ (UNSUPPORTED_DEVICE, "unsupported device") \ _ (UNSUPPORTED_DEVICE_VER, "unsupported device version") \ + _ (UNSUPPORTED_INTERFACE, "unsupported interface") \ _ (ALREADY_DONE, "already done") \ _ (NO_SUCH_INTERFACE, "no such interface") \ _ (INIT_FAILED, "init failed") diff --git a/src/vnet/dev/format.c b/src/vnet/dev/format.c index fb46fcc47bc..ffc4a3a70b4 100644 --- a/src/vnet/dev/format.c +++ b/src/vnet/dev/format.c @@ -44,9 +44,15 @@ u8 * format_vnet_dev_interface_name (u8 *s, va_list *args) { u32 i = va_arg (*args, u32); - vnet_dev_port_t *port = vnet_dev_get_port_from_dev_instance (i); + vnet_dev_instance_t *di = vnet_dev_get_dev_instance (i); + vnet_dev_port_interface_t *si; + vnet_dev_port_t *p = di->port; + + if (di->is_primary_if) + return format (s, "%s", p->interfaces->primary_interface.name); - return format (s, "%s", port->intf.name); + si = vnet_dev_port_get_sec_if_by_index (p, di->sec_if_index); + return format (s, "%s", si->name); } u8 * @@ -138,12 +144,22 @@ format_vnet_dev_port_info (u8 *s, va_list *args) format_vnet_dev_args, port->args); s = format (s, "\n%UInterface ", format_white_space, indent); - if (port->interface_created) + if (port->interfaces) { - s = format (s, "assigned, interface name is '%U', RX node is '%U'", - format_vnet_sw_if_index_name, vnm, port->intf.sw_if_index, - format_vlib_node_name, vm, - vnet_dev_get_port_rx_node_index (port)); + s = format ( + s, "assigned, primary interface name is '%U', RX node is '%U'", + format_vnet_sw_if_index_name, vnm, + port->interfaces->primary_interface.sw_if_index, format_vlib_node_name, + vm, vnet_dev_get_port_rx_node_index (port)); + pool_foreach_pointer (sif, port->interfaces->secondary_interfaces) + { + s = format (s, "\n%USecondary interface '%U'", format_white_space, + indent, format_vnet_sw_if_index_name, vnm, + sif->sw_if_index); + if (sif->args) + s = format (s, "\n%U args '%U", format_white_space, indent, + format_vnet_dev_args, sif->args); + } } else s = format (s, "not assigned"); diff --git a/src/vnet/dev/handlers.c b/src/vnet/dev/handlers.c index 2a55affe3e3..bfacbe27c99 100644 --- a/src/vnet/dev/handlers.c +++ b/src/vnet/dev/handlers.c @@ -19,7 +19,8 @@ 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_instance_t *di = vnet_dev_get_dev_instance (hw->dev_instance); + vnet_dev_port_t *p; vnet_dev_rv_t rv; vnet_dev_port_cfg_change_req_t req = { @@ -27,6 +28,11 @@ vnet_dev_port_set_max_frame_size (vnet_main_t *vnm, vnet_hw_interface_t *hw, .max_rx_frame_size = frame_size, }; + p = di->port; + + if (!di->is_primary_if) + return vnet_dev_port_err (vm, p, VNET_DEV_ERR_NOT_PRIMARY_INTERFACE, ""); + log_debug (p->dev, "size %u", frame_size); rv = vnet_dev_port_cfg_change_req_validate (vm, p, &req); @@ -49,13 +55,17 @@ 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_instance_t *di = vnet_dev_get_dev_instance (hw->dev_instance); + vnet_dev_port_t *p = di->port; vnet_dev_rv_t rv; vnet_dev_port_cfg_change_req_t req = { .type = VNET_DEV_PORT_CFG_PROMISC_MODE, }; + if (!di->is_primary_if) + return ~0; + switch (flags) { case ETHERNET_INTERFACE_FLAG_DEFAULT_L3: @@ -87,13 +97,17 @@ 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_instance_t *di = vnet_dev_get_dev_instance (hi->dev_instance); + vnet_dev_port_t *p = di->port; vnet_dev_rv_t rv; vnet_dev_port_cfg_change_req_t req = { .type = VNET_DEV_PORT_CFG_CHANGE_PRIMARY_HW_ADDR, }; + if (!di->is_primary_if) + return vnet_dev_port_err (vm, p, VNET_DEV_ERR_NOT_PRIMARY_INTERFACE, ""); + vnet_dev_set_hw_addr_eth_mac (&req.addr, new); log_debug (p->dev, "new mac %U", format_vnet_dev_hw_addr, &req.addr); @@ -116,7 +130,8 @@ 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_instance_t *di = vnet_dev_get_dev_instance (hi->dev_instance); + vnet_dev_port_t *p = di->port; vnet_dev_rv_t rv; vnet_dev_port_cfg_change_req_t req = { @@ -124,6 +139,9 @@ vnet_dev_add_del_mac_address (vnet_hw_interface_t *hi, const u8 *address, VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR, }; + if (!di->is_primary_if) + return vnet_dev_port_err (vm, p, VNET_DEV_ERR_NOT_PRIMARY_INTERFACE, ""); + 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, @@ -147,10 +165,19 @@ vnet_dev_flow_ops_fn (vnet_main_t *vnm, vnet_flow_dev_op_t op, u32 dev_instance, u32 flow_index, uword *private_data) { vlib_main_t *vm = vlib_get_main (); - vnet_dev_port_t *p = vnet_dev_get_port_from_dev_instance (dev_instance); + vnet_dev_instance_t *di = vnet_dev_get_dev_instance (dev_instance); + vnet_dev_port_t *p; vnet_dev_port_cfg_change_req_t req; vnet_dev_rv_t rv; + if (!di) + return VNET_FLOW_ERROR_NO_SUCH_INTERFACE; + + if (di->is_primary_if) + return VNET_FLOW_ERROR_NOT_SUPPORTED; + + p = di->port; + switch (op) { case VNET_FLOW_DEV_OP_ADD_FLOW: @@ -201,10 +228,12 @@ vnet_dev_interface_set_rss_queues (vnet_main_t *vnm, vnet_hw_interface_t *hi, void vnet_dev_clear_hw_interface_counters (u32 instance) { - vnet_dev_port_t *port = vnet_dev_get_port_from_dev_instance (instance); + vnet_dev_instance_t *di = vnet_dev_get_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); + if (di->is_primary_if) + vnet_dev_process_call_port_op_no_rv (vm, di->port, + vnet_dev_port_clear_counters); } void @@ -213,44 +242,49 @@ vnet_dev_set_interface_next_node (vnet_main_t *vnm, u32 hw_if_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); + vnet_dev_instance_t *di = vnet_dev_get_dev_instance (hw->dev_instance); + vnet_dev_port_interface_t *intf; int runtime_update = 0; + if (di->is_primary_if) + intf = vnet_dev_port_get_primary_if (di->port); + else + intf = vnet_dev_port_get_sec_if_by_index (di->port, di->sec_if_index); + if (node_index == ~0) { - port->intf.redirect_to_node_next_index = 0; - if (port->intf.feature_arc == 0) + intf->redirect_to_node_next_index = 0; + if (intf->feature_arc == 0) { - port->intf.rx_next_index = - vnet_dev_default_next_index_by_port_type[port->attr.type]; + intf->rx_next_index = + vnet_dev_default_next_index_by_port_type[di->port->attr.type]; runtime_update = 1; } - port->intf.redirect_to_node = 0; + 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) + intf->redirect_to_node_next_index = next_index; + if (intf->feature_arc == 0) { - port->intf.rx_next_index = next_index; + intf->rx_next_index = next_index; runtime_update = 1; } - port->intf.redirect_to_node = 1; + intf->redirect_to_node = 1; } - port->intf.rx_next_index = + intf->rx_next_index = node_index == ~0 ? - vnet_dev_default_next_index_by_port_type[port->attr.type] : - node_index; + vnet_dev_default_next_index_by_port_type[di->port->attr.type] : + node_index; if (runtime_update) { - foreach_vnet_dev_port_rx_queue (rxq, port) + foreach_vnet_dev_port_rx_queue (rxq, di->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"); + log_debug (di->port->dev, "runtime update requested due to chgange in " + "reditect-to-next configuration"); } } diff --git a/src/vnet/dev/port.c b/src/vnet/dev/port.c index 5bd4edf05c1..fccedebdcf4 100644 --- a/src/vnet/dev/port.c +++ b/src/vnet/dev/port.c @@ -94,6 +94,7 @@ vnet_dev_port_free (vlib_main_t *vm, vnet_dev_port_t *port) pool_free (port->rx_queues); pool_free (port->tx_queues); vnet_dev_arg_free (&port->args); + vnet_dev_arg_free (&port->sec_if_args); pool_put_index (dev->ports, port->index); clib_mem_free (port); } @@ -109,11 +110,23 @@ vnet_dev_port_update_tx_node_runtime (vlib_main_t *vm, vnet_dev_port_t *port) clib_bitmap_foreach (ti, q->assigned_threads) { vlib_main_t *tvm = vlib_get_main_by_index (ti); - vlib_node_runtime_t *nr = - vlib_node_get_runtime (tvm, port->intf.tx_node_index); - vnet_dev_tx_node_runtime_t *tnr = vnet_dev_get_tx_node_runtime (nr); - tnr->hw_if_index = port->intf.hw_if_index; + vlib_node_runtime_t *nr; + vnet_dev_tx_node_runtime_t *tnr; + vnet_dev_port_interfaces_t *ifs = port->interfaces; + + nr = + vlib_node_get_runtime (tvm, ifs->primary_interface.tx_node_index); + tnr = vnet_dev_get_tx_node_runtime (nr); + tnr->hw_if_index = ifs->primary_interface.hw_if_index; tnr->tx_queue = q; + + pool_foreach_pointer (sif, port->interfaces->secondary_interfaces) + { + nr = vlib_node_get_runtime (tvm, sif->tx_node_index); + tnr = vnet_dev_get_tx_node_runtime (nr); + tnr->hw_if_index = sif->hw_if_index; + tnr->tx_queue = q; + } } } } @@ -271,6 +284,11 @@ vnet_dev_port_add (vlib_main_t *vm, vnet_dev_t *dev, vnet_dev_port_id_t id, for (vnet_dev_arg_t *a = args->port.args; a->type != VNET_DEV_ARG_END; a++) vec_add1 (port->args, *a); + if (args->port.sec_if_args) + for (vnet_dev_arg_t *a = args->port.sec_if_args; + a->type != VNET_DEV_ARG_END; a++) + vec_add1 (port->sec_if_args, *a); + /* defaults out of port attributes */ port->max_rx_frame_size = args->port.attr.max_supported_rx_frame_size; port->primary_hw_addr = args->port.attr.hw_addr; @@ -466,25 +484,34 @@ vnet_dev_port_state_change (vlib_main_t *vm, vnet_dev_port_t *port, vnet_dev_port_state_changes_t changes) { vnet_main_t *vnm = vnet_get_main (); + vnet_dev_port_interfaces_t *ifs = port->interfaces; vnet_dev_port_validate (vm, port); if (changes.change.link_speed) { port->speed = changes.link_speed; - if (port->interface_created) - vnet_hw_interface_set_link_speed (vnm, port->intf.hw_if_index, - changes.link_speed); + if (port->interfaces) + vnet_hw_interface_set_link_speed ( + vnm, ifs->primary_interface.hw_if_index, changes.link_speed); log_debug (port->dev, "port speed changed to %u", changes.link_speed); } if (changes.change.link_state) { port->link_up = changes.link_state; - if (port->interface_created) - vnet_hw_interface_set_flags ( - vnm, port->intf.hw_if_index, - changes.link_state ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0); + if (ifs) + { + vnet_hw_interface_set_flags ( + vnm, ifs->primary_interface.hw_if_index, + changes.link_state ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0); + pool_foreach_pointer (sif, ifs->secondary_interfaces) + { + vnet_hw_interface_set_flags ( + vnm, sif->hw_if_index, + changes.link_state ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0); + } + } log_debug (port->dev, "port link state changed to %s", changes.link_state ? "up" : "down"); } @@ -510,19 +537,51 @@ vnet_dev_port_free_counters (vlib_main_t *vm, vnet_dev_port_t *port) vnet_dev_counters_free (vm, port->counter_main); } +static void +vnet_dev_port_init_if_rt_data (vlib_main_t *vm, vnet_dev_port_t *port, + vnet_dev_rx_queue_if_rt_data_t *rtd, + u32 sw_if_index) +{ + vnet_dev_t *dev = port->dev; + u8 buffer_pool_index = + vlib_buffer_pool_get_default_for_numa (vm, dev->numa_node); + vlib_buffer_pool_t *bp = vlib_get_buffer_pool (vm, buffer_pool_index); + + rtd->buffer_template = bp->buffer_template; + vnet_buffer (&rtd->buffer_template)->sw_if_index[VLIB_RX] = sw_if_index; + vnet_buffer (&rtd->buffer_template)->sw_if_index[VLIB_TX] = ~0; + rtd->next_index = ~0; + rtd->sw_if_index = sw_if_index; +} + vnet_dev_rv_t -vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port) +vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port, void *ptr) { vnet_main_t *vnm = vnet_get_main (); u16 n_threads = vlib_get_n_threads (); vnet_dev_main_t *dm = &vnet_dev_main; vnet_dev_t *dev = port->dev; + vnet_dev_port_if_create_args_t *a = ptr; + vnet_dev_port_interfaces_t *ifs = port->interfaces; vnet_dev_instance_t *di; vnet_dev_rv_t rv; u16 ti = 0; - u8 is_consistent_qp = port->intf.consistent_qp; - if (port->intf.name[0] == 0) + if (ifs) + return VNET_DEV_ERR_ALREADY_EXISTS; + + port->interfaces = ifs = + clib_mem_alloc (sizeof (vnet_dev_port_interfaces_t)); + + *(ifs) = (vnet_dev_port_interfaces_t){ + .num_rx_queues = a->num_rx_queues, + .num_tx_queues = a->num_tx_queues, + .rxq_sz = a->rxq_sz, + .txq_sz = a->txq_sz, + .default_is_intr_mode = a->default_is_intr_mode, + }; + + if (a->name[0] == 0) { u8 *s; s = format (0, "%s%u/%u", @@ -530,36 +589,36 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port) port->dev->index, port->index); u32 n = vec_len (s); - if (n >= sizeof (port->intf.name)) + if (n >= sizeof (a->name)) { vec_free (s); return VNET_DEV_ERR_BUG; } - clib_memcpy (port->intf.name, s, n); - port->intf.name[n] = 0; + clib_memcpy (ifs->primary_interface.name, s, n); + ifs->primary_interface.name[n] = 0; vec_free (s); } + else + clib_memcpy (ifs->primary_interface.name, a->name, + sizeof (ifs->primary_interface.name)); log_debug ( dev, "allocating %u rx queues with size %u and %u tx queues with size %u", - port->intf.num_rx_queues, port->intf.rxq_sz, port->intf.num_tx_queues, - port->intf.txq_sz); + a->num_rx_queues, a->rxq_sz, a->num_tx_queues, a->txq_sz); - for (int i = 0; i < port->intf.num_rx_queues; i++) - if ((rv = vnet_dev_rx_queue_alloc (vm, port, port->intf.rxq_sz)) != - VNET_DEV_OK) + for (int i = 0; i < ifs->num_rx_queues; i++) + if ((rv = vnet_dev_rx_queue_alloc (vm, port, ifs->rxq_sz)) != VNET_DEV_OK) goto error; - for (u32 i = 0; i < port->intf.num_tx_queues; i++) - if ((rv = vnet_dev_tx_queue_alloc (vm, port, port->intf.txq_sz)) != - VNET_DEV_OK) + for (u32 i = 0; i < ifs->num_tx_queues; i++) + if ((rv = vnet_dev_tx_queue_alloc (vm, port, ifs->txq_sz)) != VNET_DEV_OK) goto error; foreach_vnet_dev_port_tx_queue (q, port) { /* if consistent_qp is enabled, we start by assigning queues to workers * and we end with main */ - u16 real_ti = (ti + is_consistent_qp) % n_threads; + u16 real_ti = (ti + a->consistent_qp) % n_threads; q->assigned_threads = clib_bitmap_set (q->assigned_threads, real_ti, 1); log_debug (dev, "port %u tx queue %u assigned to thread %u", port->port_id, q->queue_id, real_ti); @@ -568,8 +627,9 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port) } pool_get (dm->dev_instances, di); - port->intf.dev_instance = di - dm->dev_instances; + ifs->primary_interface.dev_instance = di - dm->dev_instances; di->port = port; + di->is_primary_if = 1; if (port->attr.type == VNET_DEV_PORT_TYPE_ETHERNET) { @@ -578,7 +638,7 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port) vnet_sw_interface_t *sw; vnet_hw_interface_t *hw; vnet_hw_if_caps_t caps = 0; - u32 rx_node_index; + u32 rx_node_index, hw_if_index, sw_if_index; driver = pool_elt_at_index (dm->drivers, dev->driver_index); @@ -590,27 +650,28 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port) dev_class->tx_function_n_errors = port->tx_node.n_error_counters; /* create new interface including tx and output nodes */ - port->intf.hw_if_index = vnet_eth_register_interface ( + hw_if_index = vnet_eth_register_interface ( vnm, &(vnet_eth_interface_registration_t){ .address = port->primary_hw_addr.eth_mac, .max_frame_size = port->max_rx_frame_size, .dev_class_index = driver->dev_class_index, - .dev_instance = port->intf.dev_instance, + .dev_instance = ifs->primary_interface.dev_instance, .cb.set_max_frame_size = vnet_dev_port_set_max_frame_size, .cb.flag_change = vnet_dev_port_eth_flag_change, }); + ifs->primary_interface.hw_if_index = hw_if_index; - sw = vnet_get_hw_sw_interface (vnm, port->intf.hw_if_index); - hw = vnet_get_hw_interface (vnm, port->intf.hw_if_index); - port->intf.sw_if_index = sw->sw_if_index; + sw = vnet_get_hw_sw_interface (vnm, hw_if_index); + hw = vnet_get_hw_interface (vnm, hw_if_index); + sw_if_index = ifs->primary_interface.sw_if_index = sw->sw_if_index; vnet_hw_interface_set_flags ( - vnm, port->intf.hw_if_index, + vnm, ifs->primary_interface.hw_if_index, port->link_up ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0); if (port->speed) - vnet_hw_interface_set_link_speed (vnm, port->intf.hw_if_index, - port->speed); + vnet_hw_interface_set_link_speed ( + vnm, ifs->primary_interface.hw_if_index, port->speed); - port->intf.tx_node_index = hw->tx_node_index; + ifs->primary_interface.tx_node_index = hw->tx_node_index; caps |= port->attr.caps.interrupt_mode ? VNET_HW_IF_CAP_INT_MODE : 0; caps |= port->attr.caps.mac_filter ? VNET_HW_IF_CAP_MAC_FILTER : 0; @@ -618,14 +679,15 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port) caps |= port->attr.tx_offloads.ip4_cksum ? VNET_HW_IF_CAP_TX_CKSUM : 0; if (caps) - vnet_hw_if_set_caps (vnm, port->intf.hw_if_index, caps); + vnet_hw_if_set_caps (vnm, hw_if_index, caps); /* create / reuse rx node */ if (vec_len (dm->free_rx_node_indices)) { vlib_node_t *n; rx_node_index = vec_pop (dm->free_rx_node_indices); - vlib_node_rename (vm, rx_node_index, "%s-rx", port->intf.name); + vlib_node_rename (vm, rx_node_index, "%s-rx", + port->interfaces->primary_interface.name); n = vlib_get_node (vm, rx_node_index); n->function = vlib_node_get_preferred_node_fn_variant ( vm, port->rx_node.registrations); @@ -649,30 +711,28 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port) .error_counters = port->rx_node.error_counters, .n_errors = port->rx_node.n_error_counters, }; - rx_node_index = - vlib_register_node (vm, &rx_node_reg, "%s-rx", port->intf.name); + rx_node_index = vlib_register_node (vm, &rx_node_reg, "%s-rx", + ifs->primary_interface.name); } port->rx_node_assigned = 1; - port->intf.rx_node_index = rx_node_index; - port->intf.rx_next_index = + ifs->rx_node_index = rx_node_index; + ifs->primary_interface.rx_next_index = vnet_dev_default_next_index_by_port_type[port->attr.type]; vlib_worker_thread_node_runtime_update (); log_debug (dev, "ethernet interface created, hw_if_index %u sw_if_index %u " "rx_node_index %u tx_node_index %u", - port->intf.hw_if_index, port->intf.sw_if_index, - port->intf.rx_node_index, port->intf.tx_node_index); + hw_if_index, sw_if_index, rx_node_index, + ifs->primary_interface.tx_node_index); } - port->interface_created = 1; foreach_vnet_dev_port_rx_queue (q, port) { - vnet_buffer (&q->buffer_template)->sw_if_index[VLIB_RX] = - port->intf.sw_if_index; + vnet_dev_port_init_if_rt_data (vm, port, &q->if_rt_data, + ifs->primary_interface.sw_if_index); /* poison to catch node not calling runtime update function */ - q->next_index = ~0; - q->interrupt_mode = port->intf.default_is_intr_mode; + q->interrupt_mode = ifs->default_is_intr_mode; vnet_dev_rx_queue_rt_request ( vm, q, (vnet_dev_rx_queue_rt_req_t){ .update_next_index = 1 }); } @@ -685,6 +745,8 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port) error: if (rv != VNET_DEV_OK) vnet_dev_port_if_remove (vm, port); + else + a->sw_if_index = ifs->primary_interface.sw_if_index; return rv; } @@ -693,6 +755,7 @@ vnet_dev_port_if_remove (vlib_main_t *vm, vnet_dev_port_t *port) { vnet_dev_main_t *dm = &vnet_dev_main; vnet_main_t *vnm = vnet_get_main (); + vnet_dev_port_interfaces_t *ifs = port->interfaces; vnet_dev_port_validate (vm, port); @@ -701,23 +764,22 @@ vnet_dev_port_if_remove (vlib_main_t *vm, vnet_dev_port_t *port) if (port->rx_node_assigned) { - vlib_node_rename (vm, port->intf.rx_node_index, "deleted-%u", - port->intf.rx_node_index); - vec_add1 (dm->free_rx_node_indices, port->intf.rx_node_index); + vlib_node_rename (vm, ifs->rx_node_index, "deleted-%u", + ifs->rx_node_index); + vec_add1 (dm->free_rx_node_indices, ifs->rx_node_index); port->rx_node_assigned = 0; } - if (port->interface_created) + if (ifs) { vlib_worker_thread_barrier_sync (vm); - vnet_delete_hw_interface (vnm, port->intf.hw_if_index); + vnet_delete_hw_interface (vnm, ifs->primary_interface.hw_if_index); vlib_worker_thread_barrier_release (vm); - pool_put_index (dm->dev_instances, port->intf.dev_instance); - port->interface_created = 0; + pool_put_index (dm->dev_instances, ifs->primary_interface.dev_instance); + clib_mem_free (port->interfaces); + port->interfaces = 0; } - port->intf = (typeof (port->intf)){}; - if (port->port_ops.deinit) port->port_ops.deinit (vm, port); @@ -734,6 +796,171 @@ vnet_dev_port_if_remove (vlib_main_t *vm, vnet_dev_port_t *port) return VNET_DEV_OK; } + +vnet_dev_rv_t +vnet_dev_port_del_sec_if_internal (vlib_main_t *vm, vnet_dev_port_t *port, + vnet_dev_port_interface_t *sif) +{ + vnet_dev_rv_t rv = VNET_DEV_OK; + + if (sif && port->port_ops.add_sec_if) + rv = port->port_ops.add_sec_if (vm, port, sif); + + if (rv != VNET_DEV_OK) + return rv; + + foreach_vnet_dev_port_rx_queue (q, port) + { + vec_foreach_pointer (p, q->sec_if_rt_data) + if (p) + clib_mem_free (p); + vec_free (q->sec_if_rt_data); + } + + if (sif->interface_created) + ethernet_delete_interface (vnet_get_main (), sif->hw_if_index); + + pool_put_index (port->interfaces->secondary_interfaces, sif->index); + vnet_dev_arg_free (&sif->args); + clib_mem_free (sif); + return rv; +} + +vnet_dev_rv_t +vnet_dev_port_add_sec_if (vlib_main_t *vm, vnet_dev_port_t *port, void *ptr) +{ + vnet_dev_main_t *dm = &vnet_dev_main; + vnet_dev_port_sec_if_create_args_t *a = ptr; + vnet_main_t *vnm = vnet_get_main (); + vnet_dev_t *dev = port->dev; + vnet_dev_port_interface_t *sif = 0; + vnet_dev_port_interface_t **sip; + vnet_dev_rv_t rv = VNET_DEV_OK; + + sif = clib_mem_alloc (sizeof (vnet_dev_port_interface_t)); + pool_get (port->interfaces->secondary_interfaces, sip); + *sip = sif; + + *sif = (vnet_dev_port_interface_t){ + .index = sip - port->interfaces->secondary_interfaces, + .args = vec_dup (port->sec_if_args), + }; + + clib_memcpy (sif->name, a->name, sizeof (sif->name)); + + if (sif->args) + { + rv = vnet_dev_arg_parse (vm, dev, sif->args, a->args); + if (rv != VNET_DEV_OK) + return rv; + } + + if (port->attr.type == VNET_DEV_PORT_TYPE_ETHERNET) + { + vnet_device_class_t *dev_class; + vnet_dev_driver_t *driver; + vnet_sw_interface_t *sw; + vnet_hw_interface_t *hw; + vnet_dev_instance_t *di; + vnet_hw_if_caps_t caps = 0; + + pool_get (dm->dev_instances, di); + sif->dev_instance = di - dm->dev_instances; + di->port = port; + di->sec_if_index = sip - port->interfaces->secondary_interfaces; + + driver = pool_elt_at_index (dm->drivers, dev->driver_index); + + /* hack to provide per-port tx node function */ + dev_class = vnet_get_device_class (vnm, driver->dev_class_index); + dev_class->tx_fn_registrations = port->tx_node.registrations; + dev_class->format_tx_trace = port->tx_node.format_trace; + dev_class->tx_function_error_counters = port->tx_node.error_counters; + dev_class->tx_function_n_errors = port->tx_node.n_error_counters; + + /* create new interface including tx and output nodes */ + sif->hw_if_index = vnet_eth_register_interface ( + vnm, &(vnet_eth_interface_registration_t){ + .address = port->primary_hw_addr.eth_mac, + .max_frame_size = port->max_rx_frame_size, + .dev_class_index = driver->dev_class_index, + .dev_instance = sif->dev_instance, + .cb.set_max_frame_size = vnet_dev_port_set_max_frame_size, + .cb.flag_change = vnet_dev_port_eth_flag_change, + }); + + sw = vnet_get_hw_sw_interface (vnm, sif->hw_if_index); + hw = vnet_get_hw_interface (vnm, sif->hw_if_index); + sif->sw_if_index = sw->sw_if_index; + sif->next_index = + vnet_dev_default_next_index_by_port_type[port->attr.type]; + sif->interface_created = 1; + vnet_dev_port_update_tx_node_runtime (vm, port); + vnet_hw_interface_set_flags ( + vnm, sif->hw_if_index, + port->link_up ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0); + if (port->speed) + vnet_hw_interface_set_link_speed (vnm, sif->hw_if_index, port->speed); + + sif->tx_node_index = hw->tx_node_index; + + caps |= port->attr.caps.interrupt_mode ? VNET_HW_IF_CAP_INT_MODE : 0; + caps |= port->attr.caps.mac_filter ? VNET_HW_IF_CAP_MAC_FILTER : 0; + caps |= port->attr.tx_offloads.tcp_gso ? VNET_HW_IF_CAP_TCP_GSO : 0; + caps |= port->attr.tx_offloads.ip4_cksum ? VNET_HW_IF_CAP_TX_CKSUM : 0; + + if (caps) + vnet_hw_if_set_caps (vnm, sif->hw_if_index, caps); + } + else + return VNET_DEV_ERR_NOT_SUPPORTED; + + foreach_vnet_dev_port_rx_queue (q, port) + { + vnet_dev_rx_queue_if_rt_data_t *rtd; + vec_validate (q->sec_if_rt_data, sif->index); + + rtd = clib_mem_alloc_aligned (sizeof (vnet_dev_rx_queue_if_rt_data_t), + CLIB_CACHE_LINE_BYTES); + + q->sec_if_rt_data[sif->index] = rtd; + + vnet_dev_port_init_if_rt_data (vm, port, rtd, sif->sw_if_index); + vnet_dev_rx_queue_rt_request ( + vm, q, (vnet_dev_rx_queue_rt_req_t){ .update_next_index = 1 }); + } + + if (sif && port->port_ops.add_sec_if) + rv = port->port_ops.add_sec_if (vm, port, sif); + + if (rv != VNET_DEV_OK) + vnet_dev_port_del_sec_if_internal (vm, port, sif); + + return rv; +} + +vnet_dev_rv_t +vnet_dev_port_del_sec_if (vlib_main_t *vm, vnet_dev_port_t *port, void *ptr) +{ + vnet_dev_port_del_sec_if_args_t *a = ptr; + vnet_sw_interface_t *si; + vnet_hw_interface_t *hi; + vnet_dev_instance_t *di; + vnet_main_t *vnm = vnet_get_main (); + + log_debug (port->dev, "%u", a->sw_if_index); + + si = vnet_get_sw_interface_or_null (vnm, a->sw_if_index); + if (!si) + return VNET_DEV_ERR_UNKNOWN_INTERFACE; + + hi = vnet_get_hw_interface (vnm, si->hw_if_index); + di = vnet_dev_get_dev_instance (hi->dev_instance); + + return vnet_dev_port_del_sec_if_internal ( + vm, port, vnet_dev_port_get_sec_if_by_index (port, di->sec_if_index)); +} + void vnet_dev_port_clear_counters (vlib_main_t *vm, vnet_dev_port_t *port) { diff --git a/src/vnet/dev/queue.c b/src/vnet/dev/queue.c index 7efea5f14bd..57ed3dcae3b 100644 --- a/src/vnet/dev/queue.c +++ b/src/vnet/dev/queue.c @@ -36,7 +36,6 @@ vnet_dev_rx_queue_alloc (vlib_main_t *vm, vnet_dev_port_t *port, vnet_dev_t *dev = port->dev; vnet_dev_rv_t rv = VNET_DEV_OK; u16 n_threads = vlib_get_n_threads (); - u8 buffer_pool_index; vnet_dev_port_validate (vm, port); @@ -65,15 +64,6 @@ vnet_dev_rx_queue_alloc (vlib_main_t *vm, vnet_dev_port_t *port, dm->next_rx_queue_thread = 1; } - buffer_pool_index = - vlib_buffer_pool_get_default_for_numa (vm, dev->numa_node); - vlib_buffer_pool_t *bp = vlib_get_buffer_pool (vm, buffer_pool_index); - - rxq->buffer_template = bp->buffer_template; - vnet_buffer (&rxq->buffer_template)->sw_if_index[VLIB_TX] = ~0; - - rxq->next_index = vnet_dev_default_next_index_by_port_type[port->attr.type]; - if (port->rx_queue_ops.alloc) rv = port->rx_queue_ops.alloc (vm, rxq); |