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