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