X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fdevices%2Fdevices.c;h=e78c5cbe45b904582c76339f5306ebfbb769d18b;hb=19b697f3076d3a634f0627e1ea10310fc01bb0ce;hp=5e5e812c48befd67132a220c7af451f9980a973e;hpb=586afd762bfa149f5ca167bd5fd5a0cd59ce94fe;p=vpp.git diff --git a/src/vnet/devices/devices.c b/src/vnet/devices/devices.c index 5e5e812c48b..e78c5cbe45b 100644 --- a/src/vnet/devices/devices.c +++ b/src/vnet/devices/devices.c @@ -52,10 +52,21 @@ device_input_next_node_advance[((VNET_DEVICE_INPUT_N_NEXT_NODES / [VNET_DEVICE_INPUT_NEXT_MPLS_INPUT] = sizeof (ethernet_header_t), }; +const u32 __attribute__((aligned (CLIB_CACHE_LINE_BYTES))) +device_input_next_node_flags[((VNET_DEVICE_INPUT_N_NEXT_NODES / + CLIB_CACHE_LINE_BYTES) +1) * CLIB_CACHE_LINE_BYTES] = +{ + [VNET_DEVICE_INPUT_NEXT_IP4_INPUT] = VNET_BUFFER_F_L3_HDR_OFFSET_VALID, + [VNET_DEVICE_INPUT_NEXT_IP4_NCS_INPUT] = VNET_BUFFER_F_L3_HDR_OFFSET_VALID, + [VNET_DEVICE_INPUT_NEXT_IP6_INPUT] = VNET_BUFFER_F_L3_HDR_OFFSET_VALID, + [VNET_DEVICE_INPUT_NEXT_MPLS_INPUT] = VNET_BUFFER_F_L3_HDR_OFFSET_VALID, +}; + VNET_FEATURE_ARC_INIT (device_input, static) = { .arc_name = "device-input", .start_nodes = VNET_FEATURES ("device-input"), + .last_in_arc = "ethernet-input", .arc_index_ptr = &feature_main.device_input_feature_arc_index, }; @@ -77,6 +88,12 @@ VNET_FEATURE_INIT (span_input, static) = { .runs_before = VNET_FEATURES ("ethernet-input"), }; +VNET_FEATURE_INIT (p2p_ethernet_node, static) = { + .arc_name = "device-input", + .node_name = "p2p-ethernet-input", + .runs_before = VNET_FEATURES ("ethernet-input"), +}; + VNET_FEATURE_INIT (ethernet_input, static) = { .arc_name = "device-input", .node_name = "ethernet-input", @@ -102,13 +119,28 @@ vnet_device_queue_sort (void *a1, void *a2) return 0; } +static void +vnet_device_queue_update (vnet_main_t * vnm, vnet_device_input_runtime_t * rt) +{ + vnet_device_and_queue_t *dq; + vnet_hw_interface_t *hw; + + vec_sort_with_function (rt->devices_and_queues, vnet_device_queue_sort); + + vec_foreach (dq, rt->devices_and_queues) + { + hw = vnet_get_hw_interface (vnm, dq->hw_if_index); + vec_validate (hw->dq_runtime_index_by_queue, dq->queue_id); + hw->dq_runtime_index_by_queue[dq->queue_id] = dq - rt->devices_and_queues; + } +} + void -vnet_device_input_assign_thread (u32 hw_if_index, - u16 queue_id, uword thread_index) +vnet_hw_interface_assign_rx_thread (vnet_main_t * vnm, u32 hw_if_index, + u16 queue_id, uword thread_index) { - vnet_main_t *vnm = vnet_get_main (); vnet_device_main_t *vdm = &vnet_device_main; - vlib_main_t *vm; + vlib_main_t *vm, *vm0; vnet_device_input_runtime_t *rt; vnet_device_and_queue_t *dq; vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index); @@ -128,27 +160,40 @@ vnet_device_input_assign_thread (u32 hw_if_index, } vm = vlib_mains[thread_index]; + vm0 = vlib_get_main (); + + vlib_worker_thread_barrier_sync (vm0); + rt = vlib_node_get_runtime_data (vm, hw->input_node_index); vec_add2 (rt->devices_and_queues, dq, 1); dq->hw_if_index = hw_if_index; dq->dev_instance = hw->dev_instance; dq->queue_id = queue_id; + dq->mode = VNET_HW_INTERFACE_RX_MODE_POLLING; + rt->enabled_node_state = VLIB_NODE_STATE_POLLING; - vec_sort_with_function (rt->devices_and_queues, vnet_device_queue_sort); + vnet_device_queue_update (vnm, rt); vec_validate (hw->input_node_thread_index_by_queue, queue_id); + vec_validate (hw->rx_mode_by_queue, queue_id); hw->input_node_thread_index_by_queue[queue_id] = thread_index; + hw->rx_mode_by_queue[queue_id] = VNET_HW_INTERFACE_RX_MODE_POLLING; + + vlib_worker_thread_barrier_release (vm0); + + vlib_node_set_state (vm, hw->input_node_index, rt->enabled_node_state); } -static int -vnet_device_input_unassign_thread (u32 hw_if_index, u16 queue_id, - uword thread_index) +int +vnet_hw_interface_unassign_rx_thread (vnet_main_t * vnm, u32 hw_if_index, + u16 queue_id) { - vnet_main_t *vnm = vnet_get_main (); + vlib_main_t *vm, *vm0; vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index); vnet_device_input_runtime_t *rt; vnet_device_and_queue_t *dq; uword old_thread_index; + vnet_hw_interface_rx_mode mode; if (hw->input_node_thread_index_by_queue == 0) return VNET_API_ERROR_INVALID_INTERFACE; @@ -158,159 +203,145 @@ vnet_device_input_unassign_thread (u32 hw_if_index, u16 queue_id, old_thread_index = hw->input_node_thread_index_by_queue[queue_id]; - if (old_thread_index == thread_index) - return 0; + vm = vlib_mains[old_thread_index]; - rt = - vlib_node_get_runtime_data (vlib_mains[old_thread_index], - hw->input_node_index); + rt = vlib_node_get_runtime_data (vm, hw->input_node_index); vec_foreach (dq, rt->devices_and_queues) if (dq->hw_if_index == hw_if_index && dq->queue_id == queue_id) { - vec_del1 (rt->devices_and_queues, dq - rt->devices_and_queues); - goto deleted; + mode = dq->mode; + goto delete; } return VNET_API_ERROR_INVALID_INTERFACE; -deleted: - vec_sort_with_function (rt->devices_and_queues, vnet_device_queue_sort); +delete: - return 0; -} + vm0 = vlib_get_main (); + vlib_worker_thread_barrier_sync (vm0); + vec_del1 (rt->devices_and_queues, dq - rt->devices_and_queues); + vnet_device_queue_update (vnm, rt); + hw->rx_mode_by_queue[queue_id] = VNET_HW_INTERFACE_RX_MODE_UNKNOWN; + vlib_worker_thread_barrier_release (vm0); -static clib_error_t * -show_device_placement_fn (vlib_main_t * vm, unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - u8 *s = 0; - vnet_main_t *vnm = vnet_get_main (); - vnet_device_input_runtime_t *rt; - vnet_device_and_queue_t *dq; - vlib_node_t *pn = vlib_get_node_by_name (vm, (u8 *) "device-input"); - uword si; - int index = 0; - - /* *INDENT-OFF* */ - foreach_vlib_main (({ - clib_bitmap_foreach (si, pn->sibling_bitmap, - ({ - rt = vlib_node_get_runtime_data (this_vlib_main, si); - - if (vec_len (rt->devices_and_queues)) - s = format (s, " node %U:\n", format_vlib_node_name, vm, si); - - vec_foreach (dq, rt->devices_and_queues) - { - s = format (s, " %U queue %u\n", - format_vnet_sw_if_index_name, vnm, dq->hw_if_index, - dq->queue_id); - } - })); - if (vec_len (s) > 0) + if (vec_len (rt->devices_and_queues) == 0) + vlib_node_set_state (vm, hw->input_node_index, VLIB_NODE_STATE_DISABLED); + else if (mode == VNET_HW_INTERFACE_RX_MODE_POLLING) + { + /* + * if the deleted interface is polling, we may need to set the node state + * to interrupt if there is no more polling interface for this device's + * corresponding thread. This is because mixed interfaces + * (polling and interrupt), assigned to the same thread, set the + * thread to polling prior to the deletion. + */ + vec_foreach (dq, rt->devices_and_queues) { - vlib_cli_output(vm, "Thread %u (%v):\n%v", index, - vlib_worker_threads[index].name, s); - vec_reset_length (s); + if (dq->mode == VNET_HW_INTERFACE_RX_MODE_POLLING) + return 0; } - index++; - })); - /* *INDENT-ON* */ + rt->enabled_node_state = VLIB_NODE_STATE_INTERRUPT; + vlib_node_set_state (vm, hw->input_node_index, rt->enabled_node_state); + } - vec_free (s); return 0; } -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (memif_delete_command, static) = { - .path = "show interface placement", - .short_help = "show interface placement", - .function = show_device_placement_fn, -}; -/* *INDENT-ON* */ -static clib_error_t * -set_device_placement (vlib_main_t * vm, unformat_input_t * input, - vlib_cli_command_t * cmd) +int +vnet_hw_interface_set_rx_mode (vnet_main_t * vnm, u32 hw_if_index, + u16 queue_id, vnet_hw_interface_rx_mode mode) { - clib_error_t *error = 0; - unformat_input_t _line_input, *line_input = &_line_input; - vnet_main_t *vnm = vnet_get_main (); - vnet_device_main_t *vdm = &vnet_device_main; - u32 hw_if_index = (u32) ~ 0; - u32 queue_id = (u32) 0; - u32 thread_index = (u32) ~ 0; - int rv; + vlib_main_t *vm; + uword thread_index; + vnet_device_and_queue_t *dq; + vlib_node_state_t enabled_node_state; + ASSERT (mode < VNET_HW_INTERFACE_NUM_RX_MODES); + vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index); + vnet_device_input_runtime_t *rt; + int is_polling = 0; + + if (mode == VNET_HW_INTERFACE_RX_MODE_DEFAULT) + mode = hw->default_rx_mode; + + if (hw->input_node_thread_index_by_queue == 0 || hw->rx_mode_by_queue == 0) + return VNET_API_ERROR_INVALID_INTERFACE; - if (!unformat_user (input, unformat_line_input, line_input)) + if (hw->rx_mode_by_queue[queue_id] == mode) return 0; - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + if (mode != VNET_HW_INTERFACE_RX_MODE_POLLING && + (hw->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_INT_MODE) == 0) + return VNET_API_ERROR_UNSUPPORTED; + + if ((vec_len (hw->input_node_thread_index_by_queue) < queue_id + 1) || + (vec_len (hw->rx_mode_by_queue) < queue_id + 1)) + return VNET_API_ERROR_INVALID_QUEUE; + + hw->rx_mode_by_queue[queue_id] = mode; + thread_index = hw->input_node_thread_index_by_queue[queue_id]; + vm = vlib_mains[thread_index]; + + rt = vlib_node_get_runtime_data (vm, hw->input_node_index); + + vec_foreach (dq, rt->devices_and_queues) + { + if (dq->hw_if_index == hw_if_index && dq->queue_id == queue_id) + dq->mode = mode; + if (dq->mode == VNET_HW_INTERFACE_RX_MODE_POLLING) + is_polling = 1; + } + + if (is_polling) + enabled_node_state = VLIB_NODE_STATE_POLLING; + else + enabled_node_state = VLIB_NODE_STATE_INTERRUPT; + + if (rt->enabled_node_state != enabled_node_state) { - if (unformat - (line_input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index)) - ; - else if (unformat (line_input, "queue %d", &queue_id)) - ; - else if (unformat (line_input, "main", &thread_index)) - thread_index = 0; - else if (unformat (line_input, "worker %d", &thread_index)) - thread_index += vdm->first_worker_thread_index; - else - { - error = clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); - unformat_free (line_input); - return error; - } + rt->enabled_node_state = enabled_node_state; + if (vlib_node_get_state (vm, hw->input_node_index) != + VLIB_NODE_STATE_DISABLED) + vlib_node_set_state (vm, hw->input_node_index, enabled_node_state); } - unformat_free (line_input); + return 0; +} + +int +vnet_hw_interface_get_rx_mode (vnet_main_t * vnm, u32 hw_if_index, + u16 queue_id, vnet_hw_interface_rx_mode * mode) +{ + vlib_main_t *vm; + uword thread_index; + vnet_device_and_queue_t *dq; + vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index); + vnet_device_input_runtime_t *rt; - if (hw_if_index == (u32) ~ 0) - return clib_error_return (0, "please specify valid interface name"); + if (hw->input_node_thread_index_by_queue == 0) + return VNET_API_ERROR_INVALID_INTERFACE; - if (thread_index > vdm->last_worker_thread_index) - return clib_error_return (0, - "please specify valid worker thread or main"); + if ((vec_len (hw->input_node_thread_index_by_queue) < queue_id + 1) || + (vec_len (hw->rx_mode_by_queue) < queue_id + 1)) + return VNET_API_ERROR_INVALID_QUEUE; - rv = - vnet_device_input_unassign_thread (hw_if_index, queue_id, thread_index); + thread_index = hw->input_node_thread_index_by_queue[queue_id]; + vm = vlib_mains[thread_index]; - if (rv) - return clib_error_return (0, "not found"); + rt = vlib_node_get_runtime_data (vm, hw->input_node_index); - vnet_device_input_assign_thread (hw_if_index, queue_id, thread_index); + vec_foreach (dq, rt->devices_and_queues) + if (dq->hw_if_index == hw_if_index && dq->queue_id == queue_id) + { + *mode = dq->mode; + return 0; + } - return 0; + return VNET_API_ERROR_INVALID_INTERFACE; } -/*? - * This command is used to assign a given interface, and optionally a - * given queue, to a different thread. If the 'queue' is not provided, - * it defaults to 0. - * - * @cliexpar - * Example of how to display the interface placement: - * @cliexstart{show interface placement} - * Thread 1 (vpp_wk_0): - * GigabitEthernet0/8/0 queue 0 - * GigabitEthernet0/9/0 queue 0 - * Thread 2 (vpp_wk_1): - * GigabitEthernet0/8/0 queue 1 - * GigabitEthernet0/9/0 queue 1 - * @cliexend - * Example of how to assign a interface and queue to a thread: - * @cliexcmd{set interface placement GigabitEthernet0/8/0 queue 1 thread 1} -?*/ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (cmd_set_dpdk_if_placement,static) = { - .path = "set interface placement", - .short_help = "set interface placement [queue ] [thread | main]", - .function = set_device_placement, -}; -/* *INDENT-ON* */ + static clib_error_t * vnet_device_init (vlib_main_t * vm)