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 *
mempool_create(struct obj * obj,const char * name,struct mempool_params * params)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 *
mempool_find(struct obj * obj,const char * name)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
rss_setup(uint16_t port_id,uint16_t reta_size,struct link_params_rss * rss)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 *
link_create(struct obj * obj,const char * name,struct link_params * params)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
link_is_up(struct obj * obj,const char * name)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 *
link_find(struct obj * obj,const char * name)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 *
link_next(struct obj * obj,struct link * 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 *
pipeline_create(struct obj * obj,const char * name,int numa_node)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 *
pipeline_find(struct obj * obj,const char * name)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 *
obj_init(void)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