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