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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
15 #include <vnet/vnet.h>
16 #include <vppinfra/vec.h>
17 #include <vppinfra/error.h>
18 #include <vppinfra/format.h>
21 #include <vnet/ethernet/ethernet.h>
22 #include <vnet/devices/dpdk/dpdk.h>
23 #include <vnet/devices/dpdk/threads.h>
25 #include <vlibmemory/api.h>
26 #include <vlibmemory/vl_memory_msg_enum.h> /* enumerate all vlib messages */
28 #define vl_typedefs /* define message structures */
29 #include <vlibmemory/vl_memory_api_h.h>
32 /* instantiate all the print functions we know about */
33 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
35 #include <vlibmemory/vl_memory_api_h.h>
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
44 static inline int vlib_frame_queue_dequeue_internal (vlib_main_t *vm)
46 u32 thread_id = vm->cpu_index;
47 vlib_frame_queue_t *fq = vlib_frame_queues[thread_id];
48 vlib_frame_queue_elt_t *elt;
57 ASSERT(vm == vlib_mains[thread_id]);
60 * Gather trace data for frame queues
62 if (PREDICT_FALSE(fq->trace))
64 frame_queue_trace_t *fqt;
65 frame_queue_nelt_counter_t *fqh;
68 fqt = &dpdk_main.frame_queue_traces[thread_id];
70 fqt->nelts = fq->nelts;
72 fqt->head_hint = fq->head_hint;
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;
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 ]++;
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));
90 fqt->n_vectors[elix] = elt->n_vectors;
98 if (fq->head == fq->tail)
100 fq->head_hint = fq->head;
104 elt = fq->elts + ((fq->head+1) & (fq->nelts-1));
108 fq->head_hint = fq->head;
112 from = elt->buffer_index;
113 msg_type = elt->msg_type;
115 ASSERT (msg_type == VLIB_FRAME_QUEUE_ELT_DISPATCH_FRAME);
116 ASSERT (elt->n_vectors <= VLIB_FRAME_SIZE);
118 f = vlib_get_frame_to_node
119 (vm, 1 ? handoff_dispatch_node.index : ethernet_input_node.index);
121 to = vlib_frame_vector_args (f);
123 n_left_to_node = elt->n_vectors;
125 while (n_left_to_node >= 4)
136 while (n_left_to_node > 0)
144 vectors += elt->n_vectors;
145 f->n_vectors = elt->n_vectors;
146 vlib_put_frame_to_node
147 (vm, 1 ? handoff_dispatch_node.index : ethernet_input_node.index, f);
151 elt->msg_type = 0xfefefefe;
152 CLIB_MEMORY_BARRIER();
157 * Limit the number of packets pushed into the graph
159 if (vectors >= fq->vector_threshold)
161 fq->head_hint = fq->head;
169 int dpdk_frame_queue_dequeue (vlib_main_t *vm)
171 return vlib_frame_queue_dequeue_internal (vm);
175 * dpdk_worker_thread - Contains the main loop of a worker thread.
178 * Information for the current thread
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.
184 * If not null, this function will be called once during each main loop.
186 static_always_inline void
187 dpdk_worker_thread_internal (vlib_main_t *vm,
188 dpdk_worker_thread_callback_t callback,
191 vlib_node_main_t * nm = &vm->node_main;
192 u64 cpu_time_now = clib_cpu_time_now ();
196 vlib_worker_thread_barrier_check ();
198 vlib_frame_queue_dequeue_internal (vm);
200 /* Invoke callback if supplied */
201 if (PREDICT_FALSE(callback != NULL))
204 if (!have_io_threads)
206 vlib_node_runtime_t * n;
207 vec_foreach (n, nm->nodes_by_type[VLIB_NODE_TYPE_INPUT])
209 cpu_time_now = dispatch_node (vm, n, VLIB_NODE_TYPE_INPUT,
210 VLIB_NODE_STATE_POLLING, /* frame */ 0,
216 if (_vec_len (nm->pending_frames))
219 cpu_time_now = clib_cpu_time_now ();
220 for (i = 0; i < _vec_len (nm->pending_frames); i++) {
221 vlib_pending_frame_t *p;
223 p = nm->pending_frames + i;
225 cpu_time_now = dispatch_pending_node (vm, p, cpu_time_now);
227 _vec_len (nm->pending_frames) = 0;
229 vlib_increment_main_loop_counter (vm);
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 ();
237 void dpdk_worker_thread (vlib_worker_thread_t * w,
239 dpdk_worker_thread_callback_t callback)
243 vlib_thread_main_t * tm = vlib_get_thread_main();
244 vlib_thread_registration_t * tr;
245 dpdk_main_t * dm = &dpdk_main;
247 vm = vlib_get_main();
249 ASSERT(vm->cpu_index == os_get_cpu_number());
251 clib_time_init (&vm->clib_time);
252 clib_mem_set_heap (w->thread_mheap);
254 /* Wait until the dpdk init sequence is complete */
255 while (dm->io_thread_release == 0)
256 vlib_worker_thread_barrier_check ();
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];
262 if (tr && tr->count > 0)
263 dpdk_worker_thread_internal(vm, callback, /* have_io_threads */ 1);
265 dpdk_worker_thread_internal(vm, callback, /* have_io_threads */ 0);
268 void dpdk_worker_thread_fn (void * arg)
270 vlib_worker_thread_t *w = (vlib_worker_thread_t *) arg;
271 vlib_worker_thread_init (w);
272 dpdk_worker_thread (w, "io", 0);
276 VLIB_REGISTER_THREAD (worker_thread_reg, static) = {
279 .function = dpdk_worker_thread_fn,
283 void dpdk_io_thread_fn (void * arg)
285 vlib_worker_thread_t *w = (vlib_worker_thread_t *) arg;
286 vlib_worker_thread_init (w);
287 dpdk_io_thread (w, 0, 0, "workers", 0);
291 VLIB_REGISTER_THREAD (io_thread_reg, static) = {
294 .function = dpdk_io_thread_fn,
298 static clib_error_t *
299 dpdk_thread_init (vlib_main_t *vm)
304 VLIB_INIT_FUNCTION(dpdk_thread_init);