FD.io VPP  v16.06
Vector Packet Processing
threads.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 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 #include <vnet/vnet.h>
16 #include <vppinfra/vec.h>
17 #include <vppinfra/error.h>
18 #include <vppinfra/format.h>
19 #include <signal.h>
20 
21 #include <vnet/ethernet/ethernet.h>
22 #include <vnet/devices/dpdk/dpdk.h>
24 
25 #include <vlibmemory/api.h>
26 #include <vlibmemory/vl_memory_msg_enum.h> /* enumerate all vlib messages */
27 
28 #define vl_typedefs /* define message structures */
30 #undef vl_typedefs
31 
32 /* instantiate all the print functions we know about */
33 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
34 #define vl_printfun
36 #undef vl_printfun
37 
38 
39 /*
40  * Check the frame queue to see if any frames are available.
41  * If so, pull the packets off the frames and put them to
42  * the handoff node.
43  */
45 {
46  u32 thread_id = vm->cpu_index;
47  vlib_frame_queue_t *fq = vlib_frame_queues[thread_id];
49  u32 * from, * to;
50  vlib_frame_t * f;
51  int msg_type;
52  int processed = 0;
53  u32 n_left_to_node;
54  u32 vectors = 0;
55 
56  ASSERT (fq);
57  ASSERT(vm == vlib_mains[thread_id]);
58 
59  /*
60  * Gather trace data for frame queues
61  */
62  if (PREDICT_FALSE(fq->trace))
63  {
66  u32 elix;
67 
68  fqt = &dpdk_main.frame_queue_traces[thread_id];
69 
70  fqt->nelts = fq->nelts;
71  fqt->head = fq->head;
72  fqt->head_hint = fq->head_hint;
73  fqt->tail = fq->tail;
74  fqt->threshold = fq->vector_threshold;
75  fqt->n_in_use = fqt->tail - fqt->head;
76  if (fqt->n_in_use >= fqt->nelts){
77  // if beyond max then use max
78  fqt->n_in_use = fqt->nelts-1;
79  }
80 
81  /* Record the number of elements in use in the histogram */
82  fqh = &dpdk_main.frame_queue_histogram[thread_id];
83  fqh->count[ fqt->n_in_use ]++;
84 
85  /* Record a snapshot of the elements in use */
86  for (elix=0; elix<fqt->nelts; elix++) {
87  elt = fq->elts + ((fq->head+1 + elix) & (fq->nelts-1));
88  if (1 || elt->valid)
89  {
90  fqt->n_vectors[elix] = elt->n_vectors;
91  }
92  }
93  fqt->written = 1;
94  }
95 
96  while (1)
97  {
98  if (fq->head == fq->tail)
99  {
100  fq->head_hint = fq->head;
101  return processed;
102  }
103 
104  elt = fq->elts + ((fq->head+1) & (fq->nelts-1));
105 
106  if (!elt->valid)
107  {
108  fq->head_hint = fq->head;
109  return processed;
110  }
111 
112  from = elt->buffer_index;
113  msg_type = elt->msg_type;
114 
116  ASSERT (elt->n_vectors <= VLIB_FRAME_SIZE);
117 
119  (vm, 1 ? handoff_dispatch_node.index : ethernet_input_node.index);
120 
121  to = vlib_frame_vector_args (f);
122 
123  n_left_to_node = elt->n_vectors;
124 
125  while (n_left_to_node >= 4)
126  {
127  to[0] = from[0];
128  to[1] = from[1];
129  to[2] = from[2];
130  to[3] = from[3];
131  to += 4;
132  from += 4;
133  n_left_to_node -= 4;
134  }
135 
136  while (n_left_to_node > 0)
137  {
138  to[0] = from[0];
139  to++;
140  from++;
141  n_left_to_node--;
142  }
143 
144  vectors += elt->n_vectors;
145  f->n_vectors = elt->n_vectors;
147  (vm, 1 ? handoff_dispatch_node.index : ethernet_input_node.index, f);
148 
149  elt->valid = 0;
150  elt->n_vectors = 0;
151  elt->msg_type = 0xfefefefe;
153  fq->head++;
154  processed++;
155 
156  /*
157  * Limit the number of packets pushed into the graph
158  */
159  if (vectors >= fq->vector_threshold)
160  {
161  fq->head_hint = fq->head;
162  return processed;
163  }
164  }
165  ASSERT(0);
166  return processed;
167 }
168 
170 {
172 }
173 
174 /*
175  * dpdk_worker_thread - Contains the main loop of a worker thread.
176  *
177  * w
178  * Information for the current thread
179  * io_name
180  * The name of thread performing dpdk device IO (if any). If there are no
181  * instances of that thread, then the current thread will do dpdk device
182  * polling. Ports will be divided among instances of the current thread.
183  * callback
184  * If not null, this function will be called once during each main loop.
185  */
189  int have_io_threads)
190 {
191  vlib_node_main_t * nm = &vm->node_main;
192  u64 cpu_time_now = clib_cpu_time_now ();
193 
194  while (1)
195  {
197 
199 
200  /* Invoke callback if supplied */
201  if (PREDICT_FALSE(callback != NULL))
202  callback(vm);
203 
204  if (!have_io_threads)
205  {
208  {
209  cpu_time_now = dispatch_node (vm, n, VLIB_NODE_TYPE_INPUT,
210  VLIB_NODE_STATE_POLLING, /* frame */ 0,
211  cpu_time_now);
212  }
213 
214  }
215 
216  if (_vec_len (nm->pending_frames))
217  {
218  int i;
219  cpu_time_now = clib_cpu_time_now ();
220  for (i = 0; i < _vec_len (nm->pending_frames); i++) {
222 
223  p = nm->pending_frames + i;
224 
225  cpu_time_now = dispatch_pending_node (vm, p, cpu_time_now);
226  }
227  _vec_len (nm->pending_frames) = 0;
228  }
230 
231  /* Record time stamp in case there are no enabled nodes and above
232  calls do not update time stamp. */
233  cpu_time_now = clib_cpu_time_now ();
234  }
235 }
236 
238  char *io_name,
240 {
241  vlib_main_t *vm;
242  uword * p;
245  dpdk_main_t * dm = &dpdk_main;
246 
247  vm = vlib_get_main();
248 
250 
251  clib_time_init (&vm->clib_time);
253 
254  /* Wait until the dpdk init sequence is complete */
255  while (dm->io_thread_release == 0)
257 
258  /* any I/O threads? */
259  p = hash_get_mem (tm->thread_registrations_by_name, io_name);
260  tr = (vlib_thread_registration_t *)p[0];
261 
262  if (tr && tr->count > 0)
263  dpdk_worker_thread_internal(vm, callback, /* have_io_threads */ 1);
264  else
265  dpdk_worker_thread_internal(vm, callback, /* have_io_threads */ 0);
266 }
267 
268 void dpdk_worker_thread_fn (void * arg)
269 {
272  dpdk_worker_thread (w, "io", 0);
273 }
274 
275 #if VIRL == 0
276 VLIB_REGISTER_THREAD (worker_thread_reg, static) = {
277  .name = "workers",
278  .short_name = "wk",
279  .function = dpdk_worker_thread_fn,
280 };
281 #endif
282 
283 void dpdk_io_thread_fn (void * arg)
284 {
287  dpdk_io_thread (w, 0, 0, "workers", 0);
288 }
289 
290 #if VIRL == 0
291 VLIB_REGISTER_THREAD (io_thread_reg, static) = {
292  .name = "io",
293  .short_name = "io",
294  .function = dpdk_io_thread_fn,
295 };
296 #endif
297 
298 static clib_error_t *
300 {
301  return (0);
302 }
303 
u64 count[MAX_NELTS]
Definition: dpdk.h:274
void dpdk_io_thread(vlib_worker_thread_t *w, u32 instances, u32 instance_id, char *worker_name, dpdk_io_thread_callback_t callback)
Definition: node.c:1079
always_inline vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
dpdk_main_t dpdk_main
Definition: dpdk.h:415
void(* dpdk_worker_thread_callback_t)(vlib_main_t *vm)
Definition: threads.h:20
static void vlib_worker_thread_barrier_check(void)
Definition: threads.h:201
VLIB_REGISTER_THREAD(worker_thread_reg, static)
#define NULL
Definition: clib.h:55
clib_time_t clib_time
Definition: main.h:61
vlib_node_registration_t ethernet_input_node
(constructor) VLIB_REGISTER_NODE (ethernet_input_node)
Definition: node.c:919
u32 buffer_index[VLIB_FRAME_SIZE]
Definition: threads.h:78
volatile u32 valid
Definition: threads.h:72
always_inline vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
uword os_get_cpu_number(void)
Definition: threads.c:62
#define static_always_inline
Definition: clib.h:85
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:109
u64 dispatch_pending_node(vlib_main_t *vm, vlib_pending_frame_t *p, u64 last_time_stamp)
Definition: main.c:1076
void dpdk_io_thread_fn(void *arg)
Definition: threads.c:283
u32 cpu_index
Definition: main.h:159
unsigned long u64
Definition: types.h:89
vlib_frame_queue_elt_t * elts
Definition: threads.h:135
vlib_node_runtime_t * nodes_by_type[VLIB_N_NODE_TYPE]
Definition: node.h:580
int dpdk_frame_queue_dequeue(vlib_main_t *vm)
Definition: threads.c:169
always_inline void * vlib_frame_vector_args(vlib_frame_t *f)
Definition: node_funcs.h:202
void dpdk_worker_thread_fn(void *arg)
Definition: threads.c:268
vlib_node_registration_t handoff_dispatch_node
(constructor) VLIB_REGISTER_NODE (handoff_dispatch_node)
Definition: node.c:232
void * thread_mheap
Definition: threads.h:91
volatile u64 head
Definition: threads.h:121
#define PREDICT_FALSE(x)
Definition: clib.h:97
always_inline void * clib_mem_set_heap(void *heap)
Definition: mem.h:190
#define VLIB_FRAME_SIZE
Definition: node.h:292
vlib_frame_queue_t ** vlib_frame_queues
Definition: threads.h:139
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:191
frame_queue_nelt_counter_t * frame_queue_histogram
Definition: dpdk.h:408
void clib_time_init(clib_time_t *c)
Definition: time.c:160
volatile u64 tail
Definition: threads.h:110
u16 n_vectors
Definition: node.h:307
vlib_pending_frame_t * pending_frames
Definition: node.h:595
static_always_inline void dpdk_worker_thread_internal(vlib_main_t *vm, dpdk_worker_thread_callback_t callback, int have_io_threads)
Definition: threads.c:187
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
uword * thread_registrations_by_name
Definition: threads.h:263
void dpdk_worker_thread(vlib_worker_thread_t *w, char *io_name, dpdk_worker_thread_callback_t callback)
Definition: threads.c:237
frame_queue_trace_t * frame_queue_traces
Definition: dpdk.h:407
u64 uword
Definition: types.h:112
static clib_error_t * dpdk_thread_init(vlib_main_t *vm)
Definition: threads.c:299
vlib_node_main_t node_main
Definition: main.h:115
always_inline void vlib_increment_main_loop_counter(vlib_main_t *vm)
Definition: main.h:278
volatile u64 head_hint
Definition: threads.h:131
static int vlib_frame_queue_dequeue_internal(vlib_main_t *vm)
Definition: threads.c:44
#define hash_get_mem(h, key)
Definition: hash.h:251
u64 dispatch_node(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_node_type_t type, vlib_node_state_t dispatch_state, vlib_frame_t *frame, u64 last_time_stamp)
Definition: main.c:918
volatile u32 io_thread_release
Definition: dpdk.h:363
#define vec_foreach(var, vec)
Vector iterator.
void vlib_worker_thread_init(vlib_worker_thread_t *w)
Definition: threads.c:439
#define CLIB_MEMORY_BARRIER()
Definition: clib.h:101
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:184
always_inline u64 clib_cpu_time_now(void)
Definition: time.h:71
i32 n_vectors[MAX_NELTS]
Definition: dpdk.h:270
vlib_main_t ** vlib_mains
Definition: buffer.c:244
CLIB vectors are ubiquitous dynamically resized arrays with by user defined "headers".