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_find(struct pmd_internals *p,
68 struct pipeline *pipeline;
73 TAILQ_FOREACH(pipeline, &p->pipeline_list, node)
74 if (strcmp(name, pipeline->name) == 0)
81 softnic_pipeline_create(struct pmd_internals *softnic,
83 struct pipeline_params *params)
85 char resource_name[NAME_MAX];
86 struct rte_pipeline_params pp;
87 struct pipeline *pipeline;
88 struct rte_pipeline *p;
89 struct rte_ring *msgq_req;
90 struct rte_ring *msgq_rsp;
92 /* Check input params */
94 softnic_pipeline_find(softnic, name) ||
96 params->timer_period_ms == 0)
100 snprintf(resource_name, sizeof(resource_name), "%s-%s-REQ",
101 softnic->params.name,
104 msgq_req = rte_ring_create(resource_name,
106 softnic->params.cpu_id,
107 RING_F_SP_ENQ | RING_F_SC_DEQ);
108 if (msgq_req == NULL)
111 snprintf(resource_name, sizeof(resource_name), "%s-%s-RSP",
112 softnic->params.name,
115 msgq_rsp = rte_ring_create(resource_name,
117 softnic->params.cpu_id,
118 RING_F_SP_ENQ | RING_F_SC_DEQ);
119 if (msgq_rsp == NULL) {
120 rte_ring_free(msgq_req);
124 snprintf(resource_name, sizeof(resource_name), "%s_%s",
125 softnic->params.name,
128 pp.name = resource_name;
129 pp.socket_id = (int)softnic->params.cpu_id;
130 pp.offset_port_id = params->offset_port_id;
132 p = rte_pipeline_create(&pp);
134 rte_ring_free(msgq_rsp);
135 rte_ring_free(msgq_req);
139 /* Node allocation */
140 pipeline = calloc(1, sizeof(struct pipeline));
141 if (pipeline == NULL) {
142 rte_pipeline_free(p);
143 rte_ring_free(msgq_rsp);
144 rte_ring_free(msgq_req);
149 strlcpy(pipeline->name, name, sizeof(pipeline->name));
151 pipeline->n_ports_in = 0;
152 pipeline->n_ports_out = 0;
153 pipeline->n_tables = 0;
154 pipeline->msgq_req = msgq_req;
155 pipeline->msgq_rsp = msgq_rsp;
156 pipeline->timer_period_ms = params->timer_period_ms;
157 pipeline->enabled = 0;
158 pipeline->cpu_id = softnic->params.cpu_id;
160 /* Node add to list */
161 TAILQ_INSERT_TAIL(&softnic->pipeline_list, pipeline, node);
167 softnic_pipeline_port_in_create(struct pmd_internals *softnic,
168 const char *pipeline_name,
169 struct softnic_port_in_params *params,
172 struct rte_pipeline_port_in_params p;
175 struct rte_port_ethdev_reader_params ethdev;
176 struct rte_port_ring_reader_params ring;
177 struct rte_port_sched_reader_params sched;
178 struct rte_port_fd_reader_params fd;
179 struct rte_port_source_params source;
182 struct pipeline *pipeline;
183 struct softnic_port_in *port_in;
184 struct softnic_port_in_action_profile *ap;
185 struct rte_port_in_action *action;
189 memset(&p, 0, sizeof(p));
190 memset(&pp, 0, sizeof(pp));
192 /* Check input params */
193 if (pipeline_name == NULL ||
195 params->burst_size == 0 ||
196 params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX)
199 pipeline = softnic_pipeline_find(softnic, pipeline_name);
200 if (pipeline == NULL)
204 if (params->action_profile_name) {
205 ap = softnic_port_in_action_profile_find(softnic,
206 params->action_profile_name);
211 switch (params->type) {
214 struct softnic_link *link;
216 link = softnic_link_find(softnic, params->dev_name);
220 if (params->rxq.queue_id >= link->n_rxq)
223 pp.ethdev.port_id = link->port_id;
224 pp.ethdev.queue_id = params->rxq.queue_id;
226 p.ops = &rte_port_ethdev_reader_ops;
227 p.arg_create = &pp.ethdev;
233 struct softnic_swq *swq;
235 swq = softnic_swq_find(softnic, params->dev_name);
239 pp.ring.ring = swq->r;
241 p.ops = &rte_port_ring_reader_ops;
242 p.arg_create = &pp.ring;
248 struct softnic_tmgr_port *tmgr_port;
250 tmgr_port = softnic_tmgr_port_find(softnic, params->dev_name);
251 if (tmgr_port == NULL)
254 pp.sched.sched = tmgr_port->s;
256 p.ops = &rte_port_sched_reader_ops;
257 p.arg_create = &pp.sched;
263 struct softnic_tap *tap;
264 struct softnic_mempool *mempool;
266 tap = softnic_tap_find(softnic, params->dev_name);
267 mempool = softnic_mempool_find(softnic, params->tap.mempool_name);
268 if (tap == NULL || mempool == NULL)
272 pp.fd.mempool = mempool->m;
273 pp.fd.mtu = params->tap.mtu;
275 p.ops = &rte_port_fd_reader_ops;
276 p.arg_create = &pp.fd;
282 struct softnic_mempool *mempool;
284 mempool = softnic_mempool_find(softnic, params->source.mempool_name);
288 pp.source.mempool = mempool->m;
289 pp.source.file_name = params->source.file_name;
290 pp.source.n_bytes_per_pkt = params->source.n_bytes_per_pkt;
292 p.ops = &rte_port_source_ops;
293 p.arg_create = &pp.source;
301 p.burst_size = params->burst_size;
303 /* Resource create */
309 action = rte_port_in_action_create(ap->ap,
310 softnic->params.cpu_id);
314 status = rte_port_in_action_params_get(action,
317 rte_port_in_action_free(action);
322 status = rte_pipeline_port_in_create(pipeline->p,
326 rte_port_in_action_free(action);
331 rte_pipeline_port_in_enable(pipeline->p, port_id);
334 port_in = &pipeline->port_in[pipeline->n_ports_in];
335 memcpy(&port_in->params, params, sizeof(*params));
338 pipeline->n_ports_in++;
344 softnic_pipeline_port_in_connect_to_table(struct pmd_internals *softnic,
345 const char *pipeline_name,
349 struct pipeline *pipeline;
352 /* Check input params */
353 if (pipeline_name == NULL)
356 pipeline = softnic_pipeline_find(softnic, pipeline_name);
357 if (pipeline == NULL ||
358 port_id >= pipeline->n_ports_in ||
359 table_id >= pipeline->n_tables)
363 status = rte_pipeline_port_in_connect_to_table(pipeline->p,
371 softnic_pipeline_port_out_create(struct pmd_internals *softnic,
372 const char *pipeline_name,
373 struct softnic_port_out_params *params)
375 struct rte_pipeline_port_out_params p;
378 struct rte_port_ethdev_writer_params ethdev;
379 struct rte_port_ring_writer_params ring;
380 struct rte_port_sched_writer_params sched;
381 struct rte_port_fd_writer_params fd;
382 struct rte_port_sink_params sink;
386 struct rte_port_ethdev_writer_nodrop_params ethdev;
387 struct rte_port_ring_writer_nodrop_params ring;
388 struct rte_port_fd_writer_nodrop_params fd;
391 struct pipeline *pipeline;
395 memset(&p, 0, sizeof(p));
396 memset(&pp, 0, sizeof(pp));
397 memset(&pp_nodrop, 0, sizeof(pp_nodrop));
399 /* Check input params */
400 if (pipeline_name == NULL ||
402 params->burst_size == 0 ||
403 params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX)
406 pipeline = softnic_pipeline_find(softnic, pipeline_name);
407 if (pipeline == NULL)
410 switch (params->type) {
413 struct softnic_link *link;
415 link = softnic_link_find(softnic, params->dev_name);
419 if (params->txq.queue_id >= link->n_txq)
422 pp.ethdev.port_id = link->port_id;
423 pp.ethdev.queue_id = params->txq.queue_id;
424 pp.ethdev.tx_burst_sz = params->burst_size;
426 pp_nodrop.ethdev.port_id = link->port_id;
427 pp_nodrop.ethdev.queue_id = params->txq.queue_id;
428 pp_nodrop.ethdev.tx_burst_sz = params->burst_size;
429 pp_nodrop.ethdev.n_retries = params->n_retries;
431 if (params->retry == 0) {
432 p.ops = &rte_port_ethdev_writer_ops;
433 p.arg_create = &pp.ethdev;
435 p.ops = &rte_port_ethdev_writer_nodrop_ops;
436 p.arg_create = &pp_nodrop.ethdev;
443 struct softnic_swq *swq;
445 swq = softnic_swq_find(softnic, params->dev_name);
449 pp.ring.ring = swq->r;
450 pp.ring.tx_burst_sz = params->burst_size;
452 pp_nodrop.ring.ring = swq->r;
453 pp_nodrop.ring.tx_burst_sz = params->burst_size;
454 pp_nodrop.ring.n_retries = params->n_retries;
456 if (params->retry == 0) {
457 p.ops = &rte_port_ring_writer_ops;
458 p.arg_create = &pp.ring;
460 p.ops = &rte_port_ring_writer_nodrop_ops;
461 p.arg_create = &pp_nodrop.ring;
468 struct softnic_tmgr_port *tmgr_port;
470 tmgr_port = softnic_tmgr_port_find(softnic, params->dev_name);
471 if (tmgr_port == NULL)
474 pp.sched.sched = tmgr_port->s;
475 pp.sched.tx_burst_sz = params->burst_size;
477 p.ops = &rte_port_sched_writer_ops;
478 p.arg_create = &pp.sched;
484 struct softnic_tap *tap;
486 tap = softnic_tap_find(softnic, params->dev_name);
491 pp.fd.tx_burst_sz = params->burst_size;
493 pp_nodrop.fd.fd = tap->fd;
494 pp_nodrop.fd.tx_burst_sz = params->burst_size;
495 pp_nodrop.fd.n_retries = params->n_retries;
497 if (params->retry == 0) {
498 p.ops = &rte_port_fd_writer_ops;
499 p.arg_create = &pp.fd;
501 p.ops = &rte_port_fd_writer_nodrop_ops;
502 p.arg_create = &pp_nodrop.fd;
509 pp.sink.file_name = params->sink.file_name;
510 pp.sink.max_n_pkts = params->sink.max_n_pkts;
512 p.ops = &rte_port_sink_ops;
513 p.arg_create = &pp.sink;
524 /* Resource create */
525 status = rte_pipeline_port_out_create(pipeline->p,
533 pipeline->n_ports_out++;
538 static const struct rte_acl_field_def table_acl_field_format_ipv4[] = {
541 .type = RTE_ACL_FIELD_TYPE_BITMASK,
542 .size = sizeof(uint8_t),
545 .offset = offsetof(struct ipv4_hdr, next_proto_id),
548 /* Source IP address (IPv4) */
550 .type = RTE_ACL_FIELD_TYPE_MASK,
551 .size = sizeof(uint32_t),
554 .offset = offsetof(struct ipv4_hdr, src_addr),
557 /* Destination IP address (IPv4) */
559 .type = RTE_ACL_FIELD_TYPE_MASK,
560 .size = sizeof(uint32_t),
563 .offset = offsetof(struct ipv4_hdr, dst_addr),
568 .type = RTE_ACL_FIELD_TYPE_RANGE,
569 .size = sizeof(uint16_t),
572 .offset = sizeof(struct ipv4_hdr) +
573 offsetof(struct tcp_hdr, src_port),
576 /* Destination Port */
578 .type = RTE_ACL_FIELD_TYPE_RANGE,
579 .size = sizeof(uint16_t),
582 .offset = sizeof(struct ipv4_hdr) +
583 offsetof(struct tcp_hdr, dst_port),
587 static const struct rte_acl_field_def table_acl_field_format_ipv6[] = {
590 .type = RTE_ACL_FIELD_TYPE_BITMASK,
591 .size = sizeof(uint8_t),
594 .offset = offsetof(struct ipv6_hdr, proto),
597 /* Source IP address (IPv6) */
599 .type = RTE_ACL_FIELD_TYPE_MASK,
600 .size = sizeof(uint32_t),
603 .offset = offsetof(struct ipv6_hdr, src_addr[0]),
607 .type = RTE_ACL_FIELD_TYPE_MASK,
608 .size = sizeof(uint32_t),
611 .offset = offsetof(struct ipv6_hdr, src_addr[4]),
615 .type = RTE_ACL_FIELD_TYPE_MASK,
616 .size = sizeof(uint32_t),
619 .offset = offsetof(struct ipv6_hdr, src_addr[8]),
623 .type = RTE_ACL_FIELD_TYPE_MASK,
624 .size = sizeof(uint32_t),
627 .offset = offsetof(struct ipv6_hdr, src_addr[12]),
630 /* Destination IP address (IPv6) */
632 .type = RTE_ACL_FIELD_TYPE_MASK,
633 .size = sizeof(uint32_t),
636 .offset = offsetof(struct ipv6_hdr, dst_addr[0]),
640 .type = RTE_ACL_FIELD_TYPE_MASK,
641 .size = sizeof(uint32_t),
644 .offset = offsetof(struct ipv6_hdr, dst_addr[4]),
648 .type = RTE_ACL_FIELD_TYPE_MASK,
649 .size = sizeof(uint32_t),
652 .offset = offsetof(struct ipv6_hdr, dst_addr[8]),
656 .type = RTE_ACL_FIELD_TYPE_MASK,
657 .size = sizeof(uint32_t),
660 .offset = offsetof(struct ipv6_hdr, dst_addr[12]),
665 .type = RTE_ACL_FIELD_TYPE_RANGE,
666 .size = sizeof(uint16_t),
669 .offset = sizeof(struct ipv6_hdr) +
670 offsetof(struct tcp_hdr, src_port),
673 /* Destination Port */
675 .type = RTE_ACL_FIELD_TYPE_RANGE,
676 .size = sizeof(uint16_t),
679 .offset = sizeof(struct ipv6_hdr) +
680 offsetof(struct tcp_hdr, dst_port),
685 softnic_pipeline_table_create(struct pmd_internals *softnic,
686 const char *pipeline_name,
687 struct softnic_table_params *params)
690 struct rte_pipeline_table_params p;
693 struct rte_table_acl_params acl;
694 struct rte_table_array_params array;
695 struct rte_table_hash_params hash;
696 struct rte_table_lpm_params lpm;
697 struct rte_table_lpm_ipv6_params lpm_ipv6;
700 struct pipeline *pipeline;
701 struct softnic_table *table;
702 struct softnic_table_action_profile *ap;
703 struct rte_table_action *action;
707 memset(&p, 0, sizeof(p));
708 memset(&pp, 0, sizeof(pp));
710 /* Check input params */
711 if (pipeline_name == NULL ||
715 pipeline = softnic_pipeline_find(softnic, pipeline_name);
716 if (pipeline == NULL ||
717 pipeline->n_tables >= RTE_PIPELINE_TABLE_MAX)
721 if (params->action_profile_name) {
722 ap = softnic_table_action_profile_find(softnic,
723 params->action_profile_name);
728 snprintf(name, NAME_MAX, "%s_%s_table%u",
729 softnic->params.name, pipeline_name, pipeline->n_tables);
731 switch (params->match_type) {
734 uint32_t ip_header_offset = params->match.acl.ip_header_offset -
735 (sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM);
738 if (params->match.acl.n_rules == 0)
742 pp.acl.n_rules = params->match.acl.n_rules;
743 if (params->match.acl.ip_version) {
744 memcpy(&pp.acl.field_format,
745 &table_acl_field_format_ipv4,
746 sizeof(table_acl_field_format_ipv4));
747 pp.acl.n_rule_fields =
748 RTE_DIM(table_acl_field_format_ipv4);
750 memcpy(&pp.acl.field_format,
751 &table_acl_field_format_ipv6,
752 sizeof(table_acl_field_format_ipv6));
753 pp.acl.n_rule_fields =
754 RTE_DIM(table_acl_field_format_ipv6);
757 for (i = 0; i < pp.acl.n_rule_fields; i++)
758 pp.acl.field_format[i].offset += ip_header_offset;
760 p.ops = &rte_table_acl_ops;
761 p.arg_create = &pp.acl;
767 if (params->match.array.n_keys == 0)
770 pp.array.n_entries = params->match.array.n_keys;
771 pp.array.offset = params->match.array.key_offset;
773 p.ops = &rte_table_array_ops;
774 p.arg_create = &pp.array;
780 struct rte_table_ops *ops;
781 rte_table_hash_op_hash f_hash;
783 if (params->match.hash.n_keys == 0)
786 switch (params->match.hash.key_size) {
788 f_hash = hash_default_key8;
791 f_hash = hash_default_key16;
794 f_hash = hash_default_key24;
797 f_hash = hash_default_key32;
800 f_hash = hash_default_key40;
803 f_hash = hash_default_key48;
806 f_hash = hash_default_key56;
809 f_hash = hash_default_key64;
816 pp.hash.key_size = params->match.hash.key_size;
817 pp.hash.key_offset = params->match.hash.key_offset;
818 pp.hash.key_mask = params->match.hash.key_mask;
819 pp.hash.n_keys = params->match.hash.n_keys;
820 pp.hash.n_buckets = params->match.hash.n_buckets;
821 pp.hash.f_hash = f_hash;
824 if (params->match.hash.extendable_bucket)
825 switch (params->match.hash.key_size) {
827 ops = &rte_table_hash_key8_ext_ops;
830 ops = &rte_table_hash_key16_ext_ops;
833 ops = &rte_table_hash_ext_ops;
836 switch (params->match.hash.key_size) {
838 ops = &rte_table_hash_key8_lru_ops;
841 ops = &rte_table_hash_key16_lru_ops;
844 ops = &rte_table_hash_lru_ops;
848 p.arg_create = &pp.hash;
854 if (params->match.lpm.n_rules == 0)
857 switch (params->match.lpm.key_size) {
861 pp.lpm.n_rules = params->match.lpm.n_rules;
862 pp.lpm.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
864 pp.lpm.entry_unique_size = p.action_data_size +
865 sizeof(struct rte_pipeline_table_entry);
866 pp.lpm.offset = params->match.lpm.key_offset;
868 p.ops = &rte_table_lpm_ops;
869 p.arg_create = &pp.lpm;
875 pp.lpm_ipv6.name = name;
876 pp.lpm_ipv6.n_rules = params->match.lpm.n_rules;
877 pp.lpm_ipv6.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
878 pp.lpm_ipv6.entry_unique_size = p.action_data_size +
879 sizeof(struct rte_pipeline_table_entry);
880 pp.lpm_ipv6.offset = params->match.lpm.key_offset;
882 p.ops = &rte_table_lpm_ipv6_ops;
883 p.arg_create = &pp.lpm_ipv6;
896 p.ops = &rte_table_stub_ops;
905 /* Resource create */
907 p.f_action_hit = NULL;
908 p.f_action_miss = NULL;
912 action = rte_table_action_create(ap->ap,
913 softnic->params.cpu_id);
917 status = rte_table_action_table_params_get(action,
920 ((p.action_data_size +
921 sizeof(struct rte_pipeline_table_entry)) >
922 TABLE_RULE_ACTION_SIZE_MAX)) {
923 rte_table_action_free(action);
928 if (params->match_type == TABLE_LPM) {
929 if (params->match.lpm.key_size == 4)
930 pp.lpm.entry_unique_size = p.action_data_size +
931 sizeof(struct rte_pipeline_table_entry);
933 if (params->match.lpm.key_size == 16)
934 pp.lpm_ipv6.entry_unique_size = p.action_data_size +
935 sizeof(struct rte_pipeline_table_entry);
938 status = rte_pipeline_table_create(pipeline->p,
942 rte_table_action_free(action);
947 table = &pipeline->table[pipeline->n_tables];
948 memcpy(&table->params, params, sizeof(*params));
951 pipeline->n_tables++;