xref: /dpdk/examples/pipeline/obj.c (revision 959c84ed059ed2c8db497114f976ca197a14c56b)
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_pipeline.h>
20 #include <rte_swx_ctl.h>
21 
22 #include "obj.h"
23 
24 /*
25  * mempool
26  */
27 TAILQ_HEAD(mempool_list, mempool);
28 
29 /*
30  * link
31  */
32 TAILQ_HEAD(link_list, link);
33 
34 /*
35  * ring
36  */
37 TAILQ_HEAD(ring_list, ring);
38 
39 /*
40  * tap
41  */
42 TAILQ_HEAD(tap_list, tap);
43 
44 /*
45  * pipeline
46  */
47 TAILQ_HEAD(pipeline_list, pipeline);
48 
49 /*
50  * obj
51  */
52 struct obj {
53 	struct mempool_list mempool_list;
54 	struct link_list link_list;
55 	struct ring_list ring_list;
56 	struct pipeline_list pipeline_list;
57 	struct tap_list tap_list;
58 };
59 
60 /*
61  * mempool
62  */
63 #define BUFFER_SIZE_MIN (sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
64 
65 struct mempool *
66 mempool_create(struct obj *obj, const char *name, struct mempool_params *params)
67 {
68 	struct mempool *mempool;
69 	struct rte_mempool *m;
70 
71 	/* Check input params */
72 	if ((name == NULL) ||
73 		mempool_find(obj, name) ||
74 		(params == NULL) ||
75 		(params->buffer_size < BUFFER_SIZE_MIN) ||
76 		(params->pool_size == 0))
77 		return NULL;
78 
79 	/* Resource create */
80 	m = rte_pktmbuf_pool_create(
81 		name,
82 		params->pool_size,
83 		params->cache_size,
84 		0,
85 		params->buffer_size - sizeof(struct rte_mbuf),
86 		params->cpu_id);
87 
88 	if (m == NULL)
89 		return NULL;
90 
91 	/* Node allocation */
92 	mempool = calloc(1, sizeof(struct mempool));
93 	if (mempool == NULL) {
94 		rte_mempool_free(m);
95 		return NULL;
96 	}
97 
98 	/* Node fill in */
99 	strlcpy(mempool->name, name, sizeof(mempool->name));
100 	mempool->m = m;
101 	mempool->buffer_size = params->buffer_size;
102 
103 	/* Node add to list */
104 	TAILQ_INSERT_TAIL(&obj->mempool_list, mempool, node);
105 
106 	return mempool;
107 }
108 
109 struct mempool *
110 mempool_find(struct obj *obj, const char *name)
111 {
112 	struct mempool *mempool;
113 
114 	if (!obj || !name)
115 		return NULL;
116 
117 	TAILQ_FOREACH(mempool, &obj->mempool_list, node)
118 		if (strcmp(mempool->name, name) == 0)
119 			return mempool;
120 
121 	return NULL;
122 }
123 
124 /*
125  * link
126  */
127 static struct rte_eth_conf port_conf_default = {
128 	.link_speeds = 0,
129 	.rxmode = {
130 		.mq_mode = RTE_ETH_MQ_RX_NONE,
131 		.mtu = 9000 - (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN), /* Jumbo frame MTU */
132 		.split_hdr_size = 0, /* Header split buffer size */
133 	},
134 	.rx_adv_conf = {
135 		.rss_conf = {
136 			.rss_key = NULL,
137 			.rss_key_len = 40,
138 			.rss_hf = 0,
139 		},
140 	},
141 	.txmode = {
142 		.mq_mode = RTE_ETH_MQ_TX_NONE,
143 	},
144 	.lpbk_mode = 0,
145 };
146 
147 #define RETA_CONF_SIZE     (RTE_ETH_RSS_RETA_SIZE_512 / RTE_ETH_RETA_GROUP_SIZE)
148 
149 static int
150 rss_setup(uint16_t port_id,
151 	uint16_t reta_size,
152 	struct link_params_rss *rss)
153 {
154 	struct rte_eth_rss_reta_entry64 reta_conf[RETA_CONF_SIZE];
155 	uint32_t i;
156 	int status;
157 
158 	/* RETA setting */
159 	memset(reta_conf, 0, sizeof(reta_conf));
160 
161 	for (i = 0; i < reta_size; i++)
162 		reta_conf[i / RTE_ETH_RETA_GROUP_SIZE].mask = UINT64_MAX;
163 
164 	for (i = 0; i < reta_size; i++) {
165 		uint32_t reta_id = i / RTE_ETH_RETA_GROUP_SIZE;
166 		uint32_t reta_pos = i % RTE_ETH_RETA_GROUP_SIZE;
167 		uint32_t rss_qs_pos = i % rss->n_queues;
168 
169 		reta_conf[reta_id].reta[reta_pos] =
170 			(uint16_t) rss->queue_id[rss_qs_pos];
171 	}
172 
173 	/* RETA update */
174 	status = rte_eth_dev_rss_reta_update(port_id,
175 		reta_conf,
176 		reta_size);
177 
178 	return status;
179 }
180 
181 struct link *
182 link_create(struct obj *obj, const char *name, struct link_params *params)
183 {
184 	struct rte_eth_dev_info port_info;
185 	struct rte_eth_conf port_conf;
186 	struct link *link;
187 	struct link_params_rss *rss;
188 	struct mempool *mempool;
189 	uint32_t cpu_id, i;
190 	int status;
191 	uint16_t port_id;
192 
193 	/* Check input params */
194 	if ((name == NULL) ||
195 		link_find(obj, name) ||
196 		(params == NULL) ||
197 		(params->rx.n_queues == 0) ||
198 		(params->rx.queue_size == 0) ||
199 		(params->tx.n_queues == 0) ||
200 		(params->tx.queue_size == 0))
201 		return NULL;
202 
203 	port_id = params->port_id;
204 	if (params->dev_name) {
205 		status = rte_eth_dev_get_port_by_name(params->dev_name,
206 			&port_id);
207 
208 		if (status)
209 			return NULL;
210 	} else
211 		if (!rte_eth_dev_is_valid_port(port_id))
212 			return NULL;
213 
214 	if (rte_eth_dev_info_get(port_id, &port_info) != 0)
215 		return NULL;
216 
217 	mempool = mempool_find(obj, params->rx.mempool_name);
218 	if (mempool == NULL)
219 		return NULL;
220 
221 	rss = params->rx.rss;
222 	if (rss) {
223 		if ((port_info.reta_size == 0) ||
224 			(port_info.reta_size > RTE_ETH_RSS_RETA_SIZE_512))
225 			return NULL;
226 
227 		if ((rss->n_queues == 0) ||
228 			(rss->n_queues >= LINK_RXQ_RSS_MAX))
229 			return NULL;
230 
231 		for (i = 0; i < rss->n_queues; i++)
232 			if (rss->queue_id[i] >= port_info.max_rx_queues)
233 				return NULL;
234 	}
235 
236 	/**
237 	 * Resource create
238 	 */
239 	/* Port */
240 	memcpy(&port_conf, &port_conf_default, sizeof(port_conf));
241 	if (rss) {
242 		port_conf.rxmode.mq_mode = RTE_ETH_MQ_RX_RSS;
243 		port_conf.rx_adv_conf.rss_conf.rss_hf =
244 			(RTE_ETH_RSS_IP | RTE_ETH_RSS_TCP | RTE_ETH_RSS_UDP) &
245 			port_info.flow_type_rss_offloads;
246 	}
247 
248 	cpu_id = (uint32_t) rte_eth_dev_socket_id(port_id);
249 	if (cpu_id == (uint32_t) SOCKET_ID_ANY)
250 		cpu_id = 0;
251 
252 	status = rte_eth_dev_configure(
253 		port_id,
254 		params->rx.n_queues,
255 		params->tx.n_queues,
256 		&port_conf);
257 
258 	if (status < 0)
259 		return NULL;
260 
261 	if (params->promiscuous) {
262 		status = rte_eth_promiscuous_enable(port_id);
263 		if (status != 0)
264 			return NULL;
265 	}
266 
267 	/* Port RX */
268 	for (i = 0; i < params->rx.n_queues; i++) {
269 		status = rte_eth_rx_queue_setup(
270 			port_id,
271 			i,
272 			params->rx.queue_size,
273 			cpu_id,
274 			NULL,
275 			mempool->m);
276 
277 		if (status < 0)
278 			return NULL;
279 	}
280 
281 	/* Port TX */
282 	for (i = 0; i < params->tx.n_queues; i++) {
283 		status = rte_eth_tx_queue_setup(
284 			port_id,
285 			i,
286 			params->tx.queue_size,
287 			cpu_id,
288 			NULL);
289 
290 		if (status < 0)
291 			return NULL;
292 	}
293 
294 	/* Port start */
295 	status = rte_eth_dev_start(port_id);
296 	if (status < 0)
297 		return NULL;
298 
299 	if (rss) {
300 		status = rss_setup(port_id, port_info.reta_size, rss);
301 
302 		if (status) {
303 			rte_eth_dev_stop(port_id);
304 			return NULL;
305 		}
306 	}
307 
308 	/* Port link up */
309 	status = rte_eth_dev_set_link_up(port_id);
310 	if ((status < 0) && (status != -ENOTSUP)) {
311 		rte_eth_dev_stop(port_id);
312 		return NULL;
313 	}
314 
315 	/* Node allocation */
316 	link = calloc(1, sizeof(struct link));
317 	if (link == NULL) {
318 		rte_eth_dev_stop(port_id);
319 		return NULL;
320 	}
321 
322 	/* Node fill in */
323 	strlcpy(link->name, name, sizeof(link->name));
324 	link->port_id = port_id;
325 	rte_eth_dev_get_name_by_port(port_id, link->dev_name);
326 	link->n_rxq = params->rx.n_queues;
327 	link->n_txq = params->tx.n_queues;
328 
329 	/* Node add to list */
330 	TAILQ_INSERT_TAIL(&obj->link_list, link, node);
331 
332 	return link;
333 }
334 
335 int
336 link_is_up(struct obj *obj, const char *name)
337 {
338 	struct rte_eth_link link_params;
339 	struct link *link;
340 
341 	/* Check input params */
342 	if (!obj || !name)
343 		return 0;
344 
345 	link = link_find(obj, name);
346 	if (link == NULL)
347 		return 0;
348 
349 	/* Resource */
350 	if (rte_eth_link_get(link->port_id, &link_params) < 0)
351 		return 0;
352 
353 	return (link_params.link_status == RTE_ETH_LINK_DOWN) ? 0 : 1;
354 }
355 
356 struct link *
357 link_find(struct obj *obj, const char *name)
358 {
359 	struct link *link;
360 
361 	if (!obj || !name)
362 		return NULL;
363 
364 	TAILQ_FOREACH(link, &obj->link_list, node)
365 		if (strcmp(link->name, name) == 0)
366 			return link;
367 
368 	return NULL;
369 }
370 
371 struct link *
372 link_next(struct obj *obj, struct link *link)
373 {
374 	return (link == NULL) ?
375 		TAILQ_FIRST(&obj->link_list) : TAILQ_NEXT(link, node);
376 }
377 
378 /*
379  * ring
380  */
381 struct ring *
382 ring_create(struct obj *obj, const char *name, struct ring_params *params)
383 {
384 	struct ring *ring;
385 	struct rte_ring *r;
386 	unsigned int flags = RING_F_SP_ENQ | RING_F_SC_DEQ;
387 
388 	/* Check input params */
389 	if (!name || ring_find(obj, name) || !params || !params->size)
390 		return NULL;
391 
392 	/**
393 	 * Resource create
394 	 */
395 	r = rte_ring_create(
396 		name,
397 		params->size,
398 		params->numa_node,
399 		flags);
400 	if (!r)
401 		return NULL;
402 
403 	/* Node allocation */
404 	ring = calloc(1, sizeof(struct ring));
405 	if (!ring) {
406 		rte_ring_free(r);
407 		return NULL;
408 	}
409 
410 	/* Node fill in */
411 	strlcpy(ring->name, name, sizeof(ring->name));
412 
413 	/* Node add to list */
414 	TAILQ_INSERT_TAIL(&obj->ring_list, ring, node);
415 
416 	return ring;
417 }
418 
419 struct ring *
420 ring_find(struct obj *obj, const char *name)
421 {
422 	struct ring *ring;
423 
424 	if (!obj || !name)
425 		return NULL;
426 
427 	TAILQ_FOREACH(ring, &obj->ring_list, node)
428 		if (strcmp(ring->name, name) == 0)
429 			return ring;
430 
431 	return NULL;
432 }
433 
434 /*
435  * tap
436  */
437 #define TAP_DEV		"/dev/net/tun"
438 
439 struct tap *
440 tap_find(struct obj *obj, const char *name)
441 {
442 	struct tap *tap;
443 
444 	if (!obj || !name)
445 		return NULL;
446 
447 	TAILQ_FOREACH(tap, &obj->tap_list, node)
448 		if (strcmp(tap->name, name) == 0)
449 			return tap;
450 
451 	return NULL;
452 }
453 
454 struct tap *
455 tap_next(struct obj *obj, struct tap *tap)
456 {
457 	return (tap == NULL) ?
458 		TAILQ_FIRST(&obj->tap_list) : TAILQ_NEXT(tap, node);
459 }
460 
461 #ifndef RTE_EXEC_ENV_LINUX
462 
463 struct tap *
464 tap_create(struct obj *obj __rte_unused, const char *name __rte_unused)
465 {
466 	return NULL;
467 }
468 
469 #else
470 
471 struct tap *
472 tap_create(struct obj *obj, const char *name)
473 {
474 	struct tap *tap;
475 	struct ifreq ifr;
476 	int fd, status;
477 
478 	/* Check input params */
479 	if ((name == NULL) ||
480 		tap_find(obj, name))
481 		return NULL;
482 
483 	/* Resource create */
484 	fd = open(TAP_DEV, O_RDWR | O_NONBLOCK);
485 	if (fd < 0)
486 		return NULL;
487 
488 	memset(&ifr, 0, sizeof(ifr));
489 	ifr.ifr_flags = IFF_TAP | IFF_NO_PI; /* No packet information */
490 	strlcpy(ifr.ifr_name, name, IFNAMSIZ);
491 
492 	status = ioctl(fd, TUNSETIFF, (void *) &ifr);
493 	if (status < 0) {
494 		close(fd);
495 		return NULL;
496 	}
497 
498 	/* Node allocation */
499 	tap = calloc(1, sizeof(struct tap));
500 	if (tap == NULL) {
501 		close(fd);
502 		return NULL;
503 	}
504 	/* Node fill in */
505 	strlcpy(tap->name, name, sizeof(tap->name));
506 	tap->fd = fd;
507 
508 	/* Node add to list */
509 	TAILQ_INSERT_TAIL(&obj->tap_list, tap, node);
510 
511 	return tap;
512 }
513 
514 #endif
515 
516 /*
517  * pipeline
518  */
519 #ifndef PIPELINE_MSGQ_SIZE
520 #define PIPELINE_MSGQ_SIZE                                 64
521 #endif
522 
523 struct pipeline *
524 pipeline_create(struct obj *obj, const char *name, int numa_node)
525 {
526 	struct pipeline *pipeline;
527 	struct rte_swx_pipeline *p = NULL;
528 	int status;
529 
530 	/* Check input params */
531 	if ((name == NULL) ||
532 		pipeline_find(obj, name))
533 		return NULL;
534 
535 	/* Resource create */
536 	status = rte_swx_pipeline_config(&p, numa_node);
537 	if (status)
538 		goto error;
539 
540 	/* Node allocation */
541 	pipeline = calloc(1, sizeof(struct pipeline));
542 	if (pipeline == NULL)
543 		goto error;
544 
545 	/* Node fill in */
546 	strlcpy(pipeline->name, name, sizeof(pipeline->name));
547 	pipeline->p = p;
548 	pipeline->timer_period_ms = 10;
549 
550 	/* Node add to list */
551 	TAILQ_INSERT_TAIL(&obj->pipeline_list, pipeline, node);
552 
553 	return pipeline;
554 
555 error:
556 	rte_swx_pipeline_free(p);
557 	return NULL;
558 }
559 
560 struct pipeline *
561 pipeline_find(struct obj *obj, const char *name)
562 {
563 	struct pipeline *pipeline;
564 
565 	if (!obj || !name)
566 		return NULL;
567 
568 	TAILQ_FOREACH(pipeline, &obj->pipeline_list, node)
569 		if (strcmp(name, pipeline->name) == 0)
570 			return pipeline;
571 
572 	return NULL;
573 }
574 
575 /*
576  * obj
577  */
578 struct obj *
579 obj_init(void)
580 {
581 	struct obj *obj;
582 
583 	obj = calloc(1, sizeof(struct obj));
584 	if (!obj)
585 		return NULL;
586 
587 	TAILQ_INIT(&obj->mempool_list);
588 	TAILQ_INIT(&obj->link_list);
589 	TAILQ_INIT(&obj->ring_list);
590 	TAILQ_INIT(&obj->pipeline_list);
591 	TAILQ_INIT(&obj->tap_list);
592 
593 	return obj;
594 }
595