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