xref: /dpdk/examples/ip_pipeline/link.c (revision fb73e096110a41b77448fe27fd9be8c489ec5d82)
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_ethdev.h>
9 
10 #include "link.h"
11 #include "mempool.h"
12 
13 static struct link_list link_list;
14 
15 int
16 link_init(void)
17 {
18 	TAILQ_INIT(&link_list);
19 
20 	return 0;
21 }
22 
23 struct link *
24 link_find(const char *name)
25 {
26 	struct link *link;
27 
28 	if (name == NULL)
29 		return NULL;
30 
31 	TAILQ_FOREACH(link, &link_list, node)
32 		if (strcmp(link->name, name) == 0)
33 			return link;
34 
35 	return NULL;
36 }
37 
38 static struct rte_eth_conf port_conf_default = {
39 	.link_speeds = 0,
40 	.rxmode = {
41 		.mq_mode = ETH_MQ_RX_NONE,
42 
43 		.header_split   = 0, /* Header split */
44 		.hw_ip_checksum = 0, /* IP checksum offload */
45 		.hw_vlan_filter = 0, /* VLAN filtering */
46 		.hw_vlan_strip  = 0, /* VLAN strip */
47 		.hw_vlan_extend = 0, /* Extended VLAN */
48 		.jumbo_frame    = 0, /* Jumbo frame support */
49 		.hw_strip_crc   = 1, /* CRC strip by HW */
50 		.enable_scatter = 0, /* Scattered packets RX handler */
51 
52 		.max_rx_pkt_len = 9000, /* Jumbo frame max packet len */
53 		.split_hdr_size = 0, /* Header split buffer size */
54 	},
55 	.rx_adv_conf = {
56 		.rss_conf = {
57 			.rss_key = NULL,
58 			.rss_key_len = 40,
59 			.rss_hf = 0,
60 		},
61 	},
62 	.txmode = {
63 		.mq_mode = ETH_MQ_TX_NONE,
64 	},
65 	.lpbk_mode = 0,
66 };
67 
68 #define RETA_CONF_SIZE     (ETH_RSS_RETA_SIZE_512 / RTE_RETA_GROUP_SIZE)
69 
70 static int
71 rss_setup(uint16_t port_id,
72 	uint16_t reta_size,
73 	struct link_params_rss *rss)
74 {
75 	struct rte_eth_rss_reta_entry64 reta_conf[RETA_CONF_SIZE];
76 	uint32_t i;
77 	int status;
78 
79 	/* RETA setting */
80 	memset(reta_conf, 0, sizeof(reta_conf));
81 
82 	for (i = 0; i < reta_size; i++)
83 		reta_conf[i / RTE_RETA_GROUP_SIZE].mask = UINT64_MAX;
84 
85 	for (i = 0; i < reta_size; i++) {
86 		uint32_t reta_id = i / RTE_RETA_GROUP_SIZE;
87 		uint32_t reta_pos = i % RTE_RETA_GROUP_SIZE;
88 		uint32_t rss_qs_pos = i % rss->n_queues;
89 
90 		reta_conf[reta_id].reta[reta_pos] =
91 			(uint16_t) rss->queue_id[rss_qs_pos];
92 	}
93 
94 	/* RETA update */
95 	status = rte_eth_dev_rss_reta_update(port_id,
96 		reta_conf,
97 		reta_size);
98 
99 	return status;
100 }
101 
102 struct link *
103 link_create(const char *name, struct link_params *params)
104 {
105 	struct rte_eth_dev_info port_info;
106 	struct rte_eth_conf port_conf;
107 	struct link *link;
108 	struct link_params_rss *rss;
109 	struct mempool *mempool;
110 	uint32_t cpu_id, i;
111 	int status;
112 	uint16_t port_id;
113 
114 	/* Check input params */
115 	if ((name == NULL) ||
116 		link_find(name) ||
117 		(params == NULL) ||
118 		(params->rx.n_queues == 0) ||
119 		(params->rx.queue_size == 0) ||
120 		(params->tx.n_queues == 0) ||
121 		(params->tx.queue_size == 0))
122 		return NULL;
123 
124 	port_id = params->port_id;
125 	if (params->dev_name) {
126 		status = rte_eth_dev_get_port_by_name(params->dev_name,
127 			&port_id);
128 
129 		if (status)
130 			return NULL;
131 	} else
132 		if (!rte_eth_dev_is_valid_port(port_id))
133 			return NULL;
134 
135 	rte_eth_dev_info_get(port_id, &port_info);
136 
137 	mempool = mempool_find(params->rx.mempool_name);
138 	if (mempool == NULL)
139 		return NULL;
140 
141 	rss = params->rx.rss;
142 	if (rss) {
143 		if ((port_info.reta_size == 0) ||
144 			(port_info.reta_size > ETH_RSS_RETA_SIZE_512))
145 			return NULL;
146 
147 		if ((rss->n_queues == 0) ||
148 			(rss->n_queues >= LINK_RXQ_RSS_MAX))
149 			return NULL;
150 
151 		for (i = 0; i < rss->n_queues; i++)
152 			if (rss->queue_id[i] >= port_info.max_rx_queues)
153 				return NULL;
154 	}
155 
156 	/**
157 	 * Resource create
158 	 */
159 	/* Port */
160 	memcpy(&port_conf, &port_conf_default, sizeof(port_conf));
161 	if (rss) {
162 		port_conf.rxmode.mq_mode = ETH_MQ_RX_RSS;
163 		port_conf.rx_adv_conf.rss_conf.rss_hf =
164 			ETH_RSS_IPV4 | ETH_RSS_IPV6;
165 	}
166 
167 	cpu_id = (uint32_t) rte_eth_dev_socket_id(port_id);
168 	if (cpu_id == (uint32_t) SOCKET_ID_ANY)
169 		cpu_id = 0;
170 
171 	status = rte_eth_dev_configure(
172 		port_id,
173 		params->rx.n_queues,
174 		params->tx.n_queues,
175 		&port_conf);
176 
177 	if (status < 0)
178 		return NULL;
179 
180 	if (params->promiscuous)
181 		rte_eth_promiscuous_enable(port_id);
182 
183 	/* Port RX */
184 	for (i = 0; i < params->rx.n_queues; i++) {
185 		status = rte_eth_rx_queue_setup(
186 			port_id,
187 			i,
188 			params->rx.queue_size,
189 			cpu_id,
190 			NULL,
191 			mempool->m);
192 
193 		if (status < 0)
194 			return NULL;
195 	}
196 
197 	/* Port TX */
198 	for (i = 0; i < params->tx.n_queues; i++) {
199 		status = rte_eth_tx_queue_setup(
200 			port_id,
201 			i,
202 			params->tx.queue_size,
203 			cpu_id,
204 			NULL);
205 
206 		if (status < 0)
207 			return NULL;
208 	}
209 
210 	/* Port start */
211 	status = rte_eth_dev_start(port_id);
212 	if (status < 0)
213 		return NULL;
214 
215 	if (rss) {
216 		status = rss_setup(port_id, port_info.reta_size, rss);
217 
218 		if (status) {
219 			rte_eth_dev_stop(port_id);
220 			return NULL;
221 		}
222 	}
223 
224 	/* Port link up */
225 	status = rte_eth_dev_set_link_up(port_id);
226 	if ((status < 0) && (status != -ENOTSUP)) {
227 		rte_eth_dev_stop(port_id);
228 		return NULL;
229 	}
230 
231 	/* Node allocation */
232 	link = calloc(1, sizeof(struct link));
233 	if (link == NULL) {
234 		rte_eth_dev_stop(port_id);
235 		return NULL;
236 	}
237 
238 	/* Node fill in */
239 	strncpy(link->name, name, sizeof(link->name));
240 	link->port_id = port_id;
241 	link->n_rxq = params->rx.n_queues;
242 	link->n_txq = params->tx.n_queues;
243 
244 	/* Node add to list */
245 	TAILQ_INSERT_TAIL(&link_list, link, node);
246 
247 	return link;
248 }
249 
250 int
251 link_is_up(const char *name)
252 {
253 	struct rte_eth_link link_params;
254 	struct link *link;
255 
256 	/* Check input params */
257 	if (name == NULL)
258 		return 0;
259 
260 	link = link_find(name);
261 	if (link == NULL)
262 		return 0;
263 
264 	/* Resource */
265 	rte_eth_link_get(link->port_id, &link_params);
266 
267 	return (link_params.link_status == ETH_LINK_DOWN) ? 0 : 1;
268 }
269