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