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 * 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 * 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 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 * 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 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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