xref: /dpdk/examples/pipeline/obj.c (revision 8c76e2f6937730782baa210bf456bd19da2a9600)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2020 Intel Corporation
3  */
4 
5 #include <stdlib.h>
6 #include <string.h>
7 #include <netinet/in.h>
8 #ifdef RTE_EXEC_ENV_LINUX
9 #include <linux/if.h>
10 #include <linux/if_tun.h>
11 #endif
12 #include <sys/ioctl.h>
13 #include <fcntl.h>
14 #include <unistd.h>
15 
16 #include <rte_mempool.h>
17 #include <rte_mbuf.h>
18 #include <rte_ethdev.h>
19 #include <rte_swx_ctl.h>
20 
21 #include "obj.h"
22 
23 /*
24  * mempool
25  */
26 TAILQ_HEAD(mempool_list, mempool);
27 
28 /*
29  * link
30  */
31 TAILQ_HEAD(link_list, link);
32 
33 /*
34  * ring
35  */
36 TAILQ_HEAD(ring_list, ring);
37 
38 /*
39  * obj
40  */
41 struct obj {
42 	struct mempool_list mempool_list;
43 	struct link_list link_list;
44 	struct ring_list ring_list;
45 };
46 
47 /*
48  * mempool
49  */
50 #define BUFFER_SIZE_MIN (sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
51 
52 struct mempool *
53 mempool_create(struct obj *obj, const char *name, struct mempool_params *params)
54 {
55 	struct mempool *mempool;
56 	struct rte_mempool *m;
57 
58 	/* Check input params */
59 	if ((name == NULL) ||
60 		mempool_find(obj, name) ||
61 		(params == NULL) ||
62 		(params->buffer_size < BUFFER_SIZE_MIN) ||
63 		(params->pool_size == 0))
64 		return NULL;
65 
66 	/* Resource create */
67 	m = rte_pktmbuf_pool_create(
68 		name,
69 		params->pool_size,
70 		params->cache_size,
71 		0,
72 		params->buffer_size - sizeof(struct rte_mbuf),
73 		params->cpu_id);
74 
75 	if (m == NULL)
76 		return NULL;
77 
78 	/* Node allocation */
79 	mempool = calloc(1, sizeof(struct mempool));
80 	if (mempool == NULL) {
81 		rte_mempool_free(m);
82 		return NULL;
83 	}
84 
85 	/* Node fill in */
86 	strlcpy(mempool->name, name, sizeof(mempool->name));
87 	mempool->m = m;
88 	mempool->buffer_size = params->buffer_size;
89 
90 	/* Node add to list */
91 	TAILQ_INSERT_TAIL(&obj->mempool_list, mempool, node);
92 
93 	return mempool;
94 }
95 
96 struct mempool *
97 mempool_find(struct obj *obj, const char *name)
98 {
99 	struct mempool *mempool;
100 
101 	if (!obj || !name)
102 		return NULL;
103 
104 	TAILQ_FOREACH(mempool, &obj->mempool_list, node)
105 		if (strcmp(mempool->name, name) == 0)
106 			return mempool;
107 
108 	return NULL;
109 }
110 
111 /*
112  * link
113  */
114 static struct rte_eth_conf port_conf_default = {
115 	.link_speeds = 0,
116 	.rxmode = {
117 		.mq_mode = RTE_ETH_MQ_RX_NONE,
118 		.mtu = 9000 - (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN), /* Jumbo frame MTU */
119 		.split_hdr_size = 0, /* Header split buffer size */
120 	},
121 	.rx_adv_conf = {
122 		.rss_conf = {
123 			.rss_key = NULL,
124 			.rss_key_len = 40,
125 			.rss_hf = 0,
126 		},
127 	},
128 	.txmode = {
129 		.mq_mode = RTE_ETH_MQ_TX_NONE,
130 	},
131 	.lpbk_mode = 0,
132 };
133 
134 #define RETA_CONF_SIZE     (RTE_ETH_RSS_RETA_SIZE_512 / RTE_ETH_RETA_GROUP_SIZE)
135 
136 static int
137 rss_setup(uint16_t port_id,
138 	uint16_t reta_size,
139 	struct link_params_rss *rss)
140 {
141 	struct rte_eth_rss_reta_entry64 reta_conf[RETA_CONF_SIZE];
142 	uint32_t i;
143 	int status;
144 
145 	/* RETA setting */
146 	memset(reta_conf, 0, sizeof(reta_conf));
147 
148 	for (i = 0; i < reta_size; i++)
149 		reta_conf[i / RTE_ETH_RETA_GROUP_SIZE].mask = UINT64_MAX;
150 
151 	for (i = 0; i < reta_size; i++) {
152 		uint32_t reta_id = i / RTE_ETH_RETA_GROUP_SIZE;
153 		uint32_t reta_pos = i % RTE_ETH_RETA_GROUP_SIZE;
154 		uint32_t rss_qs_pos = i % rss->n_queues;
155 
156 		reta_conf[reta_id].reta[reta_pos] =
157 			(uint16_t) rss->queue_id[rss_qs_pos];
158 	}
159 
160 	/* RETA update */
161 	status = rte_eth_dev_rss_reta_update(port_id,
162 		reta_conf,
163 		reta_size);
164 
165 	return status;
166 }
167 
168 struct link *
169 link_create(struct obj *obj, const char *name, struct link_params *params)
170 {
171 	struct rte_eth_dev_info port_info;
172 	struct rte_eth_conf port_conf;
173 	struct link *link;
174 	struct link_params_rss *rss;
175 	struct mempool *mempool;
176 	uint32_t cpu_id, i;
177 	int status;
178 	uint16_t port_id = 0;
179 
180 	/* Check input params */
181 	if ((name == NULL) ||
182 		link_find(obj, name) ||
183 		(params == NULL) ||
184 		(params->rx.n_queues == 0) ||
185 		(params->rx.queue_size == 0) ||
186 		(params->tx.n_queues == 0) ||
187 		(params->tx.queue_size == 0))
188 		return NULL;
189 
190 	status = rte_eth_dev_get_port_by_name(name, &port_id);
191 	if (status)
192 		return NULL;
193 
194 	if (rte_eth_dev_info_get(port_id, &port_info) != 0)
195 		return NULL;
196 
197 	mempool = mempool_find(obj, params->rx.mempool_name);
198 	if (mempool == NULL)
199 		return NULL;
200 
201 	rss = params->rx.rss;
202 	if (rss) {
203 		if ((port_info.reta_size == 0) ||
204 			(port_info.reta_size > RTE_ETH_RSS_RETA_SIZE_512))
205 			return NULL;
206 
207 		if ((rss->n_queues == 0) ||
208 			(rss->n_queues >= LINK_RXQ_RSS_MAX))
209 			return NULL;
210 
211 		for (i = 0; i < rss->n_queues; i++)
212 			if (rss->queue_id[i] >= port_info.max_rx_queues)
213 				return NULL;
214 	}
215 
216 	/**
217 	 * Resource create
218 	 */
219 	/* Port */
220 	memcpy(&port_conf, &port_conf_default, sizeof(port_conf));
221 	if (rss) {
222 		port_conf.rxmode.mq_mode = RTE_ETH_MQ_RX_RSS;
223 		port_conf.rx_adv_conf.rss_conf.rss_hf =
224 			(RTE_ETH_RSS_IP | RTE_ETH_RSS_TCP | RTE_ETH_RSS_UDP) &
225 			port_info.flow_type_rss_offloads;
226 	}
227 
228 	cpu_id = (uint32_t) rte_eth_dev_socket_id(port_id);
229 	if (cpu_id == (uint32_t) SOCKET_ID_ANY)
230 		cpu_id = 0;
231 
232 	status = rte_eth_dev_configure(
233 		port_id,
234 		params->rx.n_queues,
235 		params->tx.n_queues,
236 		&port_conf);
237 
238 	if (status < 0)
239 		return NULL;
240 
241 	if (params->promiscuous) {
242 		status = rte_eth_promiscuous_enable(port_id);
243 		if (status != 0)
244 			return NULL;
245 	}
246 
247 	/* Port RX */
248 	for (i = 0; i < params->rx.n_queues; i++) {
249 		status = rte_eth_rx_queue_setup(
250 			port_id,
251 			i,
252 			params->rx.queue_size,
253 			cpu_id,
254 			NULL,
255 			mempool->m);
256 
257 		if (status < 0)
258 			return NULL;
259 	}
260 
261 	/* Port TX */
262 	for (i = 0; i < params->tx.n_queues; i++) {
263 		status = rte_eth_tx_queue_setup(
264 			port_id,
265 			i,
266 			params->tx.queue_size,
267 			cpu_id,
268 			NULL);
269 
270 		if (status < 0)
271 			return NULL;
272 	}
273 
274 	/* Port start */
275 	status = rte_eth_dev_start(port_id);
276 	if (status < 0)
277 		return NULL;
278 
279 	if (rss) {
280 		status = rss_setup(port_id, port_info.reta_size, rss);
281 
282 		if (status) {
283 			rte_eth_dev_stop(port_id);
284 			return NULL;
285 		}
286 	}
287 
288 	/* Port link up */
289 	status = rte_eth_dev_set_link_up(port_id);
290 	if ((status < 0) && (status != -ENOTSUP)) {
291 		rte_eth_dev_stop(port_id);
292 		return NULL;
293 	}
294 
295 	/* Node allocation */
296 	link = calloc(1, sizeof(struct link));
297 	if (link == NULL) {
298 		rte_eth_dev_stop(port_id);
299 		return NULL;
300 	}
301 
302 	/* Node fill in */
303 	strlcpy(link->name, name, sizeof(link->name));
304 	link->port_id = port_id;
305 	link->n_rxq = params->rx.n_queues;
306 	link->n_txq = params->tx.n_queues;
307 
308 	/* Node add to list */
309 	TAILQ_INSERT_TAIL(&obj->link_list, link, node);
310 
311 	return link;
312 }
313 
314 int
315 link_is_up(struct obj *obj, const char *name)
316 {
317 	struct rte_eth_link link_params;
318 	struct link *link;
319 
320 	/* Check input params */
321 	if (!obj || !name)
322 		return 0;
323 
324 	link = link_find(obj, name);
325 	if (link == NULL)
326 		return 0;
327 
328 	/* Resource */
329 	if (rte_eth_link_get(link->port_id, &link_params) < 0)
330 		return 0;
331 
332 	return (link_params.link_status == RTE_ETH_LINK_DOWN) ? 0 : 1;
333 }
334 
335 struct link *
336 link_find(struct obj *obj, const char *name)
337 {
338 	struct link *link;
339 
340 	if (!obj || !name)
341 		return NULL;
342 
343 	TAILQ_FOREACH(link, &obj->link_list, node)
344 		if (strcmp(link->name, name) == 0)
345 			return link;
346 
347 	return NULL;
348 }
349 
350 struct link *
351 link_next(struct obj *obj, struct link *link)
352 {
353 	return (link == NULL) ?
354 		TAILQ_FIRST(&obj->link_list) : TAILQ_NEXT(link, node);
355 }
356 
357 /*
358  * ring
359  */
360 struct ring *
361 ring_create(struct obj *obj, const char *name, struct ring_params *params)
362 {
363 	struct ring *ring;
364 	struct rte_ring *r;
365 	unsigned int flags = RING_F_SP_ENQ | RING_F_SC_DEQ;
366 
367 	/* Check input params */
368 	if (!name || ring_find(obj, name) || !params || !params->size)
369 		return NULL;
370 
371 	/**
372 	 * Resource create
373 	 */
374 	r = rte_ring_create(
375 		name,
376 		params->size,
377 		params->numa_node,
378 		flags);
379 	if (!r)
380 		return NULL;
381 
382 	/* Node allocation */
383 	ring = calloc(1, sizeof(struct ring));
384 	if (!ring) {
385 		rte_ring_free(r);
386 		return NULL;
387 	}
388 
389 	/* Node fill in */
390 	strlcpy(ring->name, name, sizeof(ring->name));
391 
392 	/* Node add to list */
393 	TAILQ_INSERT_TAIL(&obj->ring_list, ring, node);
394 
395 	return ring;
396 }
397 
398 struct ring *
399 ring_find(struct obj *obj, const char *name)
400 {
401 	struct ring *ring;
402 
403 	if (!obj || !name)
404 		return NULL;
405 
406 	TAILQ_FOREACH(ring, &obj->ring_list, node)
407 		if (strcmp(ring->name, name) == 0)
408 			return ring;
409 
410 	return NULL;
411 }
412 
413 /*
414  * obj
415  */
416 struct obj *
417 obj_init(void)
418 {
419 	struct obj *obj;
420 
421 	obj = calloc(1, sizeof(struct obj));
422 	if (!obj)
423 		return NULL;
424 
425 	TAILQ_INIT(&obj->mempool_list);
426 	TAILQ_INIT(&obj->link_list);
427 	TAILQ_INIT(&obj->ring_list);
428 
429 	return obj;
430 }
431