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