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