1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2020 Intel Corporation
7 #include <rte_common.h>
8 #include <rte_cycles.h>
12 #include <rte_table_acl.h>
13 #include <rte_table_array.h>
14 #include <rte_table_hash.h>
15 #include <rte_table_lpm.h>
16 #include <rte_table_lpm_ipv6.h>
21 #ifndef THREAD_PIPELINES_MAX
22 #define THREAD_PIPELINES_MAX 256
25 #ifndef THREAD_MSGQ_SIZE
26 #define THREAD_MSGQ_SIZE 64
29 #ifndef THREAD_TIMER_PERIOD_MS
30 #define THREAD_TIMER_PERIOD_MS 100
34 * Control thread: data plane thread context
37 struct rte_ring *msgq_req;
38 struct rte_ring *msgq_rsp;
43 static struct thread thread[RTE_MAX_LCORE];
46 * Data plane threads: context
48 struct pipeline_data {
49 struct rte_swx_pipeline *p;
50 uint64_t timer_period; /* Measured in CPU cycles. */
55 struct rte_swx_pipeline *p[THREAD_PIPELINES_MAX];
58 struct pipeline_data pipeline_data[THREAD_PIPELINES_MAX];
59 struct rte_ring *msgq_req;
60 struct rte_ring *msgq_rsp;
61 uint64_t timer_period; /* Measured in CPU cycles. */
63 uint64_t time_next_min;
64 } __rte_cache_aligned;
66 static struct thread_data thread_data[RTE_MAX_LCORE];
69 * Control thread: data plane thread init
76 for (i = 0; i < RTE_MAX_LCORE; i++) {
77 struct thread *t = &thread[i];
79 if (!rte_lcore_is_enabled(i))
84 rte_ring_free(t->msgq_req);
87 rte_ring_free(t->msgq_rsp);
96 RTE_LCORE_FOREACH_SLAVE(i) {
98 struct rte_ring *msgq_req, *msgq_rsp;
99 struct thread *t = &thread[i];
100 struct thread_data *t_data = &thread_data[i];
101 uint32_t cpu_id = rte_lcore_to_socket_id(i);
104 snprintf(name, sizeof(name), "THREAD-%04x-MSGQ-REQ", i);
106 msgq_req = rte_ring_create(name,
109 RING_F_SP_ENQ | RING_F_SC_DEQ);
111 if (msgq_req == NULL) {
116 snprintf(name, sizeof(name), "THREAD-%04x-MSGQ-RSP", i);
118 msgq_rsp = rte_ring_create(name,
121 RING_F_SP_ENQ | RING_F_SC_DEQ);
123 if (msgq_rsp == NULL) {
128 /* Control thread records */
129 t->msgq_req = msgq_req;
130 t->msgq_rsp = msgq_rsp;
133 /* Data plane thread records */
134 t_data->n_pipelines = 0;
135 t_data->msgq_req = msgq_req;
136 t_data->msgq_rsp = msgq_rsp;
137 t_data->timer_period =
138 (rte_get_tsc_hz() * THREAD_TIMER_PERIOD_MS) / 1000;
139 t_data->time_next = rte_get_tsc_cycles() + t_data->timer_period;
140 t_data->time_next_min = t_data->time_next;
147 thread_is_running(uint32_t thread_id)
149 enum rte_lcore_state_t thread_state;
151 thread_state = rte_eal_get_lcore_state(thread_id);
152 return (thread_state == RUNNING) ? 1 : 0;
156 * Control thread & data plane threads: message passing
158 enum thread_req_type {
159 THREAD_REQ_PIPELINE_ENABLE = 0,
160 THREAD_REQ_PIPELINE_DISABLE,
164 struct thread_msg_req {
165 enum thread_req_type type;
169 struct rte_swx_pipeline *p;
170 uint32_t timer_period_ms;
174 struct rte_swx_pipeline *p;
179 struct thread_msg_rsp {
186 static struct thread_msg_req *
187 thread_msg_alloc(void)
189 size_t size = RTE_MAX(sizeof(struct thread_msg_req),
190 sizeof(struct thread_msg_rsp));
192 return calloc(1, size);
196 thread_msg_free(struct thread_msg_rsp *rsp)
201 static struct thread_msg_rsp *
202 thread_msg_send_recv(uint32_t thread_id,
203 struct thread_msg_req *req)
205 struct thread *t = &thread[thread_id];
206 struct rte_ring *msgq_req = t->msgq_req;
207 struct rte_ring *msgq_rsp = t->msgq_rsp;
208 struct thread_msg_rsp *rsp;
213 status = rte_ring_sp_enqueue(msgq_req, req);
214 } while (status == -ENOBUFS);
218 status = rte_ring_sc_dequeue(msgq_rsp, (void **) &rsp);
219 } while (status != 0);
225 thread_pipeline_enable(uint32_t thread_id,
227 const char *pipeline_name)
229 struct pipeline *p = pipeline_find(obj, pipeline_name);
231 struct thread_msg_req *req;
232 struct thread_msg_rsp *rsp;
235 /* Check input params */
236 if ((thread_id >= RTE_MAX_LCORE) ||
240 t = &thread[thread_id];
244 if (!thread_is_running(thread_id)) {
245 struct thread_data *td = &thread_data[thread_id];
246 struct pipeline_data *tdp = &td->pipeline_data[td->n_pipelines];
248 if (td->n_pipelines >= THREAD_PIPELINES_MAX)
251 /* Data plane thread */
252 td->p[td->n_pipelines] = p->p;
256 (rte_get_tsc_hz() * p->timer_period_ms) / 1000;
257 tdp->time_next = rte_get_tsc_cycles() + tdp->timer_period;
262 p->thread_id = thread_id;
268 /* Allocate request */
269 req = thread_msg_alloc();
274 req->type = THREAD_REQ_PIPELINE_ENABLE;
275 req->pipeline_enable.p = p->p;
276 req->pipeline_enable.timer_period_ms = p->timer_period_ms;
278 /* Send request and wait for response */
279 rsp = thread_msg_send_recv(thread_id, req);
282 status = rsp->status;
285 thread_msg_free(rsp);
287 /* Request completion */
291 p->thread_id = thread_id;
298 thread_pipeline_disable(uint32_t thread_id,
300 const char *pipeline_name)
302 struct pipeline *p = pipeline_find(obj, pipeline_name);
304 struct thread_msg_req *req;
305 struct thread_msg_rsp *rsp;
308 /* Check input params */
309 if ((thread_id >= RTE_MAX_LCORE) ||
313 t = &thread[thread_id];
320 if (p->thread_id != thread_id)
323 if (!thread_is_running(thread_id)) {
324 struct thread_data *td = &thread_data[thread_id];
327 for (i = 0; i < td->n_pipelines; i++) {
328 struct pipeline_data *tdp = &td->pipeline_data[i];
333 /* Data plane thread */
334 if (i < td->n_pipelines - 1) {
335 struct rte_swx_pipeline *pipeline_last =
336 td->p[td->n_pipelines - 1];
337 struct pipeline_data *tdp_last =
338 &td->pipeline_data[td->n_pipelines - 1];
340 td->p[i] = pipeline_last;
341 memcpy(tdp, tdp_last, sizeof(*tdp));
355 /* Allocate request */
356 req = thread_msg_alloc();
361 req->type = THREAD_REQ_PIPELINE_DISABLE;
362 req->pipeline_disable.p = p->p;
364 /* Send request and wait for response */
365 rsp = thread_msg_send_recv(thread_id, req);
368 status = rsp->status;
371 thread_msg_free(rsp);
373 /* Request completion */
383 * Data plane threads: message handling
385 static inline struct thread_msg_req *
386 thread_msg_recv(struct rte_ring *msgq_req)
388 struct thread_msg_req *req;
390 int status = rte_ring_sc_dequeue(msgq_req, (void **) &req);
399 thread_msg_send(struct rte_ring *msgq_rsp,
400 struct thread_msg_rsp *rsp)
405 status = rte_ring_sp_enqueue(msgq_rsp, rsp);
406 } while (status == -ENOBUFS);
409 static struct thread_msg_rsp *
410 thread_msg_handle_pipeline_enable(struct thread_data *t,
411 struct thread_msg_req *req)
413 struct thread_msg_rsp *rsp = (struct thread_msg_rsp *) req;
414 struct pipeline_data *p = &t->pipeline_data[t->n_pipelines];
417 if (t->n_pipelines >= THREAD_PIPELINES_MAX) {
422 t->p[t->n_pipelines] = req->pipeline_enable.p;
424 p->p = req->pipeline_enable.p;
425 p->timer_period = (rte_get_tsc_hz() *
426 req->pipeline_enable.timer_period_ms) / 1000;
427 p->time_next = rte_get_tsc_cycles() + p->timer_period;
436 static struct thread_msg_rsp *
437 thread_msg_handle_pipeline_disable(struct thread_data *t,
438 struct thread_msg_req *req)
440 struct thread_msg_rsp *rsp = (struct thread_msg_rsp *) req;
441 uint32_t n_pipelines = t->n_pipelines;
442 struct rte_swx_pipeline *pipeline = req->pipeline_disable.p;
446 for (i = 0; i < n_pipelines; i++) {
447 struct pipeline_data *p = &t->pipeline_data[i];
449 if (p->p != pipeline)
452 if (i < n_pipelines - 1) {
453 struct rte_swx_pipeline *pipeline_last =
454 t->p[n_pipelines - 1];
455 struct pipeline_data *p_last =
456 &t->pipeline_data[n_pipelines - 1];
458 t->p[i] = pipeline_last;
459 memcpy(p, p_last, sizeof(*p));
468 /* should not get here */
474 thread_msg_handle(struct thread_data *t)
477 struct thread_msg_req *req;
478 struct thread_msg_rsp *rsp;
480 req = thread_msg_recv(t->msgq_req);
485 case THREAD_REQ_PIPELINE_ENABLE:
486 rsp = thread_msg_handle_pipeline_enable(t, req);
489 case THREAD_REQ_PIPELINE_DISABLE:
490 rsp = thread_msg_handle_pipeline_disable(t, req);
494 rsp = (struct thread_msg_rsp *) req;
498 thread_msg_send(t->msgq_rsp, rsp);
503 * Data plane threads: main
506 thread_main(void *arg __rte_unused)
508 struct thread_data *t;
509 uint32_t thread_id, i;
511 thread_id = rte_lcore_id();
512 t = &thread_data[thread_id];
519 for (j = 0; j < t->n_pipelines; j++)
520 rte_swx_pipeline_run(t->p[j], 1000000);
523 if ((i & 0xF) == 0) {
524 uint64_t time = rte_get_tsc_cycles();
525 uint64_t time_next_min = UINT64_MAX;
527 if (time < t->time_next_min)
530 /* Thread message queues */
532 uint64_t time_next = t->time_next;
534 if (time_next <= time) {
535 thread_msg_handle(t);
536 time_next = time + t->timer_period;
537 t->time_next = time_next;
540 if (time_next < time_next_min)
541 time_next_min = time_next;
544 t->time_next_min = time_next_min;