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