1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2018 Intel Corporation
3 */
4
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include <rte_common.h>
9 #include <rte_ip.h>
10 #include <rte_tcp.h>
11
12 #include <rte_string_fns.h>
13 #include <rte_port_ethdev.h>
14 #include <rte_port_ring.h>
15 #include <rte_port_source_sink.h>
16 #include <rte_port_fd.h>
17 #include <rte_port_sched.h>
18 #include <rte_port_sym_crypto.h>
19
20 #include <rte_table_acl.h>
21 #include <rte_table_array.h>
22 #include <rte_table_hash.h>
23 #include <rte_table_hash_func.h>
24 #include <rte_table_lpm.h>
25 #include <rte_table_lpm_ipv6.h>
26 #include <rte_table_stub.h>
27
28 #include "rte_eth_softnic_internals.h"
29
30 #ifndef PIPELINE_MSGQ_SIZE
31 #define PIPELINE_MSGQ_SIZE 64
32 #endif
33
34 #ifndef TABLE_LPM_NUMBER_TBL8
35 #define TABLE_LPM_NUMBER_TBL8 256
36 #endif
37
38 int
softnic_pipeline_init(struct pmd_internals * p)39 softnic_pipeline_init(struct pmd_internals *p)
40 {
41 TAILQ_INIT(&p->pipeline_list);
42
43 return 0;
44 }
45
46 static void
softnic_pipeline_table_free(struct softnic_table * table)47 softnic_pipeline_table_free(struct softnic_table *table)
48 {
49 for ( ; ; ) {
50 struct rte_flow *flow;
51
52 flow = TAILQ_FIRST(&table->flows);
53 if (flow == NULL)
54 break;
55
56 TAILQ_REMOVE(&table->flows, flow, node);
57 free(flow);
58 }
59
60 for ( ; ; ) {
61 struct softnic_table_meter_profile *mp;
62
63 mp = TAILQ_FIRST(&table->meter_profiles);
64 if (mp == NULL)
65 break;
66
67 TAILQ_REMOVE(&table->meter_profiles, mp, node);
68 free(mp);
69 }
70 }
71
72 void
softnic_pipeline_free(struct pmd_internals * p)73 softnic_pipeline_free(struct pmd_internals *p)
74 {
75 for ( ; ; ) {
76 struct pipeline *pipeline;
77 uint32_t table_id;
78
79 pipeline = TAILQ_FIRST(&p->pipeline_list);
80 if (pipeline == NULL)
81 break;
82
83 TAILQ_REMOVE(&p->pipeline_list, pipeline, node);
84
85 for (table_id = 0; table_id < pipeline->n_tables; table_id++) {
86 struct softnic_table *table =
87 &pipeline->table[table_id];
88
89 softnic_pipeline_table_free(table);
90 }
91
92 rte_ring_free(pipeline->msgq_req);
93 rte_ring_free(pipeline->msgq_rsp);
94 rte_pipeline_free(pipeline->p);
95 free(pipeline);
96 }
97 }
98
99 void
softnic_pipeline_disable_all(struct pmd_internals * p)100 softnic_pipeline_disable_all(struct pmd_internals *p)
101 {
102 struct pipeline *pipeline;
103
104 TAILQ_FOREACH(pipeline, &p->pipeline_list, node)
105 if (pipeline->enabled)
106 softnic_thread_pipeline_disable(p,
107 pipeline->thread_id,
108 pipeline->name);
109 }
110
111 uint32_t
softnic_pipeline_thread_count(struct pmd_internals * p,uint32_t thread_id)112 softnic_pipeline_thread_count(struct pmd_internals *p, uint32_t thread_id)
113 {
114 struct pipeline *pipeline;
115 uint32_t count = 0;
116
117 TAILQ_FOREACH(pipeline, &p->pipeline_list, node)
118 if ((pipeline->enabled) && (pipeline->thread_id == thread_id))
119 count++;
120
121 return count;
122 }
123
124 struct pipeline *
softnic_pipeline_find(struct pmd_internals * p,const char * name)125 softnic_pipeline_find(struct pmd_internals *p,
126 const char *name)
127 {
128 struct pipeline *pipeline;
129
130 if (name == NULL)
131 return NULL;
132
133 TAILQ_FOREACH(pipeline, &p->pipeline_list, node)
134 if (strcmp(name, pipeline->name) == 0)
135 return pipeline;
136
137 return NULL;
138 }
139
140 struct pipeline *
softnic_pipeline_create(struct pmd_internals * softnic,const char * name,struct pipeline_params * params)141 softnic_pipeline_create(struct pmd_internals *softnic,
142 const char *name,
143 struct pipeline_params *params)
144 {
145 char resource_name[NAME_MAX];
146 struct rte_pipeline_params pp;
147 struct pipeline *pipeline;
148 struct rte_pipeline *p;
149 struct rte_ring *msgq_req;
150 struct rte_ring *msgq_rsp;
151
152 /* Check input params */
153 if (name == NULL ||
154 softnic_pipeline_find(softnic, name) ||
155 params == NULL ||
156 params->timer_period_ms == 0)
157 return NULL;
158
159 /* Resource create */
160 snprintf(resource_name, sizeof(resource_name), "%s-%s-REQ",
161 softnic->params.name,
162 name);
163
164 msgq_req = rte_ring_create(resource_name,
165 PIPELINE_MSGQ_SIZE,
166 softnic->params.cpu_id,
167 RING_F_SP_ENQ | RING_F_SC_DEQ);
168 if (msgq_req == NULL)
169 return NULL;
170
171 snprintf(resource_name, sizeof(resource_name), "%s-%s-RSP",
172 softnic->params.name,
173 name);
174
175 msgq_rsp = rte_ring_create(resource_name,
176 PIPELINE_MSGQ_SIZE,
177 softnic->params.cpu_id,
178 RING_F_SP_ENQ | RING_F_SC_DEQ);
179 if (msgq_rsp == NULL) {
180 rte_ring_free(msgq_req);
181 return NULL;
182 }
183
184 snprintf(resource_name, sizeof(resource_name), "%s_%s",
185 softnic->params.name,
186 name);
187
188 pp.name = resource_name;
189 pp.socket_id = (int)softnic->params.cpu_id;
190 pp.offset_port_id = params->offset_port_id;
191
192 p = rte_pipeline_create(&pp);
193 if (p == NULL) {
194 rte_ring_free(msgq_rsp);
195 rte_ring_free(msgq_req);
196 return NULL;
197 }
198
199 /* Node allocation */
200 pipeline = calloc(1, sizeof(struct pipeline));
201 if (pipeline == NULL) {
202 rte_pipeline_free(p);
203 rte_ring_free(msgq_rsp);
204 rte_ring_free(msgq_req);
205 return NULL;
206 }
207
208 /* Node fill in */
209 strlcpy(pipeline->name, name, sizeof(pipeline->name));
210 pipeline->p = p;
211 memcpy(&pipeline->params, params, sizeof(*params));
212 pipeline->n_ports_in = 0;
213 pipeline->n_ports_out = 0;
214 pipeline->n_tables = 0;
215 pipeline->msgq_req = msgq_req;
216 pipeline->msgq_rsp = msgq_rsp;
217 pipeline->timer_period_ms = params->timer_period_ms;
218 pipeline->enabled = 0;
219 pipeline->cpu_id = softnic->params.cpu_id;
220
221 /* Node add to list */
222 TAILQ_INSERT_TAIL(&softnic->pipeline_list, pipeline, node);
223
224 return pipeline;
225 }
226
227 int
softnic_pipeline_port_in_create(struct pmd_internals * softnic,const char * pipeline_name,struct softnic_port_in_params * params,int enabled)228 softnic_pipeline_port_in_create(struct pmd_internals *softnic,
229 const char *pipeline_name,
230 struct softnic_port_in_params *params,
231 int enabled)
232 {
233 struct rte_pipeline_port_in_params p;
234
235 union {
236 struct rte_port_ethdev_reader_params ethdev;
237 struct rte_port_ring_reader_params ring;
238 struct rte_port_sched_reader_params sched;
239 struct rte_port_fd_reader_params fd;
240 struct rte_port_source_params source;
241 struct rte_port_sym_crypto_reader_params cryptodev;
242 } pp;
243
244 struct pipeline *pipeline;
245 struct softnic_port_in *port_in;
246 struct softnic_port_in_action_profile *ap;
247 struct rte_port_in_action *action;
248 uint32_t port_id;
249 int status;
250
251 memset(&p, 0, sizeof(p));
252 memset(&pp, 0, sizeof(pp));
253
254 /* Check input params */
255 if (pipeline_name == NULL ||
256 params == NULL ||
257 params->burst_size == 0 ||
258 params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX)
259 return -1;
260
261 pipeline = softnic_pipeline_find(softnic, pipeline_name);
262 if (pipeline == NULL)
263 return -1;
264
265 ap = NULL;
266 if (strlen(params->action_profile_name)) {
267 ap = softnic_port_in_action_profile_find(softnic,
268 params->action_profile_name);
269 if (ap == NULL)
270 return -1;
271 }
272
273 switch (params->type) {
274 case PORT_IN_RXQ:
275 {
276 struct softnic_link *link;
277
278 link = softnic_link_find(softnic, params->dev_name);
279 if (link == NULL)
280 return -1;
281
282 if (params->rxq.queue_id >= link->n_rxq)
283 return -1;
284
285 pp.ethdev.port_id = link->port_id;
286 pp.ethdev.queue_id = params->rxq.queue_id;
287
288 p.ops = &rte_port_ethdev_reader_ops;
289 p.arg_create = &pp.ethdev;
290 break;
291 }
292
293 case PORT_IN_SWQ:
294 {
295 struct softnic_swq *swq;
296
297 swq = softnic_swq_find(softnic, params->dev_name);
298 if (swq == NULL)
299 return -1;
300
301 pp.ring.ring = swq->r;
302
303 p.ops = &rte_port_ring_reader_ops;
304 p.arg_create = &pp.ring;
305 break;
306 }
307
308 case PORT_IN_TMGR:
309 {
310 struct softnic_tmgr_port *tmgr_port;
311
312 tmgr_port = softnic_tmgr_port_find(softnic, params->dev_name);
313 if (tmgr_port == NULL)
314 return -1;
315
316 pp.sched.sched = tmgr_port->s;
317
318 p.ops = &rte_port_sched_reader_ops;
319 p.arg_create = &pp.sched;
320 break;
321 }
322
323 case PORT_IN_TAP:
324 {
325 struct softnic_tap *tap;
326 struct softnic_mempool *mempool;
327
328 tap = softnic_tap_find(softnic, params->dev_name);
329 mempool = softnic_mempool_find(softnic, params->tap.mempool_name);
330 if (tap == NULL || mempool == NULL)
331 return -1;
332
333 pp.fd.fd = tap->fd;
334 pp.fd.mempool = mempool->m;
335 pp.fd.mtu = params->tap.mtu;
336
337 p.ops = &rte_port_fd_reader_ops;
338 p.arg_create = &pp.fd;
339 break;
340 }
341
342 case PORT_IN_SOURCE:
343 {
344 struct softnic_mempool *mempool;
345
346 mempool = softnic_mempool_find(softnic, params->source.mempool_name);
347 if (mempool == NULL)
348 return -1;
349
350 pp.source.mempool = mempool->m;
351 pp.source.file_name = params->source.file_name;
352 pp.source.n_bytes_per_pkt = params->source.n_bytes_per_pkt;
353
354 p.ops = &rte_port_source_ops;
355 p.arg_create = &pp.source;
356 break;
357 }
358
359 case PORT_IN_CRYPTODEV:
360 {
361 struct softnic_cryptodev *cryptodev;
362
363 cryptodev = softnic_cryptodev_find(softnic, params->dev_name);
364 if (cryptodev == NULL)
365 return -1;
366
367 pp.cryptodev.cryptodev_id = cryptodev->dev_id;
368 pp.cryptodev.queue_id = params->cryptodev.queue_id;
369 pp.cryptodev.f_callback = params->cryptodev.f_callback;
370 pp.cryptodev.arg_callback = params->cryptodev.arg_callback;
371 p.ops = &rte_port_sym_crypto_reader_ops;
372 p.arg_create = &pp.cryptodev;
373 break;
374 }
375
376 default:
377 return -1;
378 }
379
380 p.burst_size = params->burst_size;
381
382 /* Resource create */
383 action = NULL;
384 p.f_action = NULL;
385 p.arg_ah = NULL;
386
387 if (ap) {
388 action = rte_port_in_action_create(ap->ap,
389 softnic->params.cpu_id);
390 if (action == NULL)
391 return -1;
392
393 status = rte_port_in_action_params_get(action,
394 &p);
395 if (status) {
396 rte_port_in_action_free(action);
397 return -1;
398 }
399 }
400
401 status = rte_pipeline_port_in_create(pipeline->p,
402 &p,
403 &port_id);
404 if (status) {
405 rte_port_in_action_free(action);
406 return -1;
407 }
408
409 if (enabled)
410 rte_pipeline_port_in_enable(pipeline->p, port_id);
411
412 /* Pipeline */
413 port_in = &pipeline->port_in[pipeline->n_ports_in];
414 memcpy(&port_in->params, params, sizeof(*params));
415 port_in->ap = ap;
416 port_in->a = action;
417 pipeline->n_ports_in++;
418
419 return 0;
420 }
421
422 int
softnic_pipeline_port_in_connect_to_table(struct pmd_internals * softnic,const char * pipeline_name,uint32_t port_id,uint32_t table_id)423 softnic_pipeline_port_in_connect_to_table(struct pmd_internals *softnic,
424 const char *pipeline_name,
425 uint32_t port_id,
426 uint32_t table_id)
427 {
428 struct pipeline *pipeline;
429 int status;
430
431 /* Check input params */
432 if (pipeline_name == NULL)
433 return -1;
434
435 pipeline = softnic_pipeline_find(softnic, pipeline_name);
436 if (pipeline == NULL ||
437 port_id >= pipeline->n_ports_in ||
438 table_id >= pipeline->n_tables)
439 return -1;
440
441 /* Resource */
442 status = rte_pipeline_port_in_connect_to_table(pipeline->p,
443 port_id,
444 table_id);
445
446 return status;
447 }
448
449 int
softnic_pipeline_port_out_create(struct pmd_internals * softnic,const char * pipeline_name,struct softnic_port_out_params * params)450 softnic_pipeline_port_out_create(struct pmd_internals *softnic,
451 const char *pipeline_name,
452 struct softnic_port_out_params *params)
453 {
454 struct rte_pipeline_port_out_params p;
455
456 union {
457 struct rte_port_ethdev_writer_params ethdev;
458 struct rte_port_ring_writer_params ring;
459 struct rte_port_sched_writer_params sched;
460 struct rte_port_fd_writer_params fd;
461 struct rte_port_sink_params sink;
462 struct rte_port_sym_crypto_writer_params cryptodev;
463 } pp;
464
465 union {
466 struct rte_port_ethdev_writer_nodrop_params ethdev;
467 struct rte_port_ring_writer_nodrop_params ring;
468 struct rte_port_fd_writer_nodrop_params fd;
469 struct rte_port_sym_crypto_writer_nodrop_params cryptodev;
470 } pp_nodrop;
471
472 struct pipeline *pipeline;
473 struct softnic_port_out *port_out;
474 uint32_t port_id;
475 int status;
476
477 memset(&p, 0, sizeof(p));
478 memset(&pp, 0, sizeof(pp));
479 memset(&pp_nodrop, 0, sizeof(pp_nodrop));
480
481 /* Check input params */
482 if (pipeline_name == NULL ||
483 params == NULL ||
484 params->burst_size == 0 ||
485 params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX)
486 return -1;
487
488 pipeline = softnic_pipeline_find(softnic, pipeline_name);
489 if (pipeline == NULL)
490 return -1;
491
492 switch (params->type) {
493 case PORT_OUT_TXQ:
494 {
495 struct softnic_link *link;
496
497 link = softnic_link_find(softnic, params->dev_name);
498 if (link == NULL)
499 return -1;
500
501 if (params->txq.queue_id >= link->n_txq)
502 return -1;
503
504 pp.ethdev.port_id = link->port_id;
505 pp.ethdev.queue_id = params->txq.queue_id;
506 pp.ethdev.tx_burst_sz = params->burst_size;
507
508 pp_nodrop.ethdev.port_id = link->port_id;
509 pp_nodrop.ethdev.queue_id = params->txq.queue_id;
510 pp_nodrop.ethdev.tx_burst_sz = params->burst_size;
511 pp_nodrop.ethdev.n_retries = params->n_retries;
512
513 if (params->retry == 0) {
514 p.ops = &rte_port_ethdev_writer_ops;
515 p.arg_create = &pp.ethdev;
516 } else {
517 p.ops = &rte_port_ethdev_writer_nodrop_ops;
518 p.arg_create = &pp_nodrop.ethdev;
519 }
520 break;
521 }
522
523 case PORT_OUT_SWQ:
524 {
525 struct softnic_swq *swq;
526
527 swq = softnic_swq_find(softnic, params->dev_name);
528 if (swq == NULL)
529 return -1;
530
531 pp.ring.ring = swq->r;
532 pp.ring.tx_burst_sz = params->burst_size;
533
534 pp_nodrop.ring.ring = swq->r;
535 pp_nodrop.ring.tx_burst_sz = params->burst_size;
536 pp_nodrop.ring.n_retries = params->n_retries;
537
538 if (params->retry == 0) {
539 p.ops = &rte_port_ring_writer_ops;
540 p.arg_create = &pp.ring;
541 } else {
542 p.ops = &rte_port_ring_writer_nodrop_ops;
543 p.arg_create = &pp_nodrop.ring;
544 }
545 break;
546 }
547
548 case PORT_OUT_TMGR:
549 {
550 struct softnic_tmgr_port *tmgr_port;
551
552 tmgr_port = softnic_tmgr_port_find(softnic, params->dev_name);
553 if (tmgr_port == NULL)
554 return -1;
555
556 pp.sched.sched = tmgr_port->s;
557 pp.sched.tx_burst_sz = params->burst_size;
558
559 p.ops = &rte_port_sched_writer_ops;
560 p.arg_create = &pp.sched;
561 break;
562 }
563
564 case PORT_OUT_TAP:
565 {
566 struct softnic_tap *tap;
567
568 tap = softnic_tap_find(softnic, params->dev_name);
569 if (tap == NULL)
570 return -1;
571
572 pp.fd.fd = tap->fd;
573 pp.fd.tx_burst_sz = params->burst_size;
574
575 pp_nodrop.fd.fd = tap->fd;
576 pp_nodrop.fd.tx_burst_sz = params->burst_size;
577 pp_nodrop.fd.n_retries = params->n_retries;
578
579 if (params->retry == 0) {
580 p.ops = &rte_port_fd_writer_ops;
581 p.arg_create = &pp.fd;
582 } else {
583 p.ops = &rte_port_fd_writer_nodrop_ops;
584 p.arg_create = &pp_nodrop.fd;
585 }
586 break;
587 }
588
589 case PORT_OUT_SINK:
590 {
591 pp.sink.file_name = params->sink.file_name;
592 pp.sink.max_n_pkts = params->sink.max_n_pkts;
593
594 p.ops = &rte_port_sink_ops;
595 p.arg_create = &pp.sink;
596 break;
597 }
598
599 case PORT_OUT_CRYPTODEV:
600 {
601 struct softnic_cryptodev *cryptodev;
602
603 cryptodev = softnic_cryptodev_find(softnic, params->dev_name);
604 if (cryptodev == NULL)
605 return -1;
606
607 if (params->cryptodev.queue_id >= cryptodev->n_queues)
608 return -1;
609
610 pp.cryptodev.cryptodev_id = cryptodev->dev_id;
611 pp.cryptodev.queue_id = params->cryptodev.queue_id;
612 pp.cryptodev.tx_burst_sz = params->burst_size;
613 pp.cryptodev.crypto_op_offset = params->cryptodev.op_offset;
614
615 pp_nodrop.cryptodev.cryptodev_id = cryptodev->dev_id;
616 pp_nodrop.cryptodev.queue_id = params->cryptodev.queue_id;
617 pp_nodrop.cryptodev.tx_burst_sz = params->burst_size;
618 pp_nodrop.cryptodev.n_retries = params->retry;
619 pp_nodrop.cryptodev.crypto_op_offset =
620 params->cryptodev.op_offset;
621
622 if (params->retry == 0) {
623 p.ops = &rte_port_sym_crypto_writer_ops;
624 p.arg_create = &pp.cryptodev;
625 } else {
626 p.ops = &rte_port_sym_crypto_writer_nodrop_ops;
627 p.arg_create = &pp_nodrop.cryptodev;
628 }
629
630 break;
631 }
632
633 default:
634 return -1;
635 }
636
637 p.f_action = NULL;
638 p.arg_ah = NULL;
639
640 /* Resource create */
641 status = rte_pipeline_port_out_create(pipeline->p,
642 &p,
643 &port_id);
644
645 if (status)
646 return -1;
647
648 /* Pipeline */
649 port_out = &pipeline->port_out[pipeline->n_ports_out];
650 memcpy(&port_out->params, params, sizeof(*params));
651 pipeline->n_ports_out++;
652
653 return 0;
654 }
655
656 static const struct rte_acl_field_def table_acl_field_format_ipv4[] = {
657 /* Protocol */
658 [0] = {
659 .type = RTE_ACL_FIELD_TYPE_BITMASK,
660 .size = sizeof(uint8_t),
661 .field_index = 0,
662 .input_index = 0,
663 .offset = offsetof(struct rte_ipv4_hdr, next_proto_id),
664 },
665
666 /* Source IP address (IPv4) */
667 [1] = {
668 .type = RTE_ACL_FIELD_TYPE_MASK,
669 .size = sizeof(uint32_t),
670 .field_index = 1,
671 .input_index = 1,
672 .offset = offsetof(struct rte_ipv4_hdr, src_addr),
673 },
674
675 /* Destination IP address (IPv4) */
676 [2] = {
677 .type = RTE_ACL_FIELD_TYPE_MASK,
678 .size = sizeof(uint32_t),
679 .field_index = 2,
680 .input_index = 2,
681 .offset = offsetof(struct rte_ipv4_hdr, dst_addr),
682 },
683
684 /* Source Port */
685 [3] = {
686 .type = RTE_ACL_FIELD_TYPE_RANGE,
687 .size = sizeof(uint16_t),
688 .field_index = 3,
689 .input_index = 3,
690 .offset = sizeof(struct rte_ipv4_hdr) +
691 offsetof(struct rte_tcp_hdr, src_port),
692 },
693
694 /* Destination Port */
695 [4] = {
696 .type = RTE_ACL_FIELD_TYPE_RANGE,
697 .size = sizeof(uint16_t),
698 .field_index = 4,
699 .input_index = 3,
700 .offset = sizeof(struct rte_ipv4_hdr) +
701 offsetof(struct rte_tcp_hdr, dst_port),
702 },
703 };
704
705 static const struct rte_acl_field_def table_acl_field_format_ipv6[] = {
706 /* Protocol */
707 [0] = {
708 .type = RTE_ACL_FIELD_TYPE_BITMASK,
709 .size = sizeof(uint8_t),
710 .field_index = 0,
711 .input_index = 0,
712 .offset = offsetof(struct rte_ipv6_hdr, proto),
713 },
714
715 /* Source IP address (IPv6) */
716 [1] = {
717 .type = RTE_ACL_FIELD_TYPE_MASK,
718 .size = sizeof(uint32_t),
719 .field_index = 1,
720 .input_index = 1,
721 .offset = offsetof(struct rte_ipv6_hdr, src_addr[0]),
722 },
723
724 [2] = {
725 .type = RTE_ACL_FIELD_TYPE_MASK,
726 .size = sizeof(uint32_t),
727 .field_index = 2,
728 .input_index = 2,
729 .offset = offsetof(struct rte_ipv6_hdr, src_addr[4]),
730 },
731
732 [3] = {
733 .type = RTE_ACL_FIELD_TYPE_MASK,
734 .size = sizeof(uint32_t),
735 .field_index = 3,
736 .input_index = 3,
737 .offset = offsetof(struct rte_ipv6_hdr, src_addr[8]),
738 },
739
740 [4] = {
741 .type = RTE_ACL_FIELD_TYPE_MASK,
742 .size = sizeof(uint32_t),
743 .field_index = 4,
744 .input_index = 4,
745 .offset = offsetof(struct rte_ipv6_hdr, src_addr[12]),
746 },
747
748 /* Destination IP address (IPv6) */
749 [5] = {
750 .type = RTE_ACL_FIELD_TYPE_MASK,
751 .size = sizeof(uint32_t),
752 .field_index = 5,
753 .input_index = 5,
754 .offset = offsetof(struct rte_ipv6_hdr, dst_addr[0]),
755 },
756
757 [6] = {
758 .type = RTE_ACL_FIELD_TYPE_MASK,
759 .size = sizeof(uint32_t),
760 .field_index = 6,
761 .input_index = 6,
762 .offset = offsetof(struct rte_ipv6_hdr, dst_addr[4]),
763 },
764
765 [7] = {
766 .type = RTE_ACL_FIELD_TYPE_MASK,
767 .size = sizeof(uint32_t),
768 .field_index = 7,
769 .input_index = 7,
770 .offset = offsetof(struct rte_ipv6_hdr, dst_addr[8]),
771 },
772
773 [8] = {
774 .type = RTE_ACL_FIELD_TYPE_MASK,
775 .size = sizeof(uint32_t),
776 .field_index = 8,
777 .input_index = 8,
778 .offset = offsetof(struct rte_ipv6_hdr, dst_addr[12]),
779 },
780
781 /* Source Port */
782 [9] = {
783 .type = RTE_ACL_FIELD_TYPE_RANGE,
784 .size = sizeof(uint16_t),
785 .field_index = 9,
786 .input_index = 9,
787 .offset = sizeof(struct rte_ipv6_hdr) +
788 offsetof(struct rte_tcp_hdr, src_port),
789 },
790
791 /* Destination Port */
792 [10] = {
793 .type = RTE_ACL_FIELD_TYPE_RANGE,
794 .size = sizeof(uint16_t),
795 .field_index = 10,
796 .input_index = 9,
797 .offset = sizeof(struct rte_ipv6_hdr) +
798 offsetof(struct rte_tcp_hdr, dst_port),
799 },
800 };
801
802 int
softnic_pipeline_table_create(struct pmd_internals * softnic,const char * pipeline_name,struct softnic_table_params * params)803 softnic_pipeline_table_create(struct pmd_internals *softnic,
804 const char *pipeline_name,
805 struct softnic_table_params *params)
806 {
807 char name[NAME_MAX];
808 struct rte_pipeline_table_params p;
809
810 union {
811 struct rte_table_acl_params acl;
812 struct rte_table_array_params array;
813 struct rte_table_hash_params hash;
814 struct rte_table_lpm_params lpm;
815 struct rte_table_lpm_ipv6_params lpm_ipv6;
816 } pp;
817
818 struct pipeline *pipeline;
819 struct softnic_table *table;
820 struct softnic_table_action_profile *ap;
821 struct rte_table_action *action;
822 uint32_t table_id;
823 int status;
824
825 memset(&p, 0, sizeof(p));
826 memset(&pp, 0, sizeof(pp));
827
828 /* Check input params */
829 if (pipeline_name == NULL ||
830 params == NULL)
831 return -1;
832
833 pipeline = softnic_pipeline_find(softnic, pipeline_name);
834 if (pipeline == NULL ||
835 pipeline->n_tables >= RTE_PIPELINE_TABLE_MAX)
836 return -1;
837
838 ap = NULL;
839 if (strlen(params->action_profile_name)) {
840 ap = softnic_table_action_profile_find(softnic,
841 params->action_profile_name);
842 if (ap == NULL)
843 return -1;
844 }
845
846 snprintf(name, NAME_MAX, "%s_%s_table%u",
847 softnic->params.name, pipeline_name, pipeline->n_tables);
848
849 switch (params->match_type) {
850 case TABLE_ACL:
851 {
852 uint32_t ip_header_offset = params->match.acl.ip_header_offset -
853 (sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM);
854 uint32_t i;
855
856 if (params->match.acl.n_rules == 0)
857 return -1;
858
859 pp.acl.name = name;
860 pp.acl.n_rules = params->match.acl.n_rules;
861 if (params->match.acl.ip_version) {
862 memcpy(&pp.acl.field_format,
863 &table_acl_field_format_ipv4,
864 sizeof(table_acl_field_format_ipv4));
865 pp.acl.n_rule_fields =
866 RTE_DIM(table_acl_field_format_ipv4);
867 } else {
868 memcpy(&pp.acl.field_format,
869 &table_acl_field_format_ipv6,
870 sizeof(table_acl_field_format_ipv6));
871 pp.acl.n_rule_fields =
872 RTE_DIM(table_acl_field_format_ipv6);
873 }
874
875 for (i = 0; i < pp.acl.n_rule_fields; i++)
876 pp.acl.field_format[i].offset += ip_header_offset;
877
878 p.ops = &rte_table_acl_ops;
879 p.arg_create = &pp.acl;
880 break;
881 }
882
883 case TABLE_ARRAY:
884 {
885 if (params->match.array.n_keys == 0)
886 return -1;
887
888 pp.array.n_entries = params->match.array.n_keys;
889 pp.array.offset = params->match.array.key_offset;
890
891 p.ops = &rte_table_array_ops;
892 p.arg_create = &pp.array;
893 break;
894 }
895
896 case TABLE_HASH:
897 {
898 struct rte_table_ops *ops;
899 rte_table_hash_op_hash f_hash;
900
901 if (params->match.hash.n_keys == 0)
902 return -1;
903
904 switch (params->match.hash.key_size) {
905 case 8:
906 f_hash = rte_table_hash_crc_key8;
907 break;
908 case 16:
909 f_hash = rte_table_hash_crc_key16;
910 break;
911 case 24:
912 f_hash = rte_table_hash_crc_key24;
913 break;
914 case 32:
915 f_hash = rte_table_hash_crc_key32;
916 break;
917 case 40:
918 f_hash = rte_table_hash_crc_key40;
919 break;
920 case 48:
921 f_hash = rte_table_hash_crc_key48;
922 break;
923 case 56:
924 f_hash = rte_table_hash_crc_key56;
925 break;
926 case 64:
927 f_hash = rte_table_hash_crc_key64;
928 break;
929 default:
930 return -1;
931 }
932
933 pp.hash.name = name;
934 pp.hash.key_size = params->match.hash.key_size;
935 pp.hash.key_offset = params->match.hash.key_offset;
936 pp.hash.key_mask = params->match.hash.key_mask;
937 pp.hash.n_keys = params->match.hash.n_keys;
938 pp.hash.n_buckets = params->match.hash.n_buckets;
939 pp.hash.f_hash = f_hash;
940 pp.hash.seed = 0;
941
942 if (params->match.hash.extendable_bucket)
943 switch (params->match.hash.key_size) {
944 case 8:
945 ops = &rte_table_hash_key8_ext_ops;
946 break;
947 case 16:
948 ops = &rte_table_hash_key16_ext_ops;
949 break;
950 default:
951 ops = &rte_table_hash_ext_ops;
952 }
953 else
954 switch (params->match.hash.key_size) {
955 case 8:
956 ops = &rte_table_hash_key8_lru_ops;
957 break;
958 case 16:
959 ops = &rte_table_hash_key16_lru_ops;
960 break;
961 default:
962 ops = &rte_table_hash_lru_ops;
963 }
964
965 p.ops = ops;
966 p.arg_create = &pp.hash;
967 break;
968 }
969
970 case TABLE_LPM:
971 {
972 if (params->match.lpm.n_rules == 0)
973 return -1;
974
975 switch (params->match.lpm.key_size) {
976 case 4:
977 {
978 pp.lpm.name = name;
979 pp.lpm.n_rules = params->match.lpm.n_rules;
980 pp.lpm.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
981 pp.lpm.flags = 0;
982 pp.lpm.entry_unique_size = p.action_data_size +
983 sizeof(struct rte_pipeline_table_entry);
984 pp.lpm.offset = params->match.lpm.key_offset;
985
986 p.ops = &rte_table_lpm_ops;
987 p.arg_create = &pp.lpm;
988 break;
989 }
990
991 case 16:
992 {
993 pp.lpm_ipv6.name = name;
994 pp.lpm_ipv6.n_rules = params->match.lpm.n_rules;
995 pp.lpm_ipv6.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
996 pp.lpm_ipv6.entry_unique_size = p.action_data_size +
997 sizeof(struct rte_pipeline_table_entry);
998 pp.lpm_ipv6.offset = params->match.lpm.key_offset;
999
1000 p.ops = &rte_table_lpm_ipv6_ops;
1001 p.arg_create = &pp.lpm_ipv6;
1002 break;
1003 }
1004
1005 default:
1006 return -1;
1007 }
1008
1009 break;
1010 }
1011
1012 case TABLE_STUB:
1013 {
1014 p.ops = &rte_table_stub_ops;
1015 p.arg_create = NULL;
1016 break;
1017 }
1018
1019 default:
1020 return -1;
1021 }
1022
1023 /* Resource create */
1024 action = NULL;
1025 p.f_action_hit = NULL;
1026 p.f_action_miss = NULL;
1027 p.arg_ah = NULL;
1028
1029 if (ap) {
1030 action = rte_table_action_create(ap->ap,
1031 softnic->params.cpu_id);
1032 if (action == NULL)
1033 return -1;
1034
1035 status = rte_table_action_table_params_get(action,
1036 &p);
1037 if (status ||
1038 ((p.action_data_size +
1039 sizeof(struct rte_pipeline_table_entry)) >
1040 TABLE_RULE_ACTION_SIZE_MAX)) {
1041 rte_table_action_free(action);
1042 return -1;
1043 }
1044 }
1045
1046 if (params->match_type == TABLE_LPM) {
1047 if (params->match.lpm.key_size == 4)
1048 pp.lpm.entry_unique_size = p.action_data_size +
1049 sizeof(struct rte_pipeline_table_entry);
1050
1051 if (params->match.lpm.key_size == 16)
1052 pp.lpm_ipv6.entry_unique_size = p.action_data_size +
1053 sizeof(struct rte_pipeline_table_entry);
1054 }
1055
1056 status = rte_pipeline_table_create(pipeline->p,
1057 &p,
1058 &table_id);
1059 if (status) {
1060 rte_table_action_free(action);
1061 return -1;
1062 }
1063
1064 /* Pipeline */
1065 table = &pipeline->table[pipeline->n_tables];
1066 memcpy(&table->params, params, sizeof(*params));
1067 table->ap = ap;
1068 table->a = action;
1069 TAILQ_INIT(&table->flows);
1070 TAILQ_INIT(&table->meter_profiles);
1071 memset(&table->dscp_table, 0, sizeof(table->dscp_table));
1072 pipeline->n_tables++;
1073
1074 return 0;
1075 }
1076
1077 int
softnic_pipeline_port_out_find(struct pmd_internals * softnic,const char * pipeline_name,const char * name,uint32_t * port_id)1078 softnic_pipeline_port_out_find(struct pmd_internals *softnic,
1079 const char *pipeline_name,
1080 const char *name,
1081 uint32_t *port_id)
1082 {
1083 struct pipeline *pipeline;
1084 uint32_t i;
1085
1086 if (softnic == NULL ||
1087 pipeline_name == NULL ||
1088 name == NULL ||
1089 port_id == NULL)
1090 return -1;
1091
1092 pipeline = softnic_pipeline_find(softnic, pipeline_name);
1093 if (pipeline == NULL)
1094 return -1;
1095
1096 for (i = 0; i < pipeline->n_ports_out; i++)
1097 if (strcmp(pipeline->port_out[i].params.dev_name, name) == 0) {
1098 *port_id = i;
1099 return 0;
1100 }
1101
1102 return -1;
1103 }
1104
1105 struct softnic_table_meter_profile *
softnic_pipeline_table_meter_profile_find(struct softnic_table * table,uint32_t meter_profile_id)1106 softnic_pipeline_table_meter_profile_find(struct softnic_table *table,
1107 uint32_t meter_profile_id)
1108 {
1109 struct softnic_table_meter_profile *mp;
1110
1111 TAILQ_FOREACH(mp, &table->meter_profiles, node)
1112 if (mp->meter_profile_id == meter_profile_id)
1113 return mp;
1114
1115 return NULL;
1116 }
1117