1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2016 Intel Corporation 3 */ 4 5 #include <locale.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <stdint.h> 9 #include <ctype.h> 10 #include <getopt.h> 11 12 #include <rte_common.h> 13 #include <rte_log.h> 14 #include <rte_malloc.h> 15 #include <rte_memory.h> 16 #include <rte_memcpy.h> 17 #include <rte_eal.h> 18 #include <rte_launch.h> 19 #include <rte_atomic.h> 20 #include <rte_cycles.h> 21 #include <rte_prefetch.h> 22 #include <rte_lcore.h> 23 #include <rte_per_lcore.h> 24 #include <rte_branch_prediction.h> 25 #include <rte_interrupts.h> 26 #include <rte_debug.h> 27 #include <rte_ether.h> 28 #include <rte_ethdev.h> 29 #include <rte_mempool.h> 30 #include <rte_mbuf.h> 31 #include <rte_spinlock.h> 32 33 #include <rte_errno.h> 34 #include <rte_jobstats.h> 35 #include <rte_timer.h> 36 #include <rte_alarm.h> 37 #include <rte_pause.h> 38 39 #define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1 40 41 #define NB_MBUF 8192 42 43 #define MAX_PKT_BURST 32 44 #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */ 45 46 /* 47 * Configurable number of RX/TX ring descriptors 48 */ 49 #define RTE_TEST_RX_DESC_DEFAULT 1024 50 #define RTE_TEST_TX_DESC_DEFAULT 1024 51 static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; 52 static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; 53 54 /* ethernet addresses of ports */ 55 static struct rte_ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS]; 56 57 /* mask of enabled ports */ 58 static uint32_t l2fwd_enabled_port_mask; 59 60 /* list of enabled ports */ 61 static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS]; 62 63 #define UPDATE_STEP_UP 1 64 #define UPDATE_STEP_DOWN 32 65 66 static unsigned int l2fwd_rx_queue_per_lcore = 1; 67 68 #define MAX_RX_QUEUE_PER_LCORE 16 69 #define MAX_TX_QUEUE_PER_PORT 16 70 struct lcore_queue_conf { 71 unsigned n_rx_port; 72 unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE]; 73 uint64_t next_flush_time[RTE_MAX_ETHPORTS]; 74 75 struct rte_timer rx_timers[MAX_RX_QUEUE_PER_LCORE]; 76 struct rte_jobstats port_fwd_jobs[MAX_RX_QUEUE_PER_LCORE]; 77 78 struct rte_timer flush_timer; 79 struct rte_jobstats flush_job; 80 struct rte_jobstats idle_job; 81 struct rte_jobstats_context jobs_context; 82 83 rte_atomic16_t stats_read_pending; 84 rte_spinlock_t lock; 85 } __rte_cache_aligned; 86 struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE]; 87 88 struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS]; 89 90 static struct rte_eth_conf port_conf = { 91 .rxmode = { 92 .split_hdr_size = 0, 93 }, 94 .txmode = { 95 .mq_mode = ETH_MQ_TX_NONE, 96 }, 97 }; 98 99 struct rte_mempool *l2fwd_pktmbuf_pool = NULL; 100 101 /* Per-port statistics struct */ 102 struct l2fwd_port_statistics { 103 uint64_t tx; 104 uint64_t rx; 105 uint64_t dropped; 106 } __rte_cache_aligned; 107 struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS]; 108 109 /* 1 day max */ 110 #define MAX_TIMER_PERIOD 86400 111 /* default period is 10 seconds */ 112 static int64_t timer_period = 10; 113 /* default timer frequency */ 114 static double hz; 115 /* BURST_TX_DRAIN_US converted to cycles */ 116 uint64_t drain_tsc; 117 /* Convert cycles to ns */ 118 static inline double 119 cycles_to_ns(uint64_t cycles) 120 { 121 double t = cycles; 122 123 t *= (double)NS_PER_S; 124 t /= hz; 125 return t; 126 } 127 128 static void 129 show_lcore_stats(unsigned lcore_id) 130 { 131 struct lcore_queue_conf *qconf = &lcore_queue_conf[lcore_id]; 132 struct rte_jobstats_context *ctx = &qconf->jobs_context; 133 struct rte_jobstats *job; 134 uint8_t i; 135 136 /* LCore statistics. */ 137 uint64_t stats_period, loop_count; 138 uint64_t exec, exec_min, exec_max; 139 uint64_t management, management_min, management_max; 140 uint64_t busy, busy_min, busy_max; 141 142 /* Jobs statistics. */ 143 const uint16_t port_cnt = qconf->n_rx_port; 144 uint64_t jobs_exec_cnt[port_cnt], jobs_period[port_cnt]; 145 uint64_t jobs_exec[port_cnt], jobs_exec_min[port_cnt], 146 jobs_exec_max[port_cnt]; 147 148 uint64_t flush_exec_cnt, flush_period; 149 uint64_t flush_exec, flush_exec_min, flush_exec_max; 150 151 uint64_t idle_exec_cnt; 152 uint64_t idle_exec, idle_exec_min, idle_exec_max; 153 uint64_t collection_time = rte_get_timer_cycles(); 154 155 /* Ask forwarding thread to give us stats. */ 156 rte_atomic16_set(&qconf->stats_read_pending, 1); 157 rte_spinlock_lock(&qconf->lock); 158 rte_atomic16_set(&qconf->stats_read_pending, 0); 159 160 /* Collect context statistics. */ 161 stats_period = ctx->state_time - ctx->start_time; 162 loop_count = ctx->loop_cnt; 163 164 exec = ctx->exec_time; 165 exec_min = ctx->min_exec_time; 166 exec_max = ctx->max_exec_time; 167 168 management = ctx->management_time; 169 management_min = ctx->min_management_time; 170 management_max = ctx->max_management_time; 171 172 rte_jobstats_context_reset(ctx); 173 174 for (i = 0; i < port_cnt; i++) { 175 job = &qconf->port_fwd_jobs[i]; 176 177 jobs_exec_cnt[i] = job->exec_cnt; 178 jobs_period[i] = job->period; 179 180 jobs_exec[i] = job->exec_time; 181 jobs_exec_min[i] = job->min_exec_time; 182 jobs_exec_max[i] = job->max_exec_time; 183 184 rte_jobstats_reset(job); 185 } 186 187 flush_exec_cnt = qconf->flush_job.exec_cnt; 188 flush_period = qconf->flush_job.period; 189 flush_exec = qconf->flush_job.exec_time; 190 flush_exec_min = qconf->flush_job.min_exec_time; 191 flush_exec_max = qconf->flush_job.max_exec_time; 192 rte_jobstats_reset(&qconf->flush_job); 193 194 idle_exec_cnt = qconf->idle_job.exec_cnt; 195 idle_exec = qconf->idle_job.exec_time; 196 idle_exec_min = qconf->idle_job.min_exec_time; 197 idle_exec_max = qconf->idle_job.max_exec_time; 198 rte_jobstats_reset(&qconf->idle_job); 199 200 rte_spinlock_unlock(&qconf->lock); 201 202 exec -= idle_exec; 203 busy = exec + management; 204 busy_min = exec_min + management_min; 205 busy_max = exec_max + management_max; 206 207 208 collection_time = rte_get_timer_cycles() - collection_time; 209 210 #define STAT_FMT "\n%-18s %'14.0f %6.1f%% %'10.0f %'10.0f %'10.0f" 211 212 printf("\n----------------" 213 "\nLCore %3u: statistics (time in ns, collected in %'9.0f)" 214 "\n%-18s %14s %7s %10s %10s %10s " 215 "\n%-18s %'14.0f" 216 "\n%-18s %'14" PRIu64 217 STAT_FMT /* Exec */ 218 STAT_FMT /* Management */ 219 STAT_FMT /* Busy */ 220 STAT_FMT, /* Idle */ 221 lcore_id, cycles_to_ns(collection_time), 222 "Stat type", "total", "%total", "avg", "min", "max", 223 "Stats duration:", cycles_to_ns(stats_period), 224 "Loop count:", loop_count, 225 "Exec time", 226 cycles_to_ns(exec), exec * 100.0 / stats_period, 227 cycles_to_ns(loop_count ? exec / loop_count : 0), 228 cycles_to_ns(exec_min), 229 cycles_to_ns(exec_max), 230 "Management time", 231 cycles_to_ns(management), management * 100.0 / stats_period, 232 cycles_to_ns(loop_count ? management / loop_count : 0), 233 cycles_to_ns(management_min), 234 cycles_to_ns(management_max), 235 "Exec + management", 236 cycles_to_ns(busy), busy * 100.0 / stats_period, 237 cycles_to_ns(loop_count ? busy / loop_count : 0), 238 cycles_to_ns(busy_min), 239 cycles_to_ns(busy_max), 240 "Idle (job)", 241 cycles_to_ns(idle_exec), idle_exec * 100.0 / stats_period, 242 cycles_to_ns(idle_exec_cnt ? idle_exec / idle_exec_cnt : 0), 243 cycles_to_ns(idle_exec_min), 244 cycles_to_ns(idle_exec_max)); 245 246 for (i = 0; i < qconf->n_rx_port; i++) { 247 job = &qconf->port_fwd_jobs[i]; 248 printf("\n\nJob %" PRIu32 ": %-20s " 249 "\n%-18s %'14" PRIu64 250 "\n%-18s %'14.0f" 251 STAT_FMT, 252 i, job->name, 253 "Exec count:", jobs_exec_cnt[i], 254 "Exec period: ", cycles_to_ns(jobs_period[i]), 255 "Exec time", 256 cycles_to_ns(jobs_exec[i]), jobs_exec[i] * 100.0 / stats_period, 257 cycles_to_ns(jobs_exec_cnt[i] ? jobs_exec[i] / jobs_exec_cnt[i] 258 : 0), 259 cycles_to_ns(jobs_exec_min[i]), 260 cycles_to_ns(jobs_exec_max[i])); 261 } 262 263 if (qconf->n_rx_port > 0) { 264 job = &qconf->flush_job; 265 printf("\n\nJob %" PRIu32 ": %-20s " 266 "\n%-18s %'14" PRIu64 267 "\n%-18s %'14.0f" 268 STAT_FMT, 269 i, job->name, 270 "Exec count:", flush_exec_cnt, 271 "Exec period: ", cycles_to_ns(flush_period), 272 "Exec time", 273 cycles_to_ns(flush_exec), flush_exec * 100.0 / stats_period, 274 cycles_to_ns(flush_exec_cnt ? flush_exec / flush_exec_cnt : 0), 275 cycles_to_ns(flush_exec_min), 276 cycles_to_ns(flush_exec_max)); 277 } 278 } 279 280 /* Print out statistics on packets dropped */ 281 static void 282 show_stats_cb(__rte_unused void *param) 283 { 284 uint64_t total_packets_dropped, total_packets_tx, total_packets_rx; 285 unsigned portid, lcore_id; 286 287 total_packets_dropped = 0; 288 total_packets_tx = 0; 289 total_packets_rx = 0; 290 291 const char clr[] = { 27, '[', '2', 'J', '\0' }; 292 const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' }; 293 294 /* Clear screen and move to top left */ 295 printf("%s%s" 296 "\nPort statistics ===================================", 297 clr, topLeft); 298 299 for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { 300 /* skip disabled ports */ 301 if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 302 continue; 303 printf("\nStatistics for port %u ------------------------------" 304 "\nPackets sent: %24"PRIu64 305 "\nPackets received: %20"PRIu64 306 "\nPackets dropped: %21"PRIu64, 307 portid, 308 port_statistics[portid].tx, 309 port_statistics[portid].rx, 310 port_statistics[portid].dropped); 311 312 total_packets_dropped += port_statistics[portid].dropped; 313 total_packets_tx += port_statistics[portid].tx; 314 total_packets_rx += port_statistics[portid].rx; 315 } 316 317 printf("\nAggregate statistics ===============================" 318 "\nTotal packets sent: %18"PRIu64 319 "\nTotal packets received: %14"PRIu64 320 "\nTotal packets dropped: %15"PRIu64 321 "\n====================================================", 322 total_packets_tx, 323 total_packets_rx, 324 total_packets_dropped); 325 326 RTE_LCORE_FOREACH(lcore_id) { 327 if (lcore_queue_conf[lcore_id].n_rx_port > 0) 328 show_lcore_stats(lcore_id); 329 } 330 331 printf("\n====================================================\n"); 332 333 fflush(stdout); 334 335 rte_eal_alarm_set(timer_period * US_PER_S, show_stats_cb, NULL); 336 } 337 338 static void 339 l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid) 340 { 341 struct rte_ether_hdr *eth; 342 void *tmp; 343 int sent; 344 unsigned dst_port; 345 struct rte_eth_dev_tx_buffer *buffer; 346 347 dst_port = l2fwd_dst_ports[portid]; 348 eth = rte_pktmbuf_mtod(m, struct rte_ether_hdr *); 349 350 /* 02:00:00:00:00:xx */ 351 tmp = ð->d_addr.addr_bytes[0]; 352 *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40); 353 354 /* src addr */ 355 rte_ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], ð->s_addr); 356 357 buffer = tx_buffer[dst_port]; 358 sent = rte_eth_tx_buffer(dst_port, 0, buffer, m); 359 if (sent) 360 port_statistics[dst_port].tx += sent; 361 } 362 363 static void 364 l2fwd_job_update_cb(struct rte_jobstats *job, int64_t result) 365 { 366 int64_t err = job->target - result; 367 int64_t histeresis = job->target / 8; 368 369 if (err < -histeresis) { 370 if (job->min_period + UPDATE_STEP_DOWN < job->period) 371 job->period -= UPDATE_STEP_DOWN; 372 } else if (err > histeresis) { 373 if (job->period + UPDATE_STEP_UP < job->max_period) 374 job->period += UPDATE_STEP_UP; 375 } 376 } 377 378 static void 379 l2fwd_fwd_job(__rte_unused struct rte_timer *timer, void *arg) 380 { 381 struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; 382 struct rte_mbuf *m; 383 384 const uint16_t port_idx = (uintptr_t) arg; 385 const unsigned lcore_id = rte_lcore_id(); 386 struct lcore_queue_conf *qconf = &lcore_queue_conf[lcore_id]; 387 struct rte_jobstats *job = &qconf->port_fwd_jobs[port_idx]; 388 const uint16_t portid = qconf->rx_port_list[port_idx]; 389 390 uint8_t j; 391 uint16_t total_nb_rx; 392 393 rte_jobstats_start(&qconf->jobs_context, job); 394 395 /* Call rx burst 2 times. This allow rte_jobstats logic to see if this 396 * function must be called more frequently. */ 397 398 total_nb_rx = rte_eth_rx_burst(portid, 0, pkts_burst, 399 MAX_PKT_BURST); 400 401 for (j = 0; j < total_nb_rx; j++) { 402 m = pkts_burst[j]; 403 rte_prefetch0(rte_pktmbuf_mtod(m, void *)); 404 l2fwd_simple_forward(m, portid); 405 } 406 407 if (total_nb_rx == MAX_PKT_BURST) { 408 const uint16_t nb_rx = rte_eth_rx_burst(portid, 0, pkts_burst, 409 MAX_PKT_BURST); 410 411 total_nb_rx += nb_rx; 412 for (j = 0; j < nb_rx; j++) { 413 m = pkts_burst[j]; 414 rte_prefetch0(rte_pktmbuf_mtod(m, void *)); 415 l2fwd_simple_forward(m, portid); 416 } 417 } 418 419 port_statistics[portid].rx += total_nb_rx; 420 421 /* Adjust period time in which we are running here. */ 422 if (rte_jobstats_finish(job, total_nb_rx) != 0) { 423 rte_timer_reset(&qconf->rx_timers[port_idx], job->period, PERIODICAL, 424 lcore_id, l2fwd_fwd_job, arg); 425 } 426 } 427 428 static void 429 l2fwd_flush_job(__rte_unused struct rte_timer *timer, __rte_unused void *arg) 430 { 431 uint64_t now; 432 unsigned lcore_id; 433 struct lcore_queue_conf *qconf; 434 uint16_t portid; 435 unsigned i; 436 uint32_t sent; 437 struct rte_eth_dev_tx_buffer *buffer; 438 439 lcore_id = rte_lcore_id(); 440 qconf = &lcore_queue_conf[lcore_id]; 441 442 rte_jobstats_start(&qconf->jobs_context, &qconf->flush_job); 443 444 now = rte_get_timer_cycles(); 445 lcore_id = rte_lcore_id(); 446 qconf = &lcore_queue_conf[lcore_id]; 447 448 for (i = 0; i < qconf->n_rx_port; i++) { 449 portid = l2fwd_dst_ports[qconf->rx_port_list[i]]; 450 451 if (qconf->next_flush_time[portid] <= now) 452 continue; 453 454 buffer = tx_buffer[portid]; 455 sent = rte_eth_tx_buffer_flush(portid, 0, buffer); 456 if (sent) 457 port_statistics[portid].tx += sent; 458 459 qconf->next_flush_time[portid] = rte_get_timer_cycles() + drain_tsc; 460 } 461 462 /* Pass target to indicate that this job is happy of time interwal 463 * in which it was called. */ 464 rte_jobstats_finish(&qconf->flush_job, qconf->flush_job.target); 465 } 466 467 /* main processing loop */ 468 static void 469 l2fwd_main_loop(void) 470 { 471 unsigned lcore_id; 472 unsigned i, portid; 473 struct lcore_queue_conf *qconf; 474 uint8_t stats_read_pending = 0; 475 uint8_t need_manage; 476 477 lcore_id = rte_lcore_id(); 478 qconf = &lcore_queue_conf[lcore_id]; 479 480 if (qconf->n_rx_port == 0) { 481 RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id); 482 return; 483 } 484 485 RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id); 486 487 for (i = 0; i < qconf->n_rx_port; i++) { 488 489 portid = qconf->rx_port_list[i]; 490 RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id, 491 portid); 492 } 493 494 rte_jobstats_init(&qconf->idle_job, "idle", 0, 0, 0, 0); 495 496 for (;;) { 497 rte_spinlock_lock(&qconf->lock); 498 499 do { 500 rte_jobstats_context_start(&qconf->jobs_context); 501 502 /* Do the Idle job: 503 * - Read stats_read_pending flag 504 * - check if some real job need to be executed 505 */ 506 rte_jobstats_start(&qconf->jobs_context, &qconf->idle_job); 507 508 uint64_t repeats = 0; 509 510 do { 511 uint8_t i; 512 uint64_t now = rte_get_timer_cycles(); 513 514 repeats++; 515 need_manage = qconf->flush_timer.expire < now; 516 /* Check if we was esked to give a stats. */ 517 stats_read_pending = 518 rte_atomic16_read(&qconf->stats_read_pending); 519 need_manage |= stats_read_pending; 520 521 for (i = 0; i < qconf->n_rx_port && !need_manage; i++) 522 need_manage = qconf->rx_timers[i].expire < now; 523 524 } while (!need_manage); 525 526 if (likely(repeats != 1)) 527 rte_jobstats_finish(&qconf->idle_job, qconf->idle_job.target); 528 else 529 rte_jobstats_abort(&qconf->idle_job); 530 531 rte_timer_manage(); 532 rte_jobstats_context_finish(&qconf->jobs_context); 533 } while (likely(stats_read_pending == 0)); 534 535 rte_spinlock_unlock(&qconf->lock); 536 rte_pause(); 537 } 538 } 539 540 static int 541 l2fwd_launch_one_lcore(__rte_unused void *dummy) 542 { 543 l2fwd_main_loop(); 544 return 0; 545 } 546 547 /* display usage */ 548 static void 549 l2fwd_usage(const char *prgname) 550 { 551 printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n" 552 " -p PORTMASK: hexadecimal bitmask of ports to configure\n" 553 " -q NQ: number of queue (=ports) per lcore (default is 1)\n" 554 " -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n" 555 " -l set system default locale instead of default (\"C\" locale) for thousands separator in stats.", 556 prgname); 557 } 558 559 static int 560 l2fwd_parse_portmask(const char *portmask) 561 { 562 char *end = NULL; 563 unsigned long pm; 564 565 /* parse hexadecimal string */ 566 pm = strtoul(portmask, &end, 16); 567 if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) 568 return -1; 569 570 if (pm == 0) 571 return -1; 572 573 return pm; 574 } 575 576 static unsigned int 577 l2fwd_parse_nqueue(const char *q_arg) 578 { 579 char *end = NULL; 580 unsigned long n; 581 582 /* parse hexadecimal string */ 583 n = strtoul(q_arg, &end, 10); 584 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 585 return 0; 586 if (n == 0) 587 return 0; 588 if (n >= MAX_RX_QUEUE_PER_LCORE) 589 return 0; 590 591 return n; 592 } 593 594 static int 595 l2fwd_parse_timer_period(const char *q_arg) 596 { 597 char *end = NULL; 598 int n; 599 600 /* parse number string */ 601 n = strtol(q_arg, &end, 10); 602 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 603 return -1; 604 if (n >= MAX_TIMER_PERIOD) 605 return -1; 606 607 return n; 608 } 609 610 /* Parse the argument given in the command line of the application */ 611 static int 612 l2fwd_parse_args(int argc, char **argv) 613 { 614 int opt, ret; 615 char **argvopt; 616 int option_index; 617 char *prgname = argv[0]; 618 static struct option lgopts[] = { 619 {NULL, 0, 0, 0} 620 }; 621 622 argvopt = argv; 623 624 while ((opt = getopt_long(argc, argvopt, "p:q:T:l", 625 lgopts, &option_index)) != EOF) { 626 627 switch (opt) { 628 /* portmask */ 629 case 'p': 630 l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg); 631 if (l2fwd_enabled_port_mask == 0) { 632 printf("invalid portmask\n"); 633 l2fwd_usage(prgname); 634 return -1; 635 } 636 break; 637 638 /* nqueue */ 639 case 'q': 640 l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg); 641 if (l2fwd_rx_queue_per_lcore == 0) { 642 printf("invalid queue number\n"); 643 l2fwd_usage(prgname); 644 return -1; 645 } 646 break; 647 648 /* timer period */ 649 case 'T': 650 timer_period = l2fwd_parse_timer_period(optarg); 651 if (timer_period < 0) { 652 printf("invalid timer period\n"); 653 l2fwd_usage(prgname); 654 return -1; 655 } 656 break; 657 658 /* For thousands separator in printf. */ 659 case 'l': 660 setlocale(LC_ALL, ""); 661 break; 662 663 /* long options */ 664 case 0: 665 l2fwd_usage(prgname); 666 return -1; 667 668 default: 669 l2fwd_usage(prgname); 670 return -1; 671 } 672 } 673 674 if (optind >= 0) 675 argv[optind-1] = prgname; 676 677 ret = optind-1; 678 optind = 1; /* reset getopt lib */ 679 return ret; 680 } 681 682 /* Check the link status of all ports in up to 9s, and print them finally */ 683 static void 684 check_all_ports_link_status(uint32_t port_mask) 685 { 686 #define CHECK_INTERVAL 100 /* 100ms */ 687 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ 688 uint16_t portid; 689 uint8_t count, all_ports_up, print_flag = 0; 690 struct rte_eth_link link; 691 int ret; 692 693 printf("\nChecking link status"); 694 fflush(stdout); 695 for (count = 0; count <= MAX_CHECK_TIME; count++) { 696 all_ports_up = 1; 697 RTE_ETH_FOREACH_DEV(portid) { 698 if ((port_mask & (1 << portid)) == 0) 699 continue; 700 memset(&link, 0, sizeof(link)); 701 ret = rte_eth_link_get_nowait(portid, &link); 702 if (ret < 0) { 703 all_ports_up = 0; 704 if (print_flag == 1) 705 printf("Port %u link get failed: %s\n", 706 portid, rte_strerror(-ret)); 707 continue; 708 } 709 /* print link status if flag set */ 710 if (print_flag == 1) { 711 if (link.link_status) 712 printf( 713 "Port%d Link Up. Speed %u Mbps - %s\n", 714 portid, link.link_speed, 715 (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? 716 ("full-duplex") : ("half-duplex")); 717 else 718 printf("Port %d Link Down\n", portid); 719 continue; 720 } 721 /* clear all_ports_up flag if any link down */ 722 if (link.link_status == ETH_LINK_DOWN) { 723 all_ports_up = 0; 724 break; 725 } 726 } 727 /* after finally printing all link status, get out */ 728 if (print_flag == 1) 729 break; 730 731 if (all_ports_up == 0) { 732 printf("."); 733 fflush(stdout); 734 rte_delay_ms(CHECK_INTERVAL); 735 } 736 737 /* set the print_flag if all ports up or timeout */ 738 if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { 739 print_flag = 1; 740 printf("done\n"); 741 } 742 } 743 } 744 745 int 746 main(int argc, char **argv) 747 { 748 struct lcore_queue_conf *qconf; 749 unsigned lcore_id, rx_lcore_id; 750 unsigned nb_ports_in_mask = 0; 751 int ret; 752 char name[RTE_JOBSTATS_NAMESIZE]; 753 uint16_t nb_ports; 754 uint16_t nb_ports_available = 0; 755 uint16_t portid, last_port; 756 uint8_t i; 757 758 /* init EAL */ 759 ret = rte_eal_init(argc, argv); 760 if (ret < 0) 761 rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n"); 762 argc -= ret; 763 argv += ret; 764 765 /* parse application arguments (after the EAL ones) */ 766 ret = l2fwd_parse_args(argc, argv); 767 if (ret < 0) 768 rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n"); 769 770 rte_timer_subsystem_init(); 771 772 /* fetch default timer frequency. */ 773 hz = rte_get_timer_hz(); 774 775 /* create the mbuf pool */ 776 l2fwd_pktmbuf_pool = 777 rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF, 32, 778 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); 779 if (l2fwd_pktmbuf_pool == NULL) 780 rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n"); 781 782 nb_ports = rte_eth_dev_count_avail(); 783 if (nb_ports == 0) 784 rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n"); 785 786 /* reset l2fwd_dst_ports */ 787 for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) 788 l2fwd_dst_ports[portid] = 0; 789 last_port = 0; 790 791 /* 792 * Each logical core is assigned a dedicated TX queue on each port. 793 */ 794 RTE_ETH_FOREACH_DEV(portid) { 795 /* skip ports that are not enabled */ 796 if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 797 continue; 798 799 if (nb_ports_in_mask % 2) { 800 l2fwd_dst_ports[portid] = last_port; 801 l2fwd_dst_ports[last_port] = portid; 802 } else 803 last_port = portid; 804 805 nb_ports_in_mask++; 806 } 807 if (nb_ports_in_mask % 2) { 808 printf("Notice: odd number of ports in portmask.\n"); 809 l2fwd_dst_ports[last_port] = last_port; 810 } 811 812 rx_lcore_id = 0; 813 qconf = NULL; 814 815 /* Initialize the port/queue configuration of each logical core */ 816 RTE_ETH_FOREACH_DEV(portid) { 817 /* skip ports that are not enabled */ 818 if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 819 continue; 820 821 /* get the lcore_id for this port */ 822 while (rte_lcore_is_enabled(rx_lcore_id) == 0 || 823 lcore_queue_conf[rx_lcore_id].n_rx_port == 824 l2fwd_rx_queue_per_lcore) { 825 rx_lcore_id++; 826 if (rx_lcore_id >= RTE_MAX_LCORE) 827 rte_exit(EXIT_FAILURE, "Not enough cores\n"); 828 } 829 830 if (qconf != &lcore_queue_conf[rx_lcore_id]) 831 /* Assigned a new logical core in the loop above. */ 832 qconf = &lcore_queue_conf[rx_lcore_id]; 833 834 qconf->rx_port_list[qconf->n_rx_port] = portid; 835 qconf->n_rx_port++; 836 printf("Lcore %u: RX port %u\n", rx_lcore_id, portid); 837 } 838 839 /* Initialise each port */ 840 RTE_ETH_FOREACH_DEV(portid) { 841 struct rte_eth_dev_info dev_info; 842 struct rte_eth_rxconf rxq_conf; 843 struct rte_eth_txconf txq_conf; 844 struct rte_eth_conf local_port_conf = port_conf; 845 846 /* skip ports that are not enabled */ 847 if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) { 848 printf("Skipping disabled port %u\n", portid); 849 continue; 850 } 851 nb_ports_available++; 852 853 /* init port */ 854 printf("Initializing port %u... ", portid); 855 fflush(stdout); 856 857 ret = rte_eth_dev_info_get(portid, &dev_info); 858 if (ret != 0) 859 rte_exit(EXIT_FAILURE, 860 "Error during getting device (port %u) info: %s\n", 861 portid, strerror(-ret)); 862 863 if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) 864 local_port_conf.txmode.offloads |= 865 DEV_TX_OFFLOAD_MBUF_FAST_FREE; 866 ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf); 867 if (ret < 0) 868 rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n", 869 ret, portid); 870 871 ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, 872 &nb_txd); 873 if (ret < 0) 874 rte_exit(EXIT_FAILURE, 875 "Cannot adjust number of descriptors: err=%d, port=%u\n", 876 ret, portid); 877 878 ret = rte_eth_macaddr_get(portid, 879 &l2fwd_ports_eth_addr[portid]); 880 if (ret < 0) 881 rte_exit(EXIT_FAILURE, 882 "Cannot get MAC address: err=%d, port=%u\n", 883 ret, portid); 884 885 /* init one RX queue */ 886 fflush(stdout); 887 rxq_conf = dev_info.default_rxconf; 888 rxq_conf.offloads = local_port_conf.rxmode.offloads; 889 ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd, 890 rte_eth_dev_socket_id(portid), 891 &rxq_conf, 892 l2fwd_pktmbuf_pool); 893 if (ret < 0) 894 rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n", 895 ret, portid); 896 897 /* init one TX queue on each port */ 898 txq_conf = dev_info.default_txconf; 899 txq_conf.offloads = local_port_conf.txmode.offloads; 900 fflush(stdout); 901 ret = rte_eth_tx_queue_setup(portid, 0, nb_txd, 902 rte_eth_dev_socket_id(portid), 903 &txq_conf); 904 if (ret < 0) 905 rte_exit(EXIT_FAILURE, 906 "rte_eth_tx_queue_setup:err=%d, port=%u\n", 907 ret, portid); 908 909 /* Initialize TX buffers */ 910 tx_buffer[portid] = rte_zmalloc_socket("tx_buffer", 911 RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0, 912 rte_eth_dev_socket_id(portid)); 913 if (tx_buffer[portid] == NULL) 914 rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n", 915 portid); 916 917 rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST); 918 919 ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid], 920 rte_eth_tx_buffer_count_callback, 921 &port_statistics[portid].dropped); 922 if (ret < 0) 923 rte_exit(EXIT_FAILURE, 924 "Cannot set error callback for tx buffer on port %u\n", 925 portid); 926 927 /* Start device */ 928 ret = rte_eth_dev_start(portid); 929 if (ret < 0) 930 rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n", 931 ret, portid); 932 933 printf("done:\n"); 934 935 ret = rte_eth_promiscuous_enable(portid); 936 if (ret != 0) { 937 rte_exit(EXIT_FAILURE, 938 "rte_eth_promiscuous_enable:err=%s, port=%u\n", 939 rte_strerror(-ret), portid); 940 return ret; 941 942 } 943 944 printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n", 945 portid, 946 l2fwd_ports_eth_addr[portid].addr_bytes[0], 947 l2fwd_ports_eth_addr[portid].addr_bytes[1], 948 l2fwd_ports_eth_addr[portid].addr_bytes[2], 949 l2fwd_ports_eth_addr[portid].addr_bytes[3], 950 l2fwd_ports_eth_addr[portid].addr_bytes[4], 951 l2fwd_ports_eth_addr[portid].addr_bytes[5]); 952 953 /* initialize port stats */ 954 memset(&port_statistics, 0, sizeof(port_statistics)); 955 } 956 957 if (!nb_ports_available) { 958 rte_exit(EXIT_FAILURE, 959 "All available ports are disabled. Please set portmask.\n"); 960 } 961 962 check_all_ports_link_status(l2fwd_enabled_port_mask); 963 964 drain_tsc = (hz + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US; 965 966 RTE_LCORE_FOREACH(lcore_id) { 967 qconf = &lcore_queue_conf[lcore_id]; 968 969 rte_spinlock_init(&qconf->lock); 970 971 if (rte_jobstats_context_init(&qconf->jobs_context) != 0) 972 rte_panic("Jobs stats context for core %u init failed\n", lcore_id); 973 974 if (qconf->n_rx_port == 0) { 975 RTE_LOG(INFO, L2FWD, 976 "lcore %u: no ports so no jobs stats context initialization\n", 977 lcore_id); 978 continue; 979 } 980 /* Add flush job. 981 * Set fixed period by setting min = max = initial period. Set target to 982 * zero as it is irrelevant for this job. */ 983 rte_jobstats_init(&qconf->flush_job, "flush", drain_tsc, drain_tsc, 984 drain_tsc, 0); 985 986 rte_timer_init(&qconf->flush_timer); 987 ret = rte_timer_reset(&qconf->flush_timer, drain_tsc, PERIODICAL, 988 lcore_id, &l2fwd_flush_job, NULL); 989 990 if (ret < 0) { 991 rte_exit(1, "Failed to reset flush job timer for lcore %u: %s", 992 lcore_id, rte_strerror(-ret)); 993 } 994 995 for (i = 0; i < qconf->n_rx_port; i++) { 996 struct rte_jobstats *job = &qconf->port_fwd_jobs[i]; 997 998 portid = qconf->rx_port_list[i]; 999 printf("Setting forward job for port %u\n", portid); 1000 1001 snprintf(name, RTE_DIM(name), "port %u fwd", portid); 1002 /* Setup forward job. 1003 * Set min, max and initial period. Set target to MAX_PKT_BURST as 1004 * this is desired optimal RX/TX burst size. */ 1005 rte_jobstats_init(job, name, 0, drain_tsc, 0, MAX_PKT_BURST); 1006 rte_jobstats_set_update_period_function(job, l2fwd_job_update_cb); 1007 1008 rte_timer_init(&qconf->rx_timers[i]); 1009 ret = rte_timer_reset(&qconf->rx_timers[i], 0, PERIODICAL, lcore_id, 1010 &l2fwd_fwd_job, (void *)(uintptr_t)i); 1011 1012 if (ret < 0) { 1013 rte_exit(1, "Failed to reset lcore %u port %u job timer: %s", 1014 lcore_id, qconf->rx_port_list[i], rte_strerror(-ret)); 1015 } 1016 } 1017 } 1018 1019 if (timer_period) 1020 rte_eal_alarm_set(timer_period * MS_PER_S, show_stats_cb, NULL); 1021 else 1022 RTE_LOG(INFO, L2FWD, "Stats display disabled\n"); 1023 1024 /* launch per-lcore init on every lcore */ 1025 rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER); 1026 RTE_LCORE_FOREACH_SLAVE(lcore_id) { 1027 if (rte_eal_wait_lcore(lcore_id) < 0) 1028 return -1; 1029 } 1030 1031 return 0; 1032 } 1033