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