diff options
Diffstat (limited to 'src/vnet/dev/runtime.c')
-rw-r--r-- | src/vnet/dev/runtime.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/src/vnet/dev/runtime.c b/src/vnet/dev/runtime.c new file mode 100644 index 00000000000..79c55cfbd53 --- /dev/null +++ b/src/vnet/dev/runtime.c @@ -0,0 +1,180 @@ + +/* SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2023 Cisco Systems, Inc. + */ + +#include "vppinfra/bitmap.h" +#include "vppinfra/lock.h" +#include <vnet/vnet.h> +#include <vnet/dev/dev.h> +#include <vnet/dev/log.h> + +VLIB_REGISTER_LOG_CLASS (dev_log, static) = { + .class_name = "dev", + .subclass_name = "runtime", +}; + +static vnet_dev_rt_op_t *rt_ops; + +static void +_vnet_dev_rt_exec_op (vlib_main_t *vm, vnet_dev_rt_op_t *op) +{ + vnet_dev_port_t *port = op->port; + vnet_dev_rx_queue_t *previous = 0, *first = 0; + vnet_dev_rx_node_runtime_t *rtd; + vlib_node_state_t state = VLIB_NODE_STATE_DISABLED; + u32 node_index = port->intf.rx_node_index; + + rtd = vlib_node_get_runtime_data (vm, node_index); + + foreach_vnet_dev_port_rx_queue (q, port) + { + if (q->rx_thread_index != vm->thread_index) + continue; + + if (q->interrupt_mode == 0) + state = VLIB_NODE_STATE_POLLING; + else if (state != VLIB_NODE_STATE_POLLING) + state = VLIB_NODE_STATE_INTERRUPT; + + q->next_on_thread = 0; + if (previous == 0) + first = q; + else + previous->next_on_thread = q; + + previous = q; + } + + rtd->first_rx_queue = first; + vlib_node_set_state (vm, port->intf.rx_node_index, state); + __atomic_store_n (&op->completed, 1, __ATOMIC_RELEASE); +} + +static uword +vnet_dev_rt_mgmt_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *frame) +{ + u16 thread_index = vm->thread_index; + vnet_dev_rt_op_t *op, *ops = __atomic_load_n (&rt_ops, __ATOMIC_ACQUIRE); + u32 n_pending = 0; + uword rv = 0; + + vec_foreach (op, ops) + { + if (!op->completed && op->thread_index == thread_index) + { + if (op->in_order == 1 && n_pending) + { + vlib_node_set_interrupt_pending (vm, node->node_index); + return rv; + } + _vnet_dev_rt_exec_op (vm, op); + rv++; + } + + if (op->completed == 0) + n_pending++; + } + + return rv; +} + +VLIB_REGISTER_NODE (vnet_dev_rt_mgmt_node, static) = { + .function = vnet_dev_rt_mgmt_node_fn, + .name = "dev-rt-mgmt", + .type = VLIB_NODE_TYPE_PRE_INPUT, + .state = VLIB_NODE_STATE_INTERRUPT, +}; + +vnet_dev_rv_t +vnet_dev_rt_exec_ops (vlib_main_t *vm, vnet_dev_t *dev, vnet_dev_rt_op_t *ops, + u32 n_ops) +{ + vnet_dev_rt_op_t *op = ops; + vnet_dev_rt_op_t *remote_ops = 0; + clib_bitmap_t *remote_bmp = 0; + u32 i; + + ASSERT (rt_ops == 0); + + if (vlib_worker_thread_barrier_held ()) + { + for (op = ops; op < (ops + n_ops); op++) + { + vlib_main_t *tvm = vlib_get_main_by_index (op->thread_index); + _vnet_dev_rt_exec_op (tvm, op); + log_debug ( + dev, + "port %u rx node runtime update on thread %u executed locally", + op->port->port_id, op->thread_index); + } + return VNET_DEV_OK; + } + + while (n_ops) + { + if (op->thread_index != vm->thread_index) + break; + + _vnet_dev_rt_exec_op (vm, op); + log_debug ( + dev, "port %u rx node runtime update on thread %u executed locally", + op->port->port_id, op->thread_index); + op++; + n_ops--; + } + + if (n_ops == 0) + return VNET_DEV_OK; + + for (op = ops; op < (ops + n_ops); op++) + { + if (op->thread_index == vm->thread_index && + (op->in_order == 0 || vec_len (remote_ops) == 0)) + { + _vnet_dev_rt_exec_op (vm, op); + log_debug (dev, + "port %u rx node runtime update on thread " + "%u executed locally", + op->port->port_id, op->thread_index); + } + else + { + vec_add1 (remote_ops, *op); + log_debug (dev, + "port %u rx node runtime update on thread %u " + "enqueued for remote execution", + op->port->port_id, op->thread_index); + remote_bmp = clib_bitmap_set (remote_bmp, op->thread_index, 1); + } + } + + if (remote_ops == 0) + return VNET_DEV_OK; + + __atomic_store_n (&rt_ops, remote_ops, __ATOMIC_RELEASE); + + clib_bitmap_foreach (i, remote_bmp) + { + vlib_node_set_interrupt_pending (vlib_get_main_by_index (i), + vnet_dev_rt_mgmt_node.index); + log_debug (dev, "interrupt sent to %s node on thread %u", + vnet_dev_rt_mgmt_node.name, i); + } + + vec_foreach (op, remote_ops) + { + while (op->completed == 0) + vlib_process_suspend (vm, 5e-5); + + log_debug ( + dev, "port %u rx node runtime update on thread %u executed locally", + op->port->port_id, op->thread_index); + } + + __atomic_store_n (&rt_ops, 0, __ATOMIC_RELAXED); + vec_free (remote_ops); + clib_bitmap_free (remote_bmp); + return VNET_DEV_OK; +} |