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