net/avp: remove resources when port is closed
[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_service_component.h>
11 #include <rte_ring.h>
12
13 #include <rte_table_acl.h>
14 #include <rte_table_array.h>
15 #include <rte_table_hash.h>
16 #include <rte_table_lpm.h>
17 #include <rte_table_lpm_ipv6.h>
18 #include "rte_eth_softnic_internals.h"
19
20 /**
21  * Master thread: data plane thread init
22  */
23 void
24 softnic_thread_free(struct pmd_internals *softnic)
25 {
26         uint32_t i;
27
28         RTE_LCORE_FOREACH_SLAVE(i) {
29                 struct softnic_thread *t = &softnic->thread[i];
30
31                 /* MSGQs */
32                 if (t->msgq_req)
33                         rte_ring_free(t->msgq_req);
34
35                 if (t->msgq_rsp)
36                         rte_ring_free(t->msgq_rsp);
37         }
38 }
39
40 int
41 softnic_thread_init(struct pmd_internals *softnic)
42 {
43         uint32_t i;
44
45         for (i = 0; i < RTE_MAX_LCORE; i++) {
46                 char ring_name[NAME_MAX];
47                 struct rte_ring *msgq_req, *msgq_rsp;
48                 struct softnic_thread *t = &softnic->thread[i];
49                 struct softnic_thread_data *t_data = &softnic->thread_data[i];
50                 uint32_t cpu_id = rte_lcore_to_socket_id(i);
51
52                 /* MSGQs */
53                 snprintf(ring_name, sizeof(ring_name), "%s-TH%u-REQ",
54                         softnic->params.name,
55                         i);
56
57                 msgq_req = rte_ring_create(ring_name,
58                         THREAD_MSGQ_SIZE,
59                         cpu_id,
60                         RING_F_SP_ENQ | RING_F_SC_DEQ);
61
62                 if (msgq_req == NULL) {
63                         softnic_thread_free(softnic);
64                         return -1;
65                 }
66
67                 snprintf(ring_name, sizeof(ring_name), "%s-TH%u-RSP",
68                         softnic->params.name,
69                         i);
70
71                 msgq_rsp = rte_ring_create(ring_name,
72                         THREAD_MSGQ_SIZE,
73                         cpu_id,
74                         RING_F_SP_ENQ | RING_F_SC_DEQ);
75
76                 if (msgq_rsp == NULL) {
77                         softnic_thread_free(softnic);
78                         return -1;
79                 }
80
81                 /* Master thread records */
82                 t->msgq_req = msgq_req;
83                 t->msgq_rsp = msgq_rsp;
84                 t->service_id = UINT32_MAX;
85
86                 /* Data plane thread records */
87                 t_data->n_pipelines = 0;
88                 t_data->msgq_req = msgq_req;
89                 t_data->msgq_rsp = msgq_rsp;
90                 t_data->timer_period =
91                         (rte_get_tsc_hz() * THREAD_TIMER_PERIOD_MS) / 1000;
92                 t_data->time_next = rte_get_tsc_cycles() + t_data->timer_period;
93                 t_data->time_next_min = t_data->time_next;
94         }
95
96         return 0;
97 }
98
99 static inline int
100 thread_is_valid(struct pmd_internals *softnic, uint32_t thread_id)
101 {
102         if (thread_id == rte_get_master_lcore())
103                 return 0; /* FALSE */
104
105         if (softnic->params.sc && rte_lcore_has_role(thread_id, ROLE_SERVICE))
106                 return 1; /* TRUE */
107         if (!softnic->params.sc && rte_lcore_has_role(thread_id, ROLE_RTE))
108                 return 1; /* TRUE */
109
110         return 0; /* FALSE */
111 }
112
113 static inline int
114 thread_is_running(uint32_t thread_id)
115 {
116         enum rte_lcore_state_t thread_state;
117
118         thread_state = rte_eal_get_lcore_state(thread_id);
119         return (thread_state == RUNNING)? 1 : 0;
120 }
121
122 static int32_t
123 rte_pmd_softnic_run_internal(void *arg);
124
125 static inline int
126 thread_sc_service_up(struct pmd_internals *softnic, uint32_t thread_id)
127 {
128         struct rte_service_spec service_params;
129         struct softnic_thread *t = &softnic->thread[thread_id];
130         struct rte_eth_dev *dev;
131         int status;
132         uint16_t port_id;
133
134         /* service params */
135         status = rte_eth_dev_get_port_by_name(softnic->params.name, &port_id);
136         if (status)
137                 return status;
138
139         dev = &rte_eth_devices[port_id];
140         snprintf(service_params.name, sizeof(service_params.name), "%s_%u",
141                 softnic->params.name,
142                 thread_id);
143         service_params.callback = rte_pmd_softnic_run_internal;
144         service_params.callback_userdata = dev;
145         service_params.capabilities = 0;
146         service_params.socket_id = (int)softnic->params.cpu_id;
147
148         /* service register */
149         status = rte_service_component_register(&service_params, &t->service_id);
150         if (status)
151                 return status;
152
153         status = rte_service_component_runstate_set(t->service_id, 1);
154         if (status) {
155                 rte_service_component_unregister(t->service_id);
156                 t->service_id = UINT32_MAX;
157                 return status;
158         }
159
160         status = rte_service_runstate_set(t->service_id, 1);
161         if (status) {
162                 rte_service_component_runstate_set(t->service_id, 0);
163                 rte_service_component_unregister(t->service_id);
164                 t->service_id = UINT32_MAX;
165                 return status;
166         }
167
168         /* service map to thread */
169         status = rte_service_map_lcore_set(t->service_id, thread_id, 1);
170         if (status) {
171                 rte_service_runstate_set(t->service_id, 0);
172                 rte_service_component_runstate_set(t->service_id, 0);
173                 rte_service_component_unregister(t->service_id);
174                 t->service_id = UINT32_MAX;
175                 return status;
176         }
177
178         return 0;
179 }
180
181 static inline void
182 thread_sc_service_down(struct pmd_internals *softnic, uint32_t thread_id)
183 {
184         struct softnic_thread *t = &softnic->thread[thread_id];
185
186         /* service unmap from thread */
187         rte_service_map_lcore_set(t->service_id, thread_id, 0);
188
189         /* service unregister */
190         rte_service_runstate_set(t->service_id, 0);
191         rte_service_component_runstate_set(t->service_id, 0);
192         rte_service_component_unregister(t->service_id);
193
194         t->service_id = UINT32_MAX;
195 }
196
197 /**
198  * Pipeline is running when:
199  *    (A) Pipeline is mapped to a data plane thread AND
200  *    (B) Its data plane thread is in RUNNING state.
201  */
202 static inline int
203 pipeline_is_running(struct pipeline *p)
204 {
205         if (p->enabled == 0)
206                 return 0;
207
208         return thread_is_running(p->thread_id);
209 }
210
211 /**
212  * Master thread & data plane threads: message passing
213  */
214 enum thread_req_type {
215         THREAD_REQ_PIPELINE_ENABLE = 0,
216         THREAD_REQ_PIPELINE_DISABLE,
217         THREAD_REQ_MAX
218 };
219
220 struct thread_msg_req {
221         enum thread_req_type type;
222
223         union {
224                 struct {
225                         struct rte_pipeline *p;
226                         struct {
227                                 struct rte_table_action *a;
228                         } table[RTE_PIPELINE_TABLE_MAX];
229                         struct rte_ring *msgq_req;
230                         struct rte_ring *msgq_rsp;
231                         uint32_t timer_period_ms;
232                         uint32_t n_tables;
233                 } pipeline_enable;
234
235                 struct {
236                         struct rte_pipeline *p;
237                 } pipeline_disable;
238         };
239 };
240
241 struct thread_msg_rsp {
242         int status;
243 };
244
245 /**
246  * Master thread
247  */
248 static struct thread_msg_req *
249 thread_msg_alloc(void)
250 {
251         size_t size = RTE_MAX(sizeof(struct thread_msg_req),
252                 sizeof(struct thread_msg_rsp));
253
254         return calloc(1, size);
255 }
256
257 static void
258 thread_msg_free(struct thread_msg_rsp *rsp)
259 {
260         free(rsp);
261 }
262
263 static struct thread_msg_rsp *
264 thread_msg_send_recv(struct pmd_internals *softnic,
265         uint32_t thread_id,
266         struct thread_msg_req *req)
267 {
268         struct softnic_thread *t = &softnic->thread[thread_id];
269         struct rte_ring *msgq_req = t->msgq_req;
270         struct rte_ring *msgq_rsp = t->msgq_rsp;
271         struct thread_msg_rsp *rsp;
272         int status;
273
274         /* send */
275         do {
276                 status = rte_ring_sp_enqueue(msgq_req, req);
277         } while (status == -ENOBUFS);
278
279         /* recv */
280         do {
281                 status = rte_ring_sc_dequeue(msgq_rsp, (void **)&rsp);
282         } while (status != 0);
283
284         return rsp;
285 }
286
287 int
288 softnic_thread_pipeline_enable(struct pmd_internals *softnic,
289         uint32_t thread_id,
290         const char *pipeline_name)
291 {
292         struct pipeline *p = softnic_pipeline_find(softnic, pipeline_name);
293         struct thread_msg_req *req;
294         struct thread_msg_rsp *rsp;
295         uint32_t n_pipelines, i;
296         int status;
297
298         /* Check input params */
299         if (!thread_is_valid(softnic, thread_id) ||
300                 (p == NULL) ||
301                 (p->n_ports_in == 0) ||
302                 (p->n_ports_out == 0) ||
303                 (p->n_tables == 0) ||
304                 p->enabled)
305                 return -1;
306
307         n_pipelines = softnic_pipeline_thread_count(softnic, thread_id);
308         if (n_pipelines >= THREAD_PIPELINES_MAX)
309                 return -1;
310
311         if (softnic->params.sc && (n_pipelines == 0)) {
312                 status = thread_sc_service_up(softnic, thread_id);
313                 if (status)
314                         return status;
315         }
316
317         if (!thread_is_running(thread_id)) {
318                 struct softnic_thread_data *td = &softnic->thread_data[thread_id];
319                 struct pipeline_data *tdp = &td->pipeline_data[td->n_pipelines];
320
321                 /* Data plane thread */
322                 td->p[td->n_pipelines] = p->p;
323
324                 tdp->p = p->p;
325                 for (i = 0; i < p->n_tables; i++)
326                         tdp->table_data[i].a =
327                                 p->table[i].a;
328                 tdp->n_tables = p->n_tables;
329
330                 tdp->msgq_req = p->msgq_req;
331                 tdp->msgq_rsp = p->msgq_rsp;
332                 tdp->timer_period = (rte_get_tsc_hz() * p->timer_period_ms) / 1000;
333                 tdp->time_next = rte_get_tsc_cycles() + tdp->timer_period;
334
335                 td->n_pipelines++;
336
337                 /* Pipeline */
338                 p->thread_id = thread_id;
339                 p->enabled = 1;
340
341                 return 0;
342         }
343
344         /* Allocate request */
345         req = thread_msg_alloc();
346         if (req == NULL)
347                 return -1;
348
349         /* Write request */
350         req->type = THREAD_REQ_PIPELINE_ENABLE;
351         req->pipeline_enable.p = p->p;
352         for (i = 0; i < p->n_tables; i++)
353                 req->pipeline_enable.table[i].a =
354                         p->table[i].a;
355         req->pipeline_enable.msgq_req = p->msgq_req;
356         req->pipeline_enable.msgq_rsp = p->msgq_rsp;
357         req->pipeline_enable.timer_period_ms = p->timer_period_ms;
358         req->pipeline_enable.n_tables = p->n_tables;
359
360         /* Send request and wait for response */
361         rsp = thread_msg_send_recv(softnic, thread_id, req);
362         if (rsp == NULL)
363                 return -1;
364
365         /* Read response */
366         status = rsp->status;
367
368         /* Free response */
369         thread_msg_free(rsp);
370
371         /* Request completion */
372         if (status)
373                 return status;
374
375         p->thread_id = thread_id;
376         p->enabled = 1;
377
378         return 0;
379 }
380
381 int
382 softnic_thread_pipeline_disable(struct pmd_internals *softnic,
383         uint32_t thread_id,
384         const char *pipeline_name)
385 {
386         struct pipeline *p = softnic_pipeline_find(softnic, pipeline_name);
387         struct thread_msg_req *req;
388         struct thread_msg_rsp *rsp;
389         uint32_t n_pipelines;
390         int status;
391
392         /* Check input params */
393         if (!thread_is_valid(softnic, thread_id) ||
394                 (p == NULL) ||
395                 (p->enabled && (p->thread_id != thread_id)))
396                 return -1;
397
398         if (p->enabled == 0)
399                 return 0;
400
401         if (!thread_is_running(thread_id)) {
402                 struct softnic_thread_data *td = &softnic->thread_data[thread_id];
403                 uint32_t i;
404
405                 for (i = 0; i < td->n_pipelines; i++) {
406                         struct pipeline_data *tdp = &td->pipeline_data[i];
407
408                         if (tdp->p != p->p)
409                                 continue;
410
411                         /* Data plane thread */
412                         if (i < td->n_pipelines - 1) {
413                                 struct rte_pipeline *pipeline_last =
414                                         td->p[td->n_pipelines - 1];
415                                 struct pipeline_data *tdp_last =
416                                         &td->pipeline_data[td->n_pipelines - 1];
417
418                                 td->p[i] = pipeline_last;
419                                 memcpy(tdp, tdp_last, sizeof(*tdp));
420                         }
421
422                         td->n_pipelines--;
423
424                         /* Pipeline */
425                         p->enabled = 0;
426
427                         break;
428                 }
429
430                 if (softnic->params.sc && (td->n_pipelines == 0))
431                         thread_sc_service_down(softnic, thread_id);
432
433                 return 0;
434         }
435
436         /* Allocate request */
437         req = thread_msg_alloc();
438         if (req == NULL)
439                 return -1;
440
441         /* Write request */
442         req->type = THREAD_REQ_PIPELINE_DISABLE;
443         req->pipeline_disable.p = p->p;
444
445         /* Send request and wait for response */
446         rsp = thread_msg_send_recv(softnic, thread_id, req);
447         if (rsp == NULL)
448                 return -1;
449
450         /* Read response */
451         status = rsp->status;
452
453         /* Free response */
454         thread_msg_free(rsp);
455
456         /* Request completion */
457         if (status)
458                 return status;
459
460         p->enabled = 0;
461
462         n_pipelines = softnic_pipeline_thread_count(softnic, thread_id);
463         if (softnic->params.sc && (n_pipelines == 0))
464                 thread_sc_service_down(softnic, thread_id);
465
466         return 0;
467 }
468
469 /**
470  * Data plane threads: message handling
471  */
472 static inline struct thread_msg_req *
473 thread_msg_recv(struct rte_ring *msgq_req)
474 {
475         struct thread_msg_req *req;
476
477         int status = rte_ring_sc_dequeue(msgq_req, (void **)&req);
478
479         if (status != 0)
480                 return NULL;
481
482         return req;
483 }
484
485 static inline void
486 thread_msg_send(struct rte_ring *msgq_rsp,
487         struct thread_msg_rsp *rsp)
488 {
489         int status;
490
491         do {
492                 status = rte_ring_sp_enqueue(msgq_rsp, rsp);
493         } while (status == -ENOBUFS);
494 }
495
496 static struct thread_msg_rsp *
497 thread_msg_handle_pipeline_enable(struct softnic_thread_data *t,
498         struct thread_msg_req *req)
499 {
500         struct thread_msg_rsp *rsp = (struct thread_msg_rsp *)req;
501         struct pipeline_data *p = &t->pipeline_data[t->n_pipelines];
502         uint32_t i;
503
504         /* Request */
505         t->p[t->n_pipelines] = req->pipeline_enable.p;
506
507         p->p = req->pipeline_enable.p;
508         for (i = 0; i < req->pipeline_enable.n_tables; i++)
509                 p->table_data[i].a =
510                         req->pipeline_enable.table[i].a;
511
512         p->n_tables = req->pipeline_enable.n_tables;
513
514         p->msgq_req = req->pipeline_enable.msgq_req;
515         p->msgq_rsp = req->pipeline_enable.msgq_rsp;
516         p->timer_period =
517                 (rte_get_tsc_hz() * req->pipeline_enable.timer_period_ms) / 1000;
518         p->time_next = rte_get_tsc_cycles() + p->timer_period;
519
520         t->n_pipelines++;
521
522         /* Response */
523         rsp->status = 0;
524         return rsp;
525 }
526
527 static struct thread_msg_rsp *
528 thread_msg_handle_pipeline_disable(struct softnic_thread_data *t,
529         struct thread_msg_req *req)
530 {
531         struct thread_msg_rsp *rsp = (struct thread_msg_rsp *)req;
532         uint32_t n_pipelines = t->n_pipelines;
533         struct rte_pipeline *pipeline = req->pipeline_disable.p;
534         uint32_t i;
535
536         /* find pipeline */
537         for (i = 0; i < n_pipelines; i++) {
538                 struct pipeline_data *p = &t->pipeline_data[i];
539
540                 if (p->p != pipeline)
541                         continue;
542
543                 if (i < n_pipelines - 1) {
544                         struct rte_pipeline *pipeline_last =
545                                 t->p[n_pipelines - 1];
546                         struct pipeline_data *p_last =
547                                 &t->pipeline_data[n_pipelines - 1];
548
549                         t->p[i] = pipeline_last;
550                         memcpy(p, p_last, sizeof(*p));
551                 }
552
553                 t->n_pipelines--;
554
555                 rsp->status = 0;
556                 return rsp;
557         }
558
559         /* should not get here */
560         rsp->status = 0;
561         return rsp;
562 }
563
564 static void
565 thread_msg_handle(struct softnic_thread_data *t)
566 {
567         for ( ; ; ) {
568                 struct thread_msg_req *req;
569                 struct thread_msg_rsp *rsp;
570
571                 req = thread_msg_recv(t->msgq_req);
572                 if (req == NULL)
573                         break;
574
575                 switch (req->type) {
576                 case THREAD_REQ_PIPELINE_ENABLE:
577                         rsp = thread_msg_handle_pipeline_enable(t, req);
578                         break;
579
580                 case THREAD_REQ_PIPELINE_DISABLE:
581                         rsp = thread_msg_handle_pipeline_disable(t, req);
582                         break;
583
584                 default:
585                         rsp = (struct thread_msg_rsp *)req;
586                         rsp->status = -1;
587                 }
588
589                 thread_msg_send(t->msgq_rsp, rsp);
590         }
591 }
592
593 /**
594  * Master thread & data plane threads: message passing
595  */
596 enum pipeline_req_type {
597         /* Port IN */
598         PIPELINE_REQ_PORT_IN_STATS_READ,
599         PIPELINE_REQ_PORT_IN_ENABLE,
600         PIPELINE_REQ_PORT_IN_DISABLE,
601
602         /* Port OUT */
603         PIPELINE_REQ_PORT_OUT_STATS_READ,
604
605         /* Table */
606         PIPELINE_REQ_TABLE_STATS_READ,
607         PIPELINE_REQ_TABLE_RULE_ADD,
608         PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT,
609         PIPELINE_REQ_TABLE_RULE_ADD_BULK,
610         PIPELINE_REQ_TABLE_RULE_DELETE,
611         PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT,
612         PIPELINE_REQ_TABLE_RULE_STATS_READ,
613         PIPELINE_REQ_TABLE_MTR_PROFILE_ADD,
614         PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
615         PIPELINE_REQ_TABLE_RULE_MTR_READ,
616         PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE,
617         PIPELINE_REQ_TABLE_RULE_TTL_READ,
618         PIPELINE_REQ_MAX
619 };
620
621 struct pipeline_msg_req_port_in_stats_read {
622         int clear;
623 };
624
625 struct pipeline_msg_req_port_out_stats_read {
626         int clear;
627 };
628
629 struct pipeline_msg_req_table_stats_read {
630         int clear;
631 };
632
633 struct pipeline_msg_req_table_rule_add {
634         struct softnic_table_rule_match match;
635         struct softnic_table_rule_action action;
636 };
637
638 struct pipeline_msg_req_table_rule_add_default {
639         struct softnic_table_rule_action action;
640 };
641
642 struct pipeline_msg_req_table_rule_add_bulk {
643         struct softnic_table_rule_match *match;
644         struct softnic_table_rule_action *action;
645         void **data;
646         uint32_t n_rules;
647         int bulk;
648 };
649
650 struct pipeline_msg_req_table_rule_delete {
651         struct softnic_table_rule_match match;
652 };
653
654 struct pipeline_msg_req_table_rule_stats_read {
655         void *data;
656         int clear;
657 };
658
659 struct pipeline_msg_req_table_mtr_profile_add {
660         uint32_t meter_profile_id;
661         struct rte_table_action_meter_profile profile;
662 };
663
664 struct pipeline_msg_req_table_mtr_profile_delete {
665         uint32_t meter_profile_id;
666 };
667
668 struct pipeline_msg_req_table_rule_mtr_read {
669         void *data;
670         uint32_t tc_mask;
671         int clear;
672 };
673
674 struct pipeline_msg_req_table_dscp_table_update {
675         uint64_t dscp_mask;
676         struct rte_table_action_dscp_table dscp_table;
677 };
678
679 struct pipeline_msg_req_table_rule_ttl_read {
680         void *data;
681         int clear;
682 };
683
684 struct pipeline_msg_req {
685         enum pipeline_req_type type;
686         uint32_t id; /* Port IN, port OUT or table ID */
687
688         RTE_STD_C11
689         union {
690                 struct pipeline_msg_req_port_in_stats_read port_in_stats_read;
691                 struct pipeline_msg_req_port_out_stats_read port_out_stats_read;
692                 struct pipeline_msg_req_table_stats_read table_stats_read;
693                 struct pipeline_msg_req_table_rule_add table_rule_add;
694                 struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
695                 struct pipeline_msg_req_table_rule_add_bulk table_rule_add_bulk;
696                 struct pipeline_msg_req_table_rule_delete table_rule_delete;
697                 struct pipeline_msg_req_table_rule_stats_read table_rule_stats_read;
698                 struct pipeline_msg_req_table_mtr_profile_add table_mtr_profile_add;
699                 struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
700                 struct pipeline_msg_req_table_rule_mtr_read table_rule_mtr_read;
701                 struct pipeline_msg_req_table_dscp_table_update table_dscp_table_update;
702                 struct pipeline_msg_req_table_rule_ttl_read table_rule_ttl_read;
703         };
704 };
705
706 struct pipeline_msg_rsp_port_in_stats_read {
707         struct rte_pipeline_port_in_stats stats;
708 };
709
710 struct pipeline_msg_rsp_port_out_stats_read {
711         struct rte_pipeline_port_out_stats stats;
712 };
713
714 struct pipeline_msg_rsp_table_stats_read {
715         struct rte_pipeline_table_stats stats;
716 };
717
718 struct pipeline_msg_rsp_table_rule_add {
719         void *data;
720 };
721
722 struct pipeline_msg_rsp_table_rule_add_default {
723         void *data;
724 };
725
726 struct pipeline_msg_rsp_table_rule_add_bulk {
727         uint32_t n_rules;
728 };
729
730 struct pipeline_msg_rsp_table_rule_stats_read {
731         struct rte_table_action_stats_counters stats;
732 };
733
734 struct pipeline_msg_rsp_table_rule_mtr_read {
735         struct rte_table_action_mtr_counters stats;
736 };
737
738 struct pipeline_msg_rsp_table_rule_ttl_read {
739         struct rte_table_action_ttl_counters stats;
740 };
741
742 struct pipeline_msg_rsp {
743         int status;
744
745         RTE_STD_C11
746         union {
747                 struct pipeline_msg_rsp_port_in_stats_read port_in_stats_read;
748                 struct pipeline_msg_rsp_port_out_stats_read port_out_stats_read;
749                 struct pipeline_msg_rsp_table_stats_read table_stats_read;
750                 struct pipeline_msg_rsp_table_rule_add table_rule_add;
751                 struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
752                 struct pipeline_msg_rsp_table_rule_add_bulk table_rule_add_bulk;
753                 struct pipeline_msg_rsp_table_rule_stats_read table_rule_stats_read;
754                 struct pipeline_msg_rsp_table_rule_mtr_read table_rule_mtr_read;
755                 struct pipeline_msg_rsp_table_rule_ttl_read table_rule_ttl_read;
756         };
757 };
758
759 /**
760  * Master thread
761  */
762 static struct pipeline_msg_req *
763 pipeline_msg_alloc(void)
764 {
765         size_t size = RTE_MAX(sizeof(struct pipeline_msg_req),
766                 sizeof(struct pipeline_msg_rsp));
767
768         return calloc(1, size);
769 }
770
771 static void
772 pipeline_msg_free(struct pipeline_msg_rsp *rsp)
773 {
774         free(rsp);
775 }
776
777 static struct pipeline_msg_rsp *
778 pipeline_msg_send_recv(struct pipeline *p,
779         struct pipeline_msg_req *req)
780 {
781         struct rte_ring *msgq_req = p->msgq_req;
782         struct rte_ring *msgq_rsp = p->msgq_rsp;
783         struct pipeline_msg_rsp *rsp;
784         int status;
785
786         /* send */
787         do {
788                 status = rte_ring_sp_enqueue(msgq_req, req);
789         } while (status == -ENOBUFS);
790
791         /* recv */
792         do {
793                 status = rte_ring_sc_dequeue(msgq_rsp, (void **)&rsp);
794         } while (status != 0);
795
796         return rsp;
797 }
798
799 int
800 softnic_pipeline_port_in_stats_read(struct pmd_internals *softnic,
801         const char *pipeline_name,
802         uint32_t port_id,
803         struct rte_pipeline_port_in_stats *stats,
804         int clear)
805 {
806         struct pipeline *p;
807         struct pipeline_msg_req *req;
808         struct pipeline_msg_rsp *rsp;
809         int status;
810
811         /* Check input params */
812         if (pipeline_name == NULL ||
813                 stats == NULL)
814                 return -1;
815
816         p = softnic_pipeline_find(softnic, pipeline_name);
817         if (p == NULL ||
818                 port_id >= p->n_ports_in)
819                 return -1;
820
821         if (!pipeline_is_running(p)) {
822                 status = rte_pipeline_port_in_stats_read(p->p,
823                         port_id,
824                         stats,
825                         clear);
826
827                 return status;
828         }
829
830         /* Allocate request */
831         req = pipeline_msg_alloc();
832         if (req == NULL)
833                 return -1;
834
835         /* Write request */
836         req->type = PIPELINE_REQ_PORT_IN_STATS_READ;
837         req->id = port_id;
838         req->port_in_stats_read.clear = clear;
839
840         /* Send request and wait for response */
841         rsp = pipeline_msg_send_recv(p, req);
842         if (rsp == NULL)
843                 return -1;
844
845         /* Read response */
846         status = rsp->status;
847         if (status)
848                 memcpy(stats, &rsp->port_in_stats_read.stats, sizeof(*stats));
849
850         /* Free response */
851         pipeline_msg_free(rsp);
852
853         return status;
854 }
855
856 int
857 softnic_pipeline_port_in_enable(struct pmd_internals *softnic,
858         const char *pipeline_name,
859         uint32_t port_id)
860 {
861         struct pipeline *p;
862         struct pipeline_msg_req *req;
863         struct pipeline_msg_rsp *rsp;
864         int status;
865
866         /* Check input params */
867         if (pipeline_name == NULL)
868                 return -1;
869
870         p = softnic_pipeline_find(softnic, pipeline_name);
871         if (p == NULL ||
872                 port_id >= p->n_ports_in)
873                 return -1;
874
875         if (!pipeline_is_running(p)) {
876                 status = rte_pipeline_port_in_enable(p->p, port_id);
877                 return status;
878         }
879
880         /* Allocate request */
881         req = pipeline_msg_alloc();
882         if (req == NULL)
883                 return -1;
884
885         /* Write request */
886         req->type = PIPELINE_REQ_PORT_IN_ENABLE;
887         req->id = port_id;
888
889         /* Send request and wait for response */
890         rsp = pipeline_msg_send_recv(p, req);
891         if (rsp == NULL)
892                 return -1;
893
894         /* Read response */
895         status = rsp->status;
896
897         /* Free response */
898         pipeline_msg_free(rsp);
899
900         return status;
901 }
902
903 int
904 softnic_pipeline_port_in_disable(struct pmd_internals *softnic,
905         const char *pipeline_name,
906         uint32_t port_id)
907 {
908         struct pipeline *p;
909         struct pipeline_msg_req *req;
910         struct pipeline_msg_rsp *rsp;
911         int status;
912
913         /* Check input params */
914         if (pipeline_name == NULL)
915                 return -1;
916
917         p = softnic_pipeline_find(softnic, pipeline_name);
918         if (p == NULL ||
919                 port_id >= p->n_ports_in)
920                 return -1;
921
922         if (!pipeline_is_running(p)) {
923                 status = rte_pipeline_port_in_disable(p->p, port_id);
924                 return status;
925         }
926
927         /* Allocate request */
928         req = pipeline_msg_alloc();
929         if (req == NULL)
930                 return -1;
931
932         /* Write request */
933         req->type = PIPELINE_REQ_PORT_IN_DISABLE;
934         req->id = port_id;
935
936         /* Send request and wait for response */
937         rsp = pipeline_msg_send_recv(p, req);
938         if (rsp == NULL)
939                 return -1;
940
941         /* Read response */
942         status = rsp->status;
943
944         /* Free response */
945         pipeline_msg_free(rsp);
946
947         return status;
948 }
949
950 int
951 softnic_pipeline_port_out_stats_read(struct pmd_internals *softnic,
952         const char *pipeline_name,
953         uint32_t port_id,
954         struct rte_pipeline_port_out_stats *stats,
955         int clear)
956 {
957         struct pipeline *p;
958         struct pipeline_msg_req *req;
959         struct pipeline_msg_rsp *rsp;
960         int status;
961
962         /* Check input params */
963         if (pipeline_name == NULL ||
964                 stats == NULL)
965                 return -1;
966
967         p = softnic_pipeline_find(softnic, pipeline_name);
968         if (p == NULL ||
969                 port_id >= p->n_ports_out)
970                 return -1;
971
972         if (!pipeline_is_running(p)) {
973                 status = rte_pipeline_port_out_stats_read(p->p,
974                         port_id,
975                         stats,
976                         clear);
977
978                 return status;
979         }
980
981         /* Allocate request */
982         req = pipeline_msg_alloc();
983         if (req == NULL)
984                 return -1;
985
986         /* Write request */
987         req->type = PIPELINE_REQ_PORT_OUT_STATS_READ;
988         req->id = port_id;
989         req->port_out_stats_read.clear = clear;
990
991         /* Send request and wait for response */
992         rsp = pipeline_msg_send_recv(p, req);
993         if (rsp == NULL)
994                 return -1;
995
996         /* Read response */
997         status = rsp->status;
998         if (status)
999                 memcpy(stats, &rsp->port_out_stats_read.stats, sizeof(*stats));
1000
1001         /* Free response */
1002         pipeline_msg_free(rsp);
1003
1004         return status;
1005 }
1006
1007 int
1008 softnic_pipeline_table_stats_read(struct pmd_internals *softnic,
1009         const char *pipeline_name,
1010         uint32_t table_id,
1011         struct rte_pipeline_table_stats *stats,
1012         int clear)
1013 {
1014         struct pipeline *p;
1015         struct pipeline_msg_req *req;
1016         struct pipeline_msg_rsp *rsp;
1017         int status;
1018
1019         /* Check input params */
1020         if (pipeline_name == NULL ||
1021                 stats == NULL)
1022                 return -1;
1023
1024         p = softnic_pipeline_find(softnic, pipeline_name);
1025         if (p == NULL ||
1026                 table_id >= p->n_tables)
1027                 return -1;
1028
1029         if (!pipeline_is_running(p)) {
1030                 status = rte_pipeline_table_stats_read(p->p,
1031                         table_id,
1032                         stats,
1033                         clear);
1034
1035                 return status;
1036         }
1037
1038         /* Allocate request */
1039         req = pipeline_msg_alloc();
1040         if (req == NULL)
1041                 return -1;
1042
1043         /* Write request */
1044         req->type = PIPELINE_REQ_TABLE_STATS_READ;
1045         req->id = table_id;
1046         req->table_stats_read.clear = clear;
1047
1048         /* Send request and wait for response */
1049         rsp = pipeline_msg_send_recv(p, req);
1050         if (rsp == NULL)
1051                 return -1;
1052
1053         /* Read response */
1054         status = rsp->status;
1055         if (status)
1056                 memcpy(stats, &rsp->table_stats_read.stats, sizeof(*stats));
1057
1058         /* Free response */
1059         pipeline_msg_free(rsp);
1060
1061         return status;
1062 }
1063
1064 static int
1065 match_check(struct softnic_table_rule_match *match,
1066         struct pipeline *p,
1067         uint32_t table_id)
1068 {
1069         struct softnic_table *table;
1070
1071         if (match == NULL ||
1072                 p == NULL ||
1073                 table_id >= p->n_tables)
1074                 return -1;
1075
1076         table = &p->table[table_id];
1077         if (match->match_type != table->params.match_type)
1078                 return -1;
1079
1080         switch (match->match_type) {
1081         case TABLE_ACL:
1082         {
1083                 struct softnic_table_acl_params *t = &table->params.match.acl;
1084                 struct softnic_table_rule_match_acl *r = &match->match.acl;
1085
1086                 if ((r->ip_version && (t->ip_version == 0)) ||
1087                         ((r->ip_version == 0) && t->ip_version))
1088                         return -1;
1089
1090                 if (r->ip_version) {
1091                         if (r->sa_depth > 32 ||
1092                                 r->da_depth > 32)
1093                                 return -1;
1094                 } else {
1095                         if (r->sa_depth > 128 ||
1096                                 r->da_depth > 128)
1097                                 return -1;
1098                 }
1099                 return 0;
1100         }
1101
1102         case TABLE_ARRAY:
1103                 return 0;
1104
1105         case TABLE_HASH:
1106                 return 0;
1107
1108         case TABLE_LPM:
1109         {
1110                 struct softnic_table_lpm_params *t = &table->params.match.lpm;
1111                 struct softnic_table_rule_match_lpm *r = &match->match.lpm;
1112
1113                 if ((r->ip_version && (t->key_size != 4)) ||
1114                         ((r->ip_version == 0) && (t->key_size != 16)))
1115                         return -1;
1116
1117                 if (r->ip_version) {
1118                         if (r->depth > 32)
1119                                 return -1;
1120                 } else {
1121                         if (r->depth > 128)
1122                                 return -1;
1123                 }
1124                 return 0;
1125         }
1126
1127         case TABLE_STUB:
1128                 return -1;
1129
1130         default:
1131                 return -1;
1132         }
1133 }
1134
1135 static int
1136 action_check(struct softnic_table_rule_action *action,
1137         struct pipeline *p,
1138         uint32_t table_id)
1139 {
1140         struct softnic_table_action_profile *ap;
1141
1142         if (action == NULL ||
1143                 p == NULL ||
1144                 table_id >= p->n_tables)
1145                 return -1;
1146
1147         ap = p->table[table_id].ap;
1148         if (action->action_mask != ap->params.action_mask)
1149                 return -1;
1150
1151         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
1152                 if (action->fwd.action == RTE_PIPELINE_ACTION_PORT &&
1153                         action->fwd.id >= p->n_ports_out)
1154                         return -1;
1155
1156                 if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE &&
1157                         action->fwd.id >= p->n_tables)
1158                         return -1;
1159         }
1160
1161         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
1162                 uint32_t tc_mask0 = (1 << ap->params.mtr.n_tc) - 1;
1163                 uint32_t tc_mask1 = action->mtr.tc_mask;
1164
1165                 if (tc_mask1 != tc_mask0)
1166                         return -1;
1167         }
1168
1169         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
1170                 uint32_t n_subports_per_port =
1171                         ap->params.tm.n_subports_per_port;
1172                 uint32_t n_pipes_per_subport =
1173                         ap->params.tm.n_pipes_per_subport;
1174                 uint32_t subport_id = action->tm.subport_id;
1175                 uint32_t pipe_id = action->tm.pipe_id;
1176
1177                 if (subport_id >= n_subports_per_port ||
1178                         pipe_id >= n_pipes_per_subport)
1179                         return -1;
1180         }
1181
1182         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
1183                 uint64_t encap_mask = ap->params.encap.encap_mask;
1184                 enum rte_table_action_encap_type type = action->encap.type;
1185
1186                 if ((encap_mask & (1LLU << type)) == 0)
1187                         return -1;
1188         }
1189
1190         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
1191                 int ip_version0 = ap->params.common.ip_version;
1192                 int ip_version1 = action->nat.ip_version;
1193
1194                 if ((ip_version1 && (ip_version0 == 0)) ||
1195                         ((ip_version1 == 0) && ip_version0))
1196                         return -1;
1197         }
1198
1199         return 0;
1200 }
1201
1202 static int
1203 action_default_check(struct softnic_table_rule_action *action,
1204         struct pipeline *p,
1205         uint32_t table_id)
1206 {
1207         if (action == NULL ||
1208                 action->action_mask != (1LLU << RTE_TABLE_ACTION_FWD) ||
1209                 p == NULL ||
1210                 table_id >= p->n_tables)
1211                 return -1;
1212
1213         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
1214                 if (action->fwd.action == RTE_PIPELINE_ACTION_PORT &&
1215                         action->fwd.id >= p->n_ports_out)
1216                         return -1;
1217
1218                 if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE &&
1219                         action->fwd.id >= p->n_tables)
1220                         return -1;
1221         }
1222
1223         return 0;
1224 }
1225
1226 union table_rule_match_low_level {
1227         struct rte_table_acl_rule_add_params acl_add;
1228         struct rte_table_acl_rule_delete_params acl_delete;
1229         struct rte_table_array_key array;
1230         uint8_t hash[TABLE_RULE_MATCH_SIZE_MAX];
1231         struct rte_table_lpm_key lpm_ipv4;
1232         struct rte_table_lpm_ipv6_key lpm_ipv6;
1233 };
1234
1235 static int
1236 match_convert(struct softnic_table_rule_match *mh,
1237         union table_rule_match_low_level *ml,
1238         int add);
1239
1240 static int
1241 action_convert(struct rte_table_action *a,
1242         struct softnic_table_rule_action *action,
1243         struct rte_pipeline_table_entry *data);
1244
1245 int
1246 softnic_pipeline_table_rule_add(struct pmd_internals *softnic,
1247         const char *pipeline_name,
1248         uint32_t table_id,
1249         struct softnic_table_rule_match *match,
1250         struct softnic_table_rule_action *action,
1251         void **data)
1252 {
1253         struct pipeline *p;
1254         struct pipeline_msg_req *req;
1255         struct pipeline_msg_rsp *rsp;
1256         int status;
1257
1258         /* Check input params */
1259         if (pipeline_name == NULL ||
1260                 match == NULL ||
1261                 action == NULL ||
1262                 data == NULL)
1263                 return -1;
1264
1265         p = softnic_pipeline_find(softnic, pipeline_name);
1266         if (p == NULL ||
1267                 table_id >= p->n_tables ||
1268                 match_check(match, p, table_id) ||
1269                 action_check(action, p, table_id))
1270                 return -1;
1271
1272         if (!pipeline_is_running(p)) {
1273                 struct rte_table_action *a = p->table[table_id].a;
1274                 union table_rule_match_low_level match_ll;
1275                 struct rte_pipeline_table_entry *data_in, *data_out;
1276                 int key_found;
1277                 uint8_t *buffer;
1278
1279                 buffer = calloc(TABLE_RULE_ACTION_SIZE_MAX, sizeof(uint8_t));
1280                 if (buffer == NULL)
1281                         return -1;
1282
1283                 /* Table match-action rule conversion */
1284                 data_in = (struct rte_pipeline_table_entry *)buffer;
1285
1286                 status = match_convert(match, &match_ll, 1);
1287                 if (status) {
1288                         free(buffer);
1289                         return -1;
1290                 }
1291
1292                 status = action_convert(a, action, data_in);
1293                 if (status) {
1294                         free(buffer);
1295                         return -1;
1296                 }
1297
1298                 /* Add rule (match, action) to table */
1299                 status = rte_pipeline_table_entry_add(p->p,
1300                                 table_id,
1301                                 &match_ll,
1302                                 data_in,
1303                                 &key_found,
1304                                 &data_out);
1305                 if (status) {
1306                         free(buffer);
1307                         return -1;
1308                 }
1309
1310                 /* Write Response */
1311                 *data = data_out;
1312
1313                 free(buffer);
1314                 return 0;
1315         }
1316
1317         /* Allocate request */
1318         req = pipeline_msg_alloc();
1319         if (req == NULL)
1320                 return -1;
1321
1322         /* Write request */
1323         req->type = PIPELINE_REQ_TABLE_RULE_ADD;
1324         req->id = table_id;
1325         memcpy(&req->table_rule_add.match, match, sizeof(*match));
1326         memcpy(&req->table_rule_add.action, action, sizeof(*action));
1327
1328         /* Send request and wait for response */
1329         rsp = pipeline_msg_send_recv(p, req);
1330         if (rsp == NULL)
1331                 return -1;
1332
1333         /* Read response */
1334         status = rsp->status;
1335         if (status == 0)
1336                 *data = rsp->table_rule_add.data;
1337
1338         /* Free response */
1339         pipeline_msg_free(rsp);
1340
1341         return status;
1342 }
1343
1344 int
1345 softnic_pipeline_table_rule_add_default(struct pmd_internals *softnic,
1346         const char *pipeline_name,
1347         uint32_t table_id,
1348         struct softnic_table_rule_action *action,
1349         void **data)
1350 {
1351         struct pipeline *p;
1352         struct pipeline_msg_req *req;
1353         struct pipeline_msg_rsp *rsp;
1354         int status;
1355
1356         /* Check input params */
1357         if (pipeline_name == NULL ||
1358                 action == NULL ||
1359                 data == NULL)
1360                 return -1;
1361
1362         p = softnic_pipeline_find(softnic, pipeline_name);
1363         if (p == NULL ||
1364                 table_id >= p->n_tables ||
1365                 action_default_check(action, p, table_id))
1366                 return -1;
1367
1368         if (!pipeline_is_running(p)) {
1369                 struct rte_pipeline_table_entry *data_in, *data_out;
1370                 uint8_t *buffer;
1371
1372                 buffer = calloc(TABLE_RULE_ACTION_SIZE_MAX, sizeof(uint8_t));
1373                 if (buffer == NULL)
1374                         return -1;
1375
1376                 /* Apply actions */
1377                 data_in = (struct rte_pipeline_table_entry *)buffer;
1378
1379                 data_in->action = action->fwd.action;
1380                 if (action->fwd.action == RTE_PIPELINE_ACTION_PORT)
1381                         data_in->port_id = action->fwd.id;
1382                 if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE)
1383                         data_in->table_id = action->fwd.id;
1384
1385                 /* Add default rule to table */
1386                 status = rte_pipeline_table_default_entry_add(p->p,
1387                                 table_id,
1388                                 data_in,
1389                                 &data_out);
1390                 if (status) {
1391                         free(buffer);
1392                         return -1;
1393                 }
1394
1395                 /* Write Response */
1396                 *data = data_out;
1397
1398                 free(buffer);
1399                 return 0;
1400         }
1401
1402         /* Allocate request */
1403         req = pipeline_msg_alloc();
1404         if (req == NULL)
1405                 return -1;
1406
1407         /* Write request */
1408         req->type = PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT;
1409         req->id = table_id;
1410         memcpy(&req->table_rule_add_default.action, action, sizeof(*action));
1411
1412         /* Send request and wait for response */
1413         rsp = pipeline_msg_send_recv(p, req);
1414         if (rsp == NULL)
1415                 return -1;
1416
1417         /* Read response */
1418         status = rsp->status;
1419         if (status == 0)
1420                 *data = rsp->table_rule_add_default.data;
1421
1422         /* Free response */
1423         pipeline_msg_free(rsp);
1424
1425         return status;
1426 }
1427
1428 int
1429 softnic_pipeline_table_rule_add_bulk(struct pmd_internals *softnic,
1430         const char *pipeline_name,
1431         uint32_t table_id,
1432         struct softnic_table_rule_match *match,
1433         struct softnic_table_rule_action *action,
1434         void **data,
1435         uint32_t *n_rules)
1436 {
1437         struct pipeline *p;
1438         struct pipeline_msg_req *req;
1439         struct pipeline_msg_rsp *rsp;
1440         uint32_t i;
1441         int status;
1442
1443         /* Check input params */
1444         if (pipeline_name == NULL ||
1445                 match == NULL ||
1446                 action == NULL ||
1447                 data == NULL ||
1448                 n_rules == NULL ||
1449                 (*n_rules == 0))
1450                 return -1;
1451
1452         p = softnic_pipeline_find(softnic, pipeline_name);
1453         if (p == NULL ||
1454                 table_id >= p->n_tables)
1455                 return -1;
1456
1457         for (i = 0; i < *n_rules; i++)
1458                 if (match_check(match, p, table_id) ||
1459                         action_check(action, p, table_id))
1460                         return -1;
1461
1462         if (!pipeline_is_running(p)) {
1463                 struct rte_table_action *a = p->table[table_id].a;
1464                 union table_rule_match_low_level *match_ll;
1465                 uint8_t *action_ll;
1466                 void **match_ll_ptr;
1467                 struct rte_pipeline_table_entry **action_ll_ptr;
1468                 struct rte_pipeline_table_entry **entries_ptr =
1469                         (struct rte_pipeline_table_entry **)data;
1470                 uint32_t bulk =
1471                         (p->table[table_id].params.match_type == TABLE_ACL) ? 1 : 0;
1472                 int *found;
1473
1474                 /* Memory allocation */
1475                 match_ll = calloc(*n_rules, sizeof(union table_rule_match_low_level));
1476                 action_ll = calloc(*n_rules, TABLE_RULE_ACTION_SIZE_MAX);
1477                 match_ll_ptr = calloc(*n_rules, sizeof(void *));
1478                 action_ll_ptr =
1479                         calloc(*n_rules, sizeof(struct rte_pipeline_table_entry *));
1480                 found = calloc(*n_rules, sizeof(int));
1481
1482                 if (match_ll == NULL ||
1483                         action_ll == NULL ||
1484                         match_ll_ptr == NULL ||
1485                         action_ll_ptr == NULL ||
1486                         found == NULL)
1487                         goto fail;
1488
1489                 for (i = 0; i < *n_rules; i++) {
1490                         match_ll_ptr[i] = (void *)&match_ll[i];
1491                         action_ll_ptr[i] =
1492                                 (struct rte_pipeline_table_entry *)&action_ll[i * TABLE_RULE_ACTION_SIZE_MAX];
1493                 }
1494
1495                 /* Rule match conversion */
1496                 for (i = 0; i < *n_rules; i++) {
1497                         status = match_convert(&match[i], match_ll_ptr[i], 1);
1498                         if (status)
1499                                 goto fail;
1500                 }
1501
1502                 /* Rule action conversion */
1503                 for (i = 0; i < *n_rules; i++) {
1504                         status = action_convert(a, &action[i], action_ll_ptr[i]);
1505                         if (status)
1506                                 goto fail;
1507                 }
1508
1509                 /* Add rule (match, action) to table */
1510                 if (bulk) {
1511                         status = rte_pipeline_table_entry_add_bulk(p->p,
1512                                 table_id,
1513                                 match_ll_ptr,
1514                                 action_ll_ptr,
1515                                 *n_rules,
1516                                 found,
1517                                 entries_ptr);
1518                         if (status)
1519                                 *n_rules = 0;
1520                 } else {
1521                         for (i = 0; i < *n_rules; i++) {
1522                                 status = rte_pipeline_table_entry_add(p->p,
1523                                         table_id,
1524                                         match_ll_ptr[i],
1525                                         action_ll_ptr[i],
1526                                         &found[i],
1527                                         &entries_ptr[i]);
1528                                 if (status) {
1529                                         *n_rules = i;
1530                                         break;
1531                                 }
1532                         }
1533                 }
1534
1535                 /* Free */
1536                 free(found);
1537                 free(action_ll_ptr);
1538                 free(match_ll_ptr);
1539                 free(action_ll);
1540                 free(match_ll);
1541
1542                 return status;
1543
1544 fail:
1545                 free(found);
1546                 free(action_ll_ptr);
1547                 free(match_ll_ptr);
1548                 free(action_ll);
1549                 free(match_ll);
1550
1551                 *n_rules = 0;
1552                 return -1;
1553         }
1554
1555         /* Allocate request */
1556         req = pipeline_msg_alloc();
1557         if (req == NULL)
1558                 return -1;
1559
1560         /* Write request */
1561         req->type = PIPELINE_REQ_TABLE_RULE_ADD_BULK;
1562         req->id = table_id;
1563         req->table_rule_add_bulk.match = match;
1564         req->table_rule_add_bulk.action = action;
1565         req->table_rule_add_bulk.data = data;
1566         req->table_rule_add_bulk.n_rules = *n_rules;
1567         req->table_rule_add_bulk.bulk =
1568                 (p->table[table_id].params.match_type == TABLE_ACL) ? 1 : 0;
1569
1570         /* Send request and wait for response */
1571         rsp = pipeline_msg_send_recv(p, req);
1572         if (rsp == NULL)
1573                 return -1;
1574
1575         /* Read response */
1576         status = rsp->status;
1577         if (status == 0)
1578                 *n_rules = rsp->table_rule_add_bulk.n_rules;
1579
1580         /* Free response */
1581         pipeline_msg_free(rsp);
1582
1583         return status;
1584 }
1585
1586 int
1587 softnic_pipeline_table_rule_delete(struct pmd_internals *softnic,
1588         const char *pipeline_name,
1589         uint32_t table_id,
1590         struct softnic_table_rule_match *match)
1591 {
1592         struct pipeline *p;
1593         struct pipeline_msg_req *req;
1594         struct pipeline_msg_rsp *rsp;
1595         int status;
1596
1597         /* Check input params */
1598         if (pipeline_name == NULL ||
1599                 match == NULL)
1600                 return -1;
1601
1602         p = softnic_pipeline_find(softnic, pipeline_name);
1603         if (p == NULL ||
1604                 table_id >= p->n_tables ||
1605                 match_check(match, p, table_id))
1606                 return -1;
1607
1608         if (!pipeline_is_running(p)) {
1609                 union table_rule_match_low_level match_ll;
1610                 int key_found;
1611
1612                 status = match_convert(match, &match_ll, 0);
1613                 if (status)
1614                         return -1;
1615
1616                 status = rte_pipeline_table_entry_delete(p->p,
1617                                 table_id,
1618                                 &match_ll,
1619                                 &key_found,
1620                                 NULL);
1621
1622                 return status;
1623         }
1624
1625         /* Allocate request */
1626         req = pipeline_msg_alloc();
1627         if (req == NULL)
1628                 return -1;
1629
1630         /* Write request */
1631         req->type = PIPELINE_REQ_TABLE_RULE_DELETE;
1632         req->id = table_id;
1633         memcpy(&req->table_rule_delete.match, match, sizeof(*match));
1634
1635         /* Send request and wait for response */
1636         rsp = pipeline_msg_send_recv(p, req);
1637         if (rsp == NULL)
1638                 return -1;
1639
1640         /* Read response */
1641         status = rsp->status;
1642
1643         /* Free response */
1644         pipeline_msg_free(rsp);
1645
1646         return status;
1647 }
1648
1649 int
1650 softnic_pipeline_table_rule_delete_default(struct pmd_internals *softnic,
1651         const char *pipeline_name,
1652         uint32_t table_id)
1653 {
1654         struct pipeline *p;
1655         struct pipeline_msg_req *req;
1656         struct pipeline_msg_rsp *rsp;
1657         int status;
1658
1659         /* Check input params */
1660         if (pipeline_name == NULL)
1661                 return -1;
1662
1663         p = softnic_pipeline_find(softnic, pipeline_name);
1664         if (p == NULL ||
1665                 table_id >= p->n_tables)
1666                 return -1;
1667
1668         if (!pipeline_is_running(p)) {
1669                 status = rte_pipeline_table_default_entry_delete(p->p,
1670                         table_id,
1671                         NULL);
1672
1673                 return status;
1674         }
1675
1676         /* Allocate request */
1677         req = pipeline_msg_alloc();
1678         if (req == NULL)
1679                 return -1;
1680
1681         /* Write request */
1682         req->type = PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT;
1683         req->id = table_id;
1684
1685         /* Send request and wait for response */
1686         rsp = pipeline_msg_send_recv(p, req);
1687         if (rsp == NULL)
1688                 return -1;
1689
1690         /* Read response */
1691         status = rsp->status;
1692
1693         /* Free response */
1694         pipeline_msg_free(rsp);
1695
1696         return status;
1697 }
1698
1699 int
1700 softnic_pipeline_table_rule_stats_read(struct pmd_internals *softnic,
1701         const char *pipeline_name,
1702         uint32_t table_id,
1703         void *data,
1704         struct rte_table_action_stats_counters *stats,
1705         int clear)
1706 {
1707         struct pipeline *p;
1708         struct pipeline_msg_req *req;
1709         struct pipeline_msg_rsp *rsp;
1710         int status;
1711
1712         /* Check input params */
1713         if (pipeline_name == NULL ||
1714                 data == NULL ||
1715                 stats == NULL)
1716                 return -1;
1717
1718         p = softnic_pipeline_find(softnic, pipeline_name);
1719         if (p == NULL ||
1720                 table_id >= p->n_tables)
1721                 return -1;
1722
1723         if (!pipeline_is_running(p)) {
1724                 struct rte_table_action *a = p->table[table_id].a;
1725
1726                 status = rte_table_action_stats_read(a,
1727                         data,
1728                         stats,
1729                         clear);
1730
1731                 return status;
1732         }
1733
1734         /* Allocate request */
1735         req = pipeline_msg_alloc();
1736         if (req == NULL)
1737                 return -1;
1738
1739         /* Write request */
1740         req->type = PIPELINE_REQ_TABLE_RULE_STATS_READ;
1741         req->id = table_id;
1742         req->table_rule_stats_read.data = data;
1743         req->table_rule_stats_read.clear = clear;
1744
1745         /* Send request and wait for response */
1746         rsp = pipeline_msg_send_recv(p, req);
1747         if (rsp == NULL)
1748                 return -1;
1749
1750         /* Read response */
1751         status = rsp->status;
1752         if (status)
1753                 memcpy(stats, &rsp->table_rule_stats_read.stats, sizeof(*stats));
1754
1755         /* Free response */
1756         pipeline_msg_free(rsp);
1757
1758         return status;
1759 }
1760
1761 int
1762 softnic_pipeline_table_mtr_profile_add(struct pmd_internals *softnic,
1763         const char *pipeline_name,
1764         uint32_t table_id,
1765         uint32_t meter_profile_id,
1766         struct rte_table_action_meter_profile *profile)
1767 {
1768         struct pipeline *p;
1769         struct pipeline_msg_req *req;
1770         struct pipeline_msg_rsp *rsp;
1771         struct softnic_table *table;
1772         struct softnic_table_meter_profile *mp;
1773         int status;
1774
1775         /* Check input params */
1776         if (pipeline_name == NULL ||
1777                 profile == NULL)
1778                 return -1;
1779
1780         p = softnic_pipeline_find(softnic, pipeline_name);
1781         if (p == NULL ||
1782                 table_id >= p->n_tables)
1783                 return -1;
1784
1785         table = &p->table[table_id];
1786         mp = softnic_pipeline_table_meter_profile_find(table, meter_profile_id);
1787         if (mp)
1788                 return -1;
1789
1790         /* Resource Allocation */
1791         mp = calloc(1, sizeof(struct softnic_table_meter_profile));
1792         if (mp == NULL)
1793                 return -1;
1794
1795         mp->meter_profile_id = meter_profile_id;
1796         memcpy(&mp->profile, profile, sizeof(mp->profile));
1797
1798         if (!pipeline_is_running(p)) {
1799                 status = rte_table_action_meter_profile_add(table->a,
1800                         meter_profile_id,
1801                         profile);
1802                 if (status) {
1803                         free(mp);
1804                         return status;
1805                 }
1806
1807                 /* Add profile to the table. */
1808                 TAILQ_INSERT_TAIL(&table->meter_profiles, mp, node);
1809
1810                 return status;
1811         }
1812
1813         /* Allocate request */
1814         req = pipeline_msg_alloc();
1815         if (req == NULL) {
1816                 free(mp);
1817                 return -1;
1818         }
1819
1820         /* Write request */
1821         req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_ADD;
1822         req->id = table_id;
1823         req->table_mtr_profile_add.meter_profile_id = meter_profile_id;
1824         memcpy(&req->table_mtr_profile_add.profile, profile, sizeof(*profile));
1825
1826         /* Send request and wait for response */
1827         rsp = pipeline_msg_send_recv(p, req);
1828         if (rsp == NULL) {
1829                 free(mp);
1830                 return -1;
1831         }
1832
1833         /* Read response */
1834         status = rsp->status;
1835         if (status == 0)
1836                 TAILQ_INSERT_TAIL(&table->meter_profiles, mp, node);
1837         else
1838                 free(mp);
1839
1840         /* Free response */
1841         pipeline_msg_free(rsp);
1842
1843         return status;
1844 }
1845
1846 int
1847 softnic_pipeline_table_mtr_profile_delete(struct pmd_internals *softnic,
1848         const char *pipeline_name,
1849         uint32_t table_id,
1850         uint32_t meter_profile_id)
1851 {
1852         struct pipeline *p;
1853         struct pipeline_msg_req *req;
1854         struct pipeline_msg_rsp *rsp;
1855         int status;
1856
1857         /* Check input params */
1858         if (pipeline_name == NULL)
1859                 return -1;
1860
1861         p = softnic_pipeline_find(softnic, pipeline_name);
1862         if (p == NULL ||
1863                 table_id >= p->n_tables)
1864                 return -1;
1865
1866         if (!pipeline_is_running(p)) {
1867                 struct rte_table_action *a = p->table[table_id].a;
1868
1869                 status = rte_table_action_meter_profile_delete(a,
1870                                 meter_profile_id);
1871
1872                 return status;
1873         }
1874
1875         /* Allocate request */
1876         req = pipeline_msg_alloc();
1877         if (req == NULL)
1878                 return -1;
1879
1880         /* Write request */
1881         req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE;
1882         req->id = table_id;
1883         req->table_mtr_profile_delete.meter_profile_id = meter_profile_id;
1884
1885         /* Send request and wait for response */
1886         rsp = pipeline_msg_send_recv(p, req);
1887         if (rsp == NULL)
1888                 return -1;
1889
1890         /* Read response */
1891         status = rsp->status;
1892
1893         /* Free response */
1894         pipeline_msg_free(rsp);
1895
1896         return status;
1897 }
1898
1899 int
1900 softnic_pipeline_table_rule_mtr_read(struct pmd_internals *softnic,
1901         const char *pipeline_name,
1902         uint32_t table_id,
1903         void *data,
1904         uint32_t tc_mask,
1905         struct rte_table_action_mtr_counters *stats,
1906         int clear)
1907 {
1908         struct pipeline *p;
1909         struct pipeline_msg_req *req;
1910         struct pipeline_msg_rsp *rsp;
1911         int status;
1912
1913         /* Check input params */
1914         if (pipeline_name == NULL ||
1915                 data == NULL ||
1916                 stats == NULL)
1917                 return -1;
1918
1919         p = softnic_pipeline_find(softnic, pipeline_name);
1920         if (p == NULL ||
1921                 table_id >= p->n_tables)
1922                 return -1;
1923
1924         if (!pipeline_is_running(p)) {
1925                 struct rte_table_action *a = p->table[table_id].a;
1926
1927                 status = rte_table_action_meter_read(a,
1928                                 data,
1929                                 tc_mask,
1930                                 stats,
1931                                 clear);
1932
1933                 return status;
1934         }
1935
1936         /* Allocate request */
1937         req = pipeline_msg_alloc();
1938         if (req == NULL)
1939                 return -1;
1940
1941         /* Write request */
1942         req->type = PIPELINE_REQ_TABLE_RULE_MTR_READ;
1943         req->id = table_id;
1944         req->table_rule_mtr_read.data = data;
1945         req->table_rule_mtr_read.tc_mask = tc_mask;
1946         req->table_rule_mtr_read.clear = clear;
1947
1948         /* Send request and wait for response */
1949         rsp = pipeline_msg_send_recv(p, req);
1950         if (rsp == NULL)
1951                 return -1;
1952
1953         /* Read response */
1954         status = rsp->status;
1955         if (status)
1956                 memcpy(stats, &rsp->table_rule_mtr_read.stats, sizeof(*stats));
1957
1958         /* Free response */
1959         pipeline_msg_free(rsp);
1960
1961         return status;
1962 }
1963
1964 int
1965 softnic_pipeline_table_dscp_table_update(struct pmd_internals *softnic,
1966         const char *pipeline_name,
1967         uint32_t table_id,
1968         uint64_t dscp_mask,
1969         struct rte_table_action_dscp_table *dscp_table)
1970 {
1971         struct pipeline *p;
1972         struct pipeline_msg_req *req;
1973         struct pipeline_msg_rsp *rsp;
1974         int status;
1975
1976         /* Check input params */
1977         if (pipeline_name == NULL ||
1978                 dscp_table == NULL)
1979                 return -1;
1980
1981         p = softnic_pipeline_find(softnic, pipeline_name);
1982         if (p == NULL ||
1983                 table_id >= p->n_tables)
1984                 return -1;
1985
1986         if (!pipeline_is_running(p)) {
1987                 struct rte_table_action *a = p->table[table_id].a;
1988
1989                 status = rte_table_action_dscp_table_update(a,
1990                                 dscp_mask,
1991                                 dscp_table);
1992
1993                 /* Update table dscp table */
1994                 if (!status)
1995                         memcpy(&p->table[table_id].dscp_table, dscp_table,
1996                                 sizeof(p->table[table_id].dscp_table));
1997
1998                 return status;
1999         }
2000
2001         /* Allocate request */
2002         req = pipeline_msg_alloc();
2003         if (req == NULL)
2004                 return -1;
2005
2006         /* Write request */
2007         req->type = PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE;
2008         req->id = table_id;
2009         req->table_dscp_table_update.dscp_mask = dscp_mask;
2010         memcpy(&req->table_dscp_table_update.dscp_table,
2011                 dscp_table, sizeof(*dscp_table));
2012
2013         /* Send request and wait for response */
2014         rsp = pipeline_msg_send_recv(p, req);
2015         if (rsp == NULL)
2016                 return -1;
2017
2018         /* Read response */
2019         status = rsp->status;
2020
2021         /* Update table dscp table */
2022         if (!status)
2023                 memcpy(&p->table[table_id].dscp_table, dscp_table,
2024                         sizeof(p->table[table_id].dscp_table));
2025
2026         /* Free response */
2027         pipeline_msg_free(rsp);
2028
2029         return status;
2030 }
2031
2032 int
2033 softnic_pipeline_table_rule_ttl_read(struct pmd_internals *softnic,
2034         const char *pipeline_name,
2035         uint32_t table_id,
2036         void *data,
2037         struct rte_table_action_ttl_counters *stats,
2038         int clear)
2039 {
2040         struct pipeline *p;
2041         struct pipeline_msg_req *req;
2042         struct pipeline_msg_rsp *rsp;
2043         int status;
2044
2045         /* Check input params */
2046         if (pipeline_name == NULL ||
2047                 data == NULL ||
2048                 stats == NULL)
2049                 return -1;
2050
2051         p = softnic_pipeline_find(softnic, pipeline_name);
2052         if (p == NULL ||
2053                 table_id >= p->n_tables)
2054                 return -1;
2055
2056         if (!pipeline_is_running(p)) {
2057                 struct rte_table_action *a = p->table[table_id].a;
2058
2059                 status = rte_table_action_ttl_read(a,
2060                                 data,
2061                                 stats,
2062                                 clear);
2063
2064                 return status;
2065         }
2066
2067         /* Allocate request */
2068         req = pipeline_msg_alloc();
2069         if (req == NULL)
2070                 return -1;
2071
2072         /* Write request */
2073         req->type = PIPELINE_REQ_TABLE_RULE_TTL_READ;
2074         req->id = table_id;
2075         req->table_rule_ttl_read.data = data;
2076         req->table_rule_ttl_read.clear = clear;
2077
2078         /* Send request and wait for response */
2079         rsp = pipeline_msg_send_recv(p, req);
2080         if (rsp == NULL)
2081                 return -1;
2082
2083         /* Read response */
2084         status = rsp->status;
2085         if (status)
2086                 memcpy(stats, &rsp->table_rule_ttl_read.stats, sizeof(*stats));
2087
2088         /* Free response */
2089         pipeline_msg_free(rsp);
2090
2091         return status;
2092 }
2093
2094 /**
2095  * Data plane threads: message handling
2096  */
2097 static inline struct pipeline_msg_req *
2098 pipeline_msg_recv(struct rte_ring *msgq_req)
2099 {
2100         struct pipeline_msg_req *req;
2101
2102         int status = rte_ring_sc_dequeue(msgq_req, (void **)&req);
2103
2104         if (status != 0)
2105                 return NULL;
2106
2107         return req;
2108 }
2109
2110 static inline void
2111 pipeline_msg_send(struct rte_ring *msgq_rsp,
2112         struct pipeline_msg_rsp *rsp)
2113 {
2114         int status;
2115
2116         do {
2117                 status = rte_ring_sp_enqueue(msgq_rsp, rsp);
2118         } while (status == -ENOBUFS);
2119 }
2120
2121 static struct pipeline_msg_rsp *
2122 pipeline_msg_handle_port_in_stats_read(struct pipeline_data *p,
2123         struct pipeline_msg_req *req)
2124 {
2125         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2126         uint32_t port_id = req->id;
2127         int clear = req->port_in_stats_read.clear;
2128
2129         rsp->status = rte_pipeline_port_in_stats_read(p->p,
2130                 port_id,
2131                 &rsp->port_in_stats_read.stats,
2132                 clear);
2133
2134         return rsp;
2135 }
2136
2137 static struct pipeline_msg_rsp *
2138 pipeline_msg_handle_port_in_enable(struct pipeline_data *p,
2139         struct pipeline_msg_req *req)
2140 {
2141         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2142         uint32_t port_id = req->id;
2143
2144         rsp->status = rte_pipeline_port_in_enable(p->p,
2145                 port_id);
2146
2147         return rsp;
2148 }
2149
2150 static struct pipeline_msg_rsp *
2151 pipeline_msg_handle_port_in_disable(struct pipeline_data *p,
2152         struct pipeline_msg_req *req)
2153 {
2154         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2155         uint32_t port_id = req->id;
2156
2157         rsp->status = rte_pipeline_port_in_disable(p->p,
2158                 port_id);
2159
2160         return rsp;
2161 }
2162
2163 static struct pipeline_msg_rsp *
2164 pipeline_msg_handle_port_out_stats_read(struct pipeline_data *p,
2165         struct pipeline_msg_req *req)
2166 {
2167         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2168         uint32_t port_id = req->id;
2169         int clear = req->port_out_stats_read.clear;
2170
2171         rsp->status = rte_pipeline_port_out_stats_read(p->p,
2172                 port_id,
2173                 &rsp->port_out_stats_read.stats,
2174                 clear);
2175
2176         return rsp;
2177 }
2178
2179 static struct pipeline_msg_rsp *
2180 pipeline_msg_handle_table_stats_read(struct pipeline_data *p,
2181         struct pipeline_msg_req *req)
2182 {
2183         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2184         uint32_t port_id = req->id;
2185         int clear = req->table_stats_read.clear;
2186
2187         rsp->status = rte_pipeline_table_stats_read(p->p,
2188                 port_id,
2189                 &rsp->table_stats_read.stats,
2190                 clear);
2191
2192         return rsp;
2193 }
2194
2195 static int
2196 match_convert_ipv6_depth(uint32_t depth, uint32_t *depth32)
2197 {
2198         if (depth > 128)
2199                 return -1;
2200
2201         switch (depth / 32) {
2202         case 0:
2203                 depth32[0] = depth;
2204                 depth32[1] = 0;
2205                 depth32[2] = 0;
2206                 depth32[3] = 0;
2207                 return 0;
2208
2209         case 1:
2210                 depth32[0] = 32;
2211                 depth32[1] = depth - 32;
2212                 depth32[2] = 0;
2213                 depth32[3] = 0;
2214                 return 0;
2215
2216         case 2:
2217                 depth32[0] = 32;
2218                 depth32[1] = 32;
2219                 depth32[2] = depth - 64;
2220                 depth32[3] = 0;
2221                 return 0;
2222
2223         case 3:
2224                 depth32[0] = 32;
2225                 depth32[1] = 32;
2226                 depth32[2] = 32;
2227                 depth32[3] = depth - 96;
2228                 return 0;
2229
2230         case 4:
2231                 depth32[0] = 32;
2232                 depth32[1] = 32;
2233                 depth32[2] = 32;
2234                 depth32[3] = 32;
2235                 return 0;
2236
2237         default:
2238                 return -1;
2239         }
2240 }
2241
2242 static int
2243 match_convert(struct softnic_table_rule_match *mh,
2244         union table_rule_match_low_level *ml,
2245         int add)
2246 {
2247         memset(ml, 0, sizeof(*ml));
2248
2249         switch (mh->match_type) {
2250         case TABLE_ACL:
2251                 if (mh->match.acl.ip_version)
2252                         if (add) {
2253                                 ml->acl_add.field_value[0].value.u8 =
2254                                         mh->match.acl.proto;
2255                                 ml->acl_add.field_value[0].mask_range.u8 =
2256                                         mh->match.acl.proto_mask;
2257
2258                                 ml->acl_add.field_value[1].value.u32 =
2259                                         mh->match.acl.ipv4.sa;
2260                                 ml->acl_add.field_value[1].mask_range.u32 =
2261                                         mh->match.acl.sa_depth;
2262
2263                                 ml->acl_add.field_value[2].value.u32 =
2264                                         mh->match.acl.ipv4.da;
2265                                 ml->acl_add.field_value[2].mask_range.u32 =
2266                                         mh->match.acl.da_depth;
2267
2268                                 ml->acl_add.field_value[3].value.u16 =
2269                                         mh->match.acl.sp0;
2270                                 ml->acl_add.field_value[3].mask_range.u16 =
2271                                         mh->match.acl.sp1;
2272
2273                                 ml->acl_add.field_value[4].value.u16 =
2274                                         mh->match.acl.dp0;
2275                                 ml->acl_add.field_value[4].mask_range.u16 =
2276                                         mh->match.acl.dp1;
2277
2278                                 ml->acl_add.priority =
2279                                         (int32_t)mh->match.acl.priority;
2280                         } else {
2281                                 ml->acl_delete.field_value[0].value.u8 =
2282                                         mh->match.acl.proto;
2283                                 ml->acl_delete.field_value[0].mask_range.u8 =
2284                                         mh->match.acl.proto_mask;
2285
2286                                 ml->acl_delete.field_value[1].value.u32 =
2287                                         mh->match.acl.ipv4.sa;
2288                                 ml->acl_delete.field_value[1].mask_range.u32 =
2289                                         mh->match.acl.sa_depth;
2290
2291                                 ml->acl_delete.field_value[2].value.u32 =
2292                                         mh->match.acl.ipv4.da;
2293                                 ml->acl_delete.field_value[2].mask_range.u32 =
2294                                         mh->match.acl.da_depth;
2295
2296                                 ml->acl_delete.field_value[3].value.u16 =
2297                                         mh->match.acl.sp0;
2298                                 ml->acl_delete.field_value[3].mask_range.u16 =
2299                                         mh->match.acl.sp1;
2300
2301                                 ml->acl_delete.field_value[4].value.u16 =
2302                                         mh->match.acl.dp0;
2303                                 ml->acl_delete.field_value[4].mask_range.u16 =
2304                                         mh->match.acl.dp1;
2305                         }
2306                 else
2307                         if (add) {
2308                                 uint32_t *sa32 =
2309                                         (uint32_t *)mh->match.acl.ipv6.sa;
2310                                 uint32_t *da32 =
2311                                         (uint32_t *)mh->match.acl.ipv6.da;
2312                                 uint32_t sa32_depth[4], da32_depth[4];
2313                                 int status;
2314
2315                                 status = match_convert_ipv6_depth(mh->match.acl.sa_depth,
2316                                         sa32_depth);
2317                                 if (status)
2318                                         return status;
2319
2320                                 status = match_convert_ipv6_depth(
2321                                         mh->match.acl.da_depth,
2322                                         da32_depth);
2323                                 if (status)
2324                                         return status;
2325
2326                                 ml->acl_add.field_value[0].value.u8 =
2327                                         mh->match.acl.proto;
2328                                 ml->acl_add.field_value[0].mask_range.u8 =
2329                                         mh->match.acl.proto_mask;
2330
2331                                 ml->acl_add.field_value[1].value.u32 =
2332                                         rte_be_to_cpu_32(sa32[0]);
2333                                 ml->acl_add.field_value[1].mask_range.u32 =
2334                                         sa32_depth[0];
2335                                 ml->acl_add.field_value[2].value.u32 =
2336                                         rte_be_to_cpu_32(sa32[1]);
2337                                 ml->acl_add.field_value[2].mask_range.u32 =
2338                                         sa32_depth[1];
2339                                 ml->acl_add.field_value[3].value.u32 =
2340                                         rte_be_to_cpu_32(sa32[2]);
2341                                 ml->acl_add.field_value[3].mask_range.u32 =
2342                                         sa32_depth[2];
2343                                 ml->acl_add.field_value[4].value.u32 =
2344                                         rte_be_to_cpu_32(sa32[3]);
2345                                 ml->acl_add.field_value[4].mask_range.u32 =
2346                                         sa32_depth[3];
2347
2348                                 ml->acl_add.field_value[5].value.u32 =
2349                                         rte_be_to_cpu_32(da32[0]);
2350                                 ml->acl_add.field_value[5].mask_range.u32 =
2351                                         da32_depth[0];
2352                                 ml->acl_add.field_value[6].value.u32 =
2353                                         rte_be_to_cpu_32(da32[1]);
2354                                 ml->acl_add.field_value[6].mask_range.u32 =
2355                                         da32_depth[1];
2356                                 ml->acl_add.field_value[7].value.u32 =
2357                                         rte_be_to_cpu_32(da32[2]);
2358                                 ml->acl_add.field_value[7].mask_range.u32 =
2359                                         da32_depth[2];
2360                                 ml->acl_add.field_value[8].value.u32 =
2361                                         rte_be_to_cpu_32(da32[3]);
2362                                 ml->acl_add.field_value[8].mask_range.u32 =
2363                                         da32_depth[3];
2364
2365                                 ml->acl_add.field_value[9].value.u16 =
2366                                         mh->match.acl.sp0;
2367                                 ml->acl_add.field_value[9].mask_range.u16 =
2368                                         mh->match.acl.sp1;
2369
2370                                 ml->acl_add.field_value[10].value.u16 =
2371                                         mh->match.acl.dp0;
2372                                 ml->acl_add.field_value[10].mask_range.u16 =
2373                                         mh->match.acl.dp1;
2374
2375                                 ml->acl_add.priority =
2376                                         (int32_t)mh->match.acl.priority;
2377                         } else {
2378                                 uint32_t *sa32 =
2379                                         (uint32_t *)mh->match.acl.ipv6.sa;
2380                                 uint32_t *da32 =
2381                                         (uint32_t *)mh->match.acl.ipv6.da;
2382                                 uint32_t sa32_depth[4], da32_depth[4];
2383                                 int status;
2384
2385                                 status = match_convert_ipv6_depth(mh->match.acl.sa_depth,
2386                                         sa32_depth);
2387                                 if (status)
2388                                         return status;
2389
2390                                 status = match_convert_ipv6_depth(mh->match.acl.da_depth,
2391                                         da32_depth);
2392                                 if (status)
2393                                         return status;
2394
2395                                 ml->acl_delete.field_value[0].value.u8 =
2396                                         mh->match.acl.proto;
2397                                 ml->acl_delete.field_value[0].mask_range.u8 =
2398                                         mh->match.acl.proto_mask;
2399
2400                                 ml->acl_delete.field_value[1].value.u32 =
2401                                         rte_be_to_cpu_32(sa32[0]);
2402                                 ml->acl_delete.field_value[1].mask_range.u32 =
2403                                         sa32_depth[0];
2404                                 ml->acl_delete.field_value[2].value.u32 =
2405                                         rte_be_to_cpu_32(sa32[1]);
2406                                 ml->acl_delete.field_value[2].mask_range.u32 =
2407                                         sa32_depth[1];
2408                                 ml->acl_delete.field_value[3].value.u32 =
2409                                         rte_be_to_cpu_32(sa32[2]);
2410                                 ml->acl_delete.field_value[3].mask_range.u32 =
2411                                         sa32_depth[2];
2412                                 ml->acl_delete.field_value[4].value.u32 =
2413                                         rte_be_to_cpu_32(sa32[3]);
2414                                 ml->acl_delete.field_value[4].mask_range.u32 =
2415                                         sa32_depth[3];
2416
2417                                 ml->acl_delete.field_value[5].value.u32 =
2418                                         rte_be_to_cpu_32(da32[0]);
2419                                 ml->acl_delete.field_value[5].mask_range.u32 =
2420                                         da32_depth[0];
2421                                 ml->acl_delete.field_value[6].value.u32 =
2422                                         rte_be_to_cpu_32(da32[1]);
2423                                 ml->acl_delete.field_value[6].mask_range.u32 =
2424                                         da32_depth[1];
2425                                 ml->acl_delete.field_value[7].value.u32 =
2426                                         rte_be_to_cpu_32(da32[2]);
2427                                 ml->acl_delete.field_value[7].mask_range.u32 =
2428                                         da32_depth[2];
2429                                 ml->acl_delete.field_value[8].value.u32 =
2430                                         rte_be_to_cpu_32(da32[3]);
2431                                 ml->acl_delete.field_value[8].mask_range.u32 =
2432                                         da32_depth[3];
2433
2434                                 ml->acl_delete.field_value[9].value.u16 =
2435                                         mh->match.acl.sp0;
2436                                 ml->acl_delete.field_value[9].mask_range.u16 =
2437                                         mh->match.acl.sp1;
2438
2439                                 ml->acl_delete.field_value[10].value.u16 =
2440                                         mh->match.acl.dp0;
2441                                 ml->acl_delete.field_value[10].mask_range.u16 =
2442                                         mh->match.acl.dp1;
2443                         }
2444                 return 0;
2445
2446         case TABLE_ARRAY:
2447                 ml->array.pos = mh->match.array.pos;
2448                 return 0;
2449
2450         case TABLE_HASH:
2451                 memcpy(ml->hash, mh->match.hash.key, sizeof(ml->hash));
2452                 return 0;
2453
2454         case TABLE_LPM:
2455                 if (mh->match.lpm.ip_version) {
2456                         ml->lpm_ipv4.ip = mh->match.lpm.ipv4;
2457                         ml->lpm_ipv4.depth = mh->match.lpm.depth;
2458                 } else {
2459                         memcpy(ml->lpm_ipv6.ip,
2460                                 mh->match.lpm.ipv6, sizeof(ml->lpm_ipv6.ip));
2461                         ml->lpm_ipv6.depth = mh->match.lpm.depth;
2462                 }
2463
2464                 return 0;
2465
2466         default:
2467                 return -1;
2468         }
2469 }
2470
2471 static int
2472 action_convert(struct rte_table_action *a,
2473         struct softnic_table_rule_action *action,
2474         struct rte_pipeline_table_entry *data)
2475 {
2476         int status;
2477
2478         /* Apply actions */
2479         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
2480                 status = rte_table_action_apply(a,
2481                         data,
2482                         RTE_TABLE_ACTION_FWD,
2483                         &action->fwd);
2484
2485                 if (status)
2486                         return status;
2487         }
2488
2489         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
2490                 status = rte_table_action_apply(a,
2491                         data,
2492                         RTE_TABLE_ACTION_LB,
2493                         &action->lb);
2494
2495                 if (status)
2496                         return status;
2497         }
2498
2499         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
2500                 status = rte_table_action_apply(a,
2501                         data,
2502                         RTE_TABLE_ACTION_MTR,
2503                         &action->mtr);
2504
2505                 if (status)
2506                         return status;
2507         }
2508
2509         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
2510                 status = rte_table_action_apply(a,
2511                         data,
2512                         RTE_TABLE_ACTION_TM,
2513                         &action->tm);
2514
2515                 if (status)
2516                         return status;
2517         }
2518
2519         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
2520                 status = rte_table_action_apply(a,
2521                         data,
2522                         RTE_TABLE_ACTION_ENCAP,
2523                         &action->encap);
2524
2525                 if (status)
2526                         return status;
2527         }
2528
2529         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
2530                 status = rte_table_action_apply(a,
2531                         data,
2532                         RTE_TABLE_ACTION_NAT,
2533                         &action->nat);
2534
2535                 if (status)
2536                         return status;
2537         }
2538
2539         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
2540                 status = rte_table_action_apply(a,
2541                         data,
2542                         RTE_TABLE_ACTION_TTL,
2543                         &action->ttl);
2544
2545                 if (status)
2546                         return status;
2547         }
2548
2549         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
2550                 status = rte_table_action_apply(a,
2551                         data,
2552                         RTE_TABLE_ACTION_STATS,
2553                         &action->stats);
2554
2555                 if (status)
2556                         return status;
2557         }
2558
2559         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
2560                 status = rte_table_action_apply(a,
2561                         data,
2562                         RTE_TABLE_ACTION_TIME,
2563                         &action->time);
2564
2565                 if (status)
2566                         return status;
2567         }
2568
2569         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TAG)) {
2570                 status = rte_table_action_apply(a,
2571                         data,
2572                         RTE_TABLE_ACTION_TAG,
2573                         &action->tag);
2574
2575                 if (status)
2576                         return status;
2577         }
2578
2579         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_DECAP)) {
2580                 status = rte_table_action_apply(a,
2581                         data,
2582                         RTE_TABLE_ACTION_DECAP,
2583                         &action->decap);
2584
2585                 if (status)
2586                         return status;
2587         }
2588
2589         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_SYM_CRYPTO)) {
2590                 status = rte_table_action_apply(a,
2591                         data,
2592                         RTE_TABLE_ACTION_SYM_CRYPTO,
2593                         &action->sym_crypto);
2594
2595                 if (status)
2596                         return status;
2597         }
2598
2599         return 0;
2600 }
2601
2602 static struct pipeline_msg_rsp *
2603 pipeline_msg_handle_table_rule_add(struct pipeline_data *p,
2604         struct pipeline_msg_req *req)
2605 {
2606         union table_rule_match_low_level match_ll;
2607         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2608         struct softnic_table_rule_match *match = &req->table_rule_add.match;
2609         struct softnic_table_rule_action *action = &req->table_rule_add.action;
2610         struct rte_pipeline_table_entry *data_in, *data_out;
2611         uint32_t table_id = req->id;
2612         int key_found, status;
2613         struct rte_table_action *a = p->table_data[table_id].a;
2614
2615         /* Apply actions */
2616         memset(p->buffer, 0, sizeof(p->buffer));
2617         data_in = (struct rte_pipeline_table_entry *)p->buffer;
2618
2619         status = match_convert(match, &match_ll, 1);
2620         if (status) {
2621                 rsp->status = -1;
2622                 return rsp;
2623         }
2624
2625         status = action_convert(a, action, data_in);
2626         if (status) {
2627                 rsp->status = -1;
2628                 return rsp;
2629         }
2630
2631         status = rte_pipeline_table_entry_add(p->p,
2632                 table_id,
2633                 &match_ll,
2634                 data_in,
2635                 &key_found,
2636                 &data_out);
2637         if (status) {
2638                 rsp->status = -1;
2639                 return rsp;
2640         }
2641
2642         /* Write response */
2643         rsp->status = 0;
2644         rsp->table_rule_add.data = data_out;
2645
2646         return rsp;
2647 }
2648
2649 static struct pipeline_msg_rsp *
2650 pipeline_msg_handle_table_rule_add_default(struct pipeline_data *p,
2651         struct pipeline_msg_req *req)
2652 {
2653         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2654         struct softnic_table_rule_action *action = &req->table_rule_add_default.action;
2655         struct rte_pipeline_table_entry *data_in, *data_out;
2656         uint32_t table_id = req->id;
2657         int status;
2658
2659         /* Apply actions */
2660         memset(p->buffer, 0, sizeof(p->buffer));
2661         data_in = (struct rte_pipeline_table_entry *)p->buffer;
2662
2663         data_in->action = action->fwd.action;
2664         if (action->fwd.action == RTE_PIPELINE_ACTION_PORT)
2665                 data_in->port_id = action->fwd.id;
2666         if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE)
2667                 data_in->table_id = action->fwd.id;
2668
2669         /* Add default rule to table */
2670         status = rte_pipeline_table_default_entry_add(p->p,
2671                 table_id,
2672                 data_in,
2673                 &data_out);
2674         if (status) {
2675                 rsp->status = -1;
2676                 return rsp;
2677         }
2678
2679         /* Write response */
2680         rsp->status = 0;
2681         rsp->table_rule_add_default.data = data_out;
2682
2683         return rsp;
2684 }
2685
2686 static struct pipeline_msg_rsp *
2687 pipeline_msg_handle_table_rule_add_bulk(struct pipeline_data *p,
2688         struct pipeline_msg_req *req)
2689 {
2690         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2691
2692         uint32_t table_id = req->id;
2693         struct softnic_table_rule_match *match = req->table_rule_add_bulk.match;
2694         struct softnic_table_rule_action *action = req->table_rule_add_bulk.action;
2695         struct rte_pipeline_table_entry **data =
2696                 (struct rte_pipeline_table_entry **)req->table_rule_add_bulk.data;
2697         uint32_t n_rules = req->table_rule_add_bulk.n_rules;
2698         uint32_t bulk = req->table_rule_add_bulk.bulk;
2699
2700         struct rte_table_action *a = p->table_data[table_id].a;
2701         union table_rule_match_low_level *match_ll;
2702         uint8_t *action_ll;
2703         void **match_ll_ptr;
2704         struct rte_pipeline_table_entry **action_ll_ptr;
2705         int *found, status;
2706         uint32_t i;
2707
2708         /* Memory allocation */
2709         match_ll = calloc(n_rules, sizeof(union table_rule_match_low_level));
2710         action_ll = calloc(n_rules, TABLE_RULE_ACTION_SIZE_MAX);
2711         match_ll_ptr = calloc(n_rules, sizeof(void *));
2712         action_ll_ptr =
2713                 calloc(n_rules, sizeof(struct rte_pipeline_table_entry *));
2714         found = calloc(n_rules, sizeof(int));
2715
2716         if (match_ll == NULL ||
2717                 action_ll == NULL ||
2718                 match_ll_ptr == NULL ||
2719                 action_ll_ptr == NULL ||
2720                 found == NULL)
2721                 goto fail;
2722
2723         for (i = 0; i < n_rules; i++) {
2724                 match_ll_ptr[i] = (void *)&match_ll[i];
2725                 action_ll_ptr[i] =
2726                         (struct rte_pipeline_table_entry *)&action_ll[i * TABLE_RULE_ACTION_SIZE_MAX];
2727         }
2728
2729         /* Rule match conversion */
2730         for (i = 0; i < n_rules; i++) {
2731                 status = match_convert(&match[i], match_ll_ptr[i], 1);
2732                 if (status)
2733                         goto fail;
2734         }
2735
2736         /* Rule action conversion */
2737         for (i = 0; i < n_rules; i++) {
2738                 status = action_convert(a, &action[i], action_ll_ptr[i]);
2739                 if (status)
2740                         goto fail;
2741         }
2742
2743         /* Add rule (match, action) to table */
2744         if (bulk) {
2745                 status = rte_pipeline_table_entry_add_bulk(p->p,
2746                         table_id,
2747                         match_ll_ptr,
2748                         action_ll_ptr,
2749                         n_rules,
2750                         found,
2751                         data);
2752                 if (status)
2753                         n_rules = 0;
2754         } else {
2755                 for (i = 0; i < n_rules; i++) {
2756                         status = rte_pipeline_table_entry_add(p->p,
2757                                 table_id,
2758                                 match_ll_ptr[i],
2759                                 action_ll_ptr[i],
2760                                 &found[i],
2761                                 &data[i]);
2762                         if (status) {
2763                                 n_rules = i;
2764                                 break;
2765                         }
2766                 }
2767         }
2768
2769         /* Write response */
2770         rsp->status = 0;
2771         rsp->table_rule_add_bulk.n_rules = n_rules;
2772
2773         /* Free */
2774         free(found);
2775         free(action_ll_ptr);
2776         free(match_ll_ptr);
2777         free(action_ll);
2778         free(match_ll);
2779
2780         return rsp;
2781
2782 fail:
2783         free(found);
2784         free(action_ll_ptr);
2785         free(match_ll_ptr);
2786         free(action_ll);
2787         free(match_ll);
2788
2789         rsp->status = -1;
2790         rsp->table_rule_add_bulk.n_rules = 0;
2791         return rsp;
2792 }
2793
2794 static struct pipeline_msg_rsp *
2795 pipeline_msg_handle_table_rule_delete(struct pipeline_data *p,
2796         struct pipeline_msg_req *req)
2797 {
2798         union table_rule_match_low_level match_ll;
2799         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2800         struct softnic_table_rule_match *match = &req->table_rule_delete.match;
2801         uint32_t table_id = req->id;
2802         int key_found, status;
2803
2804         status = match_convert(match, &match_ll, 0);
2805         if (status) {
2806                 rsp->status = -1;
2807                 return rsp;
2808         }
2809
2810         rsp->status = rte_pipeline_table_entry_delete(p->p,
2811                 table_id,
2812                 &match_ll,
2813                 &key_found,
2814                 NULL);
2815
2816         return rsp;
2817 }
2818
2819 static struct pipeline_msg_rsp *
2820 pipeline_msg_handle_table_rule_delete_default(struct pipeline_data *p,
2821         struct pipeline_msg_req *req)
2822 {
2823         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2824         uint32_t table_id = req->id;
2825
2826         rsp->status = rte_pipeline_table_default_entry_delete(p->p,
2827                 table_id,
2828                 NULL);
2829
2830         return rsp;
2831 }
2832
2833 static struct pipeline_msg_rsp *
2834 pipeline_msg_handle_table_rule_stats_read(struct pipeline_data *p,
2835         struct pipeline_msg_req *req)
2836 {
2837         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2838         uint32_t table_id = req->id;
2839         void *data = req->table_rule_stats_read.data;
2840         int clear = req->table_rule_stats_read.clear;
2841         struct rte_table_action *a = p->table_data[table_id].a;
2842
2843         rsp->status = rte_table_action_stats_read(a,
2844                 data,
2845                 &rsp->table_rule_stats_read.stats,
2846                 clear);
2847
2848         return rsp;
2849 }
2850
2851 static struct pipeline_msg_rsp *
2852 pipeline_msg_handle_table_mtr_profile_add(struct pipeline_data *p,
2853         struct pipeline_msg_req *req)
2854 {
2855         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2856         uint32_t table_id = req->id;
2857         uint32_t meter_profile_id = req->table_mtr_profile_add.meter_profile_id;
2858         struct rte_table_action_meter_profile *profile =
2859                 &req->table_mtr_profile_add.profile;
2860         struct rte_table_action *a = p->table_data[table_id].a;
2861
2862         rsp->status = rte_table_action_meter_profile_add(a,
2863                 meter_profile_id,
2864                 profile);
2865
2866         return rsp;
2867 }
2868
2869 static struct pipeline_msg_rsp *
2870 pipeline_msg_handle_table_mtr_profile_delete(struct pipeline_data *p,
2871         struct pipeline_msg_req *req)
2872 {
2873         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2874         uint32_t table_id = req->id;
2875         uint32_t meter_profile_id =
2876                 req->table_mtr_profile_delete.meter_profile_id;
2877         struct rte_table_action *a = p->table_data[table_id].a;
2878
2879         rsp->status = rte_table_action_meter_profile_delete(a,
2880                 meter_profile_id);
2881
2882         return rsp;
2883 }
2884
2885 static struct pipeline_msg_rsp *
2886 pipeline_msg_handle_table_rule_mtr_read(struct pipeline_data *p,
2887         struct pipeline_msg_req *req)
2888 {
2889         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2890         uint32_t table_id = req->id;
2891         void *data = req->table_rule_mtr_read.data;
2892         uint32_t tc_mask = req->table_rule_mtr_read.tc_mask;
2893         int clear = req->table_rule_mtr_read.clear;
2894         struct rte_table_action *a = p->table_data[table_id].a;
2895
2896         rsp->status = rte_table_action_meter_read(a,
2897                 data,
2898                 tc_mask,
2899                 &rsp->table_rule_mtr_read.stats,
2900                 clear);
2901
2902         return rsp;
2903 }
2904
2905 static struct pipeline_msg_rsp *
2906 pipeline_msg_handle_table_dscp_table_update(struct pipeline_data *p,
2907         struct pipeline_msg_req *req)
2908 {
2909         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2910         uint32_t table_id = req->id;
2911         uint64_t dscp_mask = req->table_dscp_table_update.dscp_mask;
2912         struct rte_table_action_dscp_table *dscp_table =
2913                 &req->table_dscp_table_update.dscp_table;
2914         struct rte_table_action *a = p->table_data[table_id].a;
2915
2916         rsp->status = rte_table_action_dscp_table_update(a,
2917                 dscp_mask,
2918                 dscp_table);
2919
2920         return rsp;
2921 }
2922
2923 static struct pipeline_msg_rsp *
2924 pipeline_msg_handle_table_rule_ttl_read(struct pipeline_data *p,
2925         struct pipeline_msg_req *req)
2926 {
2927         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2928         uint32_t table_id = req->id;
2929         void *data = req->table_rule_ttl_read.data;
2930         int clear = req->table_rule_ttl_read.clear;
2931         struct rte_table_action *a = p->table_data[table_id].a;
2932
2933         rsp->status = rte_table_action_ttl_read(a,
2934                 data,
2935                 &rsp->table_rule_ttl_read.stats,
2936                 clear);
2937
2938         return rsp;
2939 }
2940
2941 static void
2942 pipeline_msg_handle(struct pipeline_data *p)
2943 {
2944         for ( ; ; ) {
2945                 struct pipeline_msg_req *req;
2946                 struct pipeline_msg_rsp *rsp;
2947
2948                 req = pipeline_msg_recv(p->msgq_req);
2949                 if (req == NULL)
2950                         break;
2951
2952                 switch (req->type) {
2953                 case PIPELINE_REQ_PORT_IN_STATS_READ:
2954                         rsp = pipeline_msg_handle_port_in_stats_read(p, req);
2955                         break;
2956
2957                 case PIPELINE_REQ_PORT_IN_ENABLE:
2958                         rsp = pipeline_msg_handle_port_in_enable(p, req);
2959                         break;
2960
2961                 case PIPELINE_REQ_PORT_IN_DISABLE:
2962                         rsp = pipeline_msg_handle_port_in_disable(p, req);
2963                         break;
2964
2965                 case PIPELINE_REQ_PORT_OUT_STATS_READ:
2966                         rsp = pipeline_msg_handle_port_out_stats_read(p, req);
2967                         break;
2968
2969                 case PIPELINE_REQ_TABLE_STATS_READ:
2970                         rsp = pipeline_msg_handle_table_stats_read(p, req);
2971                         break;
2972
2973                 case PIPELINE_REQ_TABLE_RULE_ADD:
2974                         rsp = pipeline_msg_handle_table_rule_add(p, req);
2975                         break;
2976
2977                 case PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT:
2978                         rsp = pipeline_msg_handle_table_rule_add_default(p,     req);
2979                         break;
2980
2981                 case PIPELINE_REQ_TABLE_RULE_ADD_BULK:
2982                         rsp = pipeline_msg_handle_table_rule_add_bulk(p, req);
2983                         break;
2984
2985                 case PIPELINE_REQ_TABLE_RULE_DELETE:
2986                         rsp = pipeline_msg_handle_table_rule_delete(p, req);
2987                         break;
2988
2989                 case PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT:
2990                         rsp = pipeline_msg_handle_table_rule_delete_default(p, req);
2991                         break;
2992
2993                 case PIPELINE_REQ_TABLE_RULE_STATS_READ:
2994                         rsp = pipeline_msg_handle_table_rule_stats_read(p, req);
2995                         break;
2996
2997                 case PIPELINE_REQ_TABLE_MTR_PROFILE_ADD:
2998                         rsp = pipeline_msg_handle_table_mtr_profile_add(p, req);
2999                         break;
3000
3001                 case PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE:
3002                         rsp = pipeline_msg_handle_table_mtr_profile_delete(p, req);
3003                         break;
3004
3005                 case PIPELINE_REQ_TABLE_RULE_MTR_READ:
3006                         rsp = pipeline_msg_handle_table_rule_mtr_read(p, req);
3007                         break;
3008
3009                 case PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE:
3010                         rsp = pipeline_msg_handle_table_dscp_table_update(p, req);
3011                         break;
3012
3013                 case PIPELINE_REQ_TABLE_RULE_TTL_READ:
3014                         rsp = pipeline_msg_handle_table_rule_ttl_read(p, req);
3015                         break;
3016
3017                 default:
3018                         rsp = (struct pipeline_msg_rsp *)req;
3019                         rsp->status = -1;
3020                 }
3021
3022                 pipeline_msg_send(p->msgq_rsp, rsp);
3023         }
3024 }
3025
3026 /**
3027  * Data plane threads: main
3028  */
3029 static int32_t
3030 rte_pmd_softnic_run_internal(void *arg)
3031 {
3032         struct rte_eth_dev *dev = arg;
3033         struct pmd_internals *softnic;
3034         struct softnic_thread_data *t;
3035         uint32_t thread_id, j;
3036
3037         softnic = dev->data->dev_private;
3038         thread_id = rte_lcore_id();
3039         t = &softnic->thread_data[thread_id];
3040         t->iter++;
3041
3042         /* Data Plane */
3043         for (j = 0; j < t->n_pipelines; j++)
3044                 rte_pipeline_run(t->p[j]);
3045
3046         /* Control Plane */
3047         if ((t->iter & 0xFLLU) == 0) {
3048                 uint64_t time = rte_get_tsc_cycles();
3049                 uint64_t time_next_min = UINT64_MAX;
3050
3051                 if (time < t->time_next_min)
3052                         return 0;
3053
3054                 /* Pipeline message queues */
3055                 for (j = 0; j < t->n_pipelines; j++) {
3056                         struct pipeline_data *p =
3057                                 &t->pipeline_data[j];
3058                         uint64_t time_next = p->time_next;
3059
3060                         if (time_next <= time) {
3061                                 pipeline_msg_handle(p);
3062                                 rte_pipeline_flush(p->p);
3063                                 time_next = time + p->timer_period;
3064                                 p->time_next = time_next;
3065                         }
3066
3067                         if (time_next < time_next_min)
3068                                 time_next_min = time_next;
3069                 }
3070
3071                 /* Thread message queues */
3072                 {
3073                         uint64_t time_next = t->time_next;
3074
3075                         if (time_next <= time) {
3076                                 thread_msg_handle(t);
3077                                 time_next = time + t->timer_period;
3078                                 t->time_next = time_next;
3079                         }
3080
3081                         if (time_next < time_next_min)
3082                                 time_next_min = time_next;
3083                 }
3084
3085                 t->time_next_min = time_next_min;
3086         }
3087
3088         return 0;
3089 }
3090
3091 int
3092 rte_pmd_softnic_run(uint16_t port_id)
3093 {
3094         struct rte_eth_dev *dev = &rte_eth_devices[port_id];
3095
3096 #ifdef RTE_LIBRTE_ETHDEV_DEBUG
3097         RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, 0);
3098 #endif
3099
3100         return (int)rte_pmd_softnic_run_internal(dev);
3101 }