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