blob: 79c55cfbd53abe80a2e83496467447ee67735569 [file] [log] [blame]
Damjan Marion38c61912023-10-17 16:06:26 +00001
2/* SPDX-License-Identifier: Apache-2.0
3 * Copyright (c) 2023 Cisco Systems, Inc.
4 */
5
6#include "vppinfra/bitmap.h"
7#include "vppinfra/lock.h"
8#include <vnet/vnet.h>
9#include <vnet/dev/dev.h>
10#include <vnet/dev/log.h>
11
12VLIB_REGISTER_LOG_CLASS (dev_log, static) = {
13 .class_name = "dev",
14 .subclass_name = "runtime",
15};
16
17static vnet_dev_rt_op_t *rt_ops;
18
19static void
20_vnet_dev_rt_exec_op (vlib_main_t *vm, vnet_dev_rt_op_t *op)
21{
Damjan Marionb8dd9812023-11-03 13:47:05 +000022 vnet_dev_port_t *port = op->port;
23 vnet_dev_rx_queue_t *previous = 0, *first = 0;
24 vnet_dev_rx_node_runtime_t *rtd;
25 vlib_node_state_t state = VLIB_NODE_STATE_DISABLED;
26 u32 node_index = port->intf.rx_node_index;
27
28 rtd = vlib_node_get_runtime_data (vm, node_index);
29
30 foreach_vnet_dev_port_rx_queue (q, port)
Damjan Marion38c61912023-10-17 16:06:26 +000031 {
Damjan Marionb8dd9812023-11-03 13:47:05 +000032 if (q->rx_thread_index != vm->thread_index)
33 continue;
Damjan Marion38c61912023-10-17 16:06:26 +000034
Damjan Marionb8dd9812023-11-03 13:47:05 +000035 if (q->interrupt_mode == 0)
36 state = VLIB_NODE_STATE_POLLING;
37 else if (state != VLIB_NODE_STATE_POLLING)
38 state = VLIB_NODE_STATE_INTERRUPT;
Damjan Marion38c61912023-10-17 16:06:26 +000039
Damjan Marionb8dd9812023-11-03 13:47:05 +000040 q->next_on_thread = 0;
41 if (previous == 0)
42 first = q;
43 else
44 previous->next_on_thread = q;
Damjan Marion38c61912023-10-17 16:06:26 +000045
Damjan Marionb8dd9812023-11-03 13:47:05 +000046 previous = q;
Damjan Marion38c61912023-10-17 16:06:26 +000047 }
Damjan Marion38c61912023-10-17 16:06:26 +000048
Damjan Marionb8dd9812023-11-03 13:47:05 +000049 rtd->first_rx_queue = first;
50 vlib_node_set_state (vm, port->intf.rx_node_index, state);
51 __atomic_store_n (&op->completed, 1, __ATOMIC_RELEASE);
Damjan Marion38c61912023-10-17 16:06:26 +000052}
53
54static uword
55vnet_dev_rt_mgmt_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
56 vlib_frame_t *frame)
57{
58 u16 thread_index = vm->thread_index;
Damjan Marionb8dd9812023-11-03 13:47:05 +000059 vnet_dev_rt_op_t *op, *ops = __atomic_load_n (&rt_ops, __ATOMIC_ACQUIRE);
60 u32 n_pending = 0;
Damjan Marion38c61912023-10-17 16:06:26 +000061 uword rv = 0;
62
63 vec_foreach (op, ops)
Damjan Marionb8dd9812023-11-03 13:47:05 +000064 {
65 if (!op->completed && op->thread_index == thread_index)
66 {
67 if (op->in_order == 1 && n_pending)
68 {
69 vlib_node_set_interrupt_pending (vm, node->node_index);
70 return rv;
71 }
72 _vnet_dev_rt_exec_op (vm, op);
73 rv++;
74 }
Damjan Marion38c61912023-10-17 16:06:26 +000075
Damjan Marionb8dd9812023-11-03 13:47:05 +000076 if (op->completed == 0)
77 n_pending++;
78 }
Damjan Marion38c61912023-10-17 16:06:26 +000079
80 return rv;
81}
82
83VLIB_REGISTER_NODE (vnet_dev_rt_mgmt_node, static) = {
84 .function = vnet_dev_rt_mgmt_node_fn,
85 .name = "dev-rt-mgmt",
86 .type = VLIB_NODE_TYPE_PRE_INPUT,
87 .state = VLIB_NODE_STATE_INTERRUPT,
88};
89
Damjan Marion38c61912023-10-17 16:06:26 +000090vnet_dev_rv_t
91vnet_dev_rt_exec_ops (vlib_main_t *vm, vnet_dev_t *dev, vnet_dev_rt_op_t *ops,
92 u32 n_ops)
93{
94 vnet_dev_rt_op_t *op = ops;
95 vnet_dev_rt_op_t *remote_ops = 0;
96 clib_bitmap_t *remote_bmp = 0;
97 u32 i;
98
99 ASSERT (rt_ops == 0);
100
Damjan Marionb8dd9812023-11-03 13:47:05 +0000101 if (vlib_worker_thread_barrier_held ())
102 {
103 for (op = ops; op < (ops + n_ops); op++)
104 {
105 vlib_main_t *tvm = vlib_get_main_by_index (op->thread_index);
106 _vnet_dev_rt_exec_op (tvm, op);
107 log_debug (
108 dev,
109 "port %u rx node runtime update on thread %u executed locally",
110 op->port->port_id, op->thread_index);
111 }
112 return VNET_DEV_OK;
113 }
114
115 while (n_ops)
116 {
117 if (op->thread_index != vm->thread_index)
118 break;
119
120 _vnet_dev_rt_exec_op (vm, op);
121 log_debug (
122 dev, "port %u rx node runtime update on thread %u executed locally",
123 op->port->port_id, op->thread_index);
124 op++;
125 n_ops--;
126 }
127
128 if (n_ops == 0)
129 return VNET_DEV_OK;
130
Damjan Marion38c61912023-10-17 16:06:26 +0000131 for (op = ops; op < (ops + n_ops); op++)
132 {
Damjan Marionb8dd9812023-11-03 13:47:05 +0000133 if (op->thread_index == vm->thread_index &&
134 (op->in_order == 0 || vec_len (remote_ops) == 0))
Damjan Marion38c61912023-10-17 16:06:26 +0000135 {
Damjan Marionb8dd9812023-11-03 13:47:05 +0000136 _vnet_dev_rt_exec_op (vm, op);
137 log_debug (dev,
138 "port %u rx node runtime update on thread "
139 "%u executed locally",
140 op->port->port_id, op->thread_index);
Damjan Marion38c61912023-10-17 16:06:26 +0000141 }
Damjan Marionb8dd9812023-11-03 13:47:05 +0000142 else
143 {
144 vec_add1 (remote_ops, *op);
145 log_debug (dev,
146 "port %u rx node runtime update on thread %u "
147 "enqueued for remote execution",
148 op->port->port_id, op->thread_index);
149 remote_bmp = clib_bitmap_set (remote_bmp, op->thread_index, 1);
150 }
Damjan Marion38c61912023-10-17 16:06:26 +0000151 }
152
153 if (remote_ops == 0)
154 return VNET_DEV_OK;
155
156 __atomic_store_n (&rt_ops, remote_ops, __ATOMIC_RELEASE);
157
158 clib_bitmap_foreach (i, remote_bmp)
159 {
160 vlib_node_set_interrupt_pending (vlib_get_main_by_index (i),
161 vnet_dev_rt_mgmt_node.index);
162 log_debug (dev, "interrupt sent to %s node on thread %u",
163 vnet_dev_rt_mgmt_node.name, i);
164 }
165
166 vec_foreach (op, remote_ops)
167 {
168 while (op->completed == 0)
Damjan Marionb8dd9812023-11-03 13:47:05 +0000169 vlib_process_suspend (vm, 5e-5);
170
171 log_debug (
172 dev, "port %u rx node runtime update on thread %u executed locally",
173 op->port->port_id, op->thread_index);
Damjan Marion38c61912023-10-17 16:06:26 +0000174 }
175
176 __atomic_store_n (&rt_ops, 0, __ATOMIC_RELAXED);
177 vec_free (remote_ops);
178 clib_bitmap_free (remote_bmp);
179 return VNET_DEV_OK;
180}