FD.io VPP  v21.10.1-2-g0a485f517
Vector Packet Processing
runtime.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <vnet/vnet.h>
17 #include <vnet/devices/devices.h>
18 #include <vnet/feature/feature.h>
19 #include <vnet/ip/ip.h>
20 #include <vnet/ethernet/ethernet.h>
23 #include <vlib/unix/unix.h>
24 
25 VLIB_REGISTER_LOG_CLASS (if_rxq_log, static) = {
26  .class_name = "interface",
27  .subclass_name = "runtime",
28 };
29 
30 #define log_debug(fmt, ...) vlib_log_debug (if_rxq_log.class, fmt, __VA_ARGS__)
31 #define log_err(fmt, ...) vlib_log_err (if_rxq_log.class, fmt, __VA_ARGS__)
32 
33 static char *node_state_str[] = {
34  [VLIB_NODE_STATE_DISABLED] = "disabled",
35  [VLIB_NODE_STATE_POLLING] = "polling",
36  [VLIB_NODE_STATE_INTERRUPT] = "interrupt",
37 };
38 
39 static int
40 poll_data_sort (void *a1, void *a2)
41 {
44 
45  if (pv1->dev_instance > pv2->dev_instance)
46  return 1;
47  else if (pv1->dev_instance < pv2->dev_instance)
48  return -1;
49  else if (pv1->queue_id > pv2->queue_id)
50  return 1;
51  else if (pv1->queue_id < pv2->queue_id)
52  return -1;
53  else
54  return 0;
55 }
56 
57 void
59 {
62  vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
63  u32 node_index = hi->input_node_index;
65  vnet_hw_if_rxq_poll_vector_t *pv, **d = 0, **a = 0;
66  vnet_hw_if_output_node_runtime_t *new_out_runtimes = 0;
67  vlib_node_state_t *per_thread_node_state = 0;
68  u32 n_threads = vlib_get_n_threads ();
69  u16 *per_thread_node_adaptive = 0;
70  int something_changed_on_rx = 0;
71  int something_changed_on_tx = 0;
72  clib_bitmap_t *pending_int = 0;
73  int last_int = -1;
74 
75  log_debug ("update node '%U' triggered by interface %v",
77 
78  vec_validate (d, n_threads - 1);
79  vec_validate (a, n_threads - 1);
80  vec_validate_init_empty (per_thread_node_state, n_threads - 1,
81  VLIB_NODE_STATE_DISABLED);
82  vec_validate_init_empty (per_thread_node_adaptive, n_threads - 1, 0);
83 
84  /* find out desired node state on each thread */
86  {
87  u32 ti = rxq->thread_index;
88  vnet_hw_interface_t *rxq_hi;
89 
92 
93  rxq_hi = vnet_get_hw_interface (vnm, rxq->hw_if_index);
94 
95  if (rxq_hi->input_node_index != node_index)
96  continue;
97 
98  if (rxq->mode == VNET_HW_IF_RX_MODE_POLLING)
99  {
100  per_thread_node_state[ti] = VLIB_NODE_STATE_POLLING;
101  per_thread_node_adaptive[ti] = 0;
102  }
103 
104  if (per_thread_node_state[ti] == VLIB_NODE_STATE_POLLING)
105  continue;
106 
107  if (rxq->mode == VNET_HW_IF_RX_MODE_INTERRUPT ||
109  per_thread_node_state[ti] = VLIB_NODE_STATE_INTERRUPT;
110 
111  if (rxq->mode == VNET_HW_IF_RX_MODE_ADAPTIVE)
112  per_thread_node_adaptive[ti] = 1;
113  }
114 
115  /* construct per-thread polling vectors */
117  {
118  u32 ti = rxq->thread_index;
119  vnet_hw_interface_t *rxq_hi;
120 
121  rxq_hi = vnet_get_hw_interface (vnm, rxq->hw_if_index);
122 
123  if (rxq_hi->input_node_index != node_index)
124  continue;
125 
126  if (rxq->mode == VNET_HW_IF_RX_MODE_INTERRUPT ||
128  last_int = clib_max (last_int, rxq - im->hw_if_rx_queues);
129 
130  if (per_thread_node_adaptive[ti])
131  {
133  pv->dev_instance = rxq->dev_instance;
134  pv->queue_id = rxq->queue_id;
135  }
136 
137  if (per_thread_node_state[ti] != VLIB_NODE_STATE_POLLING)
138  continue;
139 
141  pv->dev_instance = rxq->dev_instance;
142  pv->queue_id = rxq->queue_id;
143  }
144 
145  /* sort poll vectors and compare them with active ones to avoid
146  * unnecesary barrier */
147  for (int i = 0; i < n_threads; i++)
148  {
150  vlib_node_state_t old_state;
152 
153  old_state = vlib_node_get_state (ovm, node_index);
154  if (per_thread_node_state[i] != old_state)
155  {
156  something_changed_on_rx = 1;
157  log_debug ("state changed for node %U on thread %u from %s to %s",
159  node_state_str[old_state],
160  node_state_str[per_thread_node_state[i]]);
161  }
162 
163  /* check if something changed */
164  if (something_changed_on_rx == 0)
165  {
168  if (vec_len (rt->rxq_vector_int) != vec_len (d[i]))
169  something_changed_on_rx = 1;
170  else if (memcmp (d[i], rt->rxq_vector_int,
171  vec_len (d[i]) * sizeof (**d)))
172  something_changed_on_rx = 1;
173  if (clib_interrupt_get_n_int (rt->rxq_interrupts) != last_int + 1)
174  something_changed_on_rx = 1;
175 
176  if (something_changed_on_rx == 0 && per_thread_node_adaptive[i])
177  {
178  if (vec_len (rt->rxq_vector_poll) != vec_len (a[i]))
179  something_changed_on_rx = 1;
180  else if (memcmp (a[i], rt->rxq_vector_poll,
181  vec_len (a[i]) * sizeof (**a)))
182  something_changed_on_rx = 1;
183  }
184  }
185  }
186 
187  new_out_runtimes =
188  vec_dup_aligned (hi->output_node_thread_runtimes, CLIB_CACHE_LINE_BYTES);
189  vec_validate_aligned (new_out_runtimes, n_threads - 1,
191 
192  if (vec_len (hi->output_node_thread_runtimes) != vec_len (new_out_runtimes))
193  something_changed_on_tx = 1;
194 
195  for (int i = 0; i < vec_len (hi->tx_queue_indices); i++)
196  {
198  u32 queue_index = hi->tx_queue_indices[i];
199  vnet_hw_if_tx_queue_t *txq = vnet_hw_if_get_tx_queue (vnm, queue_index);
200  uword n_threads = clib_bitmap_count_set_bits (txq->threads);
201 
203  {
205  rt = vec_elt_at_index (new_out_runtimes, thread_index);
206  if ((rt->frame.queue_id != txq->queue_id) ||
207  (rt->n_threads != n_threads))
208  {
209  log_debug ("tx queue data changed for interface %v, thread %u "
210  "(queue_id %u -> %u, n_threads %u -> %u)",
211  hi->name, thread_index, rt->frame.queue_id,
212  txq->queue_id, rt->n_threads, n_threads);
213  something_changed_on_tx = 1;
214  rt->frame.queue_id = txq->queue_id;
215  rt->frame.shared_queue = txq->shared_queue;
216  rt->n_threads = n_threads;
217  }
218  }
219  }
220 
221  if (something_changed_on_rx || something_changed_on_tx)
222  {
223  int with_barrier;
224 
226  {
227  with_barrier = 0;
228  log_debug ("%s", "already running under the barrier");
229  }
230  else
231  with_barrier = 1;
232 
233  if (with_barrier)
235 
236  if (something_changed_on_rx)
237  {
238  for (int i = 0; i < n_threads; i++)
239  {
243  pv = rt->rxq_vector_int;
244  rt->rxq_vector_int = d[i];
245  d[i] = pv;
246 
247  if (per_thread_node_adaptive[i])
248  {
249  pv = rt->rxq_vector_poll;
250  rt->rxq_vector_poll = a[i];
251  a[i] = pv;
252  }
253 
254  if (rt->rxq_interrupts)
255  {
256  void *in = rt->rxq_interrupts;
257  int int_num = -1;
258  while ((int_num = clib_interrupt_get_next (in, int_num)) !=
259  -1)
260  {
261  clib_interrupt_clear (in, int_num);
262  pending_int = clib_bitmap_set (pending_int, int_num, 1);
263  last_int = clib_max (last_int, int_num);
264  }
265  }
266 
267  vlib_node_set_state (vm, node_index, per_thread_node_state[i]);
269  per_thread_node_adaptive[i]);
270 
271  if (last_int >= 0)
272  clib_interrupt_resize (&rt->rxq_interrupts, last_int + 1);
273  else
274  clib_interrupt_free (&rt->rxq_interrupts);
275  }
276  }
277  if (something_changed_on_tx)
278  {
280  t = hi->output_node_thread_runtimes;
281  hi->output_node_thread_runtimes = new_out_runtimes;
282  new_out_runtimes = t;
283  }
284 
285  if (with_barrier)
287  }
288  else
289  log_debug ("skipping update of node '%U', no changes detected",
291 
292  if (pending_int)
293  {
294  int i;
295  clib_bitmap_foreach (i, pending_int)
296  {
298  }
299  clib_bitmap_free (pending_int);
300  }
301 
302  for (int i = 0; i < n_threads; i++)
303  {
304  vec_free (d[i]);
305  vec_free (a[i]);
306  }
307 
308  vec_free (d);
309  vec_free (a);
310  vec_free (per_thread_node_state);
311  vec_free (per_thread_node_adaptive);
312  vec_free (new_out_runtimes);
313 }
im
vnet_interface_main_t * im
Definition: interface_output.c:415
vnet_hw_if_output_node_runtime_t
Definition: interface.h:629
clib_interrupt_free
static_always_inline void clib_interrupt_free(void **data)
Definition: interrupt.h:34
vlib_worker_thread_barrier_release
void vlib_worker_thread_barrier_release(vlib_main_t *vm)
Definition: threads.c:1375
thread_index
u32 thread_index
Definition: nat44_ei_hairpinning.c:495
VNET_HW_IF_RX_MODE_ADAPTIVE
@ VNET_HW_IF_RX_MODE_ADAPTIVE
Definition: interface.h:58
vlib_node_get_runtime_data
static void * vlib_node_get_runtime_data(vlib_main_t *vm, u32 node_index)
Get node runtime private data by node index.
Definition: node_funcs.h:137
vnet_hw_if_rxq_poll_vector_t::queue_id
u32 queue_id
Definition: interface.h:749
clib_max
#define clib_max(x, y)
Definition: clib.h:335
vnet_hw_if_rx_queue_t::mode
vnet_hw_if_rx_mode mode
Definition: interface.h:597
vlib_node_set_state
static void vlib_node_set_state(vlib_main_t *vm, u32 node_index, vlib_node_state_t new_state)
Set node dispatch state.
Definition: node_funcs.h:175
clib_bitmap_t
uword clib_bitmap_t
Definition: bitmap.h:50
vnet_hw_if_rx_queue_t::thread_index
u32 thread_index
Definition: interface.h:588
clib_interrupt_get_next
static_always_inline int clib_interrupt_get_next(void *in, int last)
Definition: interrupt.h:104
node_state_str
static char * node_state_str[]
Definition: runtime.c:33
vnet_interface_main_t
Definition: interface.h:990
vnet_hw_if_rx_queue_t::dev_instance
u32 dev_instance
Definition: interface.h:585
u16
unsigned short u16
Definition: types.h:57
VNET_HW_IF_RX_MODE_POLLING
@ VNET_HW_IF_RX_MODE_POLLING
Definition: interface.h:56
vm
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
node_index
node node_index
Definition: interface_output.c:440
VLIB_NODE_FLAG_ADAPTIVE_MODE
#define VLIB_NODE_FLAG_ADAPTIVE_MODE
Definition: node.h:296
hi
vl_api_ip4_address_t hi
Definition: arp.api:37
vnet_interface_main_t::hw_if_rx_queues
vnet_hw_if_rx_queue_t * hw_if_rx_queues
Definition: interface.h:996
ethernet.h
poll_data_sort
static int poll_data_sort(void *a1, void *a2)
Definition: runtime.c:40
ti
u32 ti
Definition: interface_output.c:425
pool_foreach
#define pool_foreach(VAR, POOL)
Iterate through pool.
Definition: pool.h:534
vnet_hw_if_rx_queue_t::queue_id
u32 queue_id
Definition: interface.h:594
vec_len
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
Definition: vec_bootstrap.h:142
feature.h
clib_interrupt_clear
static_always_inline void clib_interrupt_clear(void *in, int int_num)
Definition: interrupt.h:90
vec_elt_at_index
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
Definition: vec_bootstrap.h:203
vnet_get_hw_interface
static vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
Definition: interface_funcs.h:44
clib_interrupt_resize
__clib_export void clib_interrupt_resize(void **data, uword n_int)
Definition: interrupt.c:38
clib_bitmap_count_set_bits
static uword clib_bitmap_count_set_bits(uword *ai)
Return the number of set bits in a bitmap.
Definition: bitmap.h:449
vlib_worker_thread_barrier_sync
#define vlib_worker_thread_barrier_sync(X)
Definition: threads.h:173
rx_queue_funcs.h
vec_validate_aligned
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:534
clib_bitmap_free
#define clib_bitmap_free(v)
Free a bitmap.
Definition: bitmap.h:92
uword
u64 uword
Definition: types.h:112
vnet_hw_if_update_runtime_data
void vnet_hw_if_update_runtime_data(vnet_main_t *vnm, u32 hw_if_index)
Definition: runtime.c:58
vlib_node_state_t
vlib_node_state_t
Definition: node.h:239
VNET_HW_IF_RX_MODE_INTERRUPT
@ VNET_HW_IF_RX_MODE_INTERRUPT
Definition: interface.h:57
vnet_hw_if_tx_queue_t::queue_id
u32 queue_id
Definition: interface.h:609
vlib_node_set_flag
static void vlib_node_set_flag(vlib_main_t *vm, u32 node_index, u16 flag, u8 enable)
Definition: node_funcs.h:228
vnet_hw_if_get_tx_queue
static_always_inline vnet_hw_if_tx_queue_t * vnet_hw_if_get_tx_queue(vnet_main_t *vnm, u32 queue_index)
Definition: tx_queue_funcs.h:23
vec_validate
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment)
Definition: vec.h:523
vlib_worker_thread_barrier_held
u8 vlib_worker_thread_barrier_held(void)
Return true if the wroker thread barrier is held.
Definition: threads.c:1270
vnet_hw_if_rx_queue_set_int_pending
static_always_inline void vnet_hw_if_rx_queue_set_int_pending(vnet_main_t *vnm, u32 queue_index)
Definition: rx_queue_funcs.h:52
VNET_HW_IF_RX_MODE_DEFAULT
@ VNET_HW_IF_RX_MODE_DEFAULT
Definition: interface.h:59
clib_bitmap_set
static uword * clib_bitmap_set(uword *ai, uword i, uword value)
Sets the ith bit of a bitmap to new_value Removes trailing zeros from the bitmap.
Definition: bitmap.h:167
vec_dup_aligned
#define vec_dup_aligned(V, A)
Return copy of vector (no header, alignment specified).
Definition: vec.h:453
CLIB_CACHE_LINE_BYTES
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:58
clib_interrupt_get_n_int
static_always_inline int clib_interrupt_get_n_int(void *d)
Definition: interrupt.h:44
VLIB_REGISTER_LOG_CLASS
VLIB_REGISTER_LOG_CLASS(if_rxq_log, static)
vec_add2_aligned
#define vec_add2_aligned(V, P, N, A)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:656
vnet_hw_interface_t
Definition: interface.h:638
vnet_main_t
Definition: vnet.h:76
vec_free
#define vec_free(V)
Free vector's memory (no header).
Definition: vec.h:395
vnet_hw_if_rx_node_runtime_t
Definition: interface.h:752
format_vlib_node_name
format_function_t format_vlib_node_name
Definition: node_funcs.h:1235
ASSERT
#define ASSERT(truth)
Definition: error_bootstrap.h:69
vec_validate_init_empty
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header,...
Definition: vec.h:570
ip.h
u32
unsigned int u32
Definition: types.h:88
vlib_get_main_by_index
static vlib_main_t * vlib_get_main_by_index(u32 thread_index)
Definition: global_funcs.h:29
vnet_hw_if_tx_queue_t
Definition: interface.h:602
vnet_hw_if_tx_queue_t::shared_queue
u8 shared_queue
Definition: interface.h:604
vec_sort_with_function
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:1097
vlib_main_t
Definition: main.h:102
vlib_get_n_threads
static u32 vlib_get_n_threads()
Definition: global_funcs.h:23
vlib_get_main
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:38
a
a
Definition: bitmap.h:525
unix.h
rt
vnet_interface_output_runtime_t * rt
Definition: interface_output.c:419
vnet_hw_if_tx_queue_t::threads
clib_bitmap_t * threads
Definition: interface.h:612
i
int i
Definition: flowhash_template.h:376
vnet_hw_if_rx_queue_t::hw_if_index
u32 hw_if_index
Definition: interface.h:582
log_debug
#define log_debug(fmt,...)
Definition: runtime.c:30
vnet_hw_if_rx_queue_t
Definition: interface.h:579
devices.h
tx_queue_funcs.h
vnet_hw_interface_t::input_node_index
u32 input_node_index
Definition: interface.h:718
vnet.h
clib_bitmap_foreach
#define clib_bitmap_foreach(i, ai)
Macro to iterate across set bits in a bitmap.
Definition: bitmap.h:361
vnet_hw_if_rxq_poll_vector_t::dev_instance
u32 dev_instance
Definition: interface.h:748
vnet_main_t::interface_main
vnet_interface_main_t interface_main
Definition: vnet.h:81
vlib_node_get_state
static vlib_node_state_t vlib_node_get_state(vlib_main_t *vm, u32 node_index)
Get node dispatch state.
Definition: node_funcs.h:219
VNET_HW_IF_RX_MODE_UNKNOWN
@ VNET_HW_IF_RX_MODE_UNKNOWN
Definition: interface.h:55
vnet_hw_if_rxq_poll_vector_t
Definition: interface.h:746