4b2db66c46d96f1b05a47accd198f74225a185dc
[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 #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 }