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_hash_func.h>
23 #include <rte_table_lpm.h>
24 #include <rte_table_lpm_ipv6.h>
25 #include <rte_table_stub.h>
27 #include "rte_eth_softnic_internals.h"
29 #ifndef PIPELINE_MSGQ_SIZE
30 #define PIPELINE_MSGQ_SIZE 64
33 #ifndef TABLE_LPM_NUMBER_TBL8
34 #define TABLE_LPM_NUMBER_TBL8 256
38 softnic_pipeline_init(struct pmd_internals *p)
40 TAILQ_INIT(&p->pipeline_list);
46 softnic_pipeline_table_free(struct softnic_table *table)
49 struct rte_flow *flow;
51 flow = TAILQ_FIRST(&table->flows);
55 TAILQ_REMOVE(&table->flows, flow, node);
60 struct softnic_table_meter_profile *mp;
62 mp = TAILQ_FIRST(&table->meter_profiles);
66 TAILQ_REMOVE(&table->meter_profiles, mp, node);
72 softnic_pipeline_free(struct pmd_internals *p)
75 struct pipeline *pipeline;
78 pipeline = TAILQ_FIRST(&p->pipeline_list);
82 TAILQ_REMOVE(&p->pipeline_list, pipeline, node);
84 for (table_id = 0; table_id < pipeline->n_tables; table_id++) {
85 struct softnic_table *table =
86 &pipeline->table[table_id];
88 softnic_pipeline_table_free(table);
91 rte_ring_free(pipeline->msgq_req);
92 rte_ring_free(pipeline->msgq_rsp);
93 rte_pipeline_free(pipeline->p);
99 softnic_pipeline_disable_all(struct pmd_internals *p)
101 struct pipeline *pipeline;
103 TAILQ_FOREACH(pipeline, &p->pipeline_list, node)
104 if (pipeline->enabled)
105 softnic_thread_pipeline_disable(p,
111 softnic_pipeline_find(struct pmd_internals *p,
114 struct pipeline *pipeline;
119 TAILQ_FOREACH(pipeline, &p->pipeline_list, node)
120 if (strcmp(name, pipeline->name) == 0)
127 softnic_pipeline_create(struct pmd_internals *softnic,
129 struct pipeline_params *params)
131 char resource_name[NAME_MAX];
132 struct rte_pipeline_params pp;
133 struct pipeline *pipeline;
134 struct rte_pipeline *p;
135 struct rte_ring *msgq_req;
136 struct rte_ring *msgq_rsp;
138 /* Check input params */
140 softnic_pipeline_find(softnic, name) ||
142 params->timer_period_ms == 0)
145 /* Resource create */
146 snprintf(resource_name, sizeof(resource_name), "%s-%s-REQ",
147 softnic->params.name,
150 msgq_req = rte_ring_create(resource_name,
152 softnic->params.cpu_id,
153 RING_F_SP_ENQ | RING_F_SC_DEQ);
154 if (msgq_req == NULL)
157 snprintf(resource_name, sizeof(resource_name), "%s-%s-RSP",
158 softnic->params.name,
161 msgq_rsp = rte_ring_create(resource_name,
163 softnic->params.cpu_id,
164 RING_F_SP_ENQ | RING_F_SC_DEQ);
165 if (msgq_rsp == NULL) {
166 rte_ring_free(msgq_req);
170 snprintf(resource_name, sizeof(resource_name), "%s_%s",
171 softnic->params.name,
174 pp.name = resource_name;
175 pp.socket_id = (int)softnic->params.cpu_id;
176 pp.offset_port_id = params->offset_port_id;
178 p = rte_pipeline_create(&pp);
180 rte_ring_free(msgq_rsp);
181 rte_ring_free(msgq_req);
185 /* Node allocation */
186 pipeline = calloc(1, sizeof(struct pipeline));
187 if (pipeline == NULL) {
188 rte_pipeline_free(p);
189 rte_ring_free(msgq_rsp);
190 rte_ring_free(msgq_req);
195 strlcpy(pipeline->name, name, sizeof(pipeline->name));
197 memcpy(&pipeline->params, params, sizeof(*params));
198 pipeline->n_ports_in = 0;
199 pipeline->n_ports_out = 0;
200 pipeline->n_tables = 0;
201 pipeline->msgq_req = msgq_req;
202 pipeline->msgq_rsp = msgq_rsp;
203 pipeline->timer_period_ms = params->timer_period_ms;
204 pipeline->enabled = 0;
205 pipeline->cpu_id = softnic->params.cpu_id;
207 /* Node add to list */
208 TAILQ_INSERT_TAIL(&softnic->pipeline_list, pipeline, node);
214 softnic_pipeline_port_in_create(struct pmd_internals *softnic,
215 const char *pipeline_name,
216 struct softnic_port_in_params *params,
219 struct rte_pipeline_port_in_params p;
222 struct rte_port_ethdev_reader_params ethdev;
223 struct rte_port_ring_reader_params ring;
224 struct rte_port_sched_reader_params sched;
225 struct rte_port_fd_reader_params fd;
226 struct rte_port_source_params source;
229 struct pipeline *pipeline;
230 struct softnic_port_in *port_in;
231 struct softnic_port_in_action_profile *ap;
232 struct rte_port_in_action *action;
236 memset(&p, 0, sizeof(p));
237 memset(&pp, 0, sizeof(pp));
239 /* Check input params */
240 if (pipeline_name == NULL ||
242 params->burst_size == 0 ||
243 params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX)
246 pipeline = softnic_pipeline_find(softnic, pipeline_name);
247 if (pipeline == NULL)
251 if (strlen(params->action_profile_name)) {
252 ap = softnic_port_in_action_profile_find(softnic,
253 params->action_profile_name);
258 switch (params->type) {
261 struct softnic_link *link;
263 link = softnic_link_find(softnic, params->dev_name);
267 if (params->rxq.queue_id >= link->n_rxq)
270 pp.ethdev.port_id = link->port_id;
271 pp.ethdev.queue_id = params->rxq.queue_id;
273 p.ops = &rte_port_ethdev_reader_ops;
274 p.arg_create = &pp.ethdev;
280 struct softnic_swq *swq;
282 swq = softnic_swq_find(softnic, params->dev_name);
286 pp.ring.ring = swq->r;
288 p.ops = &rte_port_ring_reader_ops;
289 p.arg_create = &pp.ring;
295 struct softnic_tmgr_port *tmgr_port;
297 tmgr_port = softnic_tmgr_port_find(softnic, params->dev_name);
298 if (tmgr_port == NULL)
301 pp.sched.sched = tmgr_port->s;
303 p.ops = &rte_port_sched_reader_ops;
304 p.arg_create = &pp.sched;
310 struct softnic_tap *tap;
311 struct softnic_mempool *mempool;
313 tap = softnic_tap_find(softnic, params->dev_name);
314 mempool = softnic_mempool_find(softnic, params->tap.mempool_name);
315 if (tap == NULL || mempool == NULL)
319 pp.fd.mempool = mempool->m;
320 pp.fd.mtu = params->tap.mtu;
322 p.ops = &rte_port_fd_reader_ops;
323 p.arg_create = &pp.fd;
329 struct softnic_mempool *mempool;
331 mempool = softnic_mempool_find(softnic, params->source.mempool_name);
335 pp.source.mempool = mempool->m;
336 pp.source.file_name = params->source.file_name;
337 pp.source.n_bytes_per_pkt = params->source.n_bytes_per_pkt;
339 p.ops = &rte_port_source_ops;
340 p.arg_create = &pp.source;
348 p.burst_size = params->burst_size;
350 /* Resource create */
356 action = rte_port_in_action_create(ap->ap,
357 softnic->params.cpu_id);
361 status = rte_port_in_action_params_get(action,
364 rte_port_in_action_free(action);
369 status = rte_pipeline_port_in_create(pipeline->p,
373 rte_port_in_action_free(action);
378 rte_pipeline_port_in_enable(pipeline->p, port_id);
381 port_in = &pipeline->port_in[pipeline->n_ports_in];
382 memcpy(&port_in->params, params, sizeof(*params));
385 pipeline->n_ports_in++;
391 softnic_pipeline_port_in_connect_to_table(struct pmd_internals *softnic,
392 const char *pipeline_name,
396 struct pipeline *pipeline;
399 /* Check input params */
400 if (pipeline_name == NULL)
403 pipeline = softnic_pipeline_find(softnic, pipeline_name);
404 if (pipeline == NULL ||
405 port_id >= pipeline->n_ports_in ||
406 table_id >= pipeline->n_tables)
410 status = rte_pipeline_port_in_connect_to_table(pipeline->p,
418 softnic_pipeline_port_out_create(struct pmd_internals *softnic,
419 const char *pipeline_name,
420 struct softnic_port_out_params *params)
422 struct rte_pipeline_port_out_params p;
425 struct rte_port_ethdev_writer_params ethdev;
426 struct rte_port_ring_writer_params ring;
427 struct rte_port_sched_writer_params sched;
428 struct rte_port_fd_writer_params fd;
429 struct rte_port_sink_params sink;
433 struct rte_port_ethdev_writer_nodrop_params ethdev;
434 struct rte_port_ring_writer_nodrop_params ring;
435 struct rte_port_fd_writer_nodrop_params fd;
438 struct pipeline *pipeline;
439 struct softnic_port_out *port_out;
443 memset(&p, 0, sizeof(p));
444 memset(&pp, 0, sizeof(pp));
445 memset(&pp_nodrop, 0, sizeof(pp_nodrop));
447 /* Check input params */
448 if (pipeline_name == NULL ||
450 params->burst_size == 0 ||
451 params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX)
454 pipeline = softnic_pipeline_find(softnic, pipeline_name);
455 if (pipeline == NULL)
458 switch (params->type) {
461 struct softnic_link *link;
463 link = softnic_link_find(softnic, params->dev_name);
467 if (params->txq.queue_id >= link->n_txq)
470 pp.ethdev.port_id = link->port_id;
471 pp.ethdev.queue_id = params->txq.queue_id;
472 pp.ethdev.tx_burst_sz = params->burst_size;
474 pp_nodrop.ethdev.port_id = link->port_id;
475 pp_nodrop.ethdev.queue_id = params->txq.queue_id;
476 pp_nodrop.ethdev.tx_burst_sz = params->burst_size;
477 pp_nodrop.ethdev.n_retries = params->n_retries;
479 if (params->retry == 0) {
480 p.ops = &rte_port_ethdev_writer_ops;
481 p.arg_create = &pp.ethdev;
483 p.ops = &rte_port_ethdev_writer_nodrop_ops;
484 p.arg_create = &pp_nodrop.ethdev;
491 struct softnic_swq *swq;
493 swq = softnic_swq_find(softnic, params->dev_name);
497 pp.ring.ring = swq->r;
498 pp.ring.tx_burst_sz = params->burst_size;
500 pp_nodrop.ring.ring = swq->r;
501 pp_nodrop.ring.tx_burst_sz = params->burst_size;
502 pp_nodrop.ring.n_retries = params->n_retries;
504 if (params->retry == 0) {
505 p.ops = &rte_port_ring_writer_ops;
506 p.arg_create = &pp.ring;
508 p.ops = &rte_port_ring_writer_nodrop_ops;
509 p.arg_create = &pp_nodrop.ring;
516 struct softnic_tmgr_port *tmgr_port;
518 tmgr_port = softnic_tmgr_port_find(softnic, params->dev_name);
519 if (tmgr_port == NULL)
522 pp.sched.sched = tmgr_port->s;
523 pp.sched.tx_burst_sz = params->burst_size;
525 p.ops = &rte_port_sched_writer_ops;
526 p.arg_create = &pp.sched;
532 struct softnic_tap *tap;
534 tap = softnic_tap_find(softnic, params->dev_name);
539 pp.fd.tx_burst_sz = params->burst_size;
541 pp_nodrop.fd.fd = tap->fd;
542 pp_nodrop.fd.tx_burst_sz = params->burst_size;
543 pp_nodrop.fd.n_retries = params->n_retries;
545 if (params->retry == 0) {
546 p.ops = &rte_port_fd_writer_ops;
547 p.arg_create = &pp.fd;
549 p.ops = &rte_port_fd_writer_nodrop_ops;
550 p.arg_create = &pp_nodrop.fd;
557 pp.sink.file_name = params->sink.file_name;
558 pp.sink.max_n_pkts = params->sink.max_n_pkts;
560 p.ops = &rte_port_sink_ops;
561 p.arg_create = &pp.sink;
572 /* Resource create */
573 status = rte_pipeline_port_out_create(pipeline->p,
581 port_out = &pipeline->port_out[pipeline->n_ports_out];
582 memcpy(&port_out->params, params, sizeof(*params));
583 pipeline->n_ports_out++;
588 static const struct rte_acl_field_def table_acl_field_format_ipv4[] = {
591 .type = RTE_ACL_FIELD_TYPE_BITMASK,
592 .size = sizeof(uint8_t),
595 .offset = offsetof(struct ipv4_hdr, next_proto_id),
598 /* Source IP address (IPv4) */
600 .type = RTE_ACL_FIELD_TYPE_MASK,
601 .size = sizeof(uint32_t),
604 .offset = offsetof(struct ipv4_hdr, src_addr),
607 /* Destination IP address (IPv4) */
609 .type = RTE_ACL_FIELD_TYPE_MASK,
610 .size = sizeof(uint32_t),
613 .offset = offsetof(struct ipv4_hdr, dst_addr),
618 .type = RTE_ACL_FIELD_TYPE_RANGE,
619 .size = sizeof(uint16_t),
622 .offset = sizeof(struct ipv4_hdr) +
623 offsetof(struct tcp_hdr, src_port),
626 /* Destination Port */
628 .type = RTE_ACL_FIELD_TYPE_RANGE,
629 .size = sizeof(uint16_t),
632 .offset = sizeof(struct ipv4_hdr) +
633 offsetof(struct tcp_hdr, dst_port),
637 static const struct rte_acl_field_def table_acl_field_format_ipv6[] = {
640 .type = RTE_ACL_FIELD_TYPE_BITMASK,
641 .size = sizeof(uint8_t),
644 .offset = offsetof(struct ipv6_hdr, proto),
647 /* Source IP address (IPv6) */
649 .type = RTE_ACL_FIELD_TYPE_MASK,
650 .size = sizeof(uint32_t),
653 .offset = offsetof(struct ipv6_hdr, src_addr[0]),
657 .type = RTE_ACL_FIELD_TYPE_MASK,
658 .size = sizeof(uint32_t),
661 .offset = offsetof(struct ipv6_hdr, src_addr[4]),
665 .type = RTE_ACL_FIELD_TYPE_MASK,
666 .size = sizeof(uint32_t),
669 .offset = offsetof(struct ipv6_hdr, src_addr[8]),
673 .type = RTE_ACL_FIELD_TYPE_MASK,
674 .size = sizeof(uint32_t),
677 .offset = offsetof(struct ipv6_hdr, src_addr[12]),
680 /* Destination IP address (IPv6) */
682 .type = RTE_ACL_FIELD_TYPE_MASK,
683 .size = sizeof(uint32_t),
686 .offset = offsetof(struct ipv6_hdr, dst_addr[0]),
690 .type = RTE_ACL_FIELD_TYPE_MASK,
691 .size = sizeof(uint32_t),
694 .offset = offsetof(struct ipv6_hdr, dst_addr[4]),
698 .type = RTE_ACL_FIELD_TYPE_MASK,
699 .size = sizeof(uint32_t),
702 .offset = offsetof(struct ipv6_hdr, dst_addr[8]),
706 .type = RTE_ACL_FIELD_TYPE_MASK,
707 .size = sizeof(uint32_t),
710 .offset = offsetof(struct ipv6_hdr, dst_addr[12]),
715 .type = RTE_ACL_FIELD_TYPE_RANGE,
716 .size = sizeof(uint16_t),
719 .offset = sizeof(struct ipv6_hdr) +
720 offsetof(struct tcp_hdr, src_port),
723 /* Destination Port */
725 .type = RTE_ACL_FIELD_TYPE_RANGE,
726 .size = sizeof(uint16_t),
729 .offset = sizeof(struct ipv6_hdr) +
730 offsetof(struct tcp_hdr, dst_port),
735 softnic_pipeline_table_create(struct pmd_internals *softnic,
736 const char *pipeline_name,
737 struct softnic_table_params *params)
740 struct rte_pipeline_table_params p;
743 struct rte_table_acl_params acl;
744 struct rte_table_array_params array;
745 struct rte_table_hash_params hash;
746 struct rte_table_lpm_params lpm;
747 struct rte_table_lpm_ipv6_params lpm_ipv6;
750 struct pipeline *pipeline;
751 struct softnic_table *table;
752 struct softnic_table_action_profile *ap;
753 struct rte_table_action *action;
757 memset(&p, 0, sizeof(p));
758 memset(&pp, 0, sizeof(pp));
760 /* Check input params */
761 if (pipeline_name == NULL ||
765 pipeline = softnic_pipeline_find(softnic, pipeline_name);
766 if (pipeline == NULL ||
767 pipeline->n_tables >= RTE_PIPELINE_TABLE_MAX)
771 if (strlen(params->action_profile_name)) {
772 ap = softnic_table_action_profile_find(softnic,
773 params->action_profile_name);
778 snprintf(name, NAME_MAX, "%s_%s_table%u",
779 softnic->params.name, pipeline_name, pipeline->n_tables);
781 switch (params->match_type) {
784 uint32_t ip_header_offset = params->match.acl.ip_header_offset -
785 (sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM);
788 if (params->match.acl.n_rules == 0)
792 pp.acl.n_rules = params->match.acl.n_rules;
793 if (params->match.acl.ip_version) {
794 memcpy(&pp.acl.field_format,
795 &table_acl_field_format_ipv4,
796 sizeof(table_acl_field_format_ipv4));
797 pp.acl.n_rule_fields =
798 RTE_DIM(table_acl_field_format_ipv4);
800 memcpy(&pp.acl.field_format,
801 &table_acl_field_format_ipv6,
802 sizeof(table_acl_field_format_ipv6));
803 pp.acl.n_rule_fields =
804 RTE_DIM(table_acl_field_format_ipv6);
807 for (i = 0; i < pp.acl.n_rule_fields; i++)
808 pp.acl.field_format[i].offset += ip_header_offset;
810 p.ops = &rte_table_acl_ops;
811 p.arg_create = &pp.acl;
817 if (params->match.array.n_keys == 0)
820 pp.array.n_entries = params->match.array.n_keys;
821 pp.array.offset = params->match.array.key_offset;
823 p.ops = &rte_table_array_ops;
824 p.arg_create = &pp.array;
830 struct rte_table_ops *ops;
831 rte_table_hash_op_hash f_hash;
833 if (params->match.hash.n_keys == 0)
836 switch (params->match.hash.key_size) {
838 f_hash = rte_table_hash_crc_key8;
841 f_hash = rte_table_hash_crc_key16;
844 f_hash = rte_table_hash_crc_key24;
847 f_hash = rte_table_hash_crc_key32;
850 f_hash = rte_table_hash_crc_key40;
853 f_hash = rte_table_hash_crc_key48;
856 f_hash = rte_table_hash_crc_key56;
859 f_hash = rte_table_hash_crc_key64;
866 pp.hash.key_size = params->match.hash.key_size;
867 pp.hash.key_offset = params->match.hash.key_offset;
868 pp.hash.key_mask = params->match.hash.key_mask;
869 pp.hash.n_keys = params->match.hash.n_keys;
870 pp.hash.n_buckets = params->match.hash.n_buckets;
871 pp.hash.f_hash = f_hash;
874 if (params->match.hash.extendable_bucket)
875 switch (params->match.hash.key_size) {
877 ops = &rte_table_hash_key8_ext_ops;
880 ops = &rte_table_hash_key16_ext_ops;
883 ops = &rte_table_hash_ext_ops;
886 switch (params->match.hash.key_size) {
888 ops = &rte_table_hash_key8_lru_ops;
891 ops = &rte_table_hash_key16_lru_ops;
894 ops = &rte_table_hash_lru_ops;
898 p.arg_create = &pp.hash;
904 if (params->match.lpm.n_rules == 0)
907 switch (params->match.lpm.key_size) {
911 pp.lpm.n_rules = params->match.lpm.n_rules;
912 pp.lpm.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
914 pp.lpm.entry_unique_size = p.action_data_size +
915 sizeof(struct rte_pipeline_table_entry);
916 pp.lpm.offset = params->match.lpm.key_offset;
918 p.ops = &rte_table_lpm_ops;
919 p.arg_create = &pp.lpm;
925 pp.lpm_ipv6.name = name;
926 pp.lpm_ipv6.n_rules = params->match.lpm.n_rules;
927 pp.lpm_ipv6.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
928 pp.lpm_ipv6.entry_unique_size = p.action_data_size +
929 sizeof(struct rte_pipeline_table_entry);
930 pp.lpm_ipv6.offset = params->match.lpm.key_offset;
932 p.ops = &rte_table_lpm_ipv6_ops;
933 p.arg_create = &pp.lpm_ipv6;
946 p.ops = &rte_table_stub_ops;
955 /* Resource create */
957 p.f_action_hit = NULL;
958 p.f_action_miss = NULL;
962 action = rte_table_action_create(ap->ap,
963 softnic->params.cpu_id);
967 status = rte_table_action_table_params_get(action,
970 ((p.action_data_size +
971 sizeof(struct rte_pipeline_table_entry)) >
972 TABLE_RULE_ACTION_SIZE_MAX)) {
973 rte_table_action_free(action);
978 if (params->match_type == TABLE_LPM) {
979 if (params->match.lpm.key_size == 4)
980 pp.lpm.entry_unique_size = p.action_data_size +
981 sizeof(struct rte_pipeline_table_entry);
983 if (params->match.lpm.key_size == 16)
984 pp.lpm_ipv6.entry_unique_size = p.action_data_size +
985 sizeof(struct rte_pipeline_table_entry);
988 status = rte_pipeline_table_create(pipeline->p,
992 rte_table_action_free(action);
997 table = &pipeline->table[pipeline->n_tables];
998 memcpy(&table->params, params, sizeof(*params));
1001 TAILQ_INIT(&table->flows);
1002 TAILQ_INIT(&table->meter_profiles);
1003 memset(&table->dscp_table, 0, sizeof(table->dscp_table));
1004 pipeline->n_tables++;
1010 softnic_pipeline_port_out_find(struct pmd_internals *softnic,
1011 const char *pipeline_name,
1015 struct pipeline *pipeline;
1018 if (softnic == NULL ||
1019 pipeline_name == NULL ||
1024 pipeline = softnic_pipeline_find(softnic, pipeline_name);
1025 if (pipeline == NULL)
1028 for (i = 0; i < pipeline->n_ports_out; i++)
1029 if (strcmp(pipeline->port_out[i].params.dev_name, name) == 0) {
1037 struct softnic_table_meter_profile *
1038 softnic_pipeline_table_meter_profile_find(struct softnic_table *table,
1039 uint32_t meter_profile_id)
1041 struct softnic_table_meter_profile *mp;
1043 TAILQ_FOREACH(mp, &table->meter_profiles, node)
1044 if (mp->meter_profile_id == meter_profile_id)