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