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