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