1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2018 Intel Corporation
8 #include <rte_common.h>
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>
19 #include <rte_table_acl.h>
20 #include <rte_table_array.h>
21 #include <rte_table_hash.h>
22 #include <rte_table_lpm.h>
23 #include <rte_table_lpm_ipv6.h>
24 #include <rte_table_stub.h>
26 #include "rte_eth_softnic_internals.h"
28 #include "hash_func.h"
30 #ifndef PIPELINE_MSGQ_SIZE
31 #define PIPELINE_MSGQ_SIZE 64
34 #ifndef TABLE_LPM_NUMBER_TBL8
35 #define TABLE_LPM_NUMBER_TBL8 256
39 softnic_pipeline_init(struct pmd_internals *p)
41 TAILQ_INIT(&p->pipeline_list);
47 softnic_pipeline_free(struct pmd_internals *p)
50 struct pipeline *pipeline;
52 pipeline = TAILQ_FIRST(&p->pipeline_list);
56 TAILQ_REMOVE(&p->pipeline_list, pipeline, node);
57 rte_ring_free(pipeline->msgq_req);
58 rte_ring_free(pipeline->msgq_rsp);
59 rte_pipeline_free(pipeline->p);
65 softnic_pipeline_disable_all(struct pmd_internals *p)
67 struct pipeline *pipeline;
69 TAILQ_FOREACH(pipeline, &p->pipeline_list, node)
70 if (pipeline->enabled)
71 softnic_thread_pipeline_disable(p,
77 softnic_pipeline_find(struct pmd_internals *p,
80 struct pipeline *pipeline;
85 TAILQ_FOREACH(pipeline, &p->pipeline_list, node)
86 if (strcmp(name, pipeline->name) == 0)
93 softnic_pipeline_create(struct pmd_internals *softnic,
95 struct pipeline_params *params)
97 char resource_name[NAME_MAX];
98 struct rte_pipeline_params pp;
99 struct pipeline *pipeline;
100 struct rte_pipeline *p;
101 struct rte_ring *msgq_req;
102 struct rte_ring *msgq_rsp;
104 /* Check input params */
106 softnic_pipeline_find(softnic, name) ||
108 params->timer_period_ms == 0)
111 /* Resource create */
112 snprintf(resource_name, sizeof(resource_name), "%s-%s-REQ",
113 softnic->params.name,
116 msgq_req = rte_ring_create(resource_name,
118 softnic->params.cpu_id,
119 RING_F_SP_ENQ | RING_F_SC_DEQ);
120 if (msgq_req == NULL)
123 snprintf(resource_name, sizeof(resource_name), "%s-%s-RSP",
124 softnic->params.name,
127 msgq_rsp = rte_ring_create(resource_name,
129 softnic->params.cpu_id,
130 RING_F_SP_ENQ | RING_F_SC_DEQ);
131 if (msgq_rsp == NULL) {
132 rte_ring_free(msgq_req);
136 snprintf(resource_name, sizeof(resource_name), "%s_%s",
137 softnic->params.name,
140 pp.name = resource_name;
141 pp.socket_id = (int)softnic->params.cpu_id;
142 pp.offset_port_id = params->offset_port_id;
144 p = rte_pipeline_create(&pp);
146 rte_ring_free(msgq_rsp);
147 rte_ring_free(msgq_req);
151 /* Node allocation */
152 pipeline = calloc(1, sizeof(struct pipeline));
153 if (pipeline == NULL) {
154 rte_pipeline_free(p);
155 rte_ring_free(msgq_rsp);
156 rte_ring_free(msgq_req);
161 strlcpy(pipeline->name, name, sizeof(pipeline->name));
163 pipeline->n_ports_in = 0;
164 pipeline->n_ports_out = 0;
165 pipeline->n_tables = 0;
166 pipeline->msgq_req = msgq_req;
167 pipeline->msgq_rsp = msgq_rsp;
168 pipeline->timer_period_ms = params->timer_period_ms;
169 pipeline->enabled = 0;
170 pipeline->cpu_id = softnic->params.cpu_id;
172 /* Node add to list */
173 TAILQ_INSERT_TAIL(&softnic->pipeline_list, pipeline, node);
179 softnic_pipeline_port_in_create(struct pmd_internals *softnic,
180 const char *pipeline_name,
181 struct softnic_port_in_params *params,
184 struct rte_pipeline_port_in_params p;
187 struct rte_port_ethdev_reader_params ethdev;
188 struct rte_port_ring_reader_params ring;
189 struct rte_port_sched_reader_params sched;
190 struct rte_port_fd_reader_params fd;
191 struct rte_port_source_params source;
194 struct pipeline *pipeline;
195 struct softnic_port_in *port_in;
196 struct softnic_port_in_action_profile *ap;
197 struct rte_port_in_action *action;
201 memset(&p, 0, sizeof(p));
202 memset(&pp, 0, sizeof(pp));
204 /* Check input params */
205 if (pipeline_name == NULL ||
207 params->burst_size == 0 ||
208 params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX)
211 pipeline = softnic_pipeline_find(softnic, pipeline_name);
212 if (pipeline == NULL)
216 if (params->action_profile_name) {
217 ap = softnic_port_in_action_profile_find(softnic,
218 params->action_profile_name);
223 switch (params->type) {
226 struct softnic_link *link;
228 link = softnic_link_find(softnic, params->dev_name);
232 if (params->rxq.queue_id >= link->n_rxq)
235 pp.ethdev.port_id = link->port_id;
236 pp.ethdev.queue_id = params->rxq.queue_id;
238 p.ops = &rte_port_ethdev_reader_ops;
239 p.arg_create = &pp.ethdev;
245 struct softnic_swq *swq;
247 swq = softnic_swq_find(softnic, params->dev_name);
251 pp.ring.ring = swq->r;
253 p.ops = &rte_port_ring_reader_ops;
254 p.arg_create = &pp.ring;
260 struct softnic_tmgr_port *tmgr_port;
262 tmgr_port = softnic_tmgr_port_find(softnic, params->dev_name);
263 if (tmgr_port == NULL)
266 pp.sched.sched = tmgr_port->s;
268 p.ops = &rte_port_sched_reader_ops;
269 p.arg_create = &pp.sched;
275 struct softnic_tap *tap;
276 struct softnic_mempool *mempool;
278 tap = softnic_tap_find(softnic, params->dev_name);
279 mempool = softnic_mempool_find(softnic, params->tap.mempool_name);
280 if (tap == NULL || mempool == NULL)
284 pp.fd.mempool = mempool->m;
285 pp.fd.mtu = params->tap.mtu;
287 p.ops = &rte_port_fd_reader_ops;
288 p.arg_create = &pp.fd;
294 struct softnic_mempool *mempool;
296 mempool = softnic_mempool_find(softnic, params->source.mempool_name);
300 pp.source.mempool = mempool->m;
301 pp.source.file_name = params->source.file_name;
302 pp.source.n_bytes_per_pkt = params->source.n_bytes_per_pkt;
304 p.ops = &rte_port_source_ops;
305 p.arg_create = &pp.source;
313 p.burst_size = params->burst_size;
315 /* Resource create */
321 action = rte_port_in_action_create(ap->ap,
322 softnic->params.cpu_id);
326 status = rte_port_in_action_params_get(action,
329 rte_port_in_action_free(action);
334 status = rte_pipeline_port_in_create(pipeline->p,
338 rte_port_in_action_free(action);
343 rte_pipeline_port_in_enable(pipeline->p, port_id);
346 port_in = &pipeline->port_in[pipeline->n_ports_in];
347 memcpy(&port_in->params, params, sizeof(*params));
350 pipeline->n_ports_in++;
356 softnic_pipeline_port_in_connect_to_table(struct pmd_internals *softnic,
357 const char *pipeline_name,
361 struct pipeline *pipeline;
364 /* Check input params */
365 if (pipeline_name == NULL)
368 pipeline = softnic_pipeline_find(softnic, pipeline_name);
369 if (pipeline == NULL ||
370 port_id >= pipeline->n_ports_in ||
371 table_id >= pipeline->n_tables)
375 status = rte_pipeline_port_in_connect_to_table(pipeline->p,
383 softnic_pipeline_port_out_create(struct pmd_internals *softnic,
384 const char *pipeline_name,
385 struct softnic_port_out_params *params)
387 struct rte_pipeline_port_out_params p;
390 struct rte_port_ethdev_writer_params ethdev;
391 struct rte_port_ring_writer_params ring;
392 struct rte_port_sched_writer_params sched;
393 struct rte_port_fd_writer_params fd;
394 struct rte_port_sink_params sink;
398 struct rte_port_ethdev_writer_nodrop_params ethdev;
399 struct rte_port_ring_writer_nodrop_params ring;
400 struct rte_port_fd_writer_nodrop_params fd;
403 struct pipeline *pipeline;
407 memset(&p, 0, sizeof(p));
408 memset(&pp, 0, sizeof(pp));
409 memset(&pp_nodrop, 0, sizeof(pp_nodrop));
411 /* Check input params */
412 if (pipeline_name == NULL ||
414 params->burst_size == 0 ||
415 params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX)
418 pipeline = softnic_pipeline_find(softnic, pipeline_name);
419 if (pipeline == NULL)
422 switch (params->type) {
425 struct softnic_link *link;
427 link = softnic_link_find(softnic, params->dev_name);
431 if (params->txq.queue_id >= link->n_txq)
434 pp.ethdev.port_id = link->port_id;
435 pp.ethdev.queue_id = params->txq.queue_id;
436 pp.ethdev.tx_burst_sz = params->burst_size;
438 pp_nodrop.ethdev.port_id = link->port_id;
439 pp_nodrop.ethdev.queue_id = params->txq.queue_id;
440 pp_nodrop.ethdev.tx_burst_sz = params->burst_size;
441 pp_nodrop.ethdev.n_retries = params->n_retries;
443 if (params->retry == 0) {
444 p.ops = &rte_port_ethdev_writer_ops;
445 p.arg_create = &pp.ethdev;
447 p.ops = &rte_port_ethdev_writer_nodrop_ops;
448 p.arg_create = &pp_nodrop.ethdev;
455 struct softnic_swq *swq;
457 swq = softnic_swq_find(softnic, params->dev_name);
461 pp.ring.ring = swq->r;
462 pp.ring.tx_burst_sz = params->burst_size;
464 pp_nodrop.ring.ring = swq->r;
465 pp_nodrop.ring.tx_burst_sz = params->burst_size;
466 pp_nodrop.ring.n_retries = params->n_retries;
468 if (params->retry == 0) {
469 p.ops = &rte_port_ring_writer_ops;
470 p.arg_create = &pp.ring;
472 p.ops = &rte_port_ring_writer_nodrop_ops;
473 p.arg_create = &pp_nodrop.ring;
480 struct softnic_tmgr_port *tmgr_port;
482 tmgr_port = softnic_tmgr_port_find(softnic, params->dev_name);
483 if (tmgr_port == NULL)
486 pp.sched.sched = tmgr_port->s;
487 pp.sched.tx_burst_sz = params->burst_size;
489 p.ops = &rte_port_sched_writer_ops;
490 p.arg_create = &pp.sched;
496 struct softnic_tap *tap;
498 tap = softnic_tap_find(softnic, params->dev_name);
503 pp.fd.tx_burst_sz = params->burst_size;
505 pp_nodrop.fd.fd = tap->fd;
506 pp_nodrop.fd.tx_burst_sz = params->burst_size;
507 pp_nodrop.fd.n_retries = params->n_retries;
509 if (params->retry == 0) {
510 p.ops = &rte_port_fd_writer_ops;
511 p.arg_create = &pp.fd;
513 p.ops = &rte_port_fd_writer_nodrop_ops;
514 p.arg_create = &pp_nodrop.fd;
521 pp.sink.file_name = params->sink.file_name;
522 pp.sink.max_n_pkts = params->sink.max_n_pkts;
524 p.ops = &rte_port_sink_ops;
525 p.arg_create = &pp.sink;
536 /* Resource create */
537 status = rte_pipeline_port_out_create(pipeline->p,
545 pipeline->n_ports_out++;
550 static const struct rte_acl_field_def table_acl_field_format_ipv4[] = {
553 .type = RTE_ACL_FIELD_TYPE_BITMASK,
554 .size = sizeof(uint8_t),
557 .offset = offsetof(struct ipv4_hdr, next_proto_id),
560 /* Source IP address (IPv4) */
562 .type = RTE_ACL_FIELD_TYPE_MASK,
563 .size = sizeof(uint32_t),
566 .offset = offsetof(struct ipv4_hdr, src_addr),
569 /* Destination IP address (IPv4) */
571 .type = RTE_ACL_FIELD_TYPE_MASK,
572 .size = sizeof(uint32_t),
575 .offset = offsetof(struct ipv4_hdr, dst_addr),
580 .type = RTE_ACL_FIELD_TYPE_RANGE,
581 .size = sizeof(uint16_t),
584 .offset = sizeof(struct ipv4_hdr) +
585 offsetof(struct tcp_hdr, src_port),
588 /* Destination Port */
590 .type = RTE_ACL_FIELD_TYPE_RANGE,
591 .size = sizeof(uint16_t),
594 .offset = sizeof(struct ipv4_hdr) +
595 offsetof(struct tcp_hdr, dst_port),
599 static const struct rte_acl_field_def table_acl_field_format_ipv6[] = {
602 .type = RTE_ACL_FIELD_TYPE_BITMASK,
603 .size = sizeof(uint8_t),
606 .offset = offsetof(struct ipv6_hdr, proto),
609 /* Source IP address (IPv6) */
611 .type = RTE_ACL_FIELD_TYPE_MASK,
612 .size = sizeof(uint32_t),
615 .offset = offsetof(struct ipv6_hdr, src_addr[0]),
619 .type = RTE_ACL_FIELD_TYPE_MASK,
620 .size = sizeof(uint32_t),
623 .offset = offsetof(struct ipv6_hdr, src_addr[4]),
627 .type = RTE_ACL_FIELD_TYPE_MASK,
628 .size = sizeof(uint32_t),
631 .offset = offsetof(struct ipv6_hdr, src_addr[8]),
635 .type = RTE_ACL_FIELD_TYPE_MASK,
636 .size = sizeof(uint32_t),
639 .offset = offsetof(struct ipv6_hdr, src_addr[12]),
642 /* Destination IP address (IPv6) */
644 .type = RTE_ACL_FIELD_TYPE_MASK,
645 .size = sizeof(uint32_t),
648 .offset = offsetof(struct ipv6_hdr, dst_addr[0]),
652 .type = RTE_ACL_FIELD_TYPE_MASK,
653 .size = sizeof(uint32_t),
656 .offset = offsetof(struct ipv6_hdr, dst_addr[4]),
660 .type = RTE_ACL_FIELD_TYPE_MASK,
661 .size = sizeof(uint32_t),
664 .offset = offsetof(struct ipv6_hdr, dst_addr[8]),
668 .type = RTE_ACL_FIELD_TYPE_MASK,
669 .size = sizeof(uint32_t),
672 .offset = offsetof(struct ipv6_hdr, dst_addr[12]),
677 .type = RTE_ACL_FIELD_TYPE_RANGE,
678 .size = sizeof(uint16_t),
681 .offset = sizeof(struct ipv6_hdr) +
682 offsetof(struct tcp_hdr, src_port),
685 /* Destination Port */
687 .type = RTE_ACL_FIELD_TYPE_RANGE,
688 .size = sizeof(uint16_t),
691 .offset = sizeof(struct ipv6_hdr) +
692 offsetof(struct tcp_hdr, dst_port),
697 softnic_pipeline_table_create(struct pmd_internals *softnic,
698 const char *pipeline_name,
699 struct softnic_table_params *params)
702 struct rte_pipeline_table_params p;
705 struct rte_table_acl_params acl;
706 struct rte_table_array_params array;
707 struct rte_table_hash_params hash;
708 struct rte_table_lpm_params lpm;
709 struct rte_table_lpm_ipv6_params lpm_ipv6;
712 struct pipeline *pipeline;
713 struct softnic_table *table;
714 struct softnic_table_action_profile *ap;
715 struct rte_table_action *action;
719 memset(&p, 0, sizeof(p));
720 memset(&pp, 0, sizeof(pp));
722 /* Check input params */
723 if (pipeline_name == NULL ||
727 pipeline = softnic_pipeline_find(softnic, pipeline_name);
728 if (pipeline == NULL ||
729 pipeline->n_tables >= RTE_PIPELINE_TABLE_MAX)
733 if (params->action_profile_name) {
734 ap = softnic_table_action_profile_find(softnic,
735 params->action_profile_name);
740 snprintf(name, NAME_MAX, "%s_%s_table%u",
741 softnic->params.name, pipeline_name, pipeline->n_tables);
743 switch (params->match_type) {
746 uint32_t ip_header_offset = params->match.acl.ip_header_offset -
747 (sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM);
750 if (params->match.acl.n_rules == 0)
754 pp.acl.n_rules = params->match.acl.n_rules;
755 if (params->match.acl.ip_version) {
756 memcpy(&pp.acl.field_format,
757 &table_acl_field_format_ipv4,
758 sizeof(table_acl_field_format_ipv4));
759 pp.acl.n_rule_fields =
760 RTE_DIM(table_acl_field_format_ipv4);
762 memcpy(&pp.acl.field_format,
763 &table_acl_field_format_ipv6,
764 sizeof(table_acl_field_format_ipv6));
765 pp.acl.n_rule_fields =
766 RTE_DIM(table_acl_field_format_ipv6);
769 for (i = 0; i < pp.acl.n_rule_fields; i++)
770 pp.acl.field_format[i].offset += ip_header_offset;
772 p.ops = &rte_table_acl_ops;
773 p.arg_create = &pp.acl;
779 if (params->match.array.n_keys == 0)
782 pp.array.n_entries = params->match.array.n_keys;
783 pp.array.offset = params->match.array.key_offset;
785 p.ops = &rte_table_array_ops;
786 p.arg_create = &pp.array;
792 struct rte_table_ops *ops;
793 rte_table_hash_op_hash f_hash;
795 if (params->match.hash.n_keys == 0)
798 switch (params->match.hash.key_size) {
800 f_hash = hash_default_key8;
803 f_hash = hash_default_key16;
806 f_hash = hash_default_key24;
809 f_hash = hash_default_key32;
812 f_hash = hash_default_key40;
815 f_hash = hash_default_key48;
818 f_hash = hash_default_key56;
821 f_hash = hash_default_key64;
828 pp.hash.key_size = params->match.hash.key_size;
829 pp.hash.key_offset = params->match.hash.key_offset;
830 pp.hash.key_mask = params->match.hash.key_mask;
831 pp.hash.n_keys = params->match.hash.n_keys;
832 pp.hash.n_buckets = params->match.hash.n_buckets;
833 pp.hash.f_hash = f_hash;
836 if (params->match.hash.extendable_bucket)
837 switch (params->match.hash.key_size) {
839 ops = &rte_table_hash_key8_ext_ops;
842 ops = &rte_table_hash_key16_ext_ops;
845 ops = &rte_table_hash_ext_ops;
848 switch (params->match.hash.key_size) {
850 ops = &rte_table_hash_key8_lru_ops;
853 ops = &rte_table_hash_key16_lru_ops;
856 ops = &rte_table_hash_lru_ops;
860 p.arg_create = &pp.hash;
866 if (params->match.lpm.n_rules == 0)
869 switch (params->match.lpm.key_size) {
873 pp.lpm.n_rules = params->match.lpm.n_rules;
874 pp.lpm.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
876 pp.lpm.entry_unique_size = p.action_data_size +
877 sizeof(struct rte_pipeline_table_entry);
878 pp.lpm.offset = params->match.lpm.key_offset;
880 p.ops = &rte_table_lpm_ops;
881 p.arg_create = &pp.lpm;
887 pp.lpm_ipv6.name = name;
888 pp.lpm_ipv6.n_rules = params->match.lpm.n_rules;
889 pp.lpm_ipv6.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
890 pp.lpm_ipv6.entry_unique_size = p.action_data_size +
891 sizeof(struct rte_pipeline_table_entry);
892 pp.lpm_ipv6.offset = params->match.lpm.key_offset;
894 p.ops = &rte_table_lpm_ipv6_ops;
895 p.arg_create = &pp.lpm_ipv6;
908 p.ops = &rte_table_stub_ops;
917 /* Resource create */
919 p.f_action_hit = NULL;
920 p.f_action_miss = NULL;
924 action = rte_table_action_create(ap->ap,
925 softnic->params.cpu_id);
929 status = rte_table_action_table_params_get(action,
932 ((p.action_data_size +
933 sizeof(struct rte_pipeline_table_entry)) >
934 TABLE_RULE_ACTION_SIZE_MAX)) {
935 rte_table_action_free(action);
940 if (params->match_type == TABLE_LPM) {
941 if (params->match.lpm.key_size == 4)
942 pp.lpm.entry_unique_size = p.action_data_size +
943 sizeof(struct rte_pipeline_table_entry);
945 if (params->match.lpm.key_size == 16)
946 pp.lpm_ipv6.entry_unique_size = p.action_data_size +
947 sizeof(struct rte_pipeline_table_entry);
950 status = rte_pipeline_table_create(pipeline->p,
954 rte_table_action_free(action);
959 table = &pipeline->table[pipeline->n_tables];
960 memcpy(&table->params, params, sizeof(*params));
963 pipeline->n_tables++;