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 } 611