net/softnic: add command for pipeline table entries
[dpdk.git] / drivers / net / softnic / rte_eth_softnic_thread.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2018 Intel Corporation
3  */
4
5 #include <stdlib.h>
6
7 #include <rte_common.h>
8 #include <rte_cycles.h>
9 #include <rte_lcore.h>
10 #include <rte_ring.h>
11
12 #include <rte_table_acl.h>
13 #include <rte_table_array.h>
14 #include <rte_table_hash.h>
15 #include <rte_table_lpm.h>
16 #include <rte_table_lpm_ipv6.h>
17 #include "rte_eth_softnic_internals.h"
18
19 /**
20  * Master thread: data plane thread init
21  */
22 void
23 softnic_thread_free(struct pmd_internals *softnic)
24 {
25         uint32_t i;
26
27         RTE_LCORE_FOREACH_SLAVE(i) {
28                 struct softnic_thread *t = &softnic->thread[i];
29
30                 /* MSGQs */
31                 if (t->msgq_req)
32                         rte_ring_free(t->msgq_req);
33
34                 if (t->msgq_rsp)
35                         rte_ring_free(t->msgq_rsp);
36         }
37 }
38
39 int
40 softnic_thread_init(struct pmd_internals *softnic)
41 {
42         uint32_t i;
43
44         RTE_LCORE_FOREACH_SLAVE(i) {
45                 char ring_name[NAME_MAX];
46                 struct rte_ring *msgq_req, *msgq_rsp;
47                 struct softnic_thread *t = &softnic->thread[i];
48                 struct softnic_thread_data *t_data = &softnic->thread_data[i];
49                 uint32_t cpu_id = rte_lcore_to_socket_id(i);
50
51                 /* MSGQs */
52                 snprintf(ring_name, sizeof(ring_name), "%s-TH%u-REQ",
53                         softnic->params.name,
54                         i);
55
56                 msgq_req = rte_ring_create(ring_name,
57                         THREAD_MSGQ_SIZE,
58                         cpu_id,
59                         RING_F_SP_ENQ | RING_F_SC_DEQ);
60
61                 if (msgq_req == NULL) {
62                         softnic_thread_free(softnic);
63                         return -1;
64                 }
65
66                 snprintf(ring_name, sizeof(ring_name), "%s-TH%u-RSP",
67                         softnic->params.name,
68                         i);
69
70                 msgq_rsp = rte_ring_create(ring_name,
71                         THREAD_MSGQ_SIZE,
72                         cpu_id,
73                         RING_F_SP_ENQ | RING_F_SC_DEQ);
74
75                 if (msgq_rsp == NULL) {
76                         softnic_thread_free(softnic);
77                         return -1;
78                 }
79
80                 /* Master thread records */
81                 t->msgq_req = msgq_req;
82                 t->msgq_rsp = msgq_rsp;
83                 t->enabled = 1;
84
85                 /* Data plane thread records */
86                 t_data->n_pipelines = 0;
87                 t_data->msgq_req = msgq_req;
88                 t_data->msgq_rsp = msgq_rsp;
89                 t_data->timer_period =
90                         (rte_get_tsc_hz() * THREAD_TIMER_PERIOD_MS) / 1000;
91                 t_data->time_next = rte_get_tsc_cycles() + t_data->timer_period;
92                 t_data->time_next_min = t_data->time_next;
93         }
94
95         return 0;
96 }
97
98 static inline int
99 thread_is_running(uint32_t thread_id)
100 {
101         enum rte_lcore_state_t thread_state;
102
103         thread_state = rte_eal_get_lcore_state(thread_id);
104         return (thread_state == RUNNING)? 1 : 0;
105 }
106
107 /**
108  * Pipeline is running when:
109  *    (A) Pipeline is mapped to a data plane thread AND
110  *    (B) Its data plane thread is in RUNNING state.
111  */
112 static inline int
113 pipeline_is_running(struct pipeline *p)
114 {
115         if (p->enabled == 0)
116                 return 0;
117
118         return thread_is_running(p->thread_id);
119 }
120
121 /**
122  * Master thread & data plane threads: message passing
123  */
124 enum thread_req_type {
125         THREAD_REQ_PIPELINE_ENABLE = 0,
126         THREAD_REQ_PIPELINE_DISABLE,
127         THREAD_REQ_MAX
128 };
129
130 struct thread_msg_req {
131         enum thread_req_type type;
132
133         union {
134                 struct {
135                         struct rte_pipeline *p;
136                         struct {
137                                 struct rte_table_action *a;
138                         } table[RTE_PIPELINE_TABLE_MAX];
139                         struct rte_ring *msgq_req;
140                         struct rte_ring *msgq_rsp;
141                         uint32_t timer_period_ms;
142                         uint32_t n_tables;
143                 } pipeline_enable;
144
145                 struct {
146                         struct rte_pipeline *p;
147                 } pipeline_disable;
148         };
149 };
150
151 struct thread_msg_rsp {
152         int status;
153 };
154
155 /**
156  * Master thread
157  */
158 static struct thread_msg_req *
159 thread_msg_alloc(void)
160 {
161         size_t size = RTE_MAX(sizeof(struct thread_msg_req),
162                 sizeof(struct thread_msg_rsp));
163
164         return calloc(1, size);
165 }
166
167 static void
168 thread_msg_free(struct thread_msg_rsp *rsp)
169 {
170         free(rsp);
171 }
172
173 static struct thread_msg_rsp *
174 thread_msg_send_recv(struct pmd_internals *softnic,
175         uint32_t thread_id,
176         struct thread_msg_req *req)
177 {
178         struct softnic_thread *t = &softnic->thread[thread_id];
179         struct rte_ring *msgq_req = t->msgq_req;
180         struct rte_ring *msgq_rsp = t->msgq_rsp;
181         struct thread_msg_rsp *rsp;
182         int status;
183
184         /* send */
185         do {
186                 status = rte_ring_sp_enqueue(msgq_req, req);
187         } while (status == -ENOBUFS);
188
189         /* recv */
190         do {
191                 status = rte_ring_sc_dequeue(msgq_rsp, (void **)&rsp);
192         } while (status != 0);
193
194         return rsp;
195 }
196
197 int
198 softnic_thread_pipeline_enable(struct pmd_internals *softnic,
199         uint32_t thread_id,
200         const char *pipeline_name)
201 {
202         struct pipeline *p = softnic_pipeline_find(softnic, pipeline_name);
203         struct softnic_thread *t;
204         struct thread_msg_req *req;
205         struct thread_msg_rsp *rsp;
206         uint32_t i;
207         int status;
208
209         /* Check input params */
210         if ((thread_id >= RTE_MAX_LCORE) ||
211                 (p == NULL) ||
212                 (p->n_ports_in == 0) ||
213                 (p->n_ports_out == 0) ||
214                 (p->n_tables == 0))
215                 return -1;
216
217         t = &softnic->thread[thread_id];
218         if ((t->enabled == 0) ||
219                 p->enabled)
220                 return -1;
221
222         if (!thread_is_running(thread_id)) {
223                 struct softnic_thread_data *td = &softnic->thread_data[thread_id];
224                 struct pipeline_data *tdp = &td->pipeline_data[td->n_pipelines];
225
226                 if (td->n_pipelines >= THREAD_PIPELINES_MAX)
227                         return -1;
228
229                 /* Data plane thread */
230                 td->p[td->n_pipelines] = p->p;
231
232                 tdp->p = p->p;
233                 for (i = 0; i < p->n_tables; i++)
234                         tdp->table_data[i].a =
235                                 p->table[i].a;
236                 tdp->n_tables = p->n_tables;
237
238                 tdp->msgq_req = p->msgq_req;
239                 tdp->msgq_rsp = p->msgq_rsp;
240                 tdp->timer_period = (rte_get_tsc_hz() * p->timer_period_ms) / 1000;
241                 tdp->time_next = rte_get_tsc_cycles() + tdp->timer_period;
242
243                 td->n_pipelines++;
244
245                 /* Pipeline */
246                 p->thread_id = thread_id;
247                 p->enabled = 1;
248
249                 return 0;
250         }
251
252         /* Allocate request */
253         req = thread_msg_alloc();
254         if (req == NULL)
255                 return -1;
256
257         /* Write request */
258         req->type = THREAD_REQ_PIPELINE_ENABLE;
259         req->pipeline_enable.p = p->p;
260         for (i = 0; i < p->n_tables; i++)
261                 req->pipeline_enable.table[i].a =
262                         p->table[i].a;
263         req->pipeline_enable.msgq_req = p->msgq_req;
264         req->pipeline_enable.msgq_rsp = p->msgq_rsp;
265         req->pipeline_enable.timer_period_ms = p->timer_period_ms;
266         req->pipeline_enable.n_tables = p->n_tables;
267
268         /* Send request and wait for response */
269         rsp = thread_msg_send_recv(softnic, thread_id, req);
270         if (rsp == NULL)
271                 return -1;
272
273         /* Read response */
274         status = rsp->status;
275
276         /* Free response */
277         thread_msg_free(rsp);
278
279         /* Request completion */
280         if (status)
281                 return status;
282
283         p->thread_id = thread_id;
284         p->enabled = 1;
285
286         return 0;
287 }
288
289 int
290 softnic_thread_pipeline_disable(struct pmd_internals *softnic,
291         uint32_t thread_id,
292         const char *pipeline_name)
293 {
294         struct pipeline *p = softnic_pipeline_find(softnic, pipeline_name);
295         struct softnic_thread *t;
296         struct thread_msg_req *req;
297         struct thread_msg_rsp *rsp;
298         int status;
299
300         /* Check input params */
301         if ((thread_id >= RTE_MAX_LCORE) ||
302                 (p == NULL))
303                 return -1;
304
305         t = &softnic->thread[thread_id];
306         if (t->enabled == 0)
307                 return -1;
308
309         if (p->enabled == 0)
310                 return 0;
311
312         if (p->thread_id != thread_id)
313                 return -1;
314
315         if (!thread_is_running(thread_id)) {
316                 struct softnic_thread_data *td = &softnic->thread_data[thread_id];
317                 uint32_t i;
318
319                 for (i = 0; i < td->n_pipelines; i++) {
320                         struct pipeline_data *tdp = &td->pipeline_data[i];
321
322                         if (tdp->p != p->p)
323                                 continue;
324
325                         /* Data plane thread */
326                         if (i < td->n_pipelines - 1) {
327                                 struct rte_pipeline *pipeline_last =
328                                         td->p[td->n_pipelines - 1];
329                                 struct pipeline_data *tdp_last =
330                                         &td->pipeline_data[td->n_pipelines - 1];
331
332                                 td->p[i] = pipeline_last;
333                                 memcpy(tdp, tdp_last, sizeof(*tdp));
334                         }
335
336                         td->n_pipelines--;
337
338                         /* Pipeline */
339                         p->enabled = 0;
340
341                         break;
342                 }
343
344                 return 0;
345         }
346
347         /* Allocate request */
348         req = thread_msg_alloc();
349         if (req == NULL)
350                 return -1;
351
352         /* Write request */
353         req->type = THREAD_REQ_PIPELINE_DISABLE;
354         req->pipeline_disable.p = p->p;
355
356         /* Send request and wait for response */
357         rsp = thread_msg_send_recv(softnic, thread_id, req);
358         if (rsp == NULL)
359                 return -1;
360
361         /* Read response */
362         status = rsp->status;
363
364         /* Free response */
365         thread_msg_free(rsp);
366
367         /* Request completion */
368         if (status)
369                 return status;
370
371         p->enabled = 0;
372
373         return 0;
374 }
375
376 /**
377  * Data plane threads: message handling
378  */
379 static inline struct thread_msg_req *
380 thread_msg_recv(struct rte_ring *msgq_req)
381 {
382         struct thread_msg_req *req;
383
384         int status = rte_ring_sc_dequeue(msgq_req, (void **)&req);
385
386         if (status != 0)
387                 return NULL;
388
389         return req;
390 }
391
392 static inline void
393 thread_msg_send(struct rte_ring *msgq_rsp,
394         struct thread_msg_rsp *rsp)
395 {
396         int status;
397
398         do {
399                 status = rte_ring_sp_enqueue(msgq_rsp, rsp);
400         } while (status == -ENOBUFS);
401 }
402
403 static struct thread_msg_rsp *
404 thread_msg_handle_pipeline_enable(struct softnic_thread_data *t,
405         struct thread_msg_req *req)
406 {
407         struct thread_msg_rsp *rsp = (struct thread_msg_rsp *)req;
408         struct pipeline_data *p = &t->pipeline_data[t->n_pipelines];
409         uint32_t i;
410
411         /* Request */
412         if (t->n_pipelines >= THREAD_PIPELINES_MAX) {
413                 rsp->status = -1;
414                 return rsp;
415         }
416
417         t->p[t->n_pipelines] = req->pipeline_enable.p;
418
419         p->p = req->pipeline_enable.p;
420         for (i = 0; i < req->pipeline_enable.n_tables; i++)
421                 p->table_data[i].a =
422                         req->pipeline_enable.table[i].a;
423
424         p->n_tables = req->pipeline_enable.n_tables;
425
426         p->msgq_req = req->pipeline_enable.msgq_req;
427         p->msgq_rsp = req->pipeline_enable.msgq_rsp;
428         p->timer_period =
429                 (rte_get_tsc_hz() * req->pipeline_enable.timer_period_ms) / 1000;
430         p->time_next = rte_get_tsc_cycles() + p->timer_period;
431
432         t->n_pipelines++;
433
434         /* Response */
435         rsp->status = 0;
436         return rsp;
437 }
438
439 static struct thread_msg_rsp *
440 thread_msg_handle_pipeline_disable(struct softnic_thread_data *t,
441         struct thread_msg_req *req)
442 {
443         struct thread_msg_rsp *rsp = (struct thread_msg_rsp *)req;
444         uint32_t n_pipelines = t->n_pipelines;
445         struct rte_pipeline *pipeline = req->pipeline_disable.p;
446         uint32_t i;
447
448         /* find pipeline */
449         for (i = 0; i < n_pipelines; i++) {
450                 struct pipeline_data *p = &t->pipeline_data[i];
451
452                 if (p->p != pipeline)
453                         continue;
454
455                 if (i < n_pipelines - 1) {
456                         struct rte_pipeline *pipeline_last =
457                                 t->p[n_pipelines - 1];
458                         struct pipeline_data *p_last =
459                                 &t->pipeline_data[n_pipelines - 1];
460
461                         t->p[i] = pipeline_last;
462                         memcpy(p, p_last, sizeof(*p));
463                 }
464
465                 t->n_pipelines--;
466
467                 rsp->status = 0;
468                 return rsp;
469         }
470
471         /* should not get here */
472         rsp->status = 0;
473         return rsp;
474 }
475
476 static void
477 thread_msg_handle(struct softnic_thread_data *t)
478 {
479         for ( ; ; ) {
480                 struct thread_msg_req *req;
481                 struct thread_msg_rsp *rsp;
482
483                 req = thread_msg_recv(t->msgq_req);
484                 if (req == NULL)
485                         break;
486
487                 switch (req->type) {
488                 case THREAD_REQ_PIPELINE_ENABLE:
489                         rsp = thread_msg_handle_pipeline_enable(t, req);
490                         break;
491
492                 case THREAD_REQ_PIPELINE_DISABLE:
493                         rsp = thread_msg_handle_pipeline_disable(t, req);
494                         break;
495
496                 default:
497                         rsp = (struct thread_msg_rsp *)req;
498                         rsp->status = -1;
499                 }
500
501                 thread_msg_send(t->msgq_rsp, rsp);
502         }
503 }
504
505 /**
506  * Master thread & data plane threads: message passing
507  */
508 enum pipeline_req_type {
509         /* Port IN */
510         PIPELINE_REQ_PORT_IN_ENABLE,
511         PIPELINE_REQ_PORT_IN_DISABLE,
512
513         /* Table */
514         PIPELINE_REQ_TABLE_RULE_ADD,
515         PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT,
516         PIPELINE_REQ_TABLE_RULE_ADD_BULK,
517         PIPELINE_REQ_TABLE_RULE_DELETE,
518         PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT,
519
520         PIPELINE_REQ_MAX
521 };
522
523 struct pipeline_msg_req_table_rule_add {
524         struct softnic_table_rule_match match;
525         struct softnic_table_rule_action action;
526 };
527
528 struct pipeline_msg_req_table_rule_add_default {
529         struct softnic_table_rule_action action;
530 };
531
532 struct pipeline_msg_req_table_rule_add_bulk {
533         struct softnic_table_rule_match *match;
534         struct softnic_table_rule_action *action;
535         void **data;
536         uint32_t n_rules;
537         int bulk;
538 };
539
540 struct pipeline_msg_req_table_rule_delete {
541         struct softnic_table_rule_match match;
542 };
543
544 struct pipeline_msg_req {
545         enum pipeline_req_type type;
546         uint32_t id; /* Port IN, port OUT or table ID */
547
548         RTE_STD_C11
549         union {
550                 struct pipeline_msg_req_table_rule_add table_rule_add;
551                 struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
552                 struct pipeline_msg_req_table_rule_add_bulk table_rule_add_bulk;
553                 struct pipeline_msg_req_table_rule_delete table_rule_delete;
554         };
555 };
556
557 struct pipeline_msg_rsp_table_rule_add {
558         void *data;
559 };
560
561 struct pipeline_msg_rsp_table_rule_add_default {
562         void *data;
563 };
564
565 struct pipeline_msg_rsp_table_rule_add_bulk {
566         uint32_t n_rules;
567 };
568
569 struct pipeline_msg_rsp {
570         int status;
571
572         RTE_STD_C11
573         union {
574                 struct pipeline_msg_rsp_table_rule_add table_rule_add;
575                 struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
576                 struct pipeline_msg_rsp_table_rule_add_bulk table_rule_add_bulk;
577         };
578 };
579
580 /**
581  * Master thread
582  */
583 static struct pipeline_msg_req *
584 pipeline_msg_alloc(void)
585 {
586         size_t size = RTE_MAX(sizeof(struct pipeline_msg_req),
587                 sizeof(struct pipeline_msg_rsp));
588
589         return calloc(1, size);
590 }
591
592 static void
593 pipeline_msg_free(struct pipeline_msg_rsp *rsp)
594 {
595         free(rsp);
596 }
597
598 static struct pipeline_msg_rsp *
599 pipeline_msg_send_recv(struct pipeline *p,
600         struct pipeline_msg_req *req)
601 {
602         struct rte_ring *msgq_req = p->msgq_req;
603         struct rte_ring *msgq_rsp = p->msgq_rsp;
604         struct pipeline_msg_rsp *rsp;
605         int status;
606
607         /* send */
608         do {
609                 status = rte_ring_sp_enqueue(msgq_req, req);
610         } while (status == -ENOBUFS);
611
612         /* recv */
613         do {
614                 status = rte_ring_sc_dequeue(msgq_rsp, (void **)&rsp);
615         } while (status != 0);
616
617         return rsp;
618 }
619
620 int
621 softnic_pipeline_port_in_enable(struct pmd_internals *softnic,
622         const char *pipeline_name,
623         uint32_t port_id)
624 {
625         struct pipeline *p;
626         struct pipeline_msg_req *req;
627         struct pipeline_msg_rsp *rsp;
628         int status;
629
630         /* Check input params */
631         if (pipeline_name == NULL)
632                 return -1;
633
634         p = softnic_pipeline_find(softnic, pipeline_name);
635         if (p == NULL ||
636                 port_id >= p->n_ports_in)
637                 return -1;
638
639         if (!pipeline_is_running(p)) {
640                 status = rte_pipeline_port_in_enable(p->p, port_id);
641                 return status;
642         }
643
644         /* Allocate request */
645         req = pipeline_msg_alloc();
646         if (req == NULL)
647                 return -1;
648
649         /* Write request */
650         req->type = PIPELINE_REQ_PORT_IN_ENABLE;
651         req->id = port_id;
652
653         /* Send request and wait for response */
654         rsp = pipeline_msg_send_recv(p, req);
655         if (rsp == NULL)
656                 return -1;
657
658         /* Read response */
659         status = rsp->status;
660
661         /* Free response */
662         pipeline_msg_free(rsp);
663
664         return status;
665 }
666
667 int
668 softnic_pipeline_port_in_disable(struct pmd_internals *softnic,
669         const char *pipeline_name,
670         uint32_t port_id)
671 {
672         struct pipeline *p;
673         struct pipeline_msg_req *req;
674         struct pipeline_msg_rsp *rsp;
675         int status;
676
677         /* Check input params */
678         if (pipeline_name == NULL)
679                 return -1;
680
681         p = softnic_pipeline_find(softnic, pipeline_name);
682         if (p == NULL ||
683                 port_id >= p->n_ports_in)
684                 return -1;
685
686         if (!pipeline_is_running(p)) {
687                 status = rte_pipeline_port_in_disable(p->p, port_id);
688                 return status;
689         }
690
691         /* Allocate request */
692         req = pipeline_msg_alloc();
693         if (req == NULL)
694                 return -1;
695
696         /* Write request */
697         req->type = PIPELINE_REQ_PORT_IN_DISABLE;
698         req->id = port_id;
699
700         /* Send request and wait for response */
701         rsp = pipeline_msg_send_recv(p, req);
702         if (rsp == NULL)
703                 return -1;
704
705         /* Read response */
706         status = rsp->status;
707
708         /* Free response */
709         pipeline_msg_free(rsp);
710
711         return status;
712 }
713
714 static int
715 match_check(struct softnic_table_rule_match *match,
716         struct pipeline *p,
717         uint32_t table_id)
718 {
719         struct softnic_table *table;
720
721         if (match == NULL ||
722                 p == NULL ||
723                 table_id >= p->n_tables)
724                 return -1;
725
726         table = &p->table[table_id];
727         if (match->match_type != table->params.match_type)
728                 return -1;
729
730         switch (match->match_type) {
731         case TABLE_ACL:
732         {
733                 struct softnic_table_acl_params *t = &table->params.match.acl;
734                 struct softnic_table_rule_match_acl *r = &match->match.acl;
735
736                 if ((r->ip_version && (t->ip_version == 0)) ||
737                         ((r->ip_version == 0) && t->ip_version))
738                         return -1;
739
740                 if (r->ip_version) {
741                         if (r->sa_depth > 32 ||
742                                 r->da_depth > 32)
743                                 return -1;
744                 } else {
745                         if (r->sa_depth > 128 ||
746                                 r->da_depth > 128)
747                                 return -1;
748                 }
749                 return 0;
750         }
751
752         case TABLE_ARRAY:
753                 return 0;
754
755         case TABLE_HASH:
756                 return 0;
757
758         case TABLE_LPM:
759         {
760                 struct softnic_table_lpm_params *t = &table->params.match.lpm;
761                 struct softnic_table_rule_match_lpm *r = &match->match.lpm;
762
763                 if ((r->ip_version && (t->key_size != 4)) ||
764                         ((r->ip_version == 0) && (t->key_size != 16)))
765                         return -1;
766
767                 if (r->ip_version) {
768                         if (r->depth > 32)
769                                 return -1;
770                 } else {
771                         if (r->depth > 128)
772                                 return -1;
773                 }
774                 return 0;
775         }
776
777         case TABLE_STUB:
778                 return -1;
779
780         default:
781                 return -1;
782         }
783 }
784
785 static int
786 action_check(struct softnic_table_rule_action *action,
787         struct pipeline *p,
788         uint32_t table_id)
789 {
790         struct softnic_table_action_profile *ap;
791
792         if (action == NULL ||
793                 p == NULL ||
794                 table_id >= p->n_tables)
795                 return -1;
796
797         ap = p->table[table_id].ap;
798         if (action->action_mask != ap->params.action_mask)
799                 return -1;
800
801         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
802                 if (action->fwd.action == RTE_PIPELINE_ACTION_PORT &&
803                         action->fwd.id >= p->n_ports_out)
804                         return -1;
805
806                 if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE &&
807                         action->fwd.id >= p->n_tables)
808                         return -1;
809         }
810
811         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
812                 uint32_t tc_mask0 = (1 << ap->params.mtr.n_tc) - 1;
813                 uint32_t tc_mask1 = action->mtr.tc_mask;
814
815                 if (tc_mask1 != tc_mask0)
816                         return -1;
817         }
818
819         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
820                 uint32_t n_subports_per_port =
821                         ap->params.tm.n_subports_per_port;
822                 uint32_t n_pipes_per_subport =
823                         ap->params.tm.n_pipes_per_subport;
824                 uint32_t subport_id = action->tm.subport_id;
825                 uint32_t pipe_id = action->tm.pipe_id;
826
827                 if (subport_id >= n_subports_per_port ||
828                         pipe_id >= n_pipes_per_subport)
829                         return -1;
830         }
831
832         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
833                 uint64_t encap_mask = ap->params.encap.encap_mask;
834                 enum rte_table_action_encap_type type = action->encap.type;
835
836                 if ((encap_mask & (1LLU << type)) == 0)
837                         return -1;
838         }
839
840         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
841                 int ip_version0 = ap->params.common.ip_version;
842                 int ip_version1 = action->nat.ip_version;
843
844                 if ((ip_version1 && (ip_version0 == 0)) ||
845                         ((ip_version1 == 0) && ip_version0))
846                         return -1;
847         }
848
849         return 0;
850 }
851
852 static int
853 action_default_check(struct softnic_table_rule_action *action,
854         struct pipeline *p,
855         uint32_t table_id)
856 {
857         if (action == NULL ||
858                 action->action_mask != (1LLU << RTE_TABLE_ACTION_FWD) ||
859                 p == NULL ||
860                 table_id >= p->n_tables)
861                 return -1;
862
863         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
864                 if (action->fwd.action == RTE_PIPELINE_ACTION_PORT &&
865                         action->fwd.id >= p->n_ports_out)
866                         return -1;
867
868                 if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE &&
869                         action->fwd.id >= p->n_tables)
870                         return -1;
871         }
872
873         return 0;
874 }
875
876 union table_rule_match_low_level {
877         struct rte_table_acl_rule_add_params acl_add;
878         struct rte_table_acl_rule_delete_params acl_delete;
879         struct rte_table_array_key array;
880         uint8_t hash[TABLE_RULE_MATCH_SIZE_MAX];
881         struct rte_table_lpm_key lpm_ipv4;
882         struct rte_table_lpm_ipv6_key lpm_ipv6;
883 };
884
885 static int
886 match_convert(struct softnic_table_rule_match *mh,
887         union table_rule_match_low_level *ml,
888         int add);
889
890 static int
891 action_convert(struct rte_table_action *a,
892         struct softnic_table_rule_action *action,
893         struct rte_pipeline_table_entry *data);
894
895 int
896 softnic_pipeline_table_rule_add(struct pmd_internals *softnic,
897         const char *pipeline_name,
898         uint32_t table_id,
899         struct softnic_table_rule_match *match,
900         struct softnic_table_rule_action *action,
901         void **data)
902 {
903         struct pipeline *p;
904         struct pipeline_msg_req *req;
905         struct pipeline_msg_rsp *rsp;
906         int status;
907
908         /* Check input params */
909         if (pipeline_name == NULL ||
910                 match == NULL ||
911                 action == NULL ||
912                 data == NULL)
913                 return -1;
914
915         p = softnic_pipeline_find(softnic, pipeline_name);
916         if (p == NULL ||
917                 table_id >= p->n_tables ||
918                 match_check(match, p, table_id) ||
919                 action_check(action, p, table_id))
920                 return -1;
921
922         if (!pipeline_is_running(p)) {
923                 struct rte_table_action *a = p->table[table_id].a;
924                 union table_rule_match_low_level match_ll;
925                 struct rte_pipeline_table_entry *data_in, *data_out;
926                 int key_found;
927                 uint8_t *buffer;
928
929                 buffer = calloc(TABLE_RULE_ACTION_SIZE_MAX, sizeof(uint8_t));
930                 if (buffer == NULL)
931                         return -1;
932
933                 /* Table match-action rule conversion */
934                 data_in = (struct rte_pipeline_table_entry *)buffer;
935
936                 status = match_convert(match, &match_ll, 1);
937                 if (status) {
938                         free(buffer);
939                         return -1;
940                 }
941
942                 status = action_convert(a, action, data_in);
943                 if (status) {
944                         free(buffer);
945                         return -1;
946                 }
947
948                 /* Add rule (match, action) to table */
949                 status = rte_pipeline_table_entry_add(p->p,
950                                 table_id,
951                                 &match_ll,
952                                 data_in,
953                                 &key_found,
954                                 &data_out);
955                 if (status) {
956                         free(buffer);
957                         return -1;
958                 }
959
960                 /* Write Response */
961                 *data = data_out;
962
963                 free(buffer);
964                 return 0;
965         }
966
967         /* Allocate request */
968         req = pipeline_msg_alloc();
969         if (req == NULL)
970                 return -1;
971
972         /* Write request */
973         req->type = PIPELINE_REQ_TABLE_RULE_ADD;
974         req->id = table_id;
975         memcpy(&req->table_rule_add.match, match, sizeof(*match));
976         memcpy(&req->table_rule_add.action, action, sizeof(*action));
977
978         /* Send request and wait for response */
979         rsp = pipeline_msg_send_recv(p, req);
980         if (rsp == NULL)
981                 return -1;
982
983         /* Read response */
984         status = rsp->status;
985         if (status == 0)
986                 *data = rsp->table_rule_add.data;
987
988         /* Free response */
989         pipeline_msg_free(rsp);
990
991         return status;
992 }
993
994 int
995 softnic_pipeline_table_rule_add_default(struct pmd_internals *softnic,
996         const char *pipeline_name,
997         uint32_t table_id,
998         struct softnic_table_rule_action *action,
999         void **data)
1000 {
1001         struct pipeline *p;
1002         struct pipeline_msg_req *req;
1003         struct pipeline_msg_rsp *rsp;
1004         int status;
1005
1006         /* Check input params */
1007         if (pipeline_name == NULL ||
1008                 action == NULL ||
1009                 data == NULL)
1010                 return -1;
1011
1012         p = softnic_pipeline_find(softnic, pipeline_name);
1013         if (p == NULL ||
1014                 table_id >= p->n_tables ||
1015                 action_default_check(action, p, table_id))
1016                 return -1;
1017
1018         if (!pipeline_is_running(p)) {
1019                 struct rte_pipeline_table_entry *data_in, *data_out;
1020                 uint8_t *buffer;
1021
1022                 buffer = calloc(TABLE_RULE_ACTION_SIZE_MAX, sizeof(uint8_t));
1023                 if (buffer == NULL)
1024                         return -1;
1025
1026                 /* Apply actions */
1027                 data_in = (struct rte_pipeline_table_entry *)buffer;
1028
1029                 data_in->action = action->fwd.action;
1030                 if (action->fwd.action == RTE_PIPELINE_ACTION_PORT)
1031                         data_in->port_id = action->fwd.id;
1032                 if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE)
1033                         data_in->table_id = action->fwd.id;
1034
1035                 /* Add default rule to table */
1036                 status = rte_pipeline_table_default_entry_add(p->p,
1037                                 table_id,
1038                                 data_in,
1039                                 &data_out);
1040                 if (status) {
1041                         free(buffer);
1042                         return -1;
1043                 }
1044
1045                 /* Write Response */
1046                 *data = data_out;
1047
1048                 free(buffer);
1049                 return 0;
1050         }
1051
1052         /* Allocate request */
1053         req = pipeline_msg_alloc();
1054         if (req == NULL)
1055                 return -1;
1056
1057         /* Write request */
1058         req->type = PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT;
1059         req->id = table_id;
1060         memcpy(&req->table_rule_add_default.action, action, sizeof(*action));
1061
1062         /* Send request and wait for response */
1063         rsp = pipeline_msg_send_recv(p, req);
1064         if (rsp == NULL)
1065                 return -1;
1066
1067         /* Read response */
1068         status = rsp->status;
1069         if (status == 0)
1070                 *data = rsp->table_rule_add_default.data;
1071
1072         /* Free response */
1073         pipeline_msg_free(rsp);
1074
1075         return status;
1076 }
1077
1078 int
1079 softnic_pipeline_table_rule_add_bulk(struct pmd_internals *softnic,
1080         const char *pipeline_name,
1081         uint32_t table_id,
1082         struct softnic_table_rule_match *match,
1083         struct softnic_table_rule_action *action,
1084         void **data,
1085         uint32_t *n_rules)
1086 {
1087         struct pipeline *p;
1088         struct pipeline_msg_req *req;
1089         struct pipeline_msg_rsp *rsp;
1090         uint32_t i;
1091         int status;
1092
1093         /* Check input params */
1094         if (pipeline_name == NULL ||
1095                 match == NULL ||
1096                 action == NULL ||
1097                 data == NULL ||
1098                 n_rules == NULL ||
1099                 (*n_rules == 0))
1100                 return -1;
1101
1102         p = softnic_pipeline_find(softnic, pipeline_name);
1103         if (p == NULL ||
1104                 table_id >= p->n_tables)
1105                 return -1;
1106
1107         for (i = 0; i < *n_rules; i++)
1108                 if (match_check(match, p, table_id) ||
1109                         action_check(action, p, table_id))
1110                         return -1;
1111
1112         if (!pipeline_is_running(p)) {
1113                 struct rte_table_action *a = p->table[table_id].a;
1114                 union table_rule_match_low_level *match_ll;
1115                 uint8_t *action_ll;
1116                 void **match_ll_ptr;
1117                 struct rte_pipeline_table_entry **action_ll_ptr;
1118                 struct rte_pipeline_table_entry **entries_ptr =
1119                         (struct rte_pipeline_table_entry **)data;
1120                 uint32_t bulk =
1121                         (p->table[table_id].params.match_type == TABLE_ACL) ? 1 : 0;
1122                 int *found;
1123
1124                 /* Memory allocation */
1125                 match_ll = calloc(*n_rules, sizeof(union table_rule_match_low_level));
1126                 action_ll = calloc(*n_rules, TABLE_RULE_ACTION_SIZE_MAX);
1127                 match_ll_ptr = calloc(*n_rules, sizeof(void *));
1128                 action_ll_ptr =
1129                         calloc(*n_rules, sizeof(struct rte_pipeline_table_entry *));
1130                 found = calloc(*n_rules, sizeof(int));
1131
1132                 if (match_ll == NULL ||
1133                         action_ll == NULL ||
1134                         match_ll_ptr == NULL ||
1135                         action_ll_ptr == NULL ||
1136                         found == NULL)
1137                         goto fail;
1138
1139                 for (i = 0; i < *n_rules; i++) {
1140                         match_ll_ptr[i] = (void *)&match_ll[i];
1141                         action_ll_ptr[i] =
1142                                 (struct rte_pipeline_table_entry *)&action_ll[i * TABLE_RULE_ACTION_SIZE_MAX];
1143                 }
1144
1145                 /* Rule match conversion */
1146                 for (i = 0; i < *n_rules; i++) {
1147                         status = match_convert(&match[i], match_ll_ptr[i], 1);
1148                         if (status)
1149                                 goto fail;
1150                 }
1151
1152                 /* Rule action conversion */
1153                 for (i = 0; i < *n_rules; i++) {
1154                         status = action_convert(a, &action[i], action_ll_ptr[i]);
1155                         if (status)
1156                                 goto fail;
1157                 }
1158
1159                 /* Add rule (match, action) to table */
1160                 if (bulk) {
1161                         status = rte_pipeline_table_entry_add_bulk(p->p,
1162                                 table_id,
1163                                 match_ll_ptr,
1164                                 action_ll_ptr,
1165                                 *n_rules,
1166                                 found,
1167                                 entries_ptr);
1168                         if (status)
1169                                 *n_rules = 0;
1170                 } else {
1171                         for (i = 0; i < *n_rules; i++) {
1172                                 status = rte_pipeline_table_entry_add(p->p,
1173                                         table_id,
1174                                         match_ll_ptr[i],
1175                                         action_ll_ptr[i],
1176                                         &found[i],
1177                                         &entries_ptr[i]);
1178                                 if (status) {
1179                                         *n_rules = i;
1180                                         break;
1181                                 }
1182                         }
1183                 }
1184
1185                 /* Free */
1186                 free(found);
1187                 free(action_ll_ptr);
1188                 free(match_ll_ptr);
1189                 free(action_ll);
1190                 free(match_ll);
1191
1192                 return status;
1193
1194 fail:
1195                 free(found);
1196                 free(action_ll_ptr);
1197                 free(match_ll_ptr);
1198                 free(action_ll);
1199                 free(match_ll);
1200
1201                 *n_rules = 0;
1202                 return -1;
1203         }
1204
1205         /* Allocate request */
1206         req = pipeline_msg_alloc();
1207         if (req == NULL)
1208                 return -1;
1209
1210         /* Write request */
1211         req->type = PIPELINE_REQ_TABLE_RULE_ADD_BULK;
1212         req->id = table_id;
1213         req->table_rule_add_bulk.match = match;
1214         req->table_rule_add_bulk.action = action;
1215         req->table_rule_add_bulk.data = data;
1216         req->table_rule_add_bulk.n_rules = *n_rules;
1217         req->table_rule_add_bulk.bulk =
1218                 (p->table[table_id].params.match_type == TABLE_ACL) ? 1 : 0;
1219
1220         /* Send request and wait for response */
1221         rsp = pipeline_msg_send_recv(p, req);
1222         if (rsp == NULL)
1223                 return -1;
1224
1225         /* Read response */
1226         status = rsp->status;
1227         if (status == 0)
1228                 *n_rules = rsp->table_rule_add_bulk.n_rules;
1229
1230         /* Free response */
1231         pipeline_msg_free(rsp);
1232
1233         return status;
1234 }
1235
1236 int
1237 softnic_pipeline_table_rule_delete(struct pmd_internals *softnic,
1238         const char *pipeline_name,
1239         uint32_t table_id,
1240         struct softnic_table_rule_match *match)
1241 {
1242         struct pipeline *p;
1243         struct pipeline_msg_req *req;
1244         struct pipeline_msg_rsp *rsp;
1245         int status;
1246
1247         /* Check input params */
1248         if (pipeline_name == NULL ||
1249                 match == NULL)
1250                 return -1;
1251
1252         p = softnic_pipeline_find(softnic, pipeline_name);
1253         if (p == NULL ||
1254                 table_id >= p->n_tables ||
1255                 match_check(match, p, table_id))
1256                 return -1;
1257
1258         if (!pipeline_is_running(p)) {
1259                 union table_rule_match_low_level match_ll;
1260                 int key_found;
1261
1262                 status = match_convert(match, &match_ll, 0);
1263                 if (status)
1264                         return -1;
1265
1266                 status = rte_pipeline_table_entry_delete(p->p,
1267                                 table_id,
1268                                 &match_ll,
1269                                 &key_found,
1270                                 NULL);
1271
1272                 return status;
1273         }
1274
1275         /* Allocate request */
1276         req = pipeline_msg_alloc();
1277         if (req == NULL)
1278                 return -1;
1279
1280         /* Write request */
1281         req->type = PIPELINE_REQ_TABLE_RULE_DELETE;
1282         req->id = table_id;
1283         memcpy(&req->table_rule_delete.match, match, sizeof(*match));
1284
1285         /* Send request and wait for response */
1286         rsp = pipeline_msg_send_recv(p, req);
1287         if (rsp == NULL)
1288                 return -1;
1289
1290         /* Read response */
1291         status = rsp->status;
1292
1293         /* Free response */
1294         pipeline_msg_free(rsp);
1295
1296         return status;
1297 }
1298
1299 int
1300 softnic_pipeline_table_rule_delete_default(struct pmd_internals *softnic,
1301         const char *pipeline_name,
1302         uint32_t table_id)
1303 {
1304         struct pipeline *p;
1305         struct pipeline_msg_req *req;
1306         struct pipeline_msg_rsp *rsp;
1307         int status;
1308
1309         /* Check input params */
1310         if (pipeline_name == NULL)
1311                 return -1;
1312
1313         p = softnic_pipeline_find(softnic, pipeline_name);
1314         if (p == NULL ||
1315                 table_id >= p->n_tables)
1316                 return -1;
1317
1318         if (!pipeline_is_running(p)) {
1319                 status = rte_pipeline_table_default_entry_delete(p->p,
1320                         table_id,
1321                         NULL);
1322
1323                 return status;
1324         }
1325
1326         /* Allocate request */
1327         req = pipeline_msg_alloc();
1328         if (req == NULL)
1329                 return -1;
1330
1331         /* Write request */
1332         req->type = PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT;
1333         req->id = table_id;
1334
1335         /* Send request and wait for response */
1336         rsp = pipeline_msg_send_recv(p, req);
1337         if (rsp == NULL)
1338                 return -1;
1339
1340         /* Read response */
1341         status = rsp->status;
1342
1343         /* Free response */
1344         pipeline_msg_free(rsp);
1345
1346         return status;
1347 }
1348
1349 /**
1350  * Data plane threads: message handling
1351  */
1352 static inline struct pipeline_msg_req *
1353 pipeline_msg_recv(struct rte_ring *msgq_req)
1354 {
1355         struct pipeline_msg_req *req;
1356
1357         int status = rte_ring_sc_dequeue(msgq_req, (void **)&req);
1358
1359         if (status != 0)
1360                 return NULL;
1361
1362         return req;
1363 }
1364
1365 static inline void
1366 pipeline_msg_send(struct rte_ring *msgq_rsp,
1367         struct pipeline_msg_rsp *rsp)
1368 {
1369         int status;
1370
1371         do {
1372                 status = rte_ring_sp_enqueue(msgq_rsp, rsp);
1373         } while (status == -ENOBUFS);
1374 }
1375
1376 static struct pipeline_msg_rsp *
1377 pipeline_msg_handle_port_in_enable(struct pipeline_data *p,
1378         struct pipeline_msg_req *req)
1379 {
1380         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
1381         uint32_t port_id = req->id;
1382
1383         rsp->status = rte_pipeline_port_in_enable(p->p,
1384                 port_id);
1385
1386         return rsp;
1387 }
1388
1389 static struct pipeline_msg_rsp *
1390 pipeline_msg_handle_port_in_disable(struct pipeline_data *p,
1391         struct pipeline_msg_req *req)
1392 {
1393         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
1394         uint32_t port_id = req->id;
1395
1396         rsp->status = rte_pipeline_port_in_disable(p->p,
1397                 port_id);
1398
1399         return rsp;
1400 }
1401
1402 static int
1403 match_convert_ipv6_depth(uint32_t depth, uint32_t *depth32)
1404 {
1405         if (depth > 128)
1406                 return -1;
1407
1408         switch (depth / 32) {
1409         case 0:
1410                 depth32[0] = depth;
1411                 depth32[1] = 0;
1412                 depth32[2] = 0;
1413                 depth32[3] = 0;
1414                 return 0;
1415
1416         case 1:
1417                 depth32[0] = 32;
1418                 depth32[1] = depth - 32;
1419                 depth32[2] = 0;
1420                 depth32[3] = 0;
1421                 return 0;
1422
1423         case 2:
1424                 depth32[0] = 32;
1425                 depth32[1] = 32;
1426                 depth32[2] = depth - 64;
1427                 depth32[3] = 0;
1428                 return 0;
1429
1430         case 3:
1431                 depth32[0] = 32;
1432                 depth32[1] = 32;
1433                 depth32[2] = 32;
1434                 depth32[3] = depth - 96;
1435                 return 0;
1436
1437         case 4:
1438                 depth32[0] = 32;
1439                 depth32[1] = 32;
1440                 depth32[2] = 32;
1441                 depth32[3] = 32;
1442                 return 0;
1443
1444         default:
1445                 return -1;
1446         }
1447 }
1448
1449 static int
1450 match_convert(struct softnic_table_rule_match *mh,
1451         union table_rule_match_low_level *ml,
1452         int add)
1453 {
1454         memset(ml, 0, sizeof(*ml));
1455
1456         switch (mh->match_type) {
1457         case TABLE_ACL:
1458                 if (mh->match.acl.ip_version)
1459                         if (add) {
1460                                 ml->acl_add.field_value[0].value.u8 =
1461                                         mh->match.acl.proto;
1462                                 ml->acl_add.field_value[0].mask_range.u8 =
1463                                         mh->match.acl.proto_mask;
1464
1465                                 ml->acl_add.field_value[1].value.u32 =
1466                                         mh->match.acl.ipv4.sa;
1467                                 ml->acl_add.field_value[1].mask_range.u32 =
1468                                         mh->match.acl.sa_depth;
1469
1470                                 ml->acl_add.field_value[2].value.u32 =
1471                                         mh->match.acl.ipv4.da;
1472                                 ml->acl_add.field_value[2].mask_range.u32 =
1473                                         mh->match.acl.da_depth;
1474
1475                                 ml->acl_add.field_value[3].value.u16 =
1476                                         mh->match.acl.sp0;
1477                                 ml->acl_add.field_value[3].mask_range.u16 =
1478                                         mh->match.acl.sp1;
1479
1480                                 ml->acl_add.field_value[4].value.u16 =
1481                                         mh->match.acl.dp0;
1482                                 ml->acl_add.field_value[4].mask_range.u16 =
1483                                         mh->match.acl.dp1;
1484
1485                                 ml->acl_add.priority =
1486                                         (int32_t)mh->match.acl.priority;
1487                         } else {
1488                                 ml->acl_delete.field_value[0].value.u8 =
1489                                         mh->match.acl.proto;
1490                                 ml->acl_delete.field_value[0].mask_range.u8 =
1491                                         mh->match.acl.proto_mask;
1492
1493                                 ml->acl_delete.field_value[1].value.u32 =
1494                                         mh->match.acl.ipv4.sa;
1495                                 ml->acl_delete.field_value[1].mask_range.u32 =
1496                                         mh->match.acl.sa_depth;
1497
1498                                 ml->acl_delete.field_value[2].value.u32 =
1499                                         mh->match.acl.ipv4.da;
1500                                 ml->acl_delete.field_value[2].mask_range.u32 =
1501                                         mh->match.acl.da_depth;
1502
1503                                 ml->acl_delete.field_value[3].value.u16 =
1504                                         mh->match.acl.sp0;
1505                                 ml->acl_delete.field_value[3].mask_range.u16 =
1506                                         mh->match.acl.sp1;
1507
1508                                 ml->acl_delete.field_value[4].value.u16 =
1509                                         mh->match.acl.dp0;
1510                                 ml->acl_delete.field_value[4].mask_range.u16 =
1511                                         mh->match.acl.dp1;
1512                         }
1513                 else
1514                         if (add) {
1515                                 uint32_t *sa32 =
1516                                         (uint32_t *)mh->match.acl.ipv6.sa;
1517                                 uint32_t *da32 =
1518                                         (uint32_t *)mh->match.acl.ipv6.da;
1519                                 uint32_t sa32_depth[4], da32_depth[4];
1520                                 int status;
1521
1522                                 status = match_convert_ipv6_depth(mh->match.acl.sa_depth,
1523                                         sa32_depth);
1524                                 if (status)
1525                                         return status;
1526
1527                                 status = match_convert_ipv6_depth(
1528                                         mh->match.acl.da_depth,
1529                                         da32_depth);
1530                                 if (status)
1531                                         return status;
1532
1533                                 ml->acl_add.field_value[0].value.u8 =
1534                                         mh->match.acl.proto;
1535                                 ml->acl_add.field_value[0].mask_range.u8 =
1536                                         mh->match.acl.proto_mask;
1537
1538                                 ml->acl_add.field_value[1].value.u32 = sa32[0];
1539                                 ml->acl_add.field_value[1].mask_range.u32 =
1540                                         sa32_depth[0];
1541                                 ml->acl_add.field_value[2].value.u32 = sa32[1];
1542                                 ml->acl_add.field_value[2].mask_range.u32 =
1543                                         sa32_depth[1];
1544                                 ml->acl_add.field_value[3].value.u32 = sa32[2];
1545                                 ml->acl_add.field_value[3].mask_range.u32 =
1546                                         sa32_depth[2];
1547                                 ml->acl_add.field_value[4].value.u32 = sa32[3];
1548                                 ml->acl_add.field_value[4].mask_range.u32 =
1549                                         sa32_depth[3];
1550
1551                                 ml->acl_add.field_value[5].value.u32 = da32[0];
1552                                 ml->acl_add.field_value[5].mask_range.u32 =
1553                                         da32_depth[0];
1554                                 ml->acl_add.field_value[6].value.u32 = da32[1];
1555                                 ml->acl_add.field_value[6].mask_range.u32 =
1556                                         da32_depth[1];
1557                                 ml->acl_add.field_value[7].value.u32 = da32[2];
1558                                 ml->acl_add.field_value[7].mask_range.u32 =
1559                                         da32_depth[2];
1560                                 ml->acl_add.field_value[8].value.u32 = da32[3];
1561                                 ml->acl_add.field_value[8].mask_range.u32 =
1562                                         da32_depth[3];
1563
1564                                 ml->acl_add.field_value[9].value.u16 =
1565                                         mh->match.acl.sp0;
1566                                 ml->acl_add.field_value[9].mask_range.u16 =
1567                                         mh->match.acl.sp1;
1568
1569                                 ml->acl_add.field_value[10].value.u16 =
1570                                         mh->match.acl.dp0;
1571                                 ml->acl_add.field_value[10].mask_range.u16 =
1572                                         mh->match.acl.dp1;
1573
1574                                 ml->acl_add.priority =
1575                                         (int32_t)mh->match.acl.priority;
1576                         } else {
1577                                 uint32_t *sa32 =
1578                                         (uint32_t *)mh->match.acl.ipv6.sa;
1579                                 uint32_t *da32 =
1580                                         (uint32_t *)mh->match.acl.ipv6.da;
1581                                 uint32_t sa32_depth[4], da32_depth[4];
1582                                 int status;
1583
1584                                 status = match_convert_ipv6_depth(mh->match.acl.sa_depth,
1585                                         sa32_depth);
1586                                 if (status)
1587                                         return status;
1588
1589                                 status = match_convert_ipv6_depth(mh->match.acl.da_depth,
1590                                         da32_depth);
1591                                 if (status)
1592                                         return status;
1593
1594                                 ml->acl_delete.field_value[0].value.u8 =
1595                                         mh->match.acl.proto;
1596                                 ml->acl_delete.field_value[0].mask_range.u8 =
1597                                         mh->match.acl.proto_mask;
1598
1599                                 ml->acl_delete.field_value[1].value.u32 =
1600                                         sa32[0];
1601                                 ml->acl_delete.field_value[1].mask_range.u32 =
1602                                         sa32_depth[0];
1603                                 ml->acl_delete.field_value[2].value.u32 =
1604                                         sa32[1];
1605                                 ml->acl_delete.field_value[2].mask_range.u32 =
1606                                         sa32_depth[1];
1607                                 ml->acl_delete.field_value[3].value.u32 =
1608                                         sa32[2];
1609                                 ml->acl_delete.field_value[3].mask_range.u32 =
1610                                         sa32_depth[2];
1611                                 ml->acl_delete.field_value[4].value.u32 =
1612                                         sa32[3];
1613                                 ml->acl_delete.field_value[4].mask_range.u32 =
1614                                         sa32_depth[3];
1615
1616                                 ml->acl_delete.field_value[5].value.u32 =
1617                                         da32[0];
1618                                 ml->acl_delete.field_value[5].mask_range.u32 =
1619                                         da32_depth[0];
1620                                 ml->acl_delete.field_value[6].value.u32 =
1621                                         da32[1];
1622                                 ml->acl_delete.field_value[6].mask_range.u32 =
1623                                         da32_depth[1];
1624                                 ml->acl_delete.field_value[7].value.u32 =
1625                                         da32[2];
1626                                 ml->acl_delete.field_value[7].mask_range.u32 =
1627                                         da32_depth[2];
1628                                 ml->acl_delete.field_value[8].value.u32 =
1629                                         da32[3];
1630                                 ml->acl_delete.field_value[8].mask_range.u32 =
1631                                         da32_depth[3];
1632
1633                                 ml->acl_delete.field_value[9].value.u16 =
1634                                         mh->match.acl.sp0;
1635                                 ml->acl_delete.field_value[9].mask_range.u16 =
1636                                         mh->match.acl.sp1;
1637
1638                                 ml->acl_delete.field_value[10].value.u16 =
1639                                         mh->match.acl.dp0;
1640                                 ml->acl_delete.field_value[10].mask_range.u16 =
1641                                         mh->match.acl.dp1;
1642                         }
1643                 return 0;
1644
1645         case TABLE_ARRAY:
1646                 ml->array.pos = mh->match.array.pos;
1647                 return 0;
1648
1649         case TABLE_HASH:
1650                 memcpy(ml->hash, mh->match.hash.key, sizeof(ml->hash));
1651                 return 0;
1652
1653         case TABLE_LPM:
1654                 if (mh->match.lpm.ip_version) {
1655                         ml->lpm_ipv4.ip = mh->match.lpm.ipv4;
1656                         ml->lpm_ipv4.depth = mh->match.lpm.depth;
1657                 } else {
1658                         memcpy(ml->lpm_ipv6.ip,
1659                                 mh->match.lpm.ipv6, sizeof(ml->lpm_ipv6.ip));
1660                         ml->lpm_ipv6.depth = mh->match.lpm.depth;
1661                 }
1662
1663                 return 0;
1664
1665         default:
1666                 return -1;
1667         }
1668 }
1669
1670 static int
1671 action_convert(struct rte_table_action *a,
1672         struct softnic_table_rule_action *action,
1673         struct rte_pipeline_table_entry *data)
1674 {
1675         int status;
1676
1677         /* Apply actions */
1678         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
1679                 status = rte_table_action_apply(a,
1680                         data,
1681                         RTE_TABLE_ACTION_FWD,
1682                         &action->fwd);
1683
1684                 if (status)
1685                         return status;
1686         }
1687
1688         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
1689                 status = rte_table_action_apply(a,
1690                         data,
1691                         RTE_TABLE_ACTION_LB,
1692                         &action->lb);
1693
1694                 if (status)
1695                         return status;
1696         }
1697
1698         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
1699                 status = rte_table_action_apply(a,
1700                         data,
1701                         RTE_TABLE_ACTION_MTR,
1702                         &action->mtr);
1703
1704                 if (status)
1705                         return status;
1706         }
1707
1708         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
1709                 status = rte_table_action_apply(a,
1710                         data,
1711                         RTE_TABLE_ACTION_TM,
1712                         &action->tm);
1713
1714                 if (status)
1715                         return status;
1716         }
1717
1718         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
1719                 status = rte_table_action_apply(a,
1720                         data,
1721                         RTE_TABLE_ACTION_ENCAP,
1722                         &action->encap);
1723
1724                 if (status)
1725                         return status;
1726         }
1727
1728         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
1729                 status = rte_table_action_apply(a,
1730                         data,
1731                         RTE_TABLE_ACTION_NAT,
1732                         &action->nat);
1733
1734                 if (status)
1735                         return status;
1736         }
1737
1738         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
1739                 status = rte_table_action_apply(a,
1740                         data,
1741                         RTE_TABLE_ACTION_TTL,
1742                         &action->ttl);
1743
1744                 if (status)
1745                         return status;
1746         }
1747
1748         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
1749                 status = rte_table_action_apply(a,
1750                         data,
1751                         RTE_TABLE_ACTION_STATS,
1752                         &action->stats);
1753
1754                 if (status)
1755                         return status;
1756         }
1757
1758         if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
1759                 status = rte_table_action_apply(a,
1760                         data,
1761                         RTE_TABLE_ACTION_TIME,
1762                         &action->time);
1763
1764                 if (status)
1765                         return status;
1766         }
1767
1768         return 0;
1769 }
1770
1771 static struct pipeline_msg_rsp *
1772 pipeline_msg_handle_table_rule_add(struct pipeline_data *p,
1773         struct pipeline_msg_req *req)
1774 {
1775         union table_rule_match_low_level match_ll;
1776         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
1777         struct softnic_table_rule_match *match = &req->table_rule_add.match;
1778         struct softnic_table_rule_action *action = &req->table_rule_add.action;
1779         struct rte_pipeline_table_entry *data_in, *data_out;
1780         uint32_t table_id = req->id;
1781         int key_found, status;
1782         struct rte_table_action *a = p->table_data[table_id].a;
1783
1784         /* Apply actions */
1785         memset(p->buffer, 0, sizeof(p->buffer));
1786         data_in = (struct rte_pipeline_table_entry *)p->buffer;
1787
1788         status = match_convert(match, &match_ll, 1);
1789         if (status) {
1790                 rsp->status = -1;
1791                 return rsp;
1792         }
1793
1794         status = action_convert(a, action, data_in);
1795         if (status) {
1796                 rsp->status = -1;
1797                 return rsp;
1798         }
1799
1800         status = rte_pipeline_table_entry_add(p->p,
1801                 table_id,
1802                 &match_ll,
1803                 data_in,
1804                 &key_found,
1805                 &data_out);
1806         if (status) {
1807                 rsp->status = -1;
1808                 return rsp;
1809         }
1810
1811         /* Write response */
1812         rsp->status = 0;
1813         rsp->table_rule_add.data = data_out;
1814
1815         return rsp;
1816 }
1817
1818 static struct pipeline_msg_rsp *
1819 pipeline_msg_handle_table_rule_add_default(struct pipeline_data *p,
1820         struct pipeline_msg_req *req)
1821 {
1822         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
1823         struct softnic_table_rule_action *action = &req->table_rule_add_default.action;
1824         struct rte_pipeline_table_entry *data_in, *data_out;
1825         uint32_t table_id = req->id;
1826         int status;
1827
1828         /* Apply actions */
1829         memset(p->buffer, 0, sizeof(p->buffer));
1830         data_in = (struct rte_pipeline_table_entry *)p->buffer;
1831
1832         data_in->action = action->fwd.action;
1833         if (action->fwd.action == RTE_PIPELINE_ACTION_PORT)
1834                 data_in->port_id = action->fwd.id;
1835         if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE)
1836                 data_in->table_id = action->fwd.id;
1837
1838         /* Add default rule to table */
1839         status = rte_pipeline_table_default_entry_add(p->p,
1840                 table_id,
1841                 data_in,
1842                 &data_out);
1843         if (status) {
1844                 rsp->status = -1;
1845                 return rsp;
1846         }
1847
1848         /* Write response */
1849         rsp->status = 0;
1850         rsp->table_rule_add_default.data = data_out;
1851
1852         return rsp;
1853 }
1854
1855 static struct pipeline_msg_rsp *
1856 pipeline_msg_handle_table_rule_add_bulk(struct pipeline_data *p,
1857         struct pipeline_msg_req *req)
1858 {
1859         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
1860
1861         uint32_t table_id = req->id;
1862         struct softnic_table_rule_match *match = req->table_rule_add_bulk.match;
1863         struct softnic_table_rule_action *action = req->table_rule_add_bulk.action;
1864         struct rte_pipeline_table_entry **data =
1865                 (struct rte_pipeline_table_entry **)req->table_rule_add_bulk.data;
1866         uint32_t n_rules = req->table_rule_add_bulk.n_rules;
1867         uint32_t bulk = req->table_rule_add_bulk.bulk;
1868
1869         struct rte_table_action *a = p->table_data[table_id].a;
1870         union table_rule_match_low_level *match_ll;
1871         uint8_t *action_ll;
1872         void **match_ll_ptr;
1873         struct rte_pipeline_table_entry **action_ll_ptr;
1874         int *found, status;
1875         uint32_t i;
1876
1877         /* Memory allocation */
1878         match_ll = calloc(n_rules, sizeof(union table_rule_match_low_level));
1879         action_ll = calloc(n_rules, TABLE_RULE_ACTION_SIZE_MAX);
1880         match_ll_ptr = calloc(n_rules, sizeof(void *));
1881         action_ll_ptr =
1882                 calloc(n_rules, sizeof(struct rte_pipeline_table_entry *));
1883         found = calloc(n_rules, sizeof(int));
1884
1885         if (match_ll == NULL ||
1886                 action_ll == NULL ||
1887                 match_ll_ptr == NULL ||
1888                 action_ll_ptr == NULL ||
1889                 found == NULL)
1890                 goto fail;
1891
1892         for (i = 0; i < n_rules; i++) {
1893                 match_ll_ptr[i] = (void *)&match_ll[i];
1894                 action_ll_ptr[i] =
1895                         (struct rte_pipeline_table_entry *)&action_ll[i * TABLE_RULE_ACTION_SIZE_MAX];
1896         }
1897
1898         /* Rule match conversion */
1899         for (i = 0; i < n_rules; i++) {
1900                 status = match_convert(&match[i], match_ll_ptr[i], 1);
1901                 if (status)
1902                         goto fail;
1903         }
1904
1905         /* Rule action conversion */
1906         for (i = 0; i < n_rules; i++) {
1907                 status = action_convert(a, &action[i], action_ll_ptr[i]);
1908                 if (status)
1909                         goto fail;
1910         }
1911
1912         /* Add rule (match, action) to table */
1913         if (bulk) {
1914                 status = rte_pipeline_table_entry_add_bulk(p->p,
1915                         table_id,
1916                         match_ll_ptr,
1917                         action_ll_ptr,
1918                         n_rules,
1919                         found,
1920                         data);
1921                 if (status)
1922                         n_rules = 0;
1923         } else {
1924                 for (i = 0; i < n_rules; i++) {
1925                         status = rte_pipeline_table_entry_add(p->p,
1926                                 table_id,
1927                                 match_ll_ptr[i],
1928                                 action_ll_ptr[i],
1929                                 &found[i],
1930                                 &data[i]);
1931                         if (status) {
1932                                 n_rules = i;
1933                                 break;
1934                         }
1935                 }
1936         }
1937
1938         /* Write response */
1939         rsp->status = 0;
1940         rsp->table_rule_add_bulk.n_rules = n_rules;
1941
1942         /* Free */
1943         free(found);
1944         free(action_ll_ptr);
1945         free(match_ll_ptr);
1946         free(action_ll);
1947         free(match_ll);
1948
1949         return rsp;
1950
1951 fail:
1952         free(found);
1953         free(action_ll_ptr);
1954         free(match_ll_ptr);
1955         free(action_ll);
1956         free(match_ll);
1957
1958         rsp->status = -1;
1959         rsp->table_rule_add_bulk.n_rules = 0;
1960         return rsp;
1961 }
1962
1963 static struct pipeline_msg_rsp *
1964 pipeline_msg_handle_table_rule_delete(struct pipeline_data *p,
1965         struct pipeline_msg_req *req)
1966 {
1967         union table_rule_match_low_level match_ll;
1968         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
1969         struct softnic_table_rule_match *match = &req->table_rule_delete.match;
1970         uint32_t table_id = req->id;
1971         int key_found, status;
1972
1973         status = match_convert(match, &match_ll, 0);
1974         if (status) {
1975                 rsp->status = -1;
1976                 return rsp;
1977         }
1978
1979         rsp->status = rte_pipeline_table_entry_delete(p->p,
1980                 table_id,
1981                 &match_ll,
1982                 &key_found,
1983                 NULL);
1984
1985         return rsp;
1986 }
1987
1988 static struct pipeline_msg_rsp *
1989 pipeline_msg_handle_table_rule_delete_default(struct pipeline_data *p,
1990         struct pipeline_msg_req *req)
1991 {
1992         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
1993         uint32_t table_id = req->id;
1994
1995         rsp->status = rte_pipeline_table_default_entry_delete(p->p,
1996                 table_id,
1997                 NULL);
1998
1999         return rsp;
2000 }
2001
2002 static void
2003 pipeline_msg_handle(struct pipeline_data *p)
2004 {
2005         for ( ; ; ) {
2006                 struct pipeline_msg_req *req;
2007                 struct pipeline_msg_rsp *rsp;
2008
2009                 req = pipeline_msg_recv(p->msgq_req);
2010                 if (req == NULL)
2011                         break;
2012
2013                 switch (req->type) {
2014                 case PIPELINE_REQ_PORT_IN_ENABLE:
2015                         rsp = pipeline_msg_handle_port_in_enable(p, req);
2016                         break;
2017
2018                 case PIPELINE_REQ_PORT_IN_DISABLE:
2019                         rsp = pipeline_msg_handle_port_in_disable(p, req);
2020                         break;
2021
2022                 case PIPELINE_REQ_TABLE_RULE_ADD:
2023                         rsp = pipeline_msg_handle_table_rule_add(p, req);
2024                         break;
2025
2026                 case PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT:
2027                         rsp = pipeline_msg_handle_table_rule_add_default(p,     req);
2028                         break;
2029
2030                 case PIPELINE_REQ_TABLE_RULE_ADD_BULK:
2031                         rsp = pipeline_msg_handle_table_rule_add_bulk(p, req);
2032                         break;
2033
2034                 case PIPELINE_REQ_TABLE_RULE_DELETE:
2035                         rsp = pipeline_msg_handle_table_rule_delete(p, req);
2036                         break;
2037
2038                 case PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT:
2039                         rsp = pipeline_msg_handle_table_rule_delete_default(p, req);
2040                         break;
2041
2042                 default:
2043                         rsp = (struct pipeline_msg_rsp *)req;
2044                         rsp->status = -1;
2045                 }
2046
2047                 pipeline_msg_send(p->msgq_rsp, rsp);
2048         }
2049 }
2050
2051 /**
2052  * Data plane threads: main
2053  */
2054 int
2055 rte_pmd_softnic_run(uint16_t port_id)
2056 {
2057         struct rte_eth_dev *dev = &rte_eth_devices[port_id];
2058         struct pmd_internals *softnic;
2059         struct softnic_thread_data *t;
2060         uint32_t thread_id, j;
2061
2062 #ifdef RTE_LIBRTE_ETHDEV_DEBUG
2063         RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, 0);
2064 #endif
2065
2066         softnic = dev->data->dev_private;
2067         thread_id = rte_lcore_id();
2068         t = &softnic->thread_data[thread_id];
2069         t->iter++;
2070
2071         /* Data Plane */
2072         for (j = 0; j < t->n_pipelines; j++)
2073                 rte_pipeline_run(t->p[j]);
2074
2075         /* Control Plane */
2076         if ((t->iter & 0xFLLU) == 0) {
2077                 uint64_t time = rte_get_tsc_cycles();
2078                 uint64_t time_next_min = UINT64_MAX;
2079
2080                 if (time < t->time_next_min)
2081                         return 0;
2082
2083                 /* Pipeline message queues */
2084                 for (j = 0; j < t->n_pipelines; j++) {
2085                         struct pipeline_data *p =
2086                                 &t->pipeline_data[j];
2087                         uint64_t time_next = p->time_next;
2088
2089                         if (time_next <= time) {
2090                                 pipeline_msg_handle(p);
2091                                 rte_pipeline_flush(p->p);
2092                                 time_next = time + p->timer_period;
2093                                 p->time_next = time_next;
2094                         }
2095
2096                         if (time_next < time_next_min)
2097                                 time_next_min = time_next;
2098                 }
2099
2100                 /* Thread message queues */
2101                 {
2102                         uint64_t time_next = t->time_next;
2103
2104                         if (time_next <= time) {
2105                                 thread_msg_handle(t);
2106                                 time_next = time + t->timer_period;
2107                                 t->time_next = time_next;
2108                         }
2109
2110                         if (time_next < time_next_min)
2111                                 time_next_min = time_next;
2112                 }
2113
2114                 t->time_next_min = time_next_min;
2115         }
2116
2117         return 0;
2118 }