examples/ip_pipeline: add meter profile commands
[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 /**
159  * Master thread & data plane threads: message passing
160  */
161 enum thread_req_type {
162         THREAD_REQ_PIPELINE_ENABLE = 0,
163         THREAD_REQ_PIPELINE_DISABLE,
164         THREAD_REQ_MAX
165 };
166
167 struct thread_msg_req {
168         enum thread_req_type type;
169
170         union {
171                 struct {
172                         struct rte_pipeline *p;
173                         struct {
174                                 struct rte_table_action *a;
175                         } table[RTE_PIPELINE_TABLE_MAX];
176                         struct rte_ring *msgq_req;
177                         struct rte_ring *msgq_rsp;
178                         uint32_t timer_period_ms;
179                         uint32_t n_tables;
180                 } pipeline_enable;
181
182                 struct {
183                         struct rte_pipeline *p;
184                 } pipeline_disable;
185         };
186 };
187
188 struct thread_msg_rsp {
189         int status;
190 };
191
192 /**
193  * Master thread
194  */
195 static struct thread_msg_req *
196 thread_msg_alloc(void)
197 {
198         size_t size = RTE_MAX(sizeof(struct thread_msg_req),
199                 sizeof(struct thread_msg_rsp));
200
201         return calloc(1, size);
202 }
203
204 static void
205 thread_msg_free(struct thread_msg_rsp *rsp)
206 {
207         free(rsp);
208 }
209
210 static struct thread_msg_rsp *
211 thread_msg_send_recv(uint32_t thread_id,
212         struct thread_msg_req *req)
213 {
214         struct thread *t = &thread[thread_id];
215         struct rte_ring *msgq_req = t->msgq_req;
216         struct rte_ring *msgq_rsp = t->msgq_rsp;
217         struct thread_msg_rsp *rsp;
218         int status;
219
220         /* send */
221         do {
222                 status = rte_ring_sp_enqueue(msgq_req, req);
223         } while (status == -ENOBUFS);
224
225         /* recv */
226         do {
227                 status = rte_ring_sc_dequeue(msgq_rsp, (void **) &rsp);
228         } while (status != 0);
229
230         return rsp;
231 }
232
233 int
234 thread_pipeline_enable(uint32_t thread_id,
235         const char *pipeline_name)
236 {
237         struct pipeline *p = pipeline_find(pipeline_name);
238         struct thread *t;
239         struct thread_msg_req *req;
240         struct thread_msg_rsp *rsp;
241         uint32_t i;
242         int status;
243
244         /* Check input params */
245         if ((thread_id >= RTE_MAX_LCORE) ||
246                 (p == NULL) ||
247                 (p->n_ports_in == 0) ||
248                 (p->n_ports_out == 0) ||
249                 (p->n_tables == 0))
250                 return -1;
251
252         t = &thread[thread_id];
253         if ((t->enabled == 0) ||
254                 p->enabled)
255                 return -1;
256
257         /* Allocate request */
258         req = thread_msg_alloc();
259         if (req == NULL)
260                 return -1;
261
262         /* Write request */
263         req->type = THREAD_REQ_PIPELINE_ENABLE;
264         req->pipeline_enable.p = p->p;
265         for (i = 0; i < p->n_tables; i++)
266                 req->pipeline_enable.table[i].a =
267                         p->table[i].a;
268         req->pipeline_enable.msgq_req = p->msgq_req;
269         req->pipeline_enable.msgq_rsp = p->msgq_rsp;
270         req->pipeline_enable.timer_period_ms = p->timer_period_ms;
271         req->pipeline_enable.n_tables = p->n_tables;
272
273         /* Send request and wait for response */
274         rsp = thread_msg_send_recv(thread_id, req);
275         if (rsp == NULL)
276                 return -1;
277
278         /* Read response */
279         status = rsp->status;
280
281         /* Free response */
282         thread_msg_free(rsp);
283
284         /* Request completion */
285         if (status)
286                 return status;
287
288         p->thread_id = thread_id;
289         p->enabled = 1;
290
291         return 0;
292 }
293
294 int
295 thread_pipeline_disable(uint32_t thread_id,
296         const char *pipeline_name)
297 {
298         struct pipeline *p = pipeline_find(pipeline_name);
299         struct thread *t;
300         struct thread_msg_req *req;
301         struct thread_msg_rsp *rsp;
302         int status;
303
304         /* Check input params */
305         if ((thread_id >= RTE_MAX_LCORE) ||
306                 (p == NULL))
307                 return -1;
308
309         t = &thread[thread_id];
310         if (t->enabled == 0)
311                 return -1;
312
313         if (p->enabled == 0)
314                 return 0;
315
316         if (p->thread_id != thread_id)
317                 return -1;
318
319         /* Allocate request */
320         req = thread_msg_alloc();
321         if (req == NULL)
322                 return -1;
323
324         /* Write request */
325         req->type = THREAD_REQ_PIPELINE_DISABLE;
326         req->pipeline_disable.p = p->p;
327
328         /* Send request and wait for response */
329         rsp = thread_msg_send_recv(thread_id, req);
330         if (rsp == NULL)
331                 return -1;
332
333         /* Read response */
334         status = rsp->status;
335
336         /* Free response */
337         thread_msg_free(rsp);
338
339         /* Request completion */
340         if (status)
341                 return status;
342
343         p->enabled = 0;
344
345         return 0;
346 }
347
348 /**
349  * Data plane threads: message handling
350  */
351 static inline struct thread_msg_req *
352 thread_msg_recv(struct rte_ring *msgq_req)
353 {
354         struct thread_msg_req *req;
355
356         int status = rte_ring_sc_dequeue(msgq_req, (void **) &req);
357
358         if (status != 0)
359                 return NULL;
360
361         return req;
362 }
363
364 static inline void
365 thread_msg_send(struct rte_ring *msgq_rsp,
366         struct thread_msg_rsp *rsp)
367 {
368         int status;
369
370         do {
371                 status = rte_ring_sp_enqueue(msgq_rsp, rsp);
372         } while (status == -ENOBUFS);
373 }
374
375 static struct thread_msg_rsp *
376 thread_msg_handle_pipeline_enable(struct thread_data *t,
377         struct thread_msg_req *req)
378 {
379         struct thread_msg_rsp *rsp = (struct thread_msg_rsp *) req;
380         struct pipeline_data *p = &t->pipeline_data[t->n_pipelines];
381         uint32_t i;
382
383         /* Request */
384         if (t->n_pipelines >= THREAD_PIPELINES_MAX) {
385                 rsp->status = -1;
386                 return rsp;
387         }
388
389         t->p[t->n_pipelines] = req->pipeline_enable.p;
390
391         p->p = req->pipeline_enable.p;
392         for (i = 0; i < req->pipeline_enable.n_tables; i++)
393                 p->table_data[i].a =
394                         req->pipeline_enable.table[i].a;
395
396         p->n_tables = req->pipeline_enable.n_tables;
397
398         p->msgq_req = req->pipeline_enable.msgq_req;
399         p->msgq_rsp = req->pipeline_enable.msgq_rsp;
400         p->timer_period =
401                 (rte_get_tsc_hz() * req->pipeline_enable.timer_period_ms) / 1000;
402         p->time_next = rte_get_tsc_cycles() + p->timer_period;
403
404         t->n_pipelines++;
405
406         /* Response */
407         rsp->status = 0;
408         return rsp;
409 }
410
411 static struct thread_msg_rsp *
412 thread_msg_handle_pipeline_disable(struct thread_data *t,
413         struct thread_msg_req *req)
414 {
415         struct thread_msg_rsp *rsp = (struct thread_msg_rsp *) req;
416         uint32_t n_pipelines = t->n_pipelines;
417         struct rte_pipeline *pipeline = req->pipeline_disable.p;
418         uint32_t i;
419
420         /* find pipeline */
421         for (i = 0; i < n_pipelines; i++) {
422                 struct pipeline_data *p = &t->pipeline_data[i];
423
424                 if (p->p != pipeline)
425                         continue;
426
427                 if (i < n_pipelines - 1) {
428                         struct rte_pipeline *pipeline_last =
429                                 t->p[n_pipelines - 1];
430                         struct pipeline_data *p_last =
431                                 &t->pipeline_data[n_pipelines - 1];
432
433                         t->p[i] = pipeline_last;
434                         memcpy(p, p_last, sizeof(*p));
435                 }
436
437                 t->n_pipelines--;
438
439                 rsp->status = 0;
440                 return rsp;
441         }
442
443         /* should not get here */
444         rsp->status = 0;
445         return rsp;
446 }
447
448 static void
449 thread_msg_handle(struct thread_data *t)
450 {
451         for ( ; ; ) {
452                 struct thread_msg_req *req;
453                 struct thread_msg_rsp *rsp;
454
455                 req = thread_msg_recv(t->msgq_req);
456                 if (req == NULL)
457                         break;
458
459                 switch (req->type) {
460                 case THREAD_REQ_PIPELINE_ENABLE:
461                         rsp = thread_msg_handle_pipeline_enable(t, req);
462                         break;
463
464                 case THREAD_REQ_PIPELINE_DISABLE:
465                         rsp = thread_msg_handle_pipeline_disable(t, req);
466                         break;
467
468                 default:
469                         rsp = (struct thread_msg_rsp *) req;
470                         rsp->status = -1;
471                 }
472
473                 thread_msg_send(t->msgq_rsp, rsp);
474         }
475 }
476
477 /**
478  * Master thread & data plane threads: message passing
479  */
480 enum pipeline_req_type {
481         /* Port IN */
482         PIPELINE_REQ_PORT_IN_STATS_READ,
483         PIPELINE_REQ_PORT_IN_ENABLE,
484         PIPELINE_REQ_PORT_IN_DISABLE,
485
486         /* Port OUT */
487         PIPELINE_REQ_PORT_OUT_STATS_READ,
488
489         /* Table */
490         PIPELINE_REQ_TABLE_STATS_READ,
491         PIPELINE_REQ_TABLE_RULE_ADD,
492         PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT,
493         PIPELINE_REQ_TABLE_RULE_ADD_BULK,
494         PIPELINE_REQ_TABLE_RULE_DELETE,
495         PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT,
496         PIPELINE_REQ_TABLE_RULE_STATS_READ,
497         PIPELINE_REQ_TABLE_MTR_PROFILE_ADD,
498         PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
499         PIPELINE_REQ_MAX
500 };
501
502 struct pipeline_msg_req_port_in_stats_read {
503         int clear;
504 };
505
506 struct pipeline_msg_req_port_out_stats_read {
507         int clear;
508 };
509
510 struct pipeline_msg_req_table_stats_read {
511         int clear;
512 };
513
514 struct pipeline_msg_req_table_rule_add {
515         struct table_rule_match match;
516         struct table_rule_action action;
517 };
518
519 struct pipeline_msg_req_table_rule_add_default {
520         struct table_rule_action action;
521 };
522
523 struct pipeline_msg_req_table_rule_add_bulk {
524         struct table_rule_match *match;
525         struct table_rule_action *action;
526         void **data;
527         uint32_t n_rules;
528         int bulk;
529 };
530
531 struct pipeline_msg_req_table_rule_delete {
532         struct table_rule_match match;
533 };
534
535 struct pipeline_msg_req_table_rule_stats_read {
536         void *data;
537         int clear;
538 };
539
540 struct pipeline_msg_req_table_mtr_profile_add {
541         uint32_t meter_profile_id;
542         struct rte_table_action_meter_profile profile;
543 };
544
545 struct pipeline_msg_req_table_mtr_profile_delete {
546         uint32_t meter_profile_id;
547 };
548
549 struct pipeline_msg_req {
550         enum pipeline_req_type type;
551         uint32_t id; /* Port IN, port OUT or table ID */
552
553         RTE_STD_C11
554         union {
555                 struct pipeline_msg_req_port_in_stats_read port_in_stats_read;
556                 struct pipeline_msg_req_port_out_stats_read port_out_stats_read;
557                 struct pipeline_msg_req_table_stats_read table_stats_read;
558                 struct pipeline_msg_req_table_rule_add table_rule_add;
559                 struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
560                 struct pipeline_msg_req_table_rule_add_bulk table_rule_add_bulk;
561                 struct pipeline_msg_req_table_rule_delete table_rule_delete;
562                 struct pipeline_msg_req_table_rule_stats_read table_rule_stats_read;
563                 struct pipeline_msg_req_table_mtr_profile_add table_mtr_profile_add;
564                 struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
565         };
566 };
567
568 struct pipeline_msg_rsp_port_in_stats_read {
569         struct rte_pipeline_port_in_stats stats;
570 };
571
572 struct pipeline_msg_rsp_port_out_stats_read {
573         struct rte_pipeline_port_out_stats stats;
574 };
575
576 struct pipeline_msg_rsp_table_stats_read {
577         struct rte_pipeline_table_stats stats;
578 };
579
580 struct pipeline_msg_rsp_table_rule_add {
581         void *data;
582 };
583
584 struct pipeline_msg_rsp_table_rule_add_default {
585         void *data;
586 };
587
588 struct pipeline_msg_rsp_table_rule_add_bulk {
589         uint32_t n_rules;
590 };
591
592 struct pipeline_msg_rsp_table_rule_stats_read {
593         struct rte_table_action_stats_counters stats;
594 };
595
596 struct pipeline_msg_rsp {
597         int status;
598
599         RTE_STD_C11
600         union {
601                 struct pipeline_msg_rsp_port_in_stats_read port_in_stats_read;
602                 struct pipeline_msg_rsp_port_out_stats_read port_out_stats_read;
603                 struct pipeline_msg_rsp_table_stats_read table_stats_read;
604                 struct pipeline_msg_rsp_table_rule_add table_rule_add;
605                 struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
606                 struct pipeline_msg_rsp_table_rule_add_bulk table_rule_add_bulk;
607                 struct pipeline_msg_rsp_table_rule_stats_read table_rule_stats_read;
608         };
609 };
610
611 /**
612  * Master thread
613  */
614 static struct pipeline_msg_req *
615 pipeline_msg_alloc(void)
616 {
617         size_t size = RTE_MAX(sizeof(struct pipeline_msg_req),
618                 sizeof(struct pipeline_msg_rsp));
619
620         return calloc(1, size);
621 }
622
623 static void
624 pipeline_msg_free(struct pipeline_msg_rsp *rsp)
625 {
626         free(rsp);
627 }
628
629 static struct pipeline_msg_rsp *
630 pipeline_msg_send_recv(struct pipeline *p,
631         struct pipeline_msg_req *req)
632 {
633         struct rte_ring *msgq_req = p->msgq_req;
634         struct rte_ring *msgq_rsp = p->msgq_rsp;
635         struct pipeline_msg_rsp *rsp;
636         int status;
637
638         /* send */
639         do {
640                 status = rte_ring_sp_enqueue(msgq_req, req);
641         } while (status == -ENOBUFS);
642
643         /* recv */
644         do {
645                 status = rte_ring_sc_dequeue(msgq_rsp, (void **) &rsp);
646         } while (status != 0);
647
648         return rsp;
649 }
650
651 int
652 pipeline_port_in_stats_read(const char *pipeline_name,
653         uint32_t port_id,
654         struct rte_pipeline_port_in_stats *stats,
655         int clear)
656 {
657         struct pipeline *p;
658         struct pipeline_msg_req *req;
659         struct pipeline_msg_rsp *rsp;
660         int status;
661
662         /* Check input params */
663         if ((pipeline_name == NULL) ||
664                 (stats == NULL))
665                 return -1;
666
667         p = pipeline_find(pipeline_name);
668         if ((p == NULL) ||
669                 (p->enabled == 0) ||
670                 (port_id >= p->n_ports_in))
671                 return -1;
672
673         /* Allocate request */
674         req = pipeline_msg_alloc();
675         if (req == NULL)
676                 return -1;
677
678         /* Write request */
679         req->type = PIPELINE_REQ_PORT_IN_STATS_READ;
680         req->id = port_id;
681         req->port_in_stats_read.clear = clear;
682
683         /* Send request and wait for response */
684         rsp = pipeline_msg_send_recv(p, req);
685         if (rsp == NULL)
686                 return -1;
687
688         /* Read response */
689         status = rsp->status;
690         if (status)
691                 memcpy(stats, &rsp->port_in_stats_read.stats, sizeof(*stats));
692
693         /* Free response */
694         pipeline_msg_free(rsp);
695
696         return status;
697 }
698
699 int
700 pipeline_port_in_enable(const char *pipeline_name,
701         uint32_t port_id)
702 {
703         struct pipeline *p;
704         struct pipeline_msg_req *req;
705         struct pipeline_msg_rsp *rsp;
706         int status;
707
708         /* Check input params */
709         if (pipeline_name == NULL)
710                 return -1;
711
712         p = pipeline_find(pipeline_name);
713         if ((p == NULL) ||
714                 (p->enabled == 0) ||
715                 (port_id >= p->n_ports_in))
716                 return -1;
717
718         /* Allocate request */
719         req = pipeline_msg_alloc();
720         if (req == NULL)
721                 return -1;
722
723         /* Write request */
724         req->type = PIPELINE_REQ_PORT_IN_ENABLE;
725         req->id = port_id;
726
727         /* Send request and wait for response */
728         rsp = pipeline_msg_send_recv(p, req);
729         if (rsp == NULL)
730                 return -1;
731
732         /* Read response */
733         status = rsp->status;
734
735         /* Free response */
736         pipeline_msg_free(rsp);
737
738         return status;
739 }
740
741 int
742 pipeline_port_in_disable(const char *pipeline_name,
743         uint32_t port_id)
744 {
745         struct pipeline *p;
746         struct pipeline_msg_req *req;
747         struct pipeline_msg_rsp *rsp;
748         int status;
749
750         /* Check input params */
751         if (pipeline_name == NULL)
752                 return -1;
753
754         p = pipeline_find(pipeline_name);
755         if ((p == NULL) ||
756                 (p->enabled == 0) ||
757                 (port_id >= p->n_ports_in))
758                 return -1;
759
760         /* Allocate request */
761         req = pipeline_msg_alloc();
762         if (req == NULL)
763                 return -1;
764
765         /* Write request */
766         req->type = PIPELINE_REQ_PORT_IN_DISABLE;
767         req->id = port_id;
768
769         /* Send request and wait for response */
770         rsp = pipeline_msg_send_recv(p, req);
771         if (rsp == NULL)
772                 return -1;
773
774         /* Read response */
775         status = rsp->status;
776
777         /* Free response */
778         pipeline_msg_free(rsp);
779
780         return status;
781 }
782
783 int
784 pipeline_port_out_stats_read(const char *pipeline_name,
785         uint32_t port_id,
786         struct rte_pipeline_port_out_stats *stats,
787         int clear)
788 {
789         struct pipeline *p;
790         struct pipeline_msg_req *req;
791         struct pipeline_msg_rsp *rsp;
792         int status;
793
794         /* Check input params */
795         if ((pipeline_name == NULL) ||
796                 (stats == NULL))
797                 return -1;
798
799         p = pipeline_find(pipeline_name);
800         if ((p == NULL) ||
801                 (p->enabled == 0) ||
802                 (port_id >= p->n_ports_out))
803                 return -1;
804
805         /* Allocate request */
806         req = pipeline_msg_alloc();
807         if (req == NULL)
808                 return -1;
809
810         /* Write request */
811         req->type = PIPELINE_REQ_PORT_OUT_STATS_READ;
812         req->id = port_id;
813         req->port_out_stats_read.clear = clear;
814
815         /* Send request and wait for response */
816         rsp = pipeline_msg_send_recv(p, req);
817         if (rsp == NULL)
818                 return -1;
819
820         /* Read response */
821         status = rsp->status;
822         if (status)
823                 memcpy(stats, &rsp->port_out_stats_read.stats, sizeof(*stats));
824
825         /* Free response */
826         pipeline_msg_free(rsp);
827
828         return status;
829 }
830
831 int
832 pipeline_table_stats_read(const char *pipeline_name,
833         uint32_t table_id,
834         struct rte_pipeline_table_stats *stats,
835         int clear)
836 {
837         struct pipeline *p;
838         struct pipeline_msg_req *req;
839         struct pipeline_msg_rsp *rsp;
840         int status;
841
842         /* Check input params */
843         if ((pipeline_name == NULL) ||
844                 (stats == NULL))
845                 return -1;
846
847         p = pipeline_find(pipeline_name);
848         if ((p == NULL) ||
849                 (p->enabled == 0) ||
850                 (table_id >= p->n_tables))
851                 return -1;
852
853         /* Allocate request */
854         req = pipeline_msg_alloc();
855         if (req == NULL)
856                 return -1;
857
858         /* Write request */
859         req->type = PIPELINE_REQ_TABLE_STATS_READ;
860         req->id = table_id;
861         req->table_stats_read.clear = clear;
862
863         /* Send request and wait for response */
864         rsp = pipeline_msg_send_recv(p, req);
865         if (rsp == NULL)
866                 return -1;
867
868         /* Read response */
869         status = rsp->status;
870         if (status)
871                 memcpy(stats, &rsp->table_stats_read.stats, sizeof(*stats));
872
873         /* Free response */
874         pipeline_msg_free(rsp);
875
876         return status;
877 }
878
879 static int
880 match_check(struct table_rule_match *match,
881         struct pipeline *p,
882         uint32_t table_id)
883 {
884         struct table *table;
885
886         if ((match == NULL) ||
887                 (p == NULL) ||
888                 (table_id >= p->n_tables))
889                 return -1;
890
891         table = &p->table[table_id];
892         if (match->match_type != table->params.match_type)
893                 return -1;
894
895         switch (match->match_type) {
896         case TABLE_ACL:
897         {
898                 struct table_acl_params *t = &table->params.match.acl;
899                 struct table_rule_match_acl *r = &match->match.acl;
900
901                 if ((r->ip_version && (t->ip_version == 0)) ||
902                         ((r->ip_version == 0) && t->ip_version))
903                         return -1;
904
905                 if (r->ip_version) {
906                         if ((r->sa_depth > 32) ||
907                                 (r->da_depth > 32))
908                                 return -1;
909                 } else {
910                         if ((r->sa_depth > 128) ||
911                                 (r->da_depth > 128))
912                                 return -1;
913                 }
914                 return 0;
915         }
916
917         case TABLE_ARRAY:
918                 return 0;
919
920         case TABLE_HASH:
921                 return 0;
922
923         case TABLE_LPM:
924         {
925                 struct table_lpm_params *t = &table->params.match.lpm;
926                 struct table_rule_match_lpm *r = &match->match.lpm;
927
928                 if ((r->ip_version && (t->key_size != 4)) ||
929                         ((r->ip_version == 0) && (t->key_size != 16)))
930                         return -1;
931
932                 if (r->ip_version) {
933                         if (r->depth > 32)
934                                 return -1;
935                 } else {
936                         if (r->depth > 128)
937                                 return -1;
938                 }
939                 return 0;
940         }
941
942         case TABLE_STUB:
943                 return -1;
944
945         default:
946                 return -1;
947         }
948 }
949
950 static int
951 action_check(struct table_rule_action *action,
952         struct pipeline *p,
953         uint32_t table_id)
954 {
955         struct table_action_profile *ap;
956
957         if ((action == NULL) ||
958                 (p == NULL) ||
959                 (table_id >= p->n_tables))
960                 return -1;
961
962         ap = p->table[table_id].ap;
963         if (action->action_mask != ap->params.action_mask)
964                 return -1;
965
966         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
967                 if ((action->fwd.action == RTE_PIPELINE_ACTION_PORT) &&
968                         (action->fwd.id >= p->n_ports_out))
969                         return -1;
970
971                 if ((action->fwd.action == RTE_PIPELINE_ACTION_TABLE) &&
972                         (action->fwd.id >= p->n_tables))
973                         return -1;
974         }
975
976         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
977                 uint32_t tc_mask0 = (1 << ap->params.mtr.n_tc) - 1;
978                 uint32_t tc_mask1 = action->mtr.tc_mask;
979
980                 if (tc_mask1 != tc_mask0)
981                         return -1;
982         }
983
984         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
985                 uint32_t n_subports_per_port =
986                         ap->params.tm.n_subports_per_port;
987                 uint32_t n_pipes_per_subport =
988                         ap->params.tm.n_pipes_per_subport;
989                 uint32_t subport_id = action->tm.subport_id;
990                 uint32_t pipe_id = action->tm.pipe_id;
991
992                 if ((subport_id >= n_subports_per_port) ||
993                         (pipe_id >= n_pipes_per_subport))
994                         return -1;
995         }
996
997         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
998                 uint64_t encap_mask = ap->params.encap.encap_mask;
999                 enum rte_table_action_encap_type type = action->encap.type;
1000
1001                 if ((encap_mask & (1LLU << type)) == 0)
1002                         return -1;
1003         }
1004
1005         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
1006                 int ip_version0 = ap->params.common.ip_version;
1007                 int ip_version1 = action->nat.ip_version;
1008
1009                 if ((ip_version1 && (ip_version0 == 0)) ||
1010                         ((ip_version1 == 0) && ip_version0))
1011                         return -1;
1012         }
1013
1014         return 0;
1015 }
1016
1017 static int
1018 action_default_check(struct table_rule_action *action,
1019         struct pipeline *p,
1020         uint32_t table_id)
1021 {
1022         if ((action == NULL) ||
1023                 (action->action_mask != (1LLU << RTE_TABLE_ACTION_FWD)) ||
1024                 (p == NULL) ||
1025                 (table_id >= p->n_tables))
1026                 return -1;
1027
1028         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
1029                 if ((action->fwd.action == RTE_PIPELINE_ACTION_PORT) &&
1030                         (action->fwd.id >= p->n_ports_out))
1031                         return -1;
1032
1033                 if ((action->fwd.action == RTE_PIPELINE_ACTION_TABLE) &&
1034                         (action->fwd.id >= p->n_tables))
1035                         return -1;
1036         }
1037
1038         return 0;
1039 }
1040
1041 int
1042 pipeline_table_rule_add(const char *pipeline_name,
1043         uint32_t table_id,
1044         struct table_rule_match *match,
1045         struct table_rule_action *action,
1046         void **data)
1047 {
1048         struct pipeline *p;
1049         struct pipeline_msg_req *req;
1050         struct pipeline_msg_rsp *rsp;
1051         int status;
1052
1053         /* Check input params */
1054         if ((pipeline_name == NULL) ||
1055                 (match == NULL) ||
1056                 (action == NULL) ||
1057                 (data == NULL))
1058                 return -1;
1059
1060         p = pipeline_find(pipeline_name);
1061         if ((p == NULL) ||
1062                 (p->enabled == 0) ||
1063                 (table_id >= p->n_tables) ||
1064                 match_check(match, p, table_id) ||
1065                 action_check(action, p, table_id))
1066                 return -1;
1067
1068         /* Allocate request */
1069         req = pipeline_msg_alloc();
1070         if (req == NULL)
1071                 return -1;
1072
1073         /* Write request */
1074         req->type = PIPELINE_REQ_TABLE_RULE_ADD;
1075         req->id = table_id;
1076         memcpy(&req->table_rule_add.match, match, sizeof(*match));
1077         memcpy(&req->table_rule_add.action, action, sizeof(*action));
1078
1079         /* Send request and wait for response */
1080         rsp = pipeline_msg_send_recv(p, req);
1081         if (rsp == NULL)
1082                 return -1;
1083
1084         /* Read response */
1085         status = rsp->status;
1086         if (status == 0)
1087                 *data = rsp->table_rule_add.data;
1088
1089         /* Free response */
1090         pipeline_msg_free(rsp);
1091
1092         return status;
1093 }
1094
1095 int
1096 pipeline_table_rule_add_default(const char *pipeline_name,
1097         uint32_t table_id,
1098         struct table_rule_action *action,
1099         void **data)
1100 {
1101         struct pipeline *p;
1102         struct pipeline_msg_req *req;
1103         struct pipeline_msg_rsp *rsp;
1104         int status;
1105
1106         /* Check input params */
1107         if ((pipeline_name == NULL) ||
1108                 (action == NULL) ||
1109                 (data == NULL))
1110                 return -1;
1111
1112         p = pipeline_find(pipeline_name);
1113         if ((p == NULL) ||
1114                 (p->enabled == 0) ||
1115                 (table_id >= p->n_tables) ||
1116                 action_default_check(action, p, table_id))
1117                 return -1;
1118
1119         /* Allocate request */
1120         req = pipeline_msg_alloc();
1121         if (req == NULL)
1122                 return -1;
1123
1124         /* Write request */
1125         req->type = PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT;
1126         req->id = table_id;
1127         memcpy(&req->table_rule_add_default.action, action, sizeof(*action));
1128
1129         /* Send request and wait for response */
1130         rsp = pipeline_msg_send_recv(p, req);
1131         if (rsp == NULL)
1132                 return -1;
1133
1134         /* Read response */
1135         status = rsp->status;
1136         if (status == 0)
1137                 *data = rsp->table_rule_add_default.data;
1138
1139         /* Free response */
1140         pipeline_msg_free(rsp);
1141
1142         return status;
1143 }
1144
1145 int
1146 pipeline_table_rule_add_bulk(const char *pipeline_name,
1147         uint32_t table_id,
1148         struct table_rule_match *match,
1149         struct table_rule_action *action,
1150         void **data,
1151         uint32_t *n_rules)
1152 {
1153         struct pipeline *p;
1154         struct pipeline_msg_req *req;
1155         struct pipeline_msg_rsp *rsp;
1156         uint32_t i;
1157         int status;
1158
1159         /* Check input params */
1160         if ((pipeline_name == NULL) ||
1161                 (match == NULL) ||
1162                 (action == NULL) ||
1163                 (data == NULL) ||
1164                 (n_rules == NULL) ||
1165                 (*n_rules == 0))
1166                 return -1;
1167
1168         p = pipeline_find(pipeline_name);
1169         if ((p == NULL) ||
1170                 (p->enabled == 0) ||
1171                 (table_id >= p->n_tables))
1172                 return -1;
1173
1174         for (i = 0; i < *n_rules; i++)
1175                 if (match_check(match, p, table_id) ||
1176                         action_check(action, p, table_id))
1177                         return -1;
1178
1179         /* Allocate request */
1180         req = pipeline_msg_alloc();
1181         if (req == NULL)
1182                 return -1;
1183
1184         /* Write request */
1185         req->type = PIPELINE_REQ_TABLE_RULE_ADD_BULK;
1186         req->id = table_id;
1187         req->table_rule_add_bulk.match = match;
1188         req->table_rule_add_bulk.action = action;
1189         req->table_rule_add_bulk.data = data;
1190         req->table_rule_add_bulk.n_rules = *n_rules;
1191         req->table_rule_add_bulk.bulk =
1192                 (p->table[table_id].params.match_type == TABLE_ACL) ? 1 : 0;
1193
1194         /* Send request and wait for response */
1195         rsp = pipeline_msg_send_recv(p, req);
1196         if (rsp == NULL)
1197                 return -1;
1198
1199         /* Read response */
1200         status = rsp->status;
1201         if (status == 0)
1202                 *n_rules = rsp->table_rule_add_bulk.n_rules;
1203
1204         /* Free response */
1205         pipeline_msg_free(rsp);
1206
1207         return status;
1208 }
1209
1210 int
1211 pipeline_table_rule_delete(const char *pipeline_name,
1212         uint32_t table_id,
1213         struct table_rule_match *match)
1214 {
1215         struct pipeline *p;
1216         struct pipeline_msg_req *req;
1217         struct pipeline_msg_rsp *rsp;
1218         int status;
1219
1220         /* Check input params */
1221         if ((pipeline_name == NULL) ||
1222                 (match == NULL))
1223                 return -1;
1224
1225         p = pipeline_find(pipeline_name);
1226         if ((p == NULL) ||
1227                 (p->enabled == 0) ||
1228                 (table_id >= p->n_tables) ||
1229                 match_check(match, p, table_id))
1230                 return -1;
1231
1232         /* Allocate request */
1233         req = pipeline_msg_alloc();
1234         if (req == NULL)
1235                 return -1;
1236
1237         /* Write request */
1238         req->type = PIPELINE_REQ_TABLE_RULE_DELETE;
1239         req->id = table_id;
1240         memcpy(&req->table_rule_delete.match, match, sizeof(*match));
1241
1242         /* Send request and wait for response */
1243         rsp = pipeline_msg_send_recv(p, req);
1244         if (rsp == NULL)
1245                 return -1;
1246
1247         /* Read response */
1248         status = rsp->status;
1249
1250         /* Free response */
1251         pipeline_msg_free(rsp);
1252
1253         return status;
1254 }
1255
1256 int
1257 pipeline_table_rule_delete_default(const char *pipeline_name,
1258         uint32_t table_id)
1259 {
1260         struct pipeline *p;
1261         struct pipeline_msg_req *req;
1262         struct pipeline_msg_rsp *rsp;
1263         int status;
1264
1265         /* Check input params */
1266         if (pipeline_name == NULL)
1267                 return -1;
1268
1269         p = pipeline_find(pipeline_name);
1270         if ((p == NULL) ||
1271                 (p->enabled == 0) ||
1272                 (table_id >= p->n_tables))
1273                 return -1;
1274
1275         /* Allocate request */
1276         req = pipeline_msg_alloc();
1277         if (req == NULL)
1278                 return -1;
1279
1280         /* Write request */
1281         req->type = PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT;
1282         req->id = table_id;
1283
1284         /* Send request and wait for response */
1285         rsp = pipeline_msg_send_recv(p, req);
1286         if (rsp == NULL)
1287                 return -1;
1288
1289         /* Read response */
1290         status = rsp->status;
1291
1292         /* Free response */
1293         pipeline_msg_free(rsp);
1294
1295         return status;
1296 }
1297
1298 int
1299 pipeline_table_rule_stats_read(const char *pipeline_name,
1300         uint32_t table_id,
1301         void *data,
1302         struct rte_table_action_stats_counters *stats,
1303         int clear)
1304 {
1305         struct pipeline *p;
1306         struct pipeline_msg_req *req;
1307         struct pipeline_msg_rsp *rsp;
1308         int status;
1309
1310         /* Check input params */
1311         if ((pipeline_name == NULL) ||
1312                 (data == NULL) ||
1313                 (stats == NULL))
1314                 return -1;
1315
1316         p = pipeline_find(pipeline_name);
1317         if ((p == NULL) ||
1318                 (p->enabled == 0) ||
1319                 (table_id >= p->n_tables))
1320                 return -1;
1321
1322         /* Allocate request */
1323         req = pipeline_msg_alloc();
1324         if (req == NULL)
1325                 return -1;
1326
1327         /* Write request */
1328         req->type = PIPELINE_REQ_TABLE_RULE_STATS_READ;
1329         req->id = table_id;
1330         req->table_rule_stats_read.data = data;
1331         req->table_rule_stats_read.clear = clear;
1332
1333         /* Send request and wait for response */
1334         rsp = pipeline_msg_send_recv(p, req);
1335         if (rsp == NULL)
1336                 return -1;
1337
1338         /* Read response */
1339         status = rsp->status;
1340         if (status)
1341                 memcpy(stats, &rsp->table_rule_stats_read.stats, sizeof(*stats));
1342
1343         /* Free response */
1344         pipeline_msg_free(rsp);
1345
1346         return status;
1347 }
1348
1349 int
1350 pipeline_table_mtr_profile_add(const char *pipeline_name,
1351         uint32_t table_id,
1352         uint32_t meter_profile_id,
1353         struct rte_table_action_meter_profile *profile)
1354 {
1355         struct pipeline *p;
1356         struct pipeline_msg_req *req;
1357         struct pipeline_msg_rsp *rsp;
1358         int status;
1359
1360         /* Check input params */
1361         if ((pipeline_name == NULL) ||
1362                 (profile == NULL))
1363                 return -1;
1364
1365         p = pipeline_find(pipeline_name);
1366         if ((p == NULL) ||
1367                 (p->enabled == 0) ||
1368                 (table_id >= p->n_tables))
1369                 return -1;
1370
1371         /* Allocate request */
1372         req = pipeline_msg_alloc();
1373         if (req == NULL)
1374                 return -1;
1375
1376         /* Write request */
1377         req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_ADD;
1378         req->id = table_id;
1379         req->table_mtr_profile_add.meter_profile_id = meter_profile_id;
1380         memcpy(&req->table_mtr_profile_add.profile, profile, sizeof(*profile));
1381
1382         /* Send request and wait for response */
1383         rsp = pipeline_msg_send_recv(p, req);
1384         if (rsp == NULL)
1385                 return -1;
1386
1387         /* Read response */
1388         status = rsp->status;
1389
1390         /* Free response */
1391         pipeline_msg_free(rsp);
1392
1393         return status;
1394 }
1395
1396 int
1397 pipeline_table_mtr_profile_delete(const char *pipeline_name,
1398         uint32_t table_id,
1399         uint32_t meter_profile_id)
1400 {
1401         struct pipeline *p;
1402         struct pipeline_msg_req *req;
1403         struct pipeline_msg_rsp *rsp;
1404         int status;
1405
1406         /* Check input params */
1407         if (pipeline_name == NULL)
1408                 return -1;
1409
1410         p = pipeline_find(pipeline_name);
1411         if ((p == NULL) ||
1412                 (p->enabled == 0) ||
1413                 (table_id >= p->n_tables))
1414                 return -1;
1415
1416         /* Allocate request */
1417         req = pipeline_msg_alloc();
1418         if (req == NULL)
1419                 return -1;
1420
1421         /* Write request */
1422         req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE;
1423         req->id = table_id;
1424         req->table_mtr_profile_delete.meter_profile_id = meter_profile_id;
1425
1426         /* Send request and wait for response */
1427         rsp = pipeline_msg_send_recv(p, req);
1428         if (rsp == NULL)
1429                 return -1;
1430
1431         /* Read response */
1432         status = rsp->status;
1433
1434         /* Free response */
1435         pipeline_msg_free(rsp);
1436
1437         return status;
1438 }
1439
1440 /**
1441  * Data plane threads: message handling
1442  */
1443 static inline struct pipeline_msg_req *
1444 pipeline_msg_recv(struct rte_ring *msgq_req)
1445 {
1446         struct pipeline_msg_req *req;
1447
1448         int status = rte_ring_sc_dequeue(msgq_req, (void **) &req);
1449
1450         if (status != 0)
1451                 return NULL;
1452
1453         return req;
1454 }
1455
1456 static inline void
1457 pipeline_msg_send(struct rte_ring *msgq_rsp,
1458         struct pipeline_msg_rsp *rsp)
1459 {
1460         int status;
1461
1462         do {
1463                 status = rte_ring_sp_enqueue(msgq_rsp, rsp);
1464         } while (status == -ENOBUFS);
1465 }
1466
1467 static struct pipeline_msg_rsp *
1468 pipeline_msg_handle_port_in_stats_read(struct pipeline_data *p,
1469         struct pipeline_msg_req *req)
1470 {
1471         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
1472         uint32_t port_id = req->id;
1473         int clear = req->port_in_stats_read.clear;
1474
1475         rsp->status = rte_pipeline_port_in_stats_read(p->p,
1476                 port_id,
1477                 &rsp->port_in_stats_read.stats,
1478                 clear);
1479
1480         return rsp;
1481 }
1482
1483 static struct pipeline_msg_rsp *
1484 pipeline_msg_handle_port_in_enable(struct pipeline_data *p,
1485         struct pipeline_msg_req *req)
1486 {
1487         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
1488         uint32_t port_id = req->id;
1489
1490         rsp->status = rte_pipeline_port_in_enable(p->p,
1491                 port_id);
1492
1493         return rsp;
1494 }
1495
1496 static struct pipeline_msg_rsp *
1497 pipeline_msg_handle_port_in_disable(struct pipeline_data *p,
1498         struct pipeline_msg_req *req)
1499 {
1500         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
1501         uint32_t port_id = req->id;
1502
1503         rsp->status = rte_pipeline_port_in_disable(p->p,
1504                 port_id);
1505
1506         return rsp;
1507 }
1508
1509 static struct pipeline_msg_rsp *
1510 pipeline_msg_handle_port_out_stats_read(struct pipeline_data *p,
1511         struct pipeline_msg_req *req)
1512 {
1513         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
1514         uint32_t port_id = req->id;
1515         int clear = req->port_out_stats_read.clear;
1516
1517         rsp->status = rte_pipeline_port_out_stats_read(p->p,
1518                 port_id,
1519                 &rsp->port_out_stats_read.stats,
1520                 clear);
1521
1522         return rsp;
1523 }
1524
1525 static struct pipeline_msg_rsp *
1526 pipeline_msg_handle_table_stats_read(struct pipeline_data *p,
1527         struct pipeline_msg_req *req)
1528 {
1529         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
1530         uint32_t port_id = req->id;
1531         int clear = req->table_stats_read.clear;
1532
1533         rsp->status = rte_pipeline_table_stats_read(p->p,
1534                 port_id,
1535                 &rsp->table_stats_read.stats,
1536                 clear);
1537
1538         return rsp;
1539 }
1540
1541 union table_rule_match_low_level {
1542         struct rte_table_acl_rule_add_params acl_add;
1543         struct rte_table_acl_rule_delete_params acl_delete;
1544         struct rte_table_array_key array;
1545         uint8_t hash[TABLE_RULE_MATCH_SIZE_MAX];
1546         struct rte_table_lpm_key lpm_ipv4;
1547         struct rte_table_lpm_ipv6_key lpm_ipv6;
1548 };
1549
1550 static int
1551 match_convert_ipv6_depth(uint32_t depth, uint32_t *depth32)
1552 {
1553         if (depth > 128)
1554                 return -1;
1555
1556         switch (depth / 32) {
1557         case 0:
1558                 depth32[0] = depth;
1559                 depth32[1] = 0;
1560                 depth32[2] = 0;
1561                 depth32[3] = 0;
1562                 return 0;
1563
1564         case 1:
1565                 depth32[0] = 32;
1566                 depth32[1] = depth - 32;
1567                 depth32[2] = 0;
1568                 depth32[3] = 0;
1569                 return 0;
1570
1571         case 2:
1572                 depth32[0] = 32;
1573                 depth32[1] = 32;
1574                 depth32[2] = depth - 64;
1575                 depth32[3] = 0;
1576                 return 0;
1577
1578         case 3:
1579                 depth32[0] = 32;
1580                 depth32[1] = 32;
1581                 depth32[2] = 32;
1582                 depth32[3] = depth - 96;
1583                 return 0;
1584
1585         case 4:
1586                 depth32[0] = 32;
1587                 depth32[1] = 32;
1588                 depth32[2] = 32;
1589                 depth32[3] = 32;
1590                 return 0;
1591
1592         default:
1593                 return -1;
1594         }
1595 }
1596
1597 static int
1598 match_convert(struct table_rule_match *mh,
1599         union table_rule_match_low_level *ml,
1600         int add)
1601 {
1602         memset(ml, 0, sizeof(*ml));
1603
1604         switch (mh->match_type) {
1605         case TABLE_ACL:
1606                 if (mh->match.acl.ip_version)
1607                         if (add) {
1608                                 ml->acl_add.field_value[0].value.u8 =
1609                                         mh->match.acl.proto;
1610                                 ml->acl_add.field_value[0].mask_range.u8 =
1611                                         mh->match.acl.proto_mask;
1612
1613                                 ml->acl_add.field_value[1].value.u32 =
1614                                         mh->match.acl.ipv4.sa;
1615                                 ml->acl_add.field_value[1].mask_range.u32 =
1616                                         mh->match.acl.sa_depth;
1617
1618                                 ml->acl_add.field_value[2].value.u32 =
1619                                         mh->match.acl.ipv4.da;
1620                                 ml->acl_add.field_value[2].mask_range.u32 =
1621                                         mh->match.acl.da_depth;
1622
1623                                 ml->acl_add.field_value[3].value.u16 =
1624                                         mh->match.acl.sp0;
1625                                 ml->acl_add.field_value[3].mask_range.u16 =
1626                                         mh->match.acl.sp1;
1627
1628                                 ml->acl_add.field_value[4].value.u16 =
1629                                         mh->match.acl.dp0;
1630                                 ml->acl_add.field_value[4].mask_range.u16 =
1631                                         mh->match.acl.dp1;
1632
1633                                 ml->acl_add.priority =
1634                                         (int32_t) mh->match.acl.priority;
1635                         } else {
1636                                 ml->acl_delete.field_value[0].value.u8 =
1637                                         mh->match.acl.proto;
1638                                 ml->acl_delete.field_value[0].mask_range.u8 =
1639                                         mh->match.acl.proto_mask;
1640
1641                                 ml->acl_delete.field_value[1].value.u32 =
1642                                         mh->match.acl.ipv4.sa;
1643                                 ml->acl_delete.field_value[1].mask_range.u32 =
1644                                         mh->match.acl.sa_depth;
1645
1646                                 ml->acl_delete.field_value[2].value.u32 =
1647                                         mh->match.acl.ipv4.da;
1648                                 ml->acl_delete.field_value[2].mask_range.u32 =
1649                                         mh->match.acl.da_depth;
1650
1651                                 ml->acl_delete.field_value[3].value.u16 =
1652                                         mh->match.acl.sp0;
1653                                 ml->acl_delete.field_value[3].mask_range.u16 =
1654                                         mh->match.acl.sp1;
1655
1656                                 ml->acl_delete.field_value[4].value.u16 =
1657                                         mh->match.acl.dp0;
1658                                 ml->acl_delete.field_value[4].mask_range.u16 =
1659                                         mh->match.acl.dp1;
1660                         }
1661                 else
1662                         if (add) {
1663                                 uint32_t *sa32 =
1664                                         (uint32_t *) mh->match.acl.ipv6.sa;
1665                                 uint32_t *da32 =
1666                                         (uint32_t *) mh->match.acl.ipv6.da;
1667                                 uint32_t sa32_depth[4], da32_depth[4];
1668                                 int status;
1669
1670                                 status = match_convert_ipv6_depth(
1671                                         mh->match.acl.sa_depth,
1672                                         sa32_depth);
1673                                 if (status)
1674                                         return status;
1675
1676                                 status = match_convert_ipv6_depth(
1677                                         mh->match.acl.da_depth,
1678                                         da32_depth);
1679                                 if (status)
1680                                         return status;
1681
1682                                 ml->acl_add.field_value[0].value.u8 =
1683                                         mh->match.acl.proto;
1684                                 ml->acl_add.field_value[0].mask_range.u8 =
1685                                         mh->match.acl.proto_mask;
1686
1687                                 ml->acl_add.field_value[1].value.u32 = sa32[0];
1688                                 ml->acl_add.field_value[1].mask_range.u32 =
1689                                         sa32_depth[0];
1690                                 ml->acl_add.field_value[2].value.u32 = sa32[1];
1691                                 ml->acl_add.field_value[2].mask_range.u32 =
1692                                         sa32_depth[1];
1693                                 ml->acl_add.field_value[3].value.u32 = sa32[2];
1694                                 ml->acl_add.field_value[3].mask_range.u32 =
1695                                         sa32_depth[2];
1696                                 ml->acl_add.field_value[4].value.u32 = sa32[3];
1697                                 ml->acl_add.field_value[4].mask_range.u32 =
1698                                         sa32_depth[3];
1699
1700                                 ml->acl_add.field_value[5].value.u32 = da32[0];
1701                                 ml->acl_add.field_value[5].mask_range.u32 =
1702                                         da32_depth[0];
1703                                 ml->acl_add.field_value[6].value.u32 = da32[1];
1704                                 ml->acl_add.field_value[6].mask_range.u32 =
1705                                         da32_depth[1];
1706                                 ml->acl_add.field_value[7].value.u32 = da32[2];
1707                                 ml->acl_add.field_value[7].mask_range.u32 =
1708                                         da32_depth[2];
1709                                 ml->acl_add.field_value[8].value.u32 = da32[3];
1710                                 ml->acl_add.field_value[8].mask_range.u32 =
1711                                         da32_depth[3];
1712
1713                                 ml->acl_add.field_value[9].value.u16 =
1714                                         mh->match.acl.sp0;
1715                                 ml->acl_add.field_value[9].mask_range.u16 =
1716                                         mh->match.acl.sp1;
1717
1718                                 ml->acl_add.field_value[10].value.u16 =
1719                                         mh->match.acl.dp0;
1720                                 ml->acl_add.field_value[10].mask_range.u16 =
1721                                         mh->match.acl.dp1;
1722
1723                                 ml->acl_add.priority =
1724                                         (int32_t) mh->match.acl.priority;
1725                         } else {
1726                                 uint32_t *sa32 =
1727                                         (uint32_t *) mh->match.acl.ipv6.sa;
1728                                 uint32_t *da32 =
1729                                         (uint32_t *) mh->match.acl.ipv6.da;
1730                                 uint32_t sa32_depth[4], da32_depth[4];
1731                                 int status;
1732
1733                                 status = match_convert_ipv6_depth(
1734                                         mh->match.acl.sa_depth,
1735                                         sa32_depth);
1736                                 if (status)
1737                                         return status;
1738
1739                                 status = match_convert_ipv6_depth(
1740                                         mh->match.acl.da_depth,
1741                                         da32_depth);
1742                                 if (status)
1743                                         return status;
1744
1745                                 ml->acl_delete.field_value[0].value.u8 =
1746                                         mh->match.acl.proto;
1747                                 ml->acl_delete.field_value[0].mask_range.u8 =
1748                                         mh->match.acl.proto_mask;
1749
1750                                 ml->acl_delete.field_value[1].value.u32 =
1751                                         sa32[0];
1752                                 ml->acl_delete.field_value[1].mask_range.u32 =
1753                                         sa32_depth[0];
1754                                 ml->acl_delete.field_value[2].value.u32 =
1755                                         sa32[1];
1756                                 ml->acl_delete.field_value[2].mask_range.u32 =
1757                                         sa32_depth[1];
1758                                 ml->acl_delete.field_value[3].value.u32 =
1759                                         sa32[2];
1760                                 ml->acl_delete.field_value[3].mask_range.u32 =
1761                                         sa32_depth[2];
1762                                 ml->acl_delete.field_value[4].value.u32 =
1763                                         sa32[3];
1764                                 ml->acl_delete.field_value[4].mask_range.u32 =
1765                                         sa32_depth[3];
1766
1767                                 ml->acl_delete.field_value[5].value.u32 =
1768                                         da32[0];
1769                                 ml->acl_delete.field_value[5].mask_range.u32 =
1770                                         da32_depth[0];
1771                                 ml->acl_delete.field_value[6].value.u32 =
1772                                         da32[1];
1773                                 ml->acl_delete.field_value[6].mask_range.u32 =
1774                                         da32_depth[1];
1775                                 ml->acl_delete.field_value[7].value.u32 =
1776                                         da32[2];
1777                                 ml->acl_delete.field_value[7].mask_range.u32 =
1778                                         da32_depth[2];
1779                                 ml->acl_delete.field_value[8].value.u32 =
1780                                         da32[3];
1781                                 ml->acl_delete.field_value[8].mask_range.u32 =
1782                                         da32_depth[3];
1783
1784                                 ml->acl_delete.field_value[9].value.u16 =
1785                                         mh->match.acl.sp0;
1786                                 ml->acl_delete.field_value[9].mask_range.u16 =
1787                                         mh->match.acl.sp1;
1788
1789                                 ml->acl_delete.field_value[10].value.u16 =
1790                                         mh->match.acl.dp0;
1791                                 ml->acl_delete.field_value[10].mask_range.u16 =
1792                                         mh->match.acl.dp1;
1793                         }
1794                 return 0;
1795
1796         case TABLE_ARRAY:
1797                 ml->array.pos = mh->match.array.pos;
1798                 return 0;
1799
1800         case TABLE_HASH:
1801                 memcpy(ml->hash, mh->match.hash.key, sizeof(ml->hash));
1802                 return 0;
1803
1804         case TABLE_LPM:
1805                 if (mh->match.lpm.ip_version) {
1806                         ml->lpm_ipv4.ip = mh->match.lpm.ipv4;
1807                         ml->lpm_ipv4.depth = mh->match.lpm.depth;
1808                 } else {
1809                         memcpy(ml->lpm_ipv6.ip,
1810                                 mh->match.lpm.ipv6, sizeof(ml->lpm_ipv6.ip));
1811                         ml->lpm_ipv6.depth = mh->match.lpm.depth;
1812                 }
1813
1814                 return 0;
1815
1816         default:
1817                 return -1;
1818         }
1819 }
1820
1821 static struct pipeline_msg_rsp *
1822 pipeline_msg_handle_table_rule_add(struct pipeline_data *p,
1823         struct pipeline_msg_req *req)
1824 {
1825         union table_rule_match_low_level match_ll;
1826         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
1827         struct table_rule_match *match = &req->table_rule_add.match;
1828         struct table_rule_action *action = &req->table_rule_add.action;
1829         struct rte_pipeline_table_entry *data_in, *data_out;
1830         uint32_t table_id = req->id;
1831         int key_found, status;
1832         struct rte_table_action *a = p->table_data[table_id].a;
1833
1834         /* Apply actions */
1835         memset(p->buffer, 0, sizeof(p->buffer));
1836         data_in = (struct rte_pipeline_table_entry *) p->buffer;
1837
1838         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
1839                 status = rte_table_action_apply(a,
1840                         data_in,
1841                         RTE_TABLE_ACTION_FWD,
1842                         &action->fwd);
1843
1844                 if (status) {
1845                         rsp->status = -1;
1846                         return rsp;
1847                 }
1848         }
1849
1850         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
1851                 status = rte_table_action_apply(a,
1852                         data_in,
1853                         RTE_TABLE_ACTION_MTR,
1854                         &action->mtr);
1855
1856                 if (status) {
1857                         rsp->status = -1;
1858                         return rsp;
1859                 }
1860         }
1861
1862         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
1863                 status = rte_table_action_apply(a,
1864                         data_in,
1865                         RTE_TABLE_ACTION_TM,
1866                         &action->tm);
1867
1868                 if (status) {
1869                         rsp->status = -1;
1870                         return rsp;
1871                 }
1872         }
1873
1874         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
1875                 status = rte_table_action_apply(a,
1876                         data_in,
1877                         RTE_TABLE_ACTION_ENCAP,
1878                         &action->encap);
1879
1880                 if (status) {
1881                         rsp->status = -1;
1882                         return rsp;
1883                 }
1884         }
1885
1886         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
1887                 status = rte_table_action_apply(a,
1888                         data_in,
1889                         RTE_TABLE_ACTION_NAT,
1890                         &action->nat);
1891
1892                 if (status) {
1893                         rsp->status = -1;
1894                         return rsp;
1895                 }
1896         }
1897
1898         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
1899                 status = rte_table_action_apply(a,
1900                         data_in,
1901                         RTE_TABLE_ACTION_TTL,
1902                         &action->ttl);
1903
1904                 if (status) {
1905                         rsp->status = -1;
1906                         return rsp;
1907                 }
1908         }
1909
1910         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
1911                 status = rte_table_action_apply(a,
1912                         data_in,
1913                         RTE_TABLE_ACTION_STATS,
1914                         &action->stats);
1915
1916                 if (status) {
1917                         rsp->status = -1;
1918                         return rsp;
1919                 }
1920         }
1921
1922         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
1923                 status = rte_table_action_apply(a,
1924                         data_in,
1925                         RTE_TABLE_ACTION_TIME,
1926                         &action->time);
1927
1928                 if (status) {
1929                         rsp->status = -1;
1930                         return rsp;
1931                 }
1932         }
1933
1934         /* Add rule (match, action) to table */
1935         status = match_convert(match, &match_ll, 1);
1936         if (status) {
1937                 rsp->status = -1;
1938                 return rsp;
1939         }
1940
1941         status = rte_pipeline_table_entry_add(p->p,
1942                 table_id,
1943                 &match_ll,
1944                 data_in,
1945                 &key_found,
1946                 &data_out);
1947         if (status) {
1948                 rsp->status = -1;
1949                 return rsp;
1950         }
1951
1952         /* Write response */
1953         rsp->status = 0;
1954         rsp->table_rule_add.data = data_out;
1955
1956         return rsp;
1957 }
1958
1959 static struct pipeline_msg_rsp *
1960 pipeline_msg_handle_table_rule_add_default(struct pipeline_data *p,
1961         struct pipeline_msg_req *req)
1962 {
1963         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
1964         struct table_rule_action *action = &req->table_rule_add_default.action;
1965         struct rte_pipeline_table_entry *data_in, *data_out;
1966         uint32_t table_id = req->id;
1967         int status;
1968
1969         /* Apply actions */
1970         memset(p->buffer, 0, sizeof(p->buffer));
1971         data_in = (struct rte_pipeline_table_entry *) p->buffer;
1972
1973         data_in->action = action->fwd.action;
1974         if (action->fwd.action == RTE_PIPELINE_ACTION_PORT)
1975                 data_in->port_id = action->fwd.id;
1976         if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE)
1977                 data_in->table_id = action->fwd.id;
1978
1979         /* Add default rule to table */
1980         status = rte_pipeline_table_default_entry_add(p->p,
1981                 table_id,
1982                 data_in,
1983                 &data_out);
1984         if (status) {
1985                 rsp->status = -1;
1986                 return rsp;
1987         }
1988
1989         /* Write response */
1990         rsp->status = 0;
1991         rsp->table_rule_add_default.data = data_out;
1992
1993         return rsp;
1994 }
1995
1996 static struct pipeline_msg_rsp *
1997 pipeline_msg_handle_table_rule_add_bulk(struct pipeline_data *p,
1998         struct pipeline_msg_req *req)
1999 {
2000
2001         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2002
2003         uint32_t table_id = req->id;
2004         struct table_rule_match *match = req->table_rule_add_bulk.match;
2005         struct table_rule_action *action = req->table_rule_add_bulk.action;
2006         struct rte_pipeline_table_entry **data =
2007                 (struct rte_pipeline_table_entry **)req->table_rule_add_bulk.data;
2008         uint32_t n_rules = req->table_rule_add_bulk.n_rules;
2009         uint32_t bulk = req->table_rule_add_bulk.bulk;
2010
2011         struct rte_table_action *a = p->table_data[table_id].a;
2012         union table_rule_match_low_level *match_ll;
2013         uint8_t *action_ll;
2014         void **match_ll_ptr;
2015         struct rte_pipeline_table_entry **action_ll_ptr;
2016         int *found, status;
2017         uint32_t i;
2018
2019         /* Memory allocation */
2020         match_ll = calloc(n_rules, sizeof(union table_rule_match_low_level));
2021         action_ll = calloc(n_rules, TABLE_RULE_ACTION_SIZE_MAX);
2022         match_ll_ptr = calloc(n_rules, sizeof(void *));
2023         action_ll_ptr =
2024                 calloc(n_rules, sizeof(struct rte_pipeline_table_entry *));
2025         found = calloc(n_rules, sizeof(int));
2026
2027         if ((match_ll == NULL) ||
2028                 (action_ll == NULL) ||
2029                 (match_ll_ptr == NULL) ||
2030                 (action_ll_ptr == NULL) ||
2031                 (found == NULL))
2032                 goto fail;
2033
2034         for (i = 0; i < n_rules; i++) {
2035                 match_ll_ptr[i] = (void *)&match_ll[i];
2036                 action_ll_ptr[i] =
2037                         (struct rte_pipeline_table_entry *)&action_ll[i * TABLE_RULE_ACTION_SIZE_MAX];
2038         }
2039
2040         /* Rule match conversion */
2041         for (i = 0; i < n_rules; i++) {
2042                 status = match_convert(&match[i], match_ll_ptr[i], 1);
2043                 if (status)
2044                         goto fail;
2045         }
2046
2047         /* Rule action conversion */
2048         for (i = 0; i < n_rules; i++) {
2049                 void *data_in = action_ll_ptr[i];
2050                 struct table_rule_action *act = &action[i];
2051
2052                 if (act->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
2053                         status = rte_table_action_apply(a,
2054                                 data_in,
2055                                 RTE_TABLE_ACTION_FWD,
2056                                 &act->fwd);
2057
2058                         if (status)
2059                                 goto fail;
2060                 }
2061
2062                 if (act->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
2063                         status = rte_table_action_apply(a,
2064                                 data_in,
2065                                 RTE_TABLE_ACTION_MTR,
2066                                 &act->mtr);
2067
2068                         if (status)
2069                                 goto fail;
2070                 }
2071
2072                 if (act->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
2073                         status = rte_table_action_apply(a,
2074                                 data_in,
2075                                 RTE_TABLE_ACTION_TM,
2076                                 &act->tm);
2077
2078                         if (status)
2079                                 goto fail;
2080                 }
2081
2082                 if (act->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
2083                         status = rte_table_action_apply(a,
2084                                 data_in,
2085                                 RTE_TABLE_ACTION_ENCAP,
2086                                 &act->encap);
2087
2088                         if (status)
2089                                 goto fail;
2090                 }
2091
2092                 if (act->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
2093                         status = rte_table_action_apply(a,
2094                                 data_in,
2095                                 RTE_TABLE_ACTION_NAT,
2096                                 &act->nat);
2097
2098                         if (status)
2099                                 goto fail;
2100                 }
2101
2102                 if (act->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
2103                         status = rte_table_action_apply(a,
2104                                 data_in,
2105                                 RTE_TABLE_ACTION_TTL,
2106                                 &act->ttl);
2107
2108                         if (status)
2109                                 goto fail;
2110                 }
2111
2112                 if (act->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
2113                         status = rte_table_action_apply(a,
2114                                 data_in,
2115                                 RTE_TABLE_ACTION_STATS,
2116                                 &act->stats);
2117
2118                         if (status)
2119                                 goto fail;
2120                 }
2121
2122                 if (act->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
2123                         status = rte_table_action_apply(a,
2124                                 data_in,
2125                                 RTE_TABLE_ACTION_TIME,
2126                                 &act->time);
2127
2128                         if (status)
2129                                 goto fail;
2130                 }
2131         }
2132
2133         /* Add rule (match, action) to table */
2134         if (bulk) {
2135                 status = rte_pipeline_table_entry_add_bulk(p->p,
2136                         table_id,
2137                         match_ll_ptr,
2138                         action_ll_ptr,
2139                         n_rules,
2140                         found,
2141                         data);
2142                 if (status)
2143                         n_rules = 0;
2144         } else
2145                 for (i = 0; i < n_rules; i++) {
2146                         status = rte_pipeline_table_entry_add(p->p,
2147                                 table_id,
2148                                 match_ll_ptr[i],
2149                                 action_ll_ptr[i],
2150                                 &found[i],
2151                                 &data[i]);
2152                         if (status) {
2153                                 n_rules = i;
2154                                 break;
2155                         }
2156                 }
2157
2158         /* Write response */
2159         rsp->status = 0;
2160         rsp->table_rule_add_bulk.n_rules = n_rules;
2161
2162         /* Free */
2163         free(found);
2164         free(action_ll_ptr);
2165         free(match_ll_ptr);
2166         free(action_ll);
2167         free(match_ll);
2168
2169         return rsp;
2170
2171 fail:
2172         free(found);
2173         free(action_ll_ptr);
2174         free(match_ll_ptr);
2175         free(action_ll);
2176         free(match_ll);
2177
2178         rsp->status = -1;
2179         rsp->table_rule_add_bulk.n_rules = 0;
2180         return rsp;
2181 }
2182
2183 static struct pipeline_msg_rsp *
2184 pipeline_msg_handle_table_rule_delete(struct pipeline_data *p,
2185         struct pipeline_msg_req *req)
2186 {
2187         union table_rule_match_low_level match_ll;
2188         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2189         struct table_rule_match *match = &req->table_rule_delete.match;
2190         uint32_t table_id = req->id;
2191         int key_found, status;
2192
2193         status = match_convert(match, &match_ll, 0);
2194         if (status) {
2195                 rsp->status = -1;
2196                 return rsp;
2197         }
2198
2199         rsp->status = rte_pipeline_table_entry_delete(p->p,
2200                 table_id,
2201                 &match_ll,
2202                 &key_found,
2203                 NULL);
2204
2205         return rsp;
2206 }
2207
2208 static struct pipeline_msg_rsp *
2209 pipeline_msg_handle_table_rule_delete_default(struct pipeline_data *p,
2210         struct pipeline_msg_req *req)
2211 {
2212         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2213         uint32_t table_id = req->id;
2214
2215         rsp->status = rte_pipeline_table_default_entry_delete(p->p,
2216                 table_id,
2217                 NULL);
2218
2219         return rsp;
2220 }
2221
2222 static struct pipeline_msg_rsp *
2223 pipeline_msg_handle_table_rule_stats_read(struct pipeline_data *p,
2224         struct pipeline_msg_req *req)
2225 {
2226         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2227         uint32_t table_id = req->id;
2228         void *data = req->table_rule_stats_read.data;
2229         int clear = req->table_rule_stats_read.clear;
2230         struct rte_table_action *a = p->table_data[table_id].a;
2231
2232         rsp->status = rte_table_action_stats_read(a,
2233                 data,
2234                 &rsp->table_rule_stats_read.stats,
2235                 clear);
2236
2237         return rsp;
2238 }
2239
2240 static struct pipeline_msg_rsp *
2241 pipeline_msg_handle_table_mtr_profile_add(struct pipeline_data *p,
2242         struct pipeline_msg_req *req)
2243 {
2244         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2245         uint32_t table_id = req->id;
2246         uint32_t meter_profile_id = req->table_mtr_profile_add.meter_profile_id;
2247         struct rte_table_action_meter_profile *profile =
2248                 &req->table_mtr_profile_add.profile;
2249         struct rte_table_action *a = p->table_data[table_id].a;
2250
2251         rsp->status = rte_table_action_meter_profile_add(a,
2252                 meter_profile_id,
2253                 profile);
2254
2255         return rsp;
2256 }
2257
2258 static struct pipeline_msg_rsp *
2259 pipeline_msg_handle_table_mtr_profile_delete(struct pipeline_data *p,
2260         struct pipeline_msg_req *req)
2261 {
2262         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
2263         uint32_t table_id = req->id;
2264         uint32_t meter_profile_id =
2265                 req->table_mtr_profile_delete.meter_profile_id;
2266         struct rte_table_action *a = p->table_data[table_id].a;
2267
2268         rsp->status = rte_table_action_meter_profile_delete(a,
2269                 meter_profile_id);
2270
2271         return rsp;
2272 }
2273
2274 static void
2275 pipeline_msg_handle(struct pipeline_data *p)
2276 {
2277         for ( ; ; ) {
2278                 struct pipeline_msg_req *req;
2279                 struct pipeline_msg_rsp *rsp;
2280
2281                 req = pipeline_msg_recv(p->msgq_req);
2282                 if (req == NULL)
2283                         break;
2284
2285                 switch (req->type) {
2286                 case PIPELINE_REQ_PORT_IN_STATS_READ:
2287                         rsp = pipeline_msg_handle_port_in_stats_read(p, req);
2288                         break;
2289
2290                 case PIPELINE_REQ_PORT_IN_ENABLE:
2291                         rsp = pipeline_msg_handle_port_in_enable(p, req);
2292                         break;
2293
2294                 case PIPELINE_REQ_PORT_IN_DISABLE:
2295                         rsp = pipeline_msg_handle_port_in_disable(p, req);
2296                         break;
2297
2298                 case PIPELINE_REQ_PORT_OUT_STATS_READ:
2299                         rsp = pipeline_msg_handle_port_out_stats_read(p, req);
2300                         break;
2301
2302                 case PIPELINE_REQ_TABLE_STATS_READ:
2303                         rsp = pipeline_msg_handle_table_stats_read(p, req);
2304                         break;
2305
2306                 case PIPELINE_REQ_TABLE_RULE_ADD:
2307                         rsp = pipeline_msg_handle_table_rule_add(p, req);
2308                         break;
2309
2310                 case PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT:
2311                         rsp = pipeline_msg_handle_table_rule_add_default(p,     req);
2312                         break;
2313
2314                 case PIPELINE_REQ_TABLE_RULE_ADD_BULK:
2315                         rsp = pipeline_msg_handle_table_rule_add_bulk(p, req);
2316                         break;
2317
2318                 case PIPELINE_REQ_TABLE_RULE_DELETE:
2319                         rsp = pipeline_msg_handle_table_rule_delete(p, req);
2320                         break;
2321
2322                 case PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT:
2323                         rsp = pipeline_msg_handle_table_rule_delete_default(p, req);
2324                         break;
2325
2326                 case PIPELINE_REQ_TABLE_RULE_STATS_READ:
2327                         rsp = pipeline_msg_handle_table_rule_stats_read(p, req);
2328                         break;
2329
2330                 case PIPELINE_REQ_TABLE_MTR_PROFILE_ADD:
2331                         rsp = pipeline_msg_handle_table_mtr_profile_add(p, req);
2332                         break;
2333
2334                 case PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE:
2335                         rsp = pipeline_msg_handle_table_mtr_profile_delete(p, req);
2336                         break;
2337
2338                 default:
2339                         rsp = (struct pipeline_msg_rsp *) req;
2340                         rsp->status = -1;
2341                 }
2342
2343                 pipeline_msg_send(p->msgq_rsp, rsp);
2344         }
2345 }
2346
2347 /**
2348  * Data plane threads: main
2349  */
2350 int
2351 thread_main(void *arg __rte_unused)
2352 {
2353         struct thread_data *t;
2354         uint32_t thread_id, i;
2355
2356         thread_id = rte_lcore_id();
2357         t = &thread_data[thread_id];
2358
2359         /* Dispatch loop */
2360         for (i = 0; ; i++) {
2361                 uint32_t j;
2362
2363                 /* Data Plane */
2364                 for (j = 0; j < t->n_pipelines; j++)
2365                         rte_pipeline_run(t->p[j]);
2366
2367                 /* Control Plane */
2368                 if ((i & 0xF) == 0) {
2369                         uint64_t time = rte_get_tsc_cycles();
2370                         uint64_t time_next_min = UINT64_MAX;
2371
2372                         if (time < t->time_next_min)
2373                                 continue;
2374
2375                         /* Pipeline message queues */
2376                         for (j = 0; j < t->n_pipelines; j++) {
2377                                 struct pipeline_data *p =
2378                                         &t->pipeline_data[j];
2379                                 uint64_t time_next = p->time_next;
2380
2381                                 if (time_next <= time) {
2382                                         pipeline_msg_handle(p);
2383                                         rte_pipeline_flush(p->p);
2384                                         time_next = time + p->timer_period;
2385                                         p->time_next = time_next;
2386                                 }
2387
2388                                 if (time_next < time_next_min)
2389                                         time_next_min = time_next;
2390                         }
2391
2392                         /* Thread message queues */
2393                         {
2394                                 uint64_t time_next = t->time_next;
2395
2396                                 if (time_next <= time) {
2397                                         thread_msg_handle(t);
2398                                         time_next = time + t->timer_period;
2399                                         t->time_next = time_next;
2400                                 }
2401
2402                                 if (time_next < time_next_min)
2403                                         time_next_min = time_next;
2404                         }
2405
2406                         t->time_next_min = time_next_min;
2407                 }
2408         }
2409
2410         return 0;
2411 }