1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(C) 2020 Marvell International Ltd.
3 */
4
5 #include <errno.h>
6 #include <stdlib.h>
7
8 #include <rte_ethdev.h>
9 #include <rte_graph.h>
10
11 #include "rte_node_eth_api.h"
12
13 #include "ethdev_rx_priv.h"
14 #include "ethdev_tx_priv.h"
15 #include "ip4_rewrite_priv.h"
16 #include "ip6_rewrite_priv.h"
17 #include "node_private.h"
18
19 static struct ethdev_ctrl {
20 uint16_t nb_graphs;
21 } ctrl;
22
23 int
rte_node_eth_config(struct rte_node_ethdev_config * conf,uint16_t nb_confs,uint16_t nb_graphs)24 rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
25 uint16_t nb_graphs)
26 {
27 struct rte_node_register *ip4_rewrite_node;
28 struct rte_node_register *ip6_rewrite_node;
29 struct ethdev_tx_node_main *tx_node_data;
30 uint16_t tx_q_used, rx_q_used, port_id;
31 struct rte_node_register *tx_node;
32 char name[RTE_NODE_NAMESIZE];
33 const char *next_nodes = name;
34 struct rte_mempool *mp;
35 int i, j, rc;
36 uint32_t id;
37
38 ip4_rewrite_node = ip4_rewrite_node_get();
39 ip6_rewrite_node = ip6_rewrite_node_get();
40 tx_node_data = ethdev_tx_node_data_get();
41 tx_node = ethdev_tx_node_get();
42 for (i = 0; i < nb_confs; i++) {
43 port_id = conf[i].port_id;
44
45 if (!rte_eth_dev_is_valid_port(port_id))
46 return -EINVAL;
47
48 /* Check for mbuf minimum private size requirement */
49 for (j = 0; j < conf[i].mp_count; j++) {
50 mp = conf[i].mp[j];
51 if (!mp)
52 continue;
53 /* Check for minimum private space */
54 if (rte_pktmbuf_priv_size(mp) < NODE_MBUF_PRIV2_SIZE) {
55 node_err("ethdev",
56 "Minimum mbuf priv size requirement not met by mp %s",
57 mp->name);
58 return -EINVAL;
59 }
60 }
61
62 rx_q_used = conf[i].num_rx_queues;
63 tx_q_used = conf[i].num_tx_queues;
64 /* Check if we have a txq for each worker */
65 if (tx_q_used < nb_graphs)
66 return -EINVAL;
67
68 /* Create node for each rx port queue pair */
69 for (j = 0; j < rx_q_used; j++) {
70 struct ethdev_rx_node_main *rx_node_data;
71 struct rte_node_register *rx_node;
72 ethdev_rx_node_elem_t *elem;
73
74 rx_node_data = ethdev_rx_get_node_data_get();
75 rx_node = ethdev_rx_node_get();
76 snprintf(name, sizeof(name), "%u-%u", port_id, j);
77 /* Clone a new rx node with same edges as parent */
78 id = rte_node_clone(rx_node->id, name);
79 if (id == RTE_NODE_ID_INVALID)
80 return -EIO;
81
82 /* Add it to list of ethdev rx nodes for lookup */
83 elem = malloc(sizeof(ethdev_rx_node_elem_t));
84 if (elem == NULL)
85 return -ENOMEM;
86 memset(elem, 0, sizeof(ethdev_rx_node_elem_t));
87 elem->ctx.port_id = port_id;
88 elem->ctx.queue_id = j;
89 elem->ctx.cls_next = ETHDEV_RX_NEXT_PKT_CLS;
90 elem->nid = id;
91 elem->next = rx_node_data->head;
92 rx_node_data->head = elem;
93
94 node_dbg("ethdev", "Rx node %s-%s: is at %u",
95 rx_node->name, name, id);
96 }
97
98 /* Create a per port tx node from base node */
99 snprintf(name, sizeof(name), "%u", port_id);
100 /* Clone a new node with same edges as parent */
101 id = rte_node_clone(tx_node->id, name);
102 tx_node_data->nodes[port_id] = id;
103
104 node_dbg("ethdev", "Tx node %s-%s: is at %u", tx_node->name,
105 name, id);
106
107 /* Prepare the actual name of the cloned node */
108 snprintf(name, sizeof(name), "ethdev_tx-%u", port_id);
109
110 /* Add this tx port node as next to ip4_rewrite_node */
111 rte_node_edge_update(ip4_rewrite_node->id, RTE_EDGE_ID_INVALID,
112 &next_nodes, 1);
113 /* Assuming edge id is the last one alloc'ed */
114 rc = ip4_rewrite_set_next(
115 port_id, rte_node_edge_count(ip4_rewrite_node->id) - 1);
116 if (rc < 0)
117 return rc;
118
119 /* Add this tx port node as next to ip6_rewrite_node */
120 rte_node_edge_update(ip6_rewrite_node->id, RTE_EDGE_ID_INVALID,
121 &next_nodes, 1);
122 /* Assuming edge id is the last one alloc'ed */
123 rc = ip6_rewrite_set_next(
124 port_id, rte_node_edge_count(ip6_rewrite_node->id) - 1);
125 if (rc < 0)
126 return rc;
127
128 }
129
130 ctrl.nb_graphs = nb_graphs;
131 return 0;
132 }
133
134 int
rte_node_ethdev_rx_next_update(rte_node_t id,const char * edge_name)135 rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name)
136 {
137 struct ethdev_rx_node_main *data;
138 ethdev_rx_node_elem_t *elem;
139 char **next_nodes;
140 int rc = -EINVAL;
141 uint16_t i = 0;
142 uint32_t size;
143
144 if (edge_name == NULL)
145 goto exit;
146
147 size = rte_node_edge_get(id, NULL);
148
149 if (size == RTE_NODE_ID_INVALID)
150 goto exit;
151
152 next_nodes = calloc((size / sizeof(char *)) + 1, sizeof(*next_nodes));
153 if (next_nodes == NULL) {
154 rc = -ENOMEM;
155 goto exit;
156 }
157
158 size = rte_node_edge_get(id, next_nodes);
159
160 while (next_nodes[i] != NULL) {
161 if (strcmp(edge_name, next_nodes[i]) == 0) {
162 data = ethdev_rx_get_node_data_get();
163 elem = data->head;
164 while (elem->next != data->head) {
165 if (elem->nid == id) {
166 elem->ctx.cls_next = i;
167 rc = 0;
168 goto found;
169 }
170 elem = elem->next;
171 }
172 }
173 i++;
174 }
175 found:
176 free(next_nodes);
177 exit:
178 return rc;
179 }
180