examples/ip_pipeline: track table rules on add bulk
[dpdk.git] / examples / ip_pipeline / thread.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2018 Intel Corporation
3  */
4
5 #include <stdlib.h>
6
7 #include <rte_common.h>
8 #include <rte_cycles.h>
9 #include <rte_lcore.h>
10 #include <rte_ring.h>
11
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>
17
18 #include "common.h"
19 #include "thread.h"
20 #include "pipeline.h"
21
22 #ifndef THREAD_PIPELINES_MAX
23 #define THREAD_PIPELINES_MAX                               256
24 #endif
25
26 #ifndef THREAD_MSGQ_SIZE
27 #define THREAD_MSGQ_SIZE                                   64
28 #endif
29
30 #ifndef THREAD_TIMER_PERIOD_MS
31 #define THREAD_TIMER_PERIOD_MS                             100
32 #endif
33
34 /**
35  * Master thead: data plane thread context
36  */
37 struct thread {
38         struct rte_ring *msgq_req;
39         struct rte_ring *msgq_rsp;
40
41         uint32_t enabled;
42 };
43
44 static struct thread thread[RTE_MAX_LCORE];
45
46 /**
47  * Data plane threads: context
48  */
49 struct table_data {
50         struct rte_table_action *a;
51 };
52
53 struct pipeline_data {
54         struct rte_pipeline *p;
55         struct table_data table_data[RTE_PIPELINE_TABLE_MAX];
56         uint32_t n_tables;
57
58         struct rte_ring *msgq_req;
59         struct rte_ring *msgq_rsp;
60         uint64_t timer_period; /* Measured in CPU cycles. */
61         uint64_t time_next;
62
63         uint8_t buffer[TABLE_RULE_ACTION_SIZE_MAX];
64 };
65
66 struct thread_data {
67         struct rte_pipeline *p[THREAD_PIPELINES_MAX];
68         uint32_t n_pipelines;
69
70         struct pipeline_data pipeline_data[THREAD_PIPELINES_MAX];
71         struct rte_ring *msgq_req;
72         struct rte_ring *msgq_rsp;
73         uint64_t timer_period; /* Measured in CPU cycles. */
74         uint64_t time_next;
75         uint64_t time_next_min;
76 } __rte_cache_aligned;
77
78 static struct thread_data thread_data[RTE_MAX_LCORE];
79
80 /**
81  * Master thread: data plane thread init
82  */
83 static void
84 thread_free(void)
85 {
86         uint32_t i;
87
88         for (i = 0; i < RTE_MAX_LCORE; i++) {
89                 struct thread *t = &thread[i];
90
91                 if (!rte_lcore_is_enabled(i))
92                         continue;
93
94                 /* MSGQs */
95                 if (t->msgq_req)
96                         rte_ring_free(t->msgq_req);
97
98                 if (t->msgq_rsp)
99                         rte_ring_free(t->msgq_rsp);
100         }
101 }
102
103 int
104 thread_init(void)
105 {
106         uint32_t i;
107
108         RTE_LCORE_FOREACH_SLAVE(i) {
109                 char name[NAME_MAX];
110                 struct rte_ring *msgq_req, *msgq_rsp;
111                 struct thread *t = &thread[i];
112                 struct thread_data *t_data = &thread_data[i];
113                 uint32_t cpu_id = rte_lcore_to_socket_id(i);
114
115                 /* MSGQs */
116                 snprintf(name, sizeof(name), "THREAD-%04x-MSGQ-REQ", i);
117
118                 msgq_req = rte_ring_create(name,
119                         THREAD_MSGQ_SIZE,
120                         cpu_id,
121                         RING_F_SP_ENQ | RING_F_SC_DEQ);
122
123                 if (msgq_req == NULL) {
124                         thread_free();
125                         return -1;
126                 }
127
128                 snprintf(name, sizeof(name), "THREAD-%04x-MSGQ-RSP", i);
129
130                 msgq_rsp = rte_ring_create(name,
131                         THREAD_MSGQ_SIZE,
132                         cpu_id,
133                         RING_F_SP_ENQ | RING_F_SC_DEQ);
134
135                 if (msgq_rsp == NULL) {
136                         thread_free();
137                         return -1;
138                 }
139
140                 /* Master thread records */
141                 t->msgq_req = msgq_req;
142                 t->msgq_rsp = msgq_rsp;
143                 t->enabled = 1;
144
145                 /* Data plane thread records */
146                 t_data->n_pipelines = 0;
147                 t_data->msgq_req = msgq_req;
148                 t_data->msgq_rsp = msgq_rsp;
149                 t_data->timer_period =
150                         (rte_get_tsc_hz() * THREAD_TIMER_PERIOD_MS) / 1000;
151                 t_data->time_next = rte_get_tsc_cycles() + t_data->timer_period;
152                 t_data->time_next_min = t_data->time_next;
153         }
154
155         return 0;
156 }
157
158 static inline int
159 thread_is_running(uint32_t thread_id)
160 {
161         enum rte_lcore_state_t thread_state;
162
163         thread_state = rte_eal_get_lcore_state(thread_id);
164         return (thread_state == RUNNING) ? 1 : 0;
165 }
166
167 /**
168  * Pipeline is running when:
169  *    (A) Pipeline is mapped to a data plane thread AND
170  *    (B) Its data plane thread is in RUNNING state.
171  */
172 static inline int
173 pipeline_is_running(struct pipeline *p)
174 {
175         if (p->enabled == 0)
176                 return 0;
177
178         return thread_is_running(p->thread_id);
179 }
180
181 /**
182  * Master thread & data plane threads: message passing
183  */
184 enum thread_req_type {
185         THREAD_REQ_PIPELINE_ENABLE = 0,
186         THREAD_REQ_PIPELINE_DISABLE,
187         THREAD_REQ_MAX
188 };
189
190 struct thread_msg_req {
191         enum thread_req_type type;
192
193         union {
194                 struct {
195                         struct rte_pipeline *p;
196                         struct {
197                                 struct rte_table_action *a;
198                         } table[RTE_PIPELINE_TABLE_MAX];
199                         struct rte_ring *msgq_req;
200                         struct rte_ring *msgq_rsp;
201                         uint32_t timer_period_ms;
202                         uint32_t n_tables;
203                 } pipeline_enable;
204
205                 struct {
206                         struct rte_pipeline *p;
207                 } pipeline_disable;
208         };
209 };
210
211 struct thread_msg_rsp {
212         int status;
213 };
214
215 /**
216  * Master thread
217  */
218 static struct thread_msg_req *
219 thread_msg_alloc(void)
220 {
221         size_t size = RTE_MAX(sizeof(struct thread_msg_req),
222                 sizeof(struct thread_msg_rsp));
223
224         return calloc(1, size);
225 }
226
227 static void
228 thread_msg_free(struct thread_msg_rsp *rsp)
229 {
230         free(rsp);
231 }
232
233 static struct thread_msg_rsp *
234 thread_msg_send_recv(uint32_t thread_id,
235         struct thread_msg_req *req)
236 {
237         struct thread *t = &thread[thread_id];
238         struct rte_ring *msgq_req = t->msgq_req;
239         struct rte_ring *msgq_rsp = t->msgq_rsp;
240         struct thread_msg_rsp *rsp;
241         int status;
242
243         /* send */
244         do {
245                 status = rte_ring_sp_enqueue(msgq_req, req);
246         } while (status == -ENOBUFS);
247
248         /* recv */
249         do {
250                 status = rte_ring_sc_dequeue(msgq_rsp, (void **) &rsp);
251         } while (status != 0);
252
253         return rsp;
254 }
255
256 int
257 thread_pipeline_enable(uint32_t thread_id,
258         const char *pipeline_name)
259 {
260         struct pipeline *p = pipeline_find(pipeline_name);
261         struct thread *t;
262         struct thread_msg_req *req;
263         struct thread_msg_rsp *rsp;
264         uint32_t i;
265         int status;
266
267         /* Check input params */
268         if ((thread_id >= RTE_MAX_LCORE) ||
269                 (p == NULL) ||
270                 (p->n_ports_in == 0) ||
271                 (p->n_ports_out == 0) ||
272                 (p->n_tables == 0))
273                 return -1;
274
275         t = &thread[thread_id];
276         if ((t->enabled == 0) ||
277                 p->enabled)
278                 return -1;
279
280         if (!thread_is_running(thread_id)) {
281                 struct thread_data *td = &thread_data[thread_id];
282                 struct pipeline_data *tdp = &td->pipeline_data[td->n_pipelines];
283
284                 if (td->n_pipelines >= THREAD_PIPELINES_MAX)
285                         return -1;
286
287                 /* Data plane thread */
288                 td->p[td->n_pipelines] = p->p;
289
290                 tdp->p = p->p;
291                 for (i = 0; i < p->n_tables; i++)
292                         tdp->table_data[i].a = p->table[i].a;
293
294                 tdp->n_tables = p->n_tables;
295
296                 tdp->msgq_req = p->msgq_req;
297                 tdp->msgq_rsp = p->msgq_rsp;
298                 tdp->timer_period = (rte_get_tsc_hz() * p->timer_period_ms) / 1000;
299                 tdp->time_next = rte_get_tsc_cycles() + tdp->timer_period;
300
301                 td->n_pipelines++;
302
303                 /* Pipeline */
304                 p->thread_id = thread_id;
305                 p->enabled = 1;
306
307                 return 0;
308         }
309
310         /* Allocate request */
311         req = thread_msg_alloc();
312         if (req == NULL)
313                 return -1;
314
315         /* Write request */
316         req->type = THREAD_REQ_PIPELINE_ENABLE;
317         req->pipeline_enable.p = p->p;
318         for (i = 0; i < p->n_tables; i++)
319                 req->pipeline_enable.table[i].a =
320                         p->table[i].a;
321         req->pipeline_enable.msgq_req = p->msgq_req;
322         req->pipeline_enable.msgq_rsp = p->msgq_rsp;
323         req->pipeline_enable.timer_period_ms = p->timer_period_ms;
324         req->pipeline_enable.n_tables = p->n_tables;
325
326         /* Send request and wait for response */
327         rsp = thread_msg_send_recv(thread_id, req);
328         if (rsp == NULL)
329                 return -1;
330
331         /* Read response */
332         status = rsp->status;
333
334         /* Free response */
335         thread_msg_free(rsp);
336
337         /* Request completion */
338         if (status)
339                 return status;
340
341         p->thread_id = thread_id;
342         p->enabled = 1;
343
344         return 0;
345 }
346
347 int
348 thread_pipeline_disable(uint32_t thread_id,
349         const char *pipeline_name)
350 {
351         struct pipeline *p = pipeline_find(pipeline_name);
352         struct thread *t;
353         struct thread_msg_req *req;
354         struct thread_msg_rsp *rsp;
355         int status;
356
357         /* Check input params */
358         if ((thread_id >= RTE_MAX_LCORE) ||
359                 (p == NULL))
360                 return -1;
361
362         t = &thread[thread_id];
363         if (t->enabled == 0)
364                 return -1;
365
366         if (p->enabled == 0)
367                 return 0;
368
369         if (p->thread_id != thread_id)
370                 return -1;
371
372         if (!thread_is_running(thread_id)) {
373                 struct thread_data *td = &thread_data[thread_id];
374                 uint32_t i;
375
376                 for (i = 0; i < td->n_pipelines; i++) {
377                         struct pipeline_data *tdp = &td->pipeline_data[i];
378
379                         if (tdp->p != p->p)
380                                 continue;
381
382                         /* Data plane thread */
383                         if (i < td->n_pipelines - 1) {
384                                 struct rte_pipeline *pipeline_last =
385                                         td->p[td->n_pipelines - 1];
386                                 struct pipeline_data *tdp_last =
387                                         &td->pipeline_data[td->n_pipelines - 1];
388
389                                 td->p[i] = pipeline_last;
390                                 memcpy(tdp, tdp_last, sizeof(*tdp));
391                         }
392
393                         td->n_pipelines--;
394
395                         /* Pipeline */
396                         p->enabled = 0;
397
398                         break;
399                 }
400
401                 return 0;
402         }
403
404         /* Allocate request */
405         req = thread_msg_alloc();
406         if (req == NULL)
407                 return -1;
408
409         /* Write request */
410         req->type = THREAD_REQ_PIPELINE_DISABLE;
411         req->pipeline_disable.p = p->p;
412
413         /* Send request and wait for response */
414         rsp = thread_msg_send_recv(thread_id, req);
415         if (rsp == NULL)
416                 return -1;
417
418         /* Read response */
419         status = rsp->status;
420
421         /* Free response */
422         thread_msg_free(rsp);
423
424         /* Request completion */
425         if (status)
426                 return status;
427
428         p->enabled = 0;
429
430         return 0;
431 }
432
433 /**
434  * Data plane threads: message handling
435  */
436 static inline struct thread_msg_req *
437 thread_msg_recv(struct rte_ring *msgq_req)
438 {
439         struct thread_msg_req *req;
440
441         int status = rte_ring_sc_dequeue(msgq_req, (void **) &req);
442
443         if (status != 0)
444                 return NULL;
445
446         return req;
447 }
448
449 static inline void
450 thread_msg_send(struct rte_ring *msgq_rsp,
451         struct thread_msg_rsp *rsp)
452 {
453         int status;
454
455         do {
456                 status = rte_ring_sp_enqueue(msgq_rsp, rsp);
457         } while (status == -ENOBUFS);
458 }
459
460 static struct thread_msg_rsp *
461 thread_msg_handle_pipeline_enable(struct thread_data *t,
462         struct thread_msg_req *req)
463 {
464         struct thread_msg_rsp *rsp = (struct thread_msg_rsp *) req;
465         struct pipeline_data *p = &t->pipeline_data[t->n_pipelines];
466         uint32_t i;
467
468         /* Request */
469         if (t->n_pipelines >= THREAD_PIPELINES_MAX) {
470                 rsp->status = -1;
471                 return rsp;
472         }
473
474         t->p[t->n_pipelines] = req->pipeline_enable.p;
475
476         p->p = req->pipeline_enable.p;
477         for (i = 0; i < req->pipeline_enable.n_tables; i++)
478                 p->table_data[i].a =
479                         req->pipeline_enable.table[i].a;
480
481         p->n_tables = req->pipeline_enable.n_tables;
482
483         p->msgq_req = req->pipeline_enable.msgq_req;
484         p->msgq_rsp = req->pipeline_enable.msgq_rsp;
485         p->timer_period =
486                 (rte_get_tsc_hz() * req->pipeline_enable.timer_period_ms) / 1000;
487         p->time_next = rte_get_tsc_cycles() + p->timer_period;
488
489         t->n_pipelines++;
490
491         /* Response */
492         rsp->status = 0;
493         return rsp;
494 }
495
496 static struct thread_msg_rsp *
497 thread_msg_handle_pipeline_disable(struct thread_data *t,
498         struct thread_msg_req *req)
499 {
500         struct thread_msg_rsp *rsp = (struct thread_msg_rsp *) req;
501         uint32_t n_pipelines = t->n_pipelines;
502         struct rte_pipeline *pipeline = req->pipeline_disable.p;
503         uint32_t i;
504
505         /* find pipeline */
506         for (i = 0; i < n_pipelines; i++) {
507                 struct pipeline_data *p = &t->pipeline_data[i];
508
509                 if (p->p != pipeline)
510                         continue;
511
512                 if (i < n_pipelines - 1) {
513                         struct rte_pipeline *pipeline_last =
514                                 t->p[n_pipelines - 1];
515                         struct pipeline_data *p_last =
516                                 &t->pipeline_data[n_pipelines - 1];
517
518                         t->p[i] = pipeline_last;
519                         memcpy(p, p_last, sizeof(*p));
520                 }
521
522                 t->n_pipelines--;
523
524                 rsp->status = 0;
525                 return rsp;
526         }
527
528         /* should not get here */
529         rsp->status = 0;
530         return rsp;
531 }
532
533 static void
534 thread_msg_handle(struct thread_data *t)
535 {
536         for ( ; ; ) {
537                 struct thread_msg_req *req;
538                 struct thread_msg_rsp *rsp;
539
540                 req = thread_msg_recv(t->msgq_req);
541                 if (req == NULL)
542                         break;
543
544                 switch (req->type) {
545                 case THREAD_REQ_PIPELINE_ENABLE:
546                         rsp = thread_msg_handle_pipeline_enable(t, req);
547                         break;
548
549                 case THREAD_REQ_PIPELINE_DISABLE:
550                         rsp = thread_msg_handle_pipeline_disable(t, req);
551                         break;
552
553                 default:
554                         rsp = (struct thread_msg_rsp *) req;
555                         rsp->status = -1;
556                 }
557
558                 thread_msg_send(t->msgq_rsp, rsp);
559         }
560 }
561
562 /**
563  * Master thread & data plane threads: message passing
564  */
565 enum pipeline_req_type {
566         /* Port IN */
567         PIPELINE_REQ_PORT_IN_STATS_READ,
568         PIPELINE_REQ_PORT_IN_ENABLE,
569         PIPELINE_REQ_PORT_IN_DISABLE,
570
571         /* Port OUT */
572         PIPELINE_REQ_PORT_OUT_STATS_READ,
573
574         /* Table */
575         PIPELINE_REQ_TABLE_STATS_READ,
576         PIPELINE_REQ_TABLE_RULE_ADD,
577         PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT,
578         PIPELINE_REQ_TABLE_RULE_ADD_BULK,
579         PIPELINE_REQ_TABLE_RULE_DELETE,
580         PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT,
581         PIPELINE_REQ_TABLE_RULE_STATS_READ,
582         PIPELINE_REQ_TABLE_MTR_PROFILE_ADD,
583         PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
584         PIPELINE_REQ_TABLE_RULE_MTR_READ,
585         PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE,
586         PIPELINE_REQ_TABLE_RULE_TTL_READ,
587         PIPELINE_REQ_MAX
588 };
589
590 struct pipeline_msg_req_port_in_stats_read {
591         int clear;
592 };
593
594 struct pipeline_msg_req_port_out_stats_read {
595         int clear;
596 };
597
598 struct pipeline_msg_req_table_stats_read {
599         int clear;
600 };
601
602 struct pipeline_msg_req_table_rule_add {
603         struct table_rule_match match;
604         struct table_rule_action action;
605 };
606
607 struct pipeline_msg_req_table_rule_add_default {
608         struct table_rule_action action;
609 };
610
611 struct pipeline_msg_req_table_rule_add_bulk {
612         struct table_rule_list *list;
613         int bulk;
614 };
615
616 struct pipeline_msg_req_table_rule_delete {
617         struct table_rule_match match;
618 };
619
620 struct pipeline_msg_req_table_rule_stats_read {
621         void *data;
622         int clear;
623 };
624
625 struct pipeline_msg_req_table_mtr_profile_add {
626         uint32_t meter_profile_id;
627         struct rte_table_action_meter_profile profile;
628 };
629
630 struct pipeline_msg_req_table_mtr_profile_delete {
631         uint32_t meter_profile_id;
632 };
633
634 struct pipeline_msg_req_table_rule_mtr_read {
635         void *data;
636         uint32_t tc_mask;
637         int clear;
638 };
639
640 struct pipeline_msg_req_table_dscp_table_update {
641         uint64_t dscp_mask;
642         struct rte_table_action_dscp_table dscp_table;
643 };
644
645 struct pipeline_msg_req_table_rule_ttl_read {
646         void *data;
647         int clear;
648 };
649
650 struct pipeline_msg_req {
651         enum pipeline_req_type type;
652         uint32_t id; /* Port IN, port OUT or table ID */
653
654         RTE_STD_C11
655         union {
656                 struct pipeline_msg_req_port_in_stats_read port_in_stats_read;
657                 struct pipeline_msg_req_port_out_stats_read port_out_stats_read;
658                 struct pipeline_msg_req_table_stats_read table_stats_read;
659                 struct pipeline_msg_req_table_rule_add table_rule_add;
660                 struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
661                 struct pipeline_msg_req_table_rule_add_bulk table_rule_add_bulk;
662                 struct pipeline_msg_req_table_rule_delete table_rule_delete;
663                 struct pipeline_msg_req_table_rule_stats_read table_rule_stats_read;
664                 struct pipeline_msg_req_table_mtr_profile_add table_mtr_profile_add;
665                 struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
666                 struct pipeline_msg_req_table_rule_mtr_read table_rule_mtr_read;
667                 struct pipeline_msg_req_table_dscp_table_update table_dscp_table_update;
668                 struct pipeline_msg_req_table_rule_ttl_read table_rule_ttl_read;
669         };
670 };
671
672 struct pipeline_msg_rsp_port_in_stats_read {
673         struct rte_pipeline_port_in_stats stats;
674 };
675
676 struct pipeline_msg_rsp_port_out_stats_read {
677         struct rte_pipeline_port_out_stats stats;
678 };
679
680 struct pipeline_msg_rsp_table_stats_read {
681         struct rte_pipeline_table_stats stats;
682 };
683
684 struct pipeline_msg_rsp_table_rule_add {
685         void *data;
686 };
687
688 struct pipeline_msg_rsp_table_rule_add_default {
689         void *data;
690 };
691
692 struct pipeline_msg_rsp_table_rule_add_bulk {
693         uint32_t n_rules;
694 };
695
696 struct pipeline_msg_rsp_table_rule_stats_read {
697         struct rte_table_action_stats_counters stats;
698 };
699
700 struct pipeline_msg_rsp_table_rule_mtr_read {
701         struct rte_table_action_mtr_counters stats;
702 };
703
704 struct pipeline_msg_rsp_table_rule_ttl_read {
705         struct rte_table_action_ttl_counters stats;
706 };
707
708 struct pipeline_msg_rsp {
709         int status;
710
711         RTE_STD_C11
712         union {
713                 struct pipeline_msg_rsp_port_in_stats_read port_in_stats_read;
714                 struct pipeline_msg_rsp_port_out_stats_read port_out_stats_read;
715                 struct pipeline_msg_rsp_table_stats_read table_stats_read;
716                 struct pipeline_msg_rsp_table_rule_add table_rule_add;
717                 struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
718                 struct pipeline_msg_rsp_table_rule_add_bulk table_rule_add_bulk;
719                 struct pipeline_msg_rsp_table_rule_stats_read table_rule_stats_read;
720                 struct pipeline_msg_rsp_table_rule_mtr_read table_rule_mtr_read;
721                 struct pipeline_msg_rsp_table_rule_ttl_read table_rule_ttl_read;
722         };
723 };
724
725 /**
726  * Master thread
727  */
728 static struct pipeline_msg_req *
729 pipeline_msg_alloc(void)
730 {
731         size_t size = RTE_MAX(sizeof(struct pipeline_msg_req),
732                 sizeof(struct pipeline_msg_rsp));
733
734         return calloc(1, size);
735 }
736
737 static void
738 pipeline_msg_free(struct pipeline_msg_rsp *rsp)
739 {
740         free(rsp);
741 }
742
743 static struct pipeline_msg_rsp *
744 pipeline_msg_send_recv(struct pipeline *p,
745         struct pipeline_msg_req *req)
746 {
747         struct rte_ring *msgq_req = p->msgq_req;
748         struct rte_ring *msgq_rsp = p->msgq_rsp;
749         struct pipeline_msg_rsp *rsp;
750         int status;
751
752         /* send */
753         do {
754                 status = rte_ring_sp_enqueue(msgq_req, req);
755         } while (status == -ENOBUFS);
756
757         /* recv */
758         do {
759                 status = rte_ring_sc_dequeue(msgq_rsp, (void **) &rsp);
760         } while (status != 0);
761
762         return rsp;
763 }
764
765 int
766 pipeline_port_in_stats_read(const char *pipeline_name,
767         uint32_t port_id,
768         struct rte_pipeline_port_in_stats *stats,
769         int clear)
770 {
771         struct pipeline *p;
772         struct pipeline_msg_req *req;
773         struct pipeline_msg_rsp *rsp;
774         int status;
775
776         /* Check input params */
777         if ((pipeline_name == NULL) ||
778                 (stats == NULL))
779                 return -1;
780
781         p = pipeline_find(pipeline_name);
782         if ((p == NULL) ||
783                 (port_id >= p->n_ports_in))
784                 return -1;
785
786         if (!pipeline_is_running(p)) {
787                 status = rte_pipeline_port_in_stats_read(p->p,
788                         port_id,
789                         stats,
790                         clear);
791
792                 return status;
793         }
794
795         /* Allocate request */
796         req = pipeline_msg_alloc();
797         if (req == NULL)
798                 return -1;
799
800         /* Write request */
801         req->type = PIPELINE_REQ_PORT_IN_STATS_READ;
802         req->id = port_id;
803         req->port_in_stats_read.clear = clear;
804
805         /* Send request and wait for response */
806         rsp = pipeline_msg_send_recv(p, req);
807         if (rsp == NULL)
808                 return -1;
809
810         /* Read response */
811         status = rsp->status;
812         if (status)
813                 memcpy(stats, &rsp->port_in_stats_read.stats, sizeof(*stats));
814
815         /* Free response */
816         pipeline_msg_free(rsp);
817
818         return status;
819 }
820
821 int
822 pipeline_port_in_enable(const char *pipeline_name,
823         uint32_t port_id)
824 {
825         struct pipeline *p;
826         struct pipeline_msg_req *req;
827         struct pipeline_msg_rsp *rsp;
828         int status;
829
830         /* Check input params */
831         if (pipeline_name == NULL)
832                 return -1;
833
834         p = pipeline_find(pipeline_name);
835         if ((p == NULL) ||
836                 (port_id >= p->n_ports_in))
837                 return -1;
838
839         if (!pipeline_is_running(p)) {
840                 status = rte_pipeline_port_in_enable(p->p, port_id);
841                 return status;
842         }
843
844         /* Allocate request */
845         req = pipeline_msg_alloc();
846         if (req == NULL)
847                 return -1;
848
849         /* Write request */
850         req->type = PIPELINE_REQ_PORT_IN_ENABLE;
851         req->id = port_id;
852
853         /* Send request and wait for response */
854         rsp = pipeline_msg_send_recv(p, req);
855         if (rsp == NULL)
856                 return -1;
857
858         /* Read response */
859         status = rsp->status;
860
861         /* Free response */
862         pipeline_msg_free(rsp);
863
864         return status;
865 }
866
867 int
868 pipeline_port_in_disable(const char *pipeline_name,
869         uint32_t port_id)
870 {
871         struct pipeline *p;
872         struct pipeline_msg_req *req;
873         struct pipeline_msg_rsp *rsp;
874         int status;
875
876         /* Check input params */
877         if (pipeline_name == NULL)
878                 return -1;
879
880         p = pipeline_find(pipeline_name);
881         if ((p == NULL) ||
882                 (port_id >= p->n_ports_in))
883                 return -1;
884
885         if (!pipeline_is_running(p)) {
886                 status = rte_pipeline_port_in_disable(p->p, port_id);
887                 return status;
888         }
889
890         /* Allocate request */
891         req = pipeline_msg_alloc();
892         if (req == NULL)
893                 return -1;
894
895         /* Write request */
896         req->type = PIPELINE_REQ_PORT_IN_DISABLE;
897         req->id = port_id;
898
899         /* Send request and wait for response */
900         rsp = pipeline_msg_send_recv(p, req);
901         if (rsp == NULL)
902                 return -1;
903
904         /* Read response */
905         status = rsp->status;
906
907         /* Free response */
908         pipeline_msg_free(rsp);
909
910         return status;
911 }
912
913 int
914 pipeline_port_out_stats_read(const char *pipeline_name,
915         uint32_t port_id,
916         struct rte_pipeline_port_out_stats *stats,
917         int clear)
918 {
919         struct pipeline *p;
920         struct pipeline_msg_req *req;
921         struct pipeline_msg_rsp *rsp;
922         int status;
923
924         /* Check input params */
925         if ((pipeline_name == NULL) ||
926                 (stats == NULL))
927                 return -1;
928
929         p = pipeline_find(pipeline_name);
930         if ((p == NULL) ||
931                 (port_id >= p->n_ports_out))
932                 return -1;
933
934         if (!pipeline_is_running(p)) {
935                 status = rte_pipeline_port_out_stats_read(p->p,
936                         port_id,
937                         stats,
938                         clear);
939
940                 return status;
941         }
942
943         /* Allocate request */
944         req = pipeline_msg_alloc();
945         if (req == NULL)
946                 return -1;
947
948         /* Write request */
949         req->type = PIPELINE_REQ_PORT_OUT_STATS_READ;
950         req->id = port_id;
951         req->port_out_stats_read.clear = clear;
952
953         /* Send request and wait for response */
954         rsp = pipeline_msg_send_recv(p, req);
955         if (rsp == NULL)
956                 return -1;
957
958         /* Read response */
959         status = rsp->status;
960         if (status)
961                 memcpy(stats, &rsp->port_out_stats_read.stats, sizeof(*stats));
962
963         /* Free response */
964         pipeline_msg_free(rsp);
965
966         return status;
967 }
968
969 int
970 pipeline_table_stats_read(const char *pipeline_name,
971         uint32_t table_id,
972         struct rte_pipeline_table_stats *stats,
973         int clear)
974 {
975         struct pipeline *p;
976         struct pipeline_msg_req *req;
977         struct pipeline_msg_rsp *rsp;
978         int status;
979
980         /* Check input params */
981         if ((pipeline_name == NULL) ||
982                 (stats == NULL))
983                 return -1;
984
985         p = pipeline_find(pipeline_name);
986         if ((p == NULL) ||
987                 (table_id >= p->n_tables))
988                 return -1;
989
990         if (!pipeline_is_running(p)) {
991                 status = rte_pipeline_table_stats_read(p->p,
992                         table_id,
993                         stats,
994                         clear);
995
996                 return status;
997         }
998
999         /* Allocate request */
1000         req = pipeline_msg_alloc();
1001         if (req == NULL)
1002                 return -1;
1003
1004         /* Write request */
1005         req->type = PIPELINE_REQ_TABLE_STATS_READ;
1006         req->id = table_id;
1007         req->table_stats_read.clear = clear;
1008
1009         /* Send request and wait for response */
1010         rsp = pipeline_msg_send_recv(p, req);
1011         if (rsp == NULL)
1012                 return -1;
1013
1014         /* Read response */
1015         status = rsp->status;
1016         if (status)
1017                 memcpy(stats, &rsp->table_stats_read.stats, sizeof(*stats));
1018
1019         /* Free response */
1020         pipeline_msg_free(rsp);
1021
1022         return status;
1023 }
1024
1025 static int
1026 match_check(struct table_rule_match *match,
1027         struct pipeline *p,
1028         uint32_t table_id)
1029 {
1030         struct table *table;
1031
1032         if ((match == NULL) ||
1033                 (p == NULL) ||
1034                 (table_id >= p->n_tables))
1035                 return -1;
1036
1037         table = &p->table[table_id];
1038         if (match->match_type != table->params.match_type)
1039                 return -1;
1040
1041         switch (match->match_type) {
1042         case TABLE_ACL:
1043         {
1044                 struct table_acl_params *t = &table->params.match.acl;
1045                 struct table_rule_match_acl *r = &match->match.acl;
1046
1047                 if ((r->ip_version && (t->ip_version == 0)) ||
1048                         ((r->ip_version == 0) && t->ip_version))
1049                         return -1;
1050
1051                 if (r->ip_version) {
1052                         if ((r->sa_depth > 32) ||
1053                                 (r->da_depth > 32))
1054                                 return -1;
1055                 } else {
1056                         if ((r->sa_depth > 128) ||
1057                                 (r->da_depth > 128))
1058                                 return -1;
1059                 }
1060                 return 0;
1061         }
1062
1063         case TABLE_ARRAY:
1064                 return 0;
1065
1066         case TABLE_HASH:
1067                 return 0;
1068
1069         case TABLE_LPM:
1070         {
1071                 struct table_lpm_params *t = &table->params.match.lpm;
1072                 struct table_rule_match_lpm *r = &match->match.lpm;
1073
1074                 if ((r->ip_version && (t->key_size != 4)) ||
1075                         ((r->ip_version == 0) && (t->key_size != 16)))
1076                         return -1;
1077
1078                 if (r->ip_version) {
1079                         if (r->depth > 32)
1080                                 return -1;
1081                 } else {
1082                         if (r->depth > 128)
1083                                 return -1;
1084                 }
1085                 return 0;
1086         }
1087
1088         case TABLE_STUB:
1089                 return -1;
1090
1091         default:
1092                 return -1;
1093         }
1094 }
1095
1096 static int
1097 action_check(struct table_rule_action *action,
1098         struct pipeline *p,
1099         uint32_t table_id)
1100 {
1101         struct table_action_profile *ap;
1102
1103         if ((action == NULL) ||
1104                 (p == NULL) ||
1105                 (table_id >= p->n_tables))
1106                 return -1;
1107
1108         ap = p->table[table_id].ap;
1109         if (action->action_mask != ap->params.action_mask)
1110                 return -1;
1111
1112         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
1113                 if ((action->fwd.action == RTE_PIPELINE_ACTION_PORT) &&
1114                         (action->fwd.id >= p->n_ports_out))
1115                         return -1;
1116
1117                 if ((action->fwd.action == RTE_PIPELINE_ACTION_TABLE) &&
1118                         (action->fwd.id >= p->n_tables))
1119                         return -1;
1120         }
1121
1122         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
1123                 uint32_t tc_mask0 = (1 << ap->params.mtr.n_tc) - 1;
1124                 uint32_t tc_mask1 = action->mtr.tc_mask;
1125
1126                 if (tc_mask1 != tc_mask0)
1127                         return -1;
1128         }
1129
1130         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
1131                 uint32_t n_subports_per_port =
1132                         ap->params.tm.n_subports_per_port;
1133                 uint32_t n_pipes_per_subport =
1134                         ap->params.tm.n_pipes_per_subport;
1135                 uint32_t subport_id = action->tm.subport_id;
1136                 uint32_t pipe_id = action->tm.pipe_id;
1137
1138                 if ((subport_id >= n_subports_per_port) ||
1139                         (pipe_id >= n_pipes_per_subport))
1140                         return -1;
1141         }
1142
1143         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
1144                 uint64_t encap_mask = ap->params.encap.encap_mask;
1145                 enum rte_table_action_encap_type type = action->encap.type;
1146
1147                 if ((encap_mask & (1LLU << type)) == 0)
1148                         return -1;
1149         }
1150
1151         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
1152                 int ip_version0 = ap->params.common.ip_version;
1153                 int ip_version1 = action->nat.ip_version;
1154
1155                 if ((ip_version1 && (ip_version0 == 0)) ||
1156                         ((ip_version1 == 0) && ip_version0))
1157                         return -1;
1158         }
1159
1160         return 0;
1161 }
1162
1163 static int
1164 action_default_check(struct table_rule_action *action,
1165         struct pipeline *p,
1166         uint32_t table_id)
1167 {
1168         if ((action == NULL) ||
1169                 (action->action_mask != (1LLU << RTE_TABLE_ACTION_FWD)) ||
1170                 (p == NULL) ||
1171                 (table_id >= p->n_tables))
1172                 return -1;
1173
1174         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
1175                 if ((action->fwd.action == RTE_PIPELINE_ACTION_PORT) &&
1176                         (action->fwd.id >= p->n_ports_out))
1177                         return -1;
1178
1179                 if ((action->fwd.action == RTE_PIPELINE_ACTION_TABLE) &&
1180                         (action->fwd.id >= p->n_tables))
1181                         return -1;
1182         }
1183
1184         return 0;
1185 }
1186
1187 union table_rule_match_low_level {
1188         struct rte_table_acl_rule_add_params acl_add;
1189         struct rte_table_acl_rule_delete_params acl_delete;
1190         struct rte_table_array_key array;
1191         uint8_t hash[TABLE_RULE_MATCH_SIZE_MAX];
1192         struct rte_table_lpm_key lpm_ipv4;
1193         struct rte_table_lpm_ipv6_key lpm_ipv6;
1194 };
1195
1196 static int
1197 match_convert(struct table_rule_match *mh,
1198         union table_rule_match_low_level *ml,
1199         int add);
1200
1201 static int
1202 action_convert(struct rte_table_action *a,
1203         struct table_rule_action *action,
1204         struct rte_pipeline_table_entry *data);
1205
1206 struct table_ll {
1207         struct rte_pipeline *p;
1208         int table_id;
1209         struct rte_table_action *a;
1210         int bulk_supported;
1211 };
1212
1213 static int
1214 table_rule_add_bulk_ll(struct table_ll *table,
1215         struct table_rule_list *list,
1216         uint32_t *n_rules)
1217 {
1218         union table_rule_match_low_level *match_ll = NULL;
1219         uint8_t *action_ll = NULL;
1220         void **match_ll_ptr = NULL;
1221         struct rte_pipeline_table_entry **action_ll_ptr = NULL;
1222         struct rte_pipeline_table_entry **entries_ptr = NULL;
1223         int *found = NULL;
1224         struct table_rule *rule;
1225         uint32_t n, i;
1226         int status = 0;
1227
1228         n = 0;
1229         TAILQ_FOREACH(rule, list, node)
1230                 n++;
1231
1232         /* Memory allocation */
1233         match_ll = calloc(n, sizeof(union table_rule_match_low_level));
1234         action_ll = calloc(n, TABLE_RULE_ACTION_SIZE_MAX);
1235
1236         match_ll_ptr = calloc(n, sizeof(void *));
1237         action_ll_ptr = calloc(n, sizeof(struct rte_pipeline_table_entry *));
1238
1239         entries_ptr = calloc(n, sizeof(struct rte_pipeline_table_entry *));
1240         found = calloc(n, sizeof(int));
1241
1242         if (match_ll == NULL ||
1243                 action_ll == NULL ||
1244                 match_ll_ptr == NULL ||
1245                 action_ll_ptr == NULL ||
1246                 entries_ptr == NULL ||
1247                 found == NULL) {
1248                         status = -ENOMEM;
1249                         goto table_rule_add_bulk_ll_free;
1250         }
1251
1252         /* Init */
1253         for (i = 0; i < n; i++) {
1254                 match_ll_ptr[i] = (void *)&match_ll[i];
1255                 action_ll_ptr[i] = (struct rte_pipeline_table_entry *)
1256                         &action_ll[i * TABLE_RULE_ACTION_SIZE_MAX];
1257         }
1258
1259         /* Rule (match, action) conversion */
1260         i = 0;
1261         TAILQ_FOREACH(rule, list, node) {
1262                 status = match_convert(&rule->match, match_ll_ptr[i], 1);
1263                 if (status)
1264                         goto table_rule_add_bulk_ll_free;
1265
1266                 status = action_convert(table->a, &rule->action, action_ll_ptr[i]);
1267                 if (status)
1268                         goto table_rule_add_bulk_ll_free;
1269
1270                 i++;
1271         }
1272
1273         /* Add rule (match, action) to table */
1274         if (table->bulk_supported) {
1275                 status = rte_pipeline_table_entry_add_bulk(table->p,
1276                         table->table_id,
1277                         match_ll_ptr,
1278                         action_ll_ptr,
1279                         n,
1280                         found,
1281                         entries_ptr);
1282                 if (status)
1283                         goto table_rule_add_bulk_ll_free;
1284         } else
1285                 for (i = 0; i < n; i++) {
1286                         status = rte_pipeline_table_entry_add(table->p,
1287                                 table->table_id,
1288                                 match_ll_ptr[i],
1289                                 action_ll_ptr[i],
1290                                 &found[i],
1291                                 &entries_ptr[i]);
1292                         if (status) {
1293                                 if (i == 0)
1294                                         goto table_rule_add_bulk_ll_free;
1295
1296                                 /* No roll-back. */
1297                                 status = 0;
1298                                 n = i;
1299                                 break;
1300                         }
1301                 }
1302
1303         /* Write back to the rule list. */
1304         i = 0;
1305         TAILQ_FOREACH(rule, list, node) {
1306                 if (i >= n)
1307                         break;
1308
1309                 rule->data = entries_ptr[i];
1310
1311                 i++;
1312         }
1313
1314         *n_rules = n;
1315
1316         /* Free */
1317 table_rule_add_bulk_ll_free:
1318         free(found);
1319         free(entries_ptr);
1320         free(action_ll_ptr);
1321         free(match_ll_ptr);
1322         free(action_ll);
1323         free(match_ll);
1324
1325         return status;
1326 }
1327
1328 int
1329 pipeline_table_rule_add(const char *pipeline_name,
1330         uint32_t table_id,
1331         struct table_rule_match *match,
1332         struct table_rule_action *action)
1333 {
1334         struct pipeline *p;
1335         struct table *table;
1336         struct pipeline_msg_req *req;
1337         struct pipeline_msg_rsp *rsp;
1338         struct table_rule *rule;
1339         int status;
1340
1341         /* Check input params */
1342         if ((pipeline_name == NULL) ||
1343                 (match == NULL) ||
1344                 (action == NULL))
1345                 return -1;
1346
1347         p = pipeline_find(pipeline_name);
1348         if ((p == NULL) ||
1349                 (table_id >= p->n_tables) ||
1350                 match_check(match, p, table_id) ||
1351                 action_check(action, p, table_id))
1352                 return -1;
1353
1354         table = &p->table[table_id];
1355
1356         rule = calloc(1, sizeof(struct table_rule));
1357         if (rule == NULL)
1358                 return -1;
1359
1360         memcpy(&rule->match, match, sizeof(*match));
1361         memcpy(&rule->action, action, sizeof(*action));
1362
1363         if (!pipeline_is_running(p)) {
1364                 union table_rule_match_low_level match_ll;
1365                 struct rte_pipeline_table_entry *data_in, *data_out;
1366                 int key_found;
1367                 uint8_t *buffer;
1368
1369                 buffer = calloc(TABLE_RULE_ACTION_SIZE_MAX, sizeof(uint8_t));
1370                 if (buffer == NULL) {
1371                         free(rule);
1372                         return -1;
1373                 }
1374
1375                 /* Table match-action rule conversion */
1376                 data_in = (struct rte_pipeline_table_entry *)buffer;
1377
1378                 status = match_convert(match, &match_ll, 1);
1379                 if (status) {
1380                         free(buffer);
1381                         free(rule);
1382                         return -1;
1383                 }
1384
1385                 status = action_convert(table->a, action, data_in);
1386                 if (status) {
1387                         free(buffer);
1388                         free(rule);
1389                         return -1;
1390                 }
1391
1392                 /* Add rule (match, action) to table */
1393                 status = rte_pipeline_table_entry_add(p->p,
1394                                 table_id,
1395                                 &match_ll,
1396                                 data_in,
1397                                 &key_found,
1398                                 &data_out);
1399                 if (status) {
1400                         free(buffer);
1401                         free(rule);
1402                         return -1;
1403                 }
1404
1405                 /* Write Response */
1406                 rule->data = data_out;
1407                 table_rule_add(table, rule);
1408
1409                 free(buffer);
1410                 return 0;
1411         }
1412
1413         /* Allocate request */
1414         req = pipeline_msg_alloc();
1415         if (req == NULL) {
1416                 free(rule);
1417                 return -1;
1418         }
1419
1420         /* Write request */
1421         req->type = PIPELINE_REQ_TABLE_RULE_ADD;
1422         req->id = table_id;
1423         memcpy(&req->table_rule_add.match, match, sizeof(*match));
1424         memcpy(&req->table_rule_add.action, action, sizeof(*action));
1425
1426         /* Send request and wait for response */
1427         rsp = pipeline_msg_send_recv(p, req);
1428         if (rsp == NULL) {
1429                 free(rule);
1430                 return -1;
1431         }
1432
1433         /* Read response */
1434         status = rsp->status;
1435         if (status == 0) {
1436                 rule->data = rsp->table_rule_add.data;
1437                 table_rule_add(table, rule);
1438         } else
1439                 free(rule);
1440
1441         /* Free response */
1442         pipeline_msg_free(rsp);
1443
1444         return status;
1445 }
1446
1447 int
1448 pipeline_table_rule_add_default(const char *pipeline_name,
1449         uint32_t table_id,
1450         struct table_rule_action *action,
1451         void **data)
1452 {
1453         struct pipeline *p;
1454         struct pipeline_msg_req *req;
1455         struct pipeline_msg_rsp *rsp;
1456         int status;
1457
1458         /* Check input params */
1459         if ((pipeline_name == NULL) ||
1460                 (action == NULL) ||
1461                 (data == NULL))
1462                 return -1;
1463
1464         p = pipeline_find(pipeline_name);
1465         if ((p == NULL) ||
1466                 (table_id >= p->n_tables) ||
1467                 action_default_check(action, p, table_id))
1468                 return -1;
1469
1470         if (!pipeline_is_running(p)) {
1471                 struct rte_pipeline_table_entry *data_in, *data_out;
1472                 uint8_t *buffer;
1473
1474                 buffer = calloc(TABLE_RULE_ACTION_SIZE_MAX, sizeof(uint8_t));
1475                 if (buffer == NULL)
1476                         return -1;
1477
1478                 /* Apply actions */
1479                 data_in = (struct rte_pipeline_table_entry *)buffer;
1480
1481                 data_in->action = action->fwd.action;
1482                 if (action->fwd.action == RTE_PIPELINE_ACTION_PORT)
1483                         data_in->port_id = action->fwd.id;
1484                 if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE)
1485                         data_in->table_id = action->fwd.id;
1486
1487                 /* Add default rule to table */
1488                 status = rte_pipeline_table_default_entry_add(p->p,
1489                                 table_id,
1490                                 data_in,
1491                                 &data_out);
1492                 if (status) {
1493                         free(buffer);
1494                         return -1;
1495                 }
1496
1497                 /* Write Response */
1498                 *data = data_out;
1499
1500                 free(buffer);
1501                 return 0;
1502         }
1503
1504         /* Allocate request */
1505         req = pipeline_msg_alloc();
1506         if (req == NULL)
1507                 return -1;
1508
1509         /* Write request */
1510         req->type = PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT;
1511         req->id = table_id;
1512         memcpy(&req->table_rule_add_default.action, action, sizeof(*action));
1513
1514         /* Send request and wait for response */
1515         rsp = pipeline_msg_send_recv(p, req);
1516         if (rsp == NULL)
1517                 return -1;
1518
1519         /* Read response */
1520         status = rsp->status;
1521         if (status == 0)
1522                 *data = rsp->table_rule_add_default.data;
1523
1524         /* Free response */
1525         pipeline_msg_free(rsp);
1526
1527         return status;
1528 }
1529
1530 static uint32_t
1531 table_rule_list_free(struct table_rule_list *list)
1532 {
1533         uint32_t n = 0;
1534
1535         if (!list)
1536                 return 0;
1537
1538         for ( ; ; ) {
1539                 struct table_rule *rule;
1540
1541                 rule = TAILQ_FIRST(list);
1542                 if (rule == NULL)
1543                         break;
1544
1545                 TAILQ_REMOVE(list, rule, node);
1546                 free(rule);
1547                 n++;
1548         }
1549
1550         free(list);
1551         return n;
1552 }
1553
1554 int
1555 pipeline_table_rule_add_bulk(const char *pipeline_name,
1556         uint32_t table_id,
1557         struct table_rule_list *list,
1558         uint32_t *n_rules_added,
1559         uint32_t *n_rules_not_added)
1560 {
1561         struct pipeline *p;
1562         struct table *table;
1563         struct pipeline_msg_req *req;
1564         struct pipeline_msg_rsp *rsp;
1565         struct table_rule *rule;
1566         int status = 0;
1567
1568         /* Check input params */
1569         if ((pipeline_name == NULL) ||
1570                 (list == NULL) ||
1571                 TAILQ_EMPTY(list) ||
1572                 (n_rules_added == NULL) ||
1573                 (n_rules_not_added == NULL)) {
1574                 table_rule_list_free(list);
1575                 return -EINVAL;
1576         }
1577
1578         p = pipeline_find(pipeline_name);
1579         if ((p == NULL) ||
1580                 (table_id >= p->n_tables)) {
1581                 table_rule_list_free(list);
1582                 return -EINVAL;
1583         }
1584
1585         table = &p->table[table_id];
1586
1587         TAILQ_FOREACH(rule, list, node)
1588                 if (match_check(&rule->match, p, table_id) ||
1589                         action_check(&rule->action, p, table_id)) {
1590                         table_rule_list_free(list);
1591                         return -EINVAL;
1592                 }
1593
1594         if (!pipeline_is_running(p)) {
1595                 struct table_ll table_ll = {
1596                         .p = p->p,
1597                         .table_id = table_id,
1598                         .a = table->a,
1599                         .bulk_supported = table->params.match_type == TABLE_ACL,
1600                 };
1601
1602                 status = table_rule_add_bulk_ll(&table_ll, list, n_rules_added);
1603                 if (status) {
1604                         table_rule_list_free(list);
1605                         return status;
1606                 }
1607
1608                 table_rule_add_bulk(table, list, *n_rules_added);
1609                 *n_rules_not_added = table_rule_list_free(list);
1610                 return 0;
1611         }
1612
1613         /* Allocate request */
1614         req = pipeline_msg_alloc();
1615         if (req == NULL) {
1616                 table_rule_list_free(list);
1617                 return -ENOMEM;
1618         }
1619
1620         /* Write request */
1621         req->type = PIPELINE_REQ_TABLE_RULE_ADD_BULK;
1622         req->id = table_id;
1623         req->table_rule_add_bulk.list = list;
1624         req->table_rule_add_bulk.bulk = table->params.match_type == TABLE_ACL;
1625
1626         /* Send request and wait for response */
1627         rsp = pipeline_msg_send_recv(p, req);
1628         if (rsp == NULL) {
1629                 table_rule_list_free(list);
1630                 return -ENOMEM;
1631         }
1632
1633         /* Read response */
1634         status = rsp->status;
1635         if (status == 0) {
1636                 *n_rules_added = rsp->table_rule_add_bulk.n_rules;
1637
1638                 table_rule_add_bulk(table, list, *n_rules_added);
1639                 *n_rules_not_added = table_rule_list_free(list);
1640         } else
1641                 table_rule_list_free(list);
1642
1643
1644         /* Free response */
1645         pipeline_msg_free(rsp);
1646
1647         return status;
1648 }
1649
1650 int
1651 pipeline_table_rule_delete(const char *pipeline_name,
1652         uint32_t table_id,
1653         struct table_rule_match *match)
1654 {
1655         struct pipeline *p;
1656         struct pipeline_msg_req *req;
1657         struct pipeline_msg_rsp *rsp;
1658         int status;
1659
1660         /* Check input params */
1661         if ((pipeline_name == NULL) ||
1662                 (match == NULL))
1663                 return -1;
1664
1665         p = pipeline_find(pipeline_name);
1666         if ((p == NULL) ||
1667                 (table_id >= p->n_tables) ||
1668                 match_check(match, p, table_id))
1669                 return -1;
1670
1671         if (!pipeline_is_running(p)) {
1672                 union table_rule_match_low_level match_ll;
1673                 int key_found;
1674
1675                 status = match_convert(match, &match_ll, 0);
1676                 if (status)
1677                         return -1;
1678
1679                 status = rte_pipeline_table_entry_delete(p->p,
1680                                 table_id,
1681                                 &match_ll,
1682                                 &key_found,
1683                                 NULL);
1684
1685                 return status;
1686         }
1687
1688         /* Allocate request */
1689         req = pipeline_msg_alloc();
1690         if (req == NULL)
1691                 return -1;
1692
1693         /* Write request */
1694         req->type = PIPELINE_REQ_TABLE_RULE_DELETE;
1695         req->id = table_id;
1696         memcpy(&req->table_rule_delete.match, match, sizeof(*match));
1697
1698         /* Send request and wait for response */
1699         rsp = pipeline_msg_send_recv(p, req);
1700         if (rsp == NULL)
1701                 return -1;
1702
1703         /* Read response */
1704         status = rsp->status;
1705
1706         /* Free response */
1707         pipeline_msg_free(rsp);
1708
1709         return status;
1710 }
1711
1712 int
1713 pipeline_table_rule_delete_default(const char *pipeline_name,
1714         uint32_t table_id)
1715 {
1716         struct pipeline *p;
1717         struct pipeline_msg_req *req;
1718         struct pipeline_msg_rsp *rsp;
1719         int status;
1720
1721         /* Check input params */
1722         if (pipeline_name == NULL)
1723                 return -1;
1724
1725         p = pipeline_find(pipeline_name);
1726         if ((p == NULL) ||
1727                 (table_id >= p->n_tables))
1728                 return -1;
1729
1730         if (!pipeline_is_running(p)) {
1731                 status = rte_pipeline_table_default_entry_delete(p->p,
1732                         table_id,
1733                         NULL);
1734
1735                 return status;
1736         }
1737
1738         /* Allocate request */
1739         req = pipeline_msg_alloc();
1740         if (req == NULL)
1741                 return -1;
1742
1743         /* Write request */
1744         req->type = PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT;
1745         req->id = table_id;
1746
1747         /* Send request and wait for response */
1748         rsp = pipeline_msg_send_recv(p, req);
1749         if (rsp == NULL)
1750                 return -1;
1751
1752         /* Read response */
1753         status = rsp->status;
1754
1755         /* Free response */
1756         pipeline_msg_free(rsp);
1757
1758         return status;
1759 }
1760
1761 int
1762 pipeline_table_rule_stats_read(const char *pipeline_name,
1763         uint32_t table_id,
1764         void *data,
1765         struct rte_table_action_stats_counters *stats,
1766         int clear)
1767 {
1768         struct pipeline *p;
1769         struct pipeline_msg_req *req;
1770         struct pipeline_msg_rsp *rsp;
1771         int status;
1772
1773         /* Check input params */
1774         if ((pipeline_name == NULL) ||
1775                 (data == NULL) ||
1776                 (stats == NULL))
1777                 return -1;
1778
1779         p = pipeline_find(pipeline_name);
1780         if ((p == NULL) ||
1781                 (table_id >= p->n_tables))
1782                 return -1;
1783
1784         if (!pipeline_is_running(p)) {
1785                 struct rte_table_action *a = p->table[table_id].a;
1786
1787                 status = rte_table_action_stats_read(a,
1788                         data,
1789                         stats,
1790                         clear);
1791
1792                 return status;
1793         }
1794
1795         /* Allocate request */
1796         req = pipeline_msg_alloc();
1797         if (req == NULL)
1798                 return -1;
1799
1800         /* Write request */
1801         req->type = PIPELINE_REQ_TABLE_RULE_STATS_READ;
1802         req->id = table_id;
1803         req->table_rule_stats_read.data = data;
1804         req->table_rule_stats_read.clear = clear;
1805
1806         /* Send request and wait for response */
1807         rsp = pipeline_msg_send_recv(p, req);
1808         if (rsp == NULL)
1809                 return -1;
1810
1811         /* Read response */
1812         status = rsp->status;
1813         if (status)
1814                 memcpy(stats, &rsp->table_rule_stats_read.stats, sizeof(*stats));
1815
1816         /* Free response */
1817         pipeline_msg_free(rsp);
1818
1819         return status;
1820 }
1821
1822 int
1823 pipeline_table_mtr_profile_add(const char *pipeline_name,
1824         uint32_t table_id,
1825         uint32_t meter_profile_id,
1826         struct rte_table_action_meter_profile *profile)
1827 {
1828         struct pipeline *p;
1829         struct pipeline_msg_req *req;
1830         struct pipeline_msg_rsp *rsp;
1831         int status;
1832
1833         /* Check input params */
1834         if ((pipeline_name == NULL) ||
1835                 (profile == NULL))
1836                 return -1;
1837
1838         p = pipeline_find(pipeline_name);
1839         if ((p == NULL) ||
1840                 (table_id >= p->n_tables))
1841                 return -1;
1842
1843         if (!pipeline_is_running(p)) {
1844                 struct rte_table_action *a = p->table[table_id].a;
1845
1846                 status = rte_table_action_meter_profile_add(a,
1847                         meter_profile_id,
1848                         profile);
1849
1850                 return status;
1851         }
1852
1853         /* Allocate request */
1854         req = pipeline_msg_alloc();
1855         if (req == NULL)
1856                 return -1;
1857
1858         /* Write request */
1859         req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_ADD;
1860         req->id = table_id;
1861         req->table_mtr_profile_add.meter_profile_id = meter_profile_id;
1862         memcpy(&req->table_mtr_profile_add.profile, profile, sizeof(*profile));
1863
1864         /* Send request and wait for response */
1865         rsp = pipeline_msg_send_recv(p, req);
1866         if (rsp == NULL)
1867                 return -1;
1868
1869         /* Read response */
1870         status = rsp->status;
1871
1872         /* Free response */
1873         pipeline_msg_free(rsp);
1874
1875         return status;
1876 }
1877
1878 int
1879 pipeline_table_mtr_profile_delete(const char *pipeline_name,
1880         uint32_t table_id,
1881         uint32_t meter_profile_id)
1882 {
1883         struct pipeline *p;
1884         struct pipeline_msg_req *req;
1885         struct pipeline_msg_rsp *rsp;
1886         int status;
1887
1888         /* Check input params */
1889         if (pipeline_name == NULL)
1890                 return -1;
1891
1892         p = pipeline_find(pipeline_name);
1893         if ((p == NULL) ||
1894                 (table_id >= p->n_tables))
1895                 return -1;
1896
1897         if (!pipeline_is_running(p)) {
1898                 struct rte_table_action *a = p->table[table_id].a;
1899
1900                 status = rte_table_action_meter_profile_delete(a,
1901                                 meter_profile_id);
1902
1903                 return status;
1904         }
1905
1906         /* Allocate request */
1907         req = pipeline_msg_alloc();
1908         if (req == NULL)
1909                 return -1;
1910
1911         /* Write request */
1912         req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE;
1913         req->id = table_id;
1914         req->table_mtr_profile_delete.meter_profile_id = meter_profile_id;
1915
1916         /* Send request and wait for response */
1917         rsp = pipeline_msg_send_recv(p, req);
1918         if (rsp == NULL)
1919                 return -1;
1920
1921         /* Read response */
1922         status = rsp->status;
1923
1924         /* Free response */
1925         pipeline_msg_free(rsp);
1926
1927         return status;
1928 }
1929
1930 int
1931 pipeline_table_rule_mtr_read(const char *pipeline_name,
1932         uint32_t table_id,
1933         void *data,
1934         uint32_t tc_mask,
1935         struct rte_table_action_mtr_counters *stats,
1936         int clear)
1937 {
1938         struct pipeline *p;
1939         struct pipeline_msg_req *req;
1940         struct pipeline_msg_rsp *rsp;
1941         int status;
1942
1943         /* Check input params */
1944         if ((pipeline_name == NULL) ||
1945                 (data == NULL) ||
1946                 (stats == NULL))
1947                 return -1;
1948
1949         p = pipeline_find(pipeline_name);
1950         if ((p == NULL) ||
1951                 (table_id >= p->n_tables))
1952                 return -1;
1953
1954         if (!pipeline_is_running(p)) {
1955                 struct rte_table_action *a = p->table[table_id].a;
1956
1957                 status = rte_table_action_meter_read(a,
1958                                 data,
1959                                 tc_mask,
1960                                 stats,
1961                                 clear);
1962
1963                 return status;
1964         }
1965
1966         /* Allocate request */
1967         req = pipeline_msg_alloc();
1968         if (req == NULL)
1969                 return -1;
1970
1971         /* Write request */
1972         req->type = PIPELINE_REQ_TABLE_RULE_MTR_READ;
1973         req->id = table_id;
1974         req->table_rule_mtr_read.data = data;
1975         req->table_rule_mtr_read.tc_mask = tc_mask;
1976         req->table_rule_mtr_read.clear = clear;
1977
1978         /* Send request and wait for response */
1979         rsp = pipeline_msg_send_recv(p, req);
1980         if (rsp == NULL)
1981                 return -1;
1982
1983         /* Read response */
1984         status = rsp->status;
1985         if (status)
1986                 memcpy(stats, &rsp->table_rule_mtr_read.stats, sizeof(*stats));
1987
1988         /* Free response */
1989         pipeline_msg_free(rsp);
1990
1991         return status;
1992 }
1993
1994 int
1995 pipeline_table_dscp_table_update(const char *pipeline_name,
1996         uint32_t table_id,
1997         uint64_t dscp_mask,
1998         struct rte_table_action_dscp_table *dscp_table)
1999 {
2000         struct pipeline *p;
2001         struct pipeline_msg_req *req;
2002         struct pipeline_msg_rsp *rsp;
2003         int status;
2004
2005         /* Check input params */
2006         if ((pipeline_name == NULL) ||
2007                 (dscp_table == NULL))
2008                 return -1;
2009
2010         p = pipeline_find(pipeline_name);
2011         if ((p == NULL) ||
2012                 (table_id >= p->n_tables))
2013                 return -1;
2014
2015         if (!pipeline_is_running(p)) {
2016                 struct rte_table_action *a = p->table[table_id].a;
2017
2018                 status = rte_table_action_dscp_table_update(a,
2019                                 dscp_mask,
2020                                 dscp_table);
2021
2022                 return status;
2023         }
2024
2025         /* Allocate request */
2026         req = pipeline_msg_alloc();
2027         if (req == NULL)
2028                 return -1;
2029
2030         /* Write request */
2031         req->type = PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE;
2032         req->id = table_id;
2033         req->table_dscp_table_update.dscp_mask = dscp_mask;
2034         memcpy(&req->table_dscp_table_update.dscp_table,
2035                 dscp_table, sizeof(*dscp_table));
2036
2037         /* Send request and wait for response */
2038         rsp = pipeline_msg_send_recv(p, req);
2039         if (rsp == NULL)
2040                 return -1;
2041
2042         /* Read response */
2043         status = rsp->status;
2044
2045         /* Free response */
2046         pipeline_msg_free(rsp);
2047
2048         return status;
2049 }
2050
2051 int
2052 pipeline_table_rule_ttl_read(const char *pipeline_name,
2053         uint32_t table_id,
2054         void *data,
2055         struct rte_table_action_ttl_counters *stats,
2056         int clear)
2057 {
2058         struct pipeline *p;
2059         struct pipeline_msg_req *req;
2060         struct pipeline_msg_rsp *rsp;
2061         int status;
2062
2063         /* Check input params */
2064         if ((pipeline_name == NULL) ||
2065                 (data == NULL) ||
2066                 (stats == NULL))
2067                 return -1;
2068
2069         p = pipeline_find(pipeline_name);
2070         if ((p == NULL) ||
2071                 (table_id >= p->n_tables))
2072                 return -1;
2073
2074         if (!pipeline_is_running(p)) {
2075                 struct rte_table_action *a = p->table[table_id].a;
2076
2077                 status = rte_table_action_ttl_read(a,
2078                                 data,
2079                                 stats,
2080                                 clear);
2081
2082                 return status;
2083         }
2084
2085         /* Allocate request */
2086         req = pipeline_msg_alloc();
2087         if (req == NULL)
2088                 return -1;
2089
2090         /* Write request */
2091         req->type = PIPELINE_REQ_TABLE_RULE_TTL_READ;
2092         req->id = table_id;
2093         req->table_rule_ttl_read.data = data;
2094         req->table_rule_ttl_read.clear = clear;
2095
2096         /* Send request and wait for response */
2097         rsp = pipeline_msg_send_recv(p, req);
2098         if (rsp == NULL)
2099                 return -1;
2100
2101         /* Read response */
2102         status = rsp->status;
2103         if (status)
2104                 memcpy(stats, &rsp->table_rule_ttl_read.stats, sizeof(*stats));
2105
2106         /* Free response */
2107         pipeline_msg_free(rsp);
2108
2109         return status;
2110 }
2111
2112 /**
2113  * Data plane threads: message handling
2114  */
2115 static inline struct pipeline_msg_req *
2116 pipeline_msg_recv(struct rte_ring *msgq_req)
2117 {
2118         struct pipeline_msg_req *req;
2119
2120         int status = rte_ring_sc_dequeue(msgq_req, (void **) &req);
2121
2122         if (status != 0)
2123                 return NULL;
2124
2125         return req;
2126 }
2127
2128 static inline void
2129 pipeline_msg_send(struct rte_ring *msgq_rsp,
2130         struct pipeline_msg_rsp *rsp)
2131 {
2132         int status;
2133
2134         do {
2135                 status = rte_ring_sp_enqueue(msgq_rsp, rsp);
2136         } while (status == -ENOBUFS);
2137 }
2138
2139 static struct pipeline_msg_rsp *
2140 pipeline_msg_handle_port_in_stats_read(struct pipeline_data *p,
2141         struct pipeline_msg_req *req)
2142 {
2143         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2144         uint32_t port_id = req->id;
2145         int clear = req->port_in_stats_read.clear;
2146
2147         rsp->status = rte_pipeline_port_in_stats_read(p->p,
2148                 port_id,
2149                 &rsp->port_in_stats_read.stats,
2150                 clear);
2151
2152         return rsp;
2153 }
2154
2155 static struct pipeline_msg_rsp *
2156 pipeline_msg_handle_port_in_enable(struct pipeline_data *p,
2157         struct pipeline_msg_req *req)
2158 {
2159         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2160         uint32_t port_id = req->id;
2161
2162         rsp->status = rte_pipeline_port_in_enable(p->p,
2163                 port_id);
2164
2165         return rsp;
2166 }
2167
2168 static struct pipeline_msg_rsp *
2169 pipeline_msg_handle_port_in_disable(struct pipeline_data *p,
2170         struct pipeline_msg_req *req)
2171 {
2172         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2173         uint32_t port_id = req->id;
2174
2175         rsp->status = rte_pipeline_port_in_disable(p->p,
2176                 port_id);
2177
2178         return rsp;
2179 }
2180
2181 static struct pipeline_msg_rsp *
2182 pipeline_msg_handle_port_out_stats_read(struct pipeline_data *p,
2183         struct pipeline_msg_req *req)
2184 {
2185         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2186         uint32_t port_id = req->id;
2187         int clear = req->port_out_stats_read.clear;
2188
2189         rsp->status = rte_pipeline_port_out_stats_read(p->p,
2190                 port_id,
2191                 &rsp->port_out_stats_read.stats,
2192                 clear);
2193
2194         return rsp;
2195 }
2196
2197 static struct pipeline_msg_rsp *
2198 pipeline_msg_handle_table_stats_read(struct pipeline_data *p,
2199         struct pipeline_msg_req *req)
2200 {
2201         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2202         uint32_t port_id = req->id;
2203         int clear = req->table_stats_read.clear;
2204
2205         rsp->status = rte_pipeline_table_stats_read(p->p,
2206                 port_id,
2207                 &rsp->table_stats_read.stats,
2208                 clear);
2209
2210         return rsp;
2211 }
2212
2213 static int
2214 match_convert_ipv6_depth(uint32_t depth, uint32_t *depth32)
2215 {
2216         if (depth > 128)
2217                 return -1;
2218
2219         switch (depth / 32) {
2220         case 0:
2221                 depth32[0] = depth;
2222                 depth32[1] = 0;
2223                 depth32[2] = 0;
2224                 depth32[3] = 0;
2225                 return 0;
2226
2227         case 1:
2228                 depth32[0] = 32;
2229                 depth32[1] = depth - 32;
2230                 depth32[2] = 0;
2231                 depth32[3] = 0;
2232                 return 0;
2233
2234         case 2:
2235                 depth32[0] = 32;
2236                 depth32[1] = 32;
2237                 depth32[2] = depth - 64;
2238                 depth32[3] = 0;
2239                 return 0;
2240
2241         case 3:
2242                 depth32[0] = 32;
2243                 depth32[1] = 32;
2244                 depth32[2] = 32;
2245                 depth32[3] = depth - 96;
2246                 return 0;
2247
2248         case 4:
2249                 depth32[0] = 32;
2250                 depth32[1] = 32;
2251                 depth32[2] = 32;
2252                 depth32[3] = 32;
2253                 return 0;
2254
2255         default:
2256                 return -1;
2257         }
2258 }
2259
2260 static int
2261 match_convert(struct table_rule_match *mh,
2262         union table_rule_match_low_level *ml,
2263         int add)
2264 {
2265         memset(ml, 0, sizeof(*ml));
2266
2267         switch (mh->match_type) {
2268         case TABLE_ACL:
2269                 if (mh->match.acl.ip_version)
2270                         if (add) {
2271                                 ml->acl_add.field_value[0].value.u8 =
2272                                         mh->match.acl.proto;
2273                                 ml->acl_add.field_value[0].mask_range.u8 =
2274                                         mh->match.acl.proto_mask;
2275
2276                                 ml->acl_add.field_value[1].value.u32 =
2277                                         mh->match.acl.ipv4.sa;
2278                                 ml->acl_add.field_value[1].mask_range.u32 =
2279                                         mh->match.acl.sa_depth;
2280
2281                                 ml->acl_add.field_value[2].value.u32 =
2282                                         mh->match.acl.ipv4.da;
2283                                 ml->acl_add.field_value[2].mask_range.u32 =
2284                                         mh->match.acl.da_depth;
2285
2286                                 ml->acl_add.field_value[3].value.u16 =
2287                                         mh->match.acl.sp0;
2288                                 ml->acl_add.field_value[3].mask_range.u16 =
2289                                         mh->match.acl.sp1;
2290
2291                                 ml->acl_add.field_value[4].value.u16 =
2292                                         mh->match.acl.dp0;
2293                                 ml->acl_add.field_value[4].mask_range.u16 =
2294                                         mh->match.acl.dp1;
2295
2296                                 ml->acl_add.priority =
2297                                         (int32_t) mh->match.acl.priority;
2298                         } else {
2299                                 ml->acl_delete.field_value[0].value.u8 =
2300                                         mh->match.acl.proto;
2301                                 ml->acl_delete.field_value[0].mask_range.u8 =
2302                                         mh->match.acl.proto_mask;
2303
2304                                 ml->acl_delete.field_value[1].value.u32 =
2305                                         mh->match.acl.ipv4.sa;
2306                                 ml->acl_delete.field_value[1].mask_range.u32 =
2307                                         mh->match.acl.sa_depth;
2308
2309                                 ml->acl_delete.field_value[2].value.u32 =
2310                                         mh->match.acl.ipv4.da;
2311                                 ml->acl_delete.field_value[2].mask_range.u32 =
2312                                         mh->match.acl.da_depth;
2313
2314                                 ml->acl_delete.field_value[3].value.u16 =
2315                                         mh->match.acl.sp0;
2316                                 ml->acl_delete.field_value[3].mask_range.u16 =
2317                                         mh->match.acl.sp1;
2318
2319                                 ml->acl_delete.field_value[4].value.u16 =
2320                                         mh->match.acl.dp0;
2321                                 ml->acl_delete.field_value[4].mask_range.u16 =
2322                                         mh->match.acl.dp1;
2323                         }
2324                 else
2325                         if (add) {
2326                                 uint32_t *sa32 =
2327                                         (uint32_t *) mh->match.acl.ipv6.sa;
2328                                 uint32_t *da32 =
2329                                         (uint32_t *) mh->match.acl.ipv6.da;
2330                                 uint32_t sa32_depth[4], da32_depth[4];
2331                                 int status;
2332
2333                                 status = match_convert_ipv6_depth(
2334                                         mh->match.acl.sa_depth,
2335                                         sa32_depth);
2336                                 if (status)
2337                                         return status;
2338
2339                                 status = match_convert_ipv6_depth(
2340                                         mh->match.acl.da_depth,
2341                                         da32_depth);
2342                                 if (status)
2343                                         return status;
2344
2345                                 ml->acl_add.field_value[0].value.u8 =
2346                                         mh->match.acl.proto;
2347                                 ml->acl_add.field_value[0].mask_range.u8 =
2348                                         mh->match.acl.proto_mask;
2349
2350                                 ml->acl_add.field_value[1].value.u32 =
2351                                         rte_be_to_cpu_32(sa32[0]);
2352                                 ml->acl_add.field_value[1].mask_range.u32 =
2353                                         sa32_depth[0];
2354                                 ml->acl_add.field_value[2].value.u32 =
2355                                         rte_be_to_cpu_32(sa32[1]);
2356                                 ml->acl_add.field_value[2].mask_range.u32 =
2357                                         sa32_depth[1];
2358                                 ml->acl_add.field_value[3].value.u32 =
2359                                         rte_be_to_cpu_32(sa32[2]);
2360                                 ml->acl_add.field_value[3].mask_range.u32 =
2361                                         sa32_depth[2];
2362                                 ml->acl_add.field_value[4].value.u32 =
2363                                         rte_be_to_cpu_32(sa32[3]);
2364                                 ml->acl_add.field_value[4].mask_range.u32 =
2365                                         sa32_depth[3];
2366
2367                                 ml->acl_add.field_value[5].value.u32 =
2368                                         rte_be_to_cpu_32(da32[0]);
2369                                 ml->acl_add.field_value[5].mask_range.u32 =
2370                                         da32_depth[0];
2371                                 ml->acl_add.field_value[6].value.u32 =
2372                                         rte_be_to_cpu_32(da32[1]);
2373                                 ml->acl_add.field_value[6].mask_range.u32 =
2374                                         da32_depth[1];
2375                                 ml->acl_add.field_value[7].value.u32 =
2376                                         rte_be_to_cpu_32(da32[2]);
2377                                 ml->acl_add.field_value[7].mask_range.u32 =
2378                                         da32_depth[2];
2379                                 ml->acl_add.field_value[8].value.u32 =
2380                                         rte_be_to_cpu_32(da32[3]);
2381                                 ml->acl_add.field_value[8].mask_range.u32 =
2382                                         da32_depth[3];
2383
2384                                 ml->acl_add.field_value[9].value.u16 =
2385                                         mh->match.acl.sp0;
2386                                 ml->acl_add.field_value[9].mask_range.u16 =
2387                                         mh->match.acl.sp1;
2388
2389                                 ml->acl_add.field_value[10].value.u16 =
2390                                         mh->match.acl.dp0;
2391                                 ml->acl_add.field_value[10].mask_range.u16 =
2392                                         mh->match.acl.dp1;
2393
2394                                 ml->acl_add.priority =
2395                                         (int32_t) mh->match.acl.priority;
2396                         } else {
2397                                 uint32_t *sa32 =
2398                                         (uint32_t *) mh->match.acl.ipv6.sa;
2399                                 uint32_t *da32 =
2400                                         (uint32_t *) mh->match.acl.ipv6.da;
2401                                 uint32_t sa32_depth[4], da32_depth[4];
2402                                 int status;
2403
2404                                 status = match_convert_ipv6_depth(
2405                                         mh->match.acl.sa_depth,
2406                                         sa32_depth);
2407                                 if (status)
2408                                         return status;
2409
2410                                 status = match_convert_ipv6_depth(
2411                                         mh->match.acl.da_depth,
2412                                         da32_depth);
2413                                 if (status)
2414                                         return status;
2415
2416                                 ml->acl_delete.field_value[0].value.u8 =
2417                                         mh->match.acl.proto;
2418                                 ml->acl_delete.field_value[0].mask_range.u8 =
2419                                         mh->match.acl.proto_mask;
2420
2421                                 ml->acl_delete.field_value[1].value.u32 =
2422                                         rte_be_to_cpu_32(sa32[0]);
2423                                 ml->acl_delete.field_value[1].mask_range.u32 =
2424                                         sa32_depth[0];
2425                                 ml->acl_delete.field_value[2].value.u32 =
2426                                         rte_be_to_cpu_32(sa32[1]);
2427                                 ml->acl_delete.field_value[2].mask_range.u32 =
2428                                         sa32_depth[1];
2429                                 ml->acl_delete.field_value[3].value.u32 =
2430                                         rte_be_to_cpu_32(sa32[2]);
2431                                 ml->acl_delete.field_value[3].mask_range.u32 =
2432                                         sa32_depth[2];
2433                                 ml->acl_delete.field_value[4].value.u32 =
2434                                         rte_be_to_cpu_32(sa32[3]);
2435                                 ml->acl_delete.field_value[4].mask_range.u32 =
2436                                         sa32_depth[3];
2437
2438                                 ml->acl_delete.field_value[5].value.u32 =
2439                                         rte_be_to_cpu_32(da32[0]);
2440                                 ml->acl_delete.field_value[5].mask_range.u32 =
2441                                         da32_depth[0];
2442                                 ml->acl_delete.field_value[6].value.u32 =
2443                                         rte_be_to_cpu_32(da32[1]);
2444                                 ml->acl_delete.field_value[6].mask_range.u32 =
2445                                         da32_depth[1];
2446                                 ml->acl_delete.field_value[7].value.u32 =
2447                                         rte_be_to_cpu_32(da32[2]);
2448                                 ml->acl_delete.field_value[7].mask_range.u32 =
2449                                         da32_depth[2];
2450                                 ml->acl_delete.field_value[8].value.u32 =
2451                                         rte_be_to_cpu_32(da32[3]);
2452                                 ml->acl_delete.field_value[8].mask_range.u32 =
2453                                         da32_depth[3];
2454
2455                                 ml->acl_delete.field_value[9].value.u16 =
2456                                         mh->match.acl.sp0;
2457                                 ml->acl_delete.field_value[9].mask_range.u16 =
2458                                         mh->match.acl.sp1;
2459
2460                                 ml->acl_delete.field_value[10].value.u16 =
2461                                         mh->match.acl.dp0;
2462                                 ml->acl_delete.field_value[10].mask_range.u16 =
2463                                         mh->match.acl.dp1;
2464                         }
2465                 return 0;
2466
2467         case TABLE_ARRAY:
2468                 ml->array.pos = mh->match.array.pos;
2469                 return 0;
2470
2471         case TABLE_HASH:
2472                 memcpy(ml->hash, mh->match.hash.key, sizeof(ml->hash));
2473                 return 0;
2474
2475         case TABLE_LPM:
2476                 if (mh->match.lpm.ip_version) {
2477                         ml->lpm_ipv4.ip = mh->match.lpm.ipv4;
2478                         ml->lpm_ipv4.depth = mh->match.lpm.depth;
2479                 } else {
2480                         memcpy(ml->lpm_ipv6.ip,
2481                                 mh->match.lpm.ipv6, sizeof(ml->lpm_ipv6.ip));
2482                         ml->lpm_ipv6.depth = mh->match.lpm.depth;
2483                 }
2484
2485                 return 0;
2486
2487         default:
2488                 return -1;
2489         }
2490 }
2491
2492 static int
2493 action_convert(struct rte_table_action *a,
2494         struct table_rule_action *action,
2495         struct rte_pipeline_table_entry *data)
2496 {
2497         int status;
2498
2499         /* Apply actions */
2500         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
2501                 status = rte_table_action_apply(a,
2502                         data,
2503                         RTE_TABLE_ACTION_FWD,
2504                         &action->fwd);
2505
2506                 if (status)
2507                         return status;
2508         }
2509
2510         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
2511                 status = rte_table_action_apply(a,
2512                         data,
2513                         RTE_TABLE_ACTION_LB,
2514                         &action->lb);
2515
2516                 if (status)
2517                         return status;
2518         }
2519
2520         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
2521                 status = rte_table_action_apply(a,
2522                         data,
2523                         RTE_TABLE_ACTION_MTR,
2524                         &action->mtr);
2525
2526                 if (status)
2527                         return status;
2528         }
2529
2530         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
2531                 status = rte_table_action_apply(a,
2532                         data,
2533                         RTE_TABLE_ACTION_TM,
2534                         &action->tm);
2535
2536                 if (status)
2537                         return status;
2538         }
2539
2540         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
2541                 status = rte_table_action_apply(a,
2542                         data,
2543                         RTE_TABLE_ACTION_ENCAP,
2544                         &action->encap);
2545
2546                 if (status)
2547                         return status;
2548         }
2549
2550         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
2551                 status = rte_table_action_apply(a,
2552                         data,
2553                         RTE_TABLE_ACTION_NAT,
2554                         &action->nat);
2555
2556                 if (status)
2557                         return status;
2558         }
2559
2560         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
2561                 status = rte_table_action_apply(a,
2562                         data,
2563                         RTE_TABLE_ACTION_TTL,
2564                         &action->ttl);
2565
2566                 if (status)
2567                         return status;
2568         }
2569
2570         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
2571                 status = rte_table_action_apply(a,
2572                         data,
2573                         RTE_TABLE_ACTION_STATS,
2574                         &action->stats);
2575
2576                 if (status)
2577                         return status;
2578         }
2579
2580         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
2581                 status = rte_table_action_apply(a,
2582                         data,
2583                         RTE_TABLE_ACTION_TIME,
2584                         &action->time);
2585
2586                 if (status)
2587                         return status;
2588         }
2589
2590         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_SYM_CRYPTO)) {
2591                 status = rte_table_action_apply(a,
2592                         data,
2593                         RTE_TABLE_ACTION_SYM_CRYPTO,
2594                         &action->sym_crypto);
2595
2596                 if (status)
2597                         return status;
2598         }
2599
2600         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TAG)) {
2601                 status = rte_table_action_apply(a,
2602                         data,
2603                         RTE_TABLE_ACTION_TAG,
2604                         &action->tag);
2605
2606                 if (status)
2607                         return status;
2608         }
2609
2610         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_DECAP)) {
2611                 status = rte_table_action_apply(a,
2612                         data,
2613                         RTE_TABLE_ACTION_DECAP,
2614                         &action->decap);
2615
2616                 if (status)
2617                         return status;
2618         }
2619
2620         return 0;
2621 }
2622
2623 static struct pipeline_msg_rsp *
2624 pipeline_msg_handle_table_rule_add(struct pipeline_data *p,
2625         struct pipeline_msg_req *req)
2626 {
2627         union table_rule_match_low_level match_ll;
2628         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2629         struct table_rule_match *match = &req->table_rule_add.match;
2630         struct table_rule_action *action = &req->table_rule_add.action;
2631         struct rte_pipeline_table_entry *data_in, *data_out;
2632         uint32_t table_id = req->id;
2633         int key_found, status;
2634         struct rte_table_action *a = p->table_data[table_id].a;
2635
2636         /* Apply actions */
2637         memset(p->buffer, 0, sizeof(p->buffer));
2638         data_in = (struct rte_pipeline_table_entry *) p->buffer;
2639
2640         status = match_convert(match, &match_ll, 1);
2641         if (status) {
2642                 rsp->status = -1;
2643                 return rsp;
2644         }
2645
2646         status = action_convert(a, action, data_in);
2647         if (status) {
2648                 rsp->status = -1;
2649                 return rsp;
2650         }
2651
2652         status = rte_pipeline_table_entry_add(p->p,
2653                 table_id,
2654                 &match_ll,
2655                 data_in,
2656                 &key_found,
2657                 &data_out);
2658         if (status) {
2659                 rsp->status = -1;
2660                 return rsp;
2661         }
2662
2663         /* Write response */
2664         rsp->status = 0;
2665         rsp->table_rule_add.data = data_out;
2666
2667         return rsp;
2668 }
2669
2670 static struct pipeline_msg_rsp *
2671 pipeline_msg_handle_table_rule_add_default(struct pipeline_data *p,
2672         struct pipeline_msg_req *req)
2673 {
2674         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2675         struct table_rule_action *action = &req->table_rule_add_default.action;
2676         struct rte_pipeline_table_entry *data_in, *data_out;
2677         uint32_t table_id = req->id;
2678         int status;
2679
2680         /* Apply actions */
2681         memset(p->buffer, 0, sizeof(p->buffer));
2682         data_in = (struct rte_pipeline_table_entry *) p->buffer;
2683
2684         data_in->action = action->fwd.action;
2685         if (action->fwd.action == RTE_PIPELINE_ACTION_PORT)
2686                 data_in->port_id = action->fwd.id;
2687         if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE)
2688                 data_in->table_id = action->fwd.id;
2689
2690         /* Add default rule to table */
2691         status = rte_pipeline_table_default_entry_add(p->p,
2692                 table_id,
2693                 data_in,
2694                 &data_out);
2695         if (status) {
2696                 rsp->status = -1;
2697                 return rsp;
2698         }
2699
2700         /* Write response */
2701         rsp->status = 0;
2702         rsp->table_rule_add_default.data = data_out;
2703
2704         return rsp;
2705 }
2706
2707 static struct pipeline_msg_rsp *
2708 pipeline_msg_handle_table_rule_add_bulk(struct pipeline_data *p,
2709         struct pipeline_msg_req *req)
2710 {
2711         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2712
2713         uint32_t table_id = req->id;
2714         struct table_rule_list *list = req->table_rule_add_bulk.list;
2715         uint32_t bulk = req->table_rule_add_bulk.bulk;
2716
2717         uint32_t n_rules_added;
2718         int status;
2719
2720         struct table_ll table_ll = {
2721                 .p = p->p,
2722                 .table_id = table_id,
2723                 .a = p->table_data[table_id].a,
2724                 .bulk_supported = bulk,
2725         };
2726
2727         status = table_rule_add_bulk_ll(&table_ll, list, &n_rules_added);
2728         if (status) {
2729                 rsp->status = -1;
2730                 rsp->table_rule_add_bulk.n_rules = 0;
2731                 return rsp;
2732         }
2733
2734         /* Write response */
2735         rsp->status = 0;
2736         rsp->table_rule_add_bulk.n_rules = n_rules_added;
2737         return rsp;
2738 }
2739
2740 static struct pipeline_msg_rsp *
2741 pipeline_msg_handle_table_rule_delete(struct pipeline_data *p,
2742         struct pipeline_msg_req *req)
2743 {
2744         union table_rule_match_low_level match_ll;
2745         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2746         struct table_rule_match *match = &req->table_rule_delete.match;
2747         uint32_t table_id = req->id;
2748         int key_found, status;
2749
2750         status = match_convert(match, &match_ll, 0);
2751         if (status) {
2752                 rsp->status = -1;
2753                 return rsp;
2754         }
2755
2756         rsp->status = rte_pipeline_table_entry_delete(p->p,
2757                 table_id,
2758                 &match_ll,
2759                 &key_found,
2760                 NULL);
2761
2762         return rsp;
2763 }
2764
2765 static struct pipeline_msg_rsp *
2766 pipeline_msg_handle_table_rule_delete_default(struct pipeline_data *p,
2767         struct pipeline_msg_req *req)
2768 {
2769         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2770         uint32_t table_id = req->id;
2771
2772         rsp->status = rte_pipeline_table_default_entry_delete(p->p,
2773                 table_id,
2774                 NULL);
2775
2776         return rsp;
2777 }
2778
2779 static struct pipeline_msg_rsp *
2780 pipeline_msg_handle_table_rule_stats_read(struct pipeline_data *p,
2781         struct pipeline_msg_req *req)
2782 {
2783         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2784         uint32_t table_id = req->id;
2785         void *data = req->table_rule_stats_read.data;
2786         int clear = req->table_rule_stats_read.clear;
2787         struct rte_table_action *a = p->table_data[table_id].a;
2788
2789         rsp->status = rte_table_action_stats_read(a,
2790                 data,
2791                 &rsp->table_rule_stats_read.stats,
2792                 clear);
2793
2794         return rsp;
2795 }
2796
2797 static struct pipeline_msg_rsp *
2798 pipeline_msg_handle_table_mtr_profile_add(struct pipeline_data *p,
2799         struct pipeline_msg_req *req)
2800 {
2801         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2802         uint32_t table_id = req->id;
2803         uint32_t meter_profile_id = req->table_mtr_profile_add.meter_profile_id;
2804         struct rte_table_action_meter_profile *profile =
2805                 &req->table_mtr_profile_add.profile;
2806         struct rte_table_action *a = p->table_data[table_id].a;
2807
2808         rsp->status = rte_table_action_meter_profile_add(a,
2809                 meter_profile_id,
2810                 profile);
2811
2812         return rsp;
2813 }
2814
2815 static struct pipeline_msg_rsp *
2816 pipeline_msg_handle_table_mtr_profile_delete(struct pipeline_data *p,
2817         struct pipeline_msg_req *req)
2818 {
2819         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2820         uint32_t table_id = req->id;
2821         uint32_t meter_profile_id =
2822                 req->table_mtr_profile_delete.meter_profile_id;
2823         struct rte_table_action *a = p->table_data[table_id].a;
2824
2825         rsp->status = rte_table_action_meter_profile_delete(a,
2826                 meter_profile_id);
2827
2828         return rsp;
2829 }
2830
2831 static struct pipeline_msg_rsp *
2832 pipeline_msg_handle_table_rule_mtr_read(struct pipeline_data *p,
2833         struct pipeline_msg_req *req)
2834 {
2835         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2836         uint32_t table_id = req->id;
2837         void *data = req->table_rule_mtr_read.data;
2838         uint32_t tc_mask = req->table_rule_mtr_read.tc_mask;
2839         int clear = req->table_rule_mtr_read.clear;
2840         struct rte_table_action *a = p->table_data[table_id].a;
2841
2842         rsp->status = rte_table_action_meter_read(a,
2843                 data,
2844                 tc_mask,
2845                 &rsp->table_rule_mtr_read.stats,
2846                 clear);
2847
2848         return rsp;
2849 }
2850
2851 static struct pipeline_msg_rsp *
2852 pipeline_msg_handle_table_dscp_table_update(struct pipeline_data *p,
2853         struct pipeline_msg_req *req)
2854 {
2855         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2856         uint32_t table_id = req->id;
2857         uint64_t dscp_mask = req->table_dscp_table_update.dscp_mask;
2858         struct rte_table_action_dscp_table *dscp_table =
2859                 &req->table_dscp_table_update.dscp_table;
2860         struct rte_table_action *a = p->table_data[table_id].a;
2861
2862         rsp->status = rte_table_action_dscp_table_update(a,
2863                 dscp_mask,
2864                 dscp_table);
2865
2866         return rsp;
2867 }
2868
2869 static struct pipeline_msg_rsp *
2870 pipeline_msg_handle_table_rule_ttl_read(struct pipeline_data *p,
2871         struct pipeline_msg_req *req)
2872 {
2873         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2874         uint32_t table_id = req->id;
2875         void *data = req->table_rule_ttl_read.data;
2876         int clear = req->table_rule_ttl_read.clear;
2877         struct rte_table_action *a = p->table_data[table_id].a;
2878
2879         rsp->status = rte_table_action_ttl_read(a,
2880                 data,
2881                 &rsp->table_rule_ttl_read.stats,
2882                 clear);
2883
2884         return rsp;
2885 }
2886
2887 static void
2888 pipeline_msg_handle(struct pipeline_data *p)
2889 {
2890         for ( ; ; ) {
2891                 struct pipeline_msg_req *req;
2892                 struct pipeline_msg_rsp *rsp;
2893
2894                 req = pipeline_msg_recv(p->msgq_req);
2895                 if (req == NULL)
2896                         break;
2897
2898                 switch (req->type) {
2899                 case PIPELINE_REQ_PORT_IN_STATS_READ:
2900                         rsp = pipeline_msg_handle_port_in_stats_read(p, req);
2901                         break;
2902
2903                 case PIPELINE_REQ_PORT_IN_ENABLE:
2904                         rsp = pipeline_msg_handle_port_in_enable(p, req);
2905                         break;
2906
2907                 case PIPELINE_REQ_PORT_IN_DISABLE:
2908                         rsp = pipeline_msg_handle_port_in_disable(p, req);
2909                         break;
2910
2911                 case PIPELINE_REQ_PORT_OUT_STATS_READ:
2912                         rsp = pipeline_msg_handle_port_out_stats_read(p, req);
2913                         break;
2914
2915                 case PIPELINE_REQ_TABLE_STATS_READ:
2916                         rsp = pipeline_msg_handle_table_stats_read(p, req);
2917                         break;
2918
2919                 case PIPELINE_REQ_TABLE_RULE_ADD:
2920                         rsp = pipeline_msg_handle_table_rule_add(p, req);
2921                         break;
2922
2923                 case PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT:
2924                         rsp = pipeline_msg_handle_table_rule_add_default(p,     req);
2925                         break;
2926
2927                 case PIPELINE_REQ_TABLE_RULE_ADD_BULK:
2928                         rsp = pipeline_msg_handle_table_rule_add_bulk(p, req);
2929                         break;
2930
2931                 case PIPELINE_REQ_TABLE_RULE_DELETE:
2932                         rsp = pipeline_msg_handle_table_rule_delete(p, req);
2933                         break;
2934
2935                 case PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT:
2936                         rsp = pipeline_msg_handle_table_rule_delete_default(p, req);
2937                         break;
2938
2939                 case PIPELINE_REQ_TABLE_RULE_STATS_READ:
2940                         rsp = pipeline_msg_handle_table_rule_stats_read(p, req);
2941                         break;
2942
2943                 case PIPELINE_REQ_TABLE_MTR_PROFILE_ADD:
2944                         rsp = pipeline_msg_handle_table_mtr_profile_add(p, req);
2945                         break;
2946
2947                 case PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE:
2948                         rsp = pipeline_msg_handle_table_mtr_profile_delete(p, req);
2949                         break;
2950
2951                 case PIPELINE_REQ_TABLE_RULE_MTR_READ:
2952                         rsp = pipeline_msg_handle_table_rule_mtr_read(p, req);
2953                         break;
2954
2955                 case PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE:
2956                         rsp = pipeline_msg_handle_table_dscp_table_update(p, req);
2957                         break;
2958
2959                 case PIPELINE_REQ_TABLE_RULE_TTL_READ:
2960                         rsp = pipeline_msg_handle_table_rule_ttl_read(p, req);
2961                         break;
2962
2963                 default:
2964                         rsp = (struct pipeline_msg_rsp *) req;
2965                         rsp->status = -1;
2966                 }
2967
2968                 pipeline_msg_send(p->msgq_rsp, rsp);
2969         }
2970 }
2971
2972 /**
2973  * Data plane threads: main
2974  */
2975 int
2976 thread_main(void *arg __rte_unused)
2977 {
2978         struct thread_data *t;
2979         uint32_t thread_id, i;
2980
2981         thread_id = rte_lcore_id();
2982         t = &thread_data[thread_id];
2983
2984         /* Dispatch loop */
2985         for (i = 0; ; i++) {
2986                 uint32_t j;
2987
2988                 /* Data Plane */
2989                 for (j = 0; j < t->n_pipelines; j++)
2990                         rte_pipeline_run(t->p[j]);
2991
2992                 /* Control Plane */
2993                 if ((i & 0xF) == 0) {
2994                         uint64_t time = rte_get_tsc_cycles();
2995                         uint64_t time_next_min = UINT64_MAX;
2996
2997                         if (time < t->time_next_min)
2998                                 continue;
2999
3000                         /* Pipeline message queues */
3001                         for (j = 0; j < t->n_pipelines; j++) {
3002                                 struct pipeline_data *p =
3003                                         &t->pipeline_data[j];
3004                                 uint64_t time_next = p->time_next;
3005
3006                                 if (time_next <= time) {
3007                                         pipeline_msg_handle(p);
3008                                         rte_pipeline_flush(p->p);
3009                                         time_next = time + p->timer_period;
3010                                         p->time_next = time_next;
3011                                 }
3012
3013                                 if (time_next < time_next_min)
3014                                         time_next_min = time_next;
3015                         }
3016
3017                         /* Thread message queues */
3018                         {
3019                                 uint64_t time_next = t->time_next;
3020
3021                                 if (time_next <= time) {
3022                                         thread_msg_handle(t);
3023                                         time_next = time + t->timer_period;
3024                                         t->time_next = time_next;
3025                                 }
3026
3027                                 if (time_next < time_next_min)
3028                                         time_next_min = time_next;
3029                         }
3030
3031                         t->time_next_min = time_next_min;
3032                 }
3033         }
3034
3035         return 0;
3036 }