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 0; 569 570 return pm; 571 } 572 573 static unsigned int 574 l2fwd_parse_nqueue(const char *q_arg) 575 { 576 char *end = NULL; 577 unsigned long n; 578 579 /* parse hexadecimal string */ 580 n = strtoul(q_arg, &end, 10); 581 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 582 return 0; 583 if (n == 0) 584 return 0; 585 if (n >= MAX_RX_QUEUE_PER_LCORE) 586 return 0; 587 588 return n; 589 } 590 591 static int 592 l2fwd_parse_timer_period(const char *q_arg) 593 { 594 char *end = NULL; 595 int n; 596 597 /* parse number string */ 598 n = strtol(q_arg, &end, 10); 599 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 600 return -1; 601 if (n >= MAX_TIMER_PERIOD) 602 return -1; 603 604 return n; 605 } 606 607 /* Parse the argument given in the command line of the application */ 608 static int 609 l2fwd_parse_args(int argc, char **argv) 610 { 611 int opt, ret; 612 char **argvopt; 613 int option_index; 614 char *prgname = argv[0]; 615 static struct option lgopts[] = { 616 {NULL, 0, 0, 0} 617 }; 618 619 argvopt = argv; 620 621 while ((opt = getopt_long(argc, argvopt, "p:q:T:l", 622 lgopts, &option_index)) != EOF) { 623 624 switch (opt) { 625 /* portmask */ 626 case 'p': 627 l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg); 628 if (l2fwd_enabled_port_mask == 0) { 629 printf("invalid portmask\n"); 630 l2fwd_usage(prgname); 631 return -1; 632 } 633 break; 634 635 /* nqueue */ 636 case 'q': 637 l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg); 638 if (l2fwd_rx_queue_per_lcore == 0) { 639 printf("invalid queue number\n"); 640 l2fwd_usage(prgname); 641 return -1; 642 } 643 break; 644 645 /* timer period */ 646 case 'T': 647 timer_period = l2fwd_parse_timer_period(optarg); 648 if (timer_period < 0) { 649 printf("invalid timer period\n"); 650 l2fwd_usage(prgname); 651 return -1; 652 } 653 break; 654 655 /* For thousands separator in printf. */ 656 case 'l': 657 setlocale(LC_ALL, ""); 658 break; 659 660 /* long options */ 661 case 0: 662 l2fwd_usage(prgname); 663 return -1; 664 665 default: 666 l2fwd_usage(prgname); 667 return -1; 668 } 669 } 670 671 if (optind >= 0) 672 argv[optind-1] = prgname; 673 674 ret = optind-1; 675 optind = 1; /* reset getopt lib */ 676 return ret; 677 } 678 679 /* Check the link status of all ports in up to 9s, and print them finally */ 680 static void 681 check_all_ports_link_status(uint32_t port_mask) 682 { 683 #define CHECK_INTERVAL 100 /* 100ms */ 684 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ 685 uint16_t portid; 686 uint8_t count, all_ports_up, print_flag = 0; 687 struct rte_eth_link link; 688 int ret; 689 690 printf("\nChecking link status"); 691 fflush(stdout); 692 for (count = 0; count <= MAX_CHECK_TIME; count++) { 693 all_ports_up = 1; 694 RTE_ETH_FOREACH_DEV(portid) { 695 if ((port_mask & (1 << portid)) == 0) 696 continue; 697 memset(&link, 0, sizeof(link)); 698 ret = rte_eth_link_get_nowait(portid, &link); 699 if (ret < 0) { 700 all_ports_up = 0; 701 if (print_flag == 1) 702 printf("Port %u link get failed: %s\n", 703 portid, rte_strerror(-ret)); 704 continue; 705 } 706 /* print link status if flag set */ 707 if (print_flag == 1) { 708 if (link.link_status) 709 printf( 710 "Port%d Link Up. Speed %u Mbps - %s\n", 711 portid, link.link_speed, 712 (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? 713 ("full-duplex") : ("half-duplex")); 714 else 715 printf("Port %d Link Down\n", portid); 716 continue; 717 } 718 /* clear all_ports_up flag if any link down */ 719 if (link.link_status == ETH_LINK_DOWN) { 720 all_ports_up = 0; 721 break; 722 } 723 } 724 /* after finally printing all link status, get out */ 725 if (print_flag == 1) 726 break; 727 728 if (all_ports_up == 0) { 729 printf("."); 730 fflush(stdout); 731 rte_delay_ms(CHECK_INTERVAL); 732 } 733 734 /* set the print_flag if all ports up or timeout */ 735 if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { 736 print_flag = 1; 737 printf("done\n"); 738 } 739 } 740 } 741 742 int 743 main(int argc, char **argv) 744 { 745 struct lcore_queue_conf *qconf; 746 unsigned lcore_id, rx_lcore_id; 747 unsigned nb_ports_in_mask = 0; 748 int ret; 749 char name[RTE_JOBSTATS_NAMESIZE]; 750 uint16_t nb_ports; 751 uint16_t nb_ports_available = 0; 752 uint16_t portid, last_port; 753 uint8_t i; 754 755 /* init EAL */ 756 ret = rte_eal_init(argc, argv); 757 if (ret < 0) 758 rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n"); 759 argc -= ret; 760 argv += ret; 761 762 /* parse application arguments (after the EAL ones) */ 763 ret = l2fwd_parse_args(argc, argv); 764 if (ret < 0) 765 rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n"); 766 767 rte_timer_subsystem_init(); 768 769 /* fetch default timer frequency. */ 770 hz = rte_get_timer_hz(); 771 772 /* create the mbuf pool */ 773 l2fwd_pktmbuf_pool = 774 rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF, 32, 775 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); 776 if (l2fwd_pktmbuf_pool == NULL) 777 rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n"); 778 779 nb_ports = rte_eth_dev_count_avail(); 780 if (nb_ports == 0) 781 rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n"); 782 783 /* reset l2fwd_dst_ports */ 784 for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) 785 l2fwd_dst_ports[portid] = 0; 786 last_port = 0; 787 788 /* 789 * Each logical core is assigned a dedicated TX queue on each port. 790 */ 791 RTE_ETH_FOREACH_DEV(portid) { 792 /* skip ports that are not enabled */ 793 if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 794 continue; 795 796 if (nb_ports_in_mask % 2) { 797 l2fwd_dst_ports[portid] = last_port; 798 l2fwd_dst_ports[last_port] = portid; 799 } else 800 last_port = portid; 801 802 nb_ports_in_mask++; 803 } 804 if (nb_ports_in_mask % 2) { 805 printf("Notice: odd number of ports in portmask.\n"); 806 l2fwd_dst_ports[last_port] = last_port; 807 } 808 809 rx_lcore_id = 0; 810 qconf = NULL; 811 812 /* Initialize the port/queue configuration of each logical core */ 813 RTE_ETH_FOREACH_DEV(portid) { 814 /* skip ports that are not enabled */ 815 if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 816 continue; 817 818 /* get the lcore_id for this port */ 819 while (rte_lcore_is_enabled(rx_lcore_id) == 0 || 820 lcore_queue_conf[rx_lcore_id].n_rx_port == 821 l2fwd_rx_queue_per_lcore) { 822 rx_lcore_id++; 823 if (rx_lcore_id >= RTE_MAX_LCORE) 824 rte_exit(EXIT_FAILURE, "Not enough cores\n"); 825 } 826 827 if (qconf != &lcore_queue_conf[rx_lcore_id]) 828 /* Assigned a new logical core in the loop above. */ 829 qconf = &lcore_queue_conf[rx_lcore_id]; 830 831 qconf->rx_port_list[qconf->n_rx_port] = portid; 832 qconf->n_rx_port++; 833 printf("Lcore %u: RX port %u\n", rx_lcore_id, portid); 834 } 835 836 /* Initialise each port */ 837 RTE_ETH_FOREACH_DEV(portid) { 838 struct rte_eth_dev_info dev_info; 839 struct rte_eth_rxconf rxq_conf; 840 struct rte_eth_txconf txq_conf; 841 struct rte_eth_conf local_port_conf = port_conf; 842 843 /* skip ports that are not enabled */ 844 if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) { 845 printf("Skipping disabled port %u\n", portid); 846 continue; 847 } 848 nb_ports_available++; 849 850 /* init port */ 851 printf("Initializing port %u... ", portid); 852 fflush(stdout); 853 854 ret = rte_eth_dev_info_get(portid, &dev_info); 855 if (ret != 0) 856 rte_exit(EXIT_FAILURE, 857 "Error during getting device (port %u) info: %s\n", 858 portid, strerror(-ret)); 859 860 if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) 861 local_port_conf.txmode.offloads |= 862 DEV_TX_OFFLOAD_MBUF_FAST_FREE; 863 ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf); 864 if (ret < 0) 865 rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n", 866 ret, portid); 867 868 ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, 869 &nb_txd); 870 if (ret < 0) 871 rte_exit(EXIT_FAILURE, 872 "Cannot adjust number of descriptors: err=%d, port=%u\n", 873 ret, portid); 874 875 ret = rte_eth_macaddr_get(portid, 876 &l2fwd_ports_eth_addr[portid]); 877 if (ret < 0) 878 rte_exit(EXIT_FAILURE, 879 "Cannot get MAC address: err=%d, port=%u\n", 880 ret, portid); 881 882 /* init one RX queue */ 883 fflush(stdout); 884 rxq_conf = dev_info.default_rxconf; 885 rxq_conf.offloads = local_port_conf.rxmode.offloads; 886 ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd, 887 rte_eth_dev_socket_id(portid), 888 &rxq_conf, 889 l2fwd_pktmbuf_pool); 890 if (ret < 0) 891 rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n", 892 ret, portid); 893 894 /* init one TX queue on each port */ 895 txq_conf = dev_info.default_txconf; 896 txq_conf.offloads = local_port_conf.txmode.offloads; 897 fflush(stdout); 898 ret = rte_eth_tx_queue_setup(portid, 0, nb_txd, 899 rte_eth_dev_socket_id(portid), 900 &txq_conf); 901 if (ret < 0) 902 rte_exit(EXIT_FAILURE, 903 "rte_eth_tx_queue_setup:err=%d, port=%u\n", 904 ret, portid); 905 906 /* Initialize TX buffers */ 907 tx_buffer[portid] = rte_zmalloc_socket("tx_buffer", 908 RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0, 909 rte_eth_dev_socket_id(portid)); 910 if (tx_buffer[portid] == NULL) 911 rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n", 912 portid); 913 914 rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST); 915 916 ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid], 917 rte_eth_tx_buffer_count_callback, 918 &port_statistics[portid].dropped); 919 if (ret < 0) 920 rte_exit(EXIT_FAILURE, 921 "Cannot set error callback for tx buffer on port %u\n", 922 portid); 923 924 /* Start device */ 925 ret = rte_eth_dev_start(portid); 926 if (ret < 0) 927 rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n", 928 ret, portid); 929 930 printf("done:\n"); 931 932 ret = rte_eth_promiscuous_enable(portid); 933 if (ret != 0) { 934 rte_exit(EXIT_FAILURE, 935 "rte_eth_promiscuous_enable:err=%s, port=%u\n", 936 rte_strerror(-ret), portid); 937 return ret; 938 939 } 940 941 printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n", 942 portid, 943 l2fwd_ports_eth_addr[portid].addr_bytes[0], 944 l2fwd_ports_eth_addr[portid].addr_bytes[1], 945 l2fwd_ports_eth_addr[portid].addr_bytes[2], 946 l2fwd_ports_eth_addr[portid].addr_bytes[3], 947 l2fwd_ports_eth_addr[portid].addr_bytes[4], 948 l2fwd_ports_eth_addr[portid].addr_bytes[5]); 949 950 /* initialize port stats */ 951 memset(&port_statistics, 0, sizeof(port_statistics)); 952 } 953 954 if (!nb_ports_available) { 955 rte_exit(EXIT_FAILURE, 956 "All available ports are disabled. Please set portmask.\n"); 957 } 958 959 check_all_ports_link_status(l2fwd_enabled_port_mask); 960 961 drain_tsc = (hz + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US; 962 963 RTE_LCORE_FOREACH(lcore_id) { 964 qconf = &lcore_queue_conf[lcore_id]; 965 966 rte_spinlock_init(&qconf->lock); 967 968 if (rte_jobstats_context_init(&qconf->jobs_context) != 0) 969 rte_panic("Jobs stats context for core %u init failed\n", lcore_id); 970 971 if (qconf->n_rx_port == 0) { 972 RTE_LOG(INFO, L2FWD, 973 "lcore %u: no ports so no jobs stats context initialization\n", 974 lcore_id); 975 continue; 976 } 977 /* Add flush job. 978 * Set fixed period by setting min = max = initial period. Set target to 979 * zero as it is irrelevant for this job. */ 980 rte_jobstats_init(&qconf->flush_job, "flush", drain_tsc, drain_tsc, 981 drain_tsc, 0); 982 983 rte_timer_init(&qconf->flush_timer); 984 ret = rte_timer_reset(&qconf->flush_timer, drain_tsc, PERIODICAL, 985 lcore_id, &l2fwd_flush_job, NULL); 986 987 if (ret < 0) { 988 rte_exit(1, "Failed to reset flush job timer for lcore %u: %s", 989 lcore_id, rte_strerror(-ret)); 990 } 991 992 for (i = 0; i < qconf->n_rx_port; i++) { 993 struct rte_jobstats *job = &qconf->port_fwd_jobs[i]; 994 995 portid = qconf->rx_port_list[i]; 996 printf("Setting forward job for port %u\n", portid); 997 998 snprintf(name, RTE_DIM(name), "port %u fwd", portid); 999 /* Setup forward job. 1000 * Set min, max and initial period. Set target to MAX_PKT_BURST as 1001 * this is desired optimal RX/TX burst size. */ 1002 rte_jobstats_init(job, name, 0, drain_tsc, 0, MAX_PKT_BURST); 1003 rte_jobstats_set_update_period_function(job, l2fwd_job_update_cb); 1004 1005 rte_timer_init(&qconf->rx_timers[i]); 1006 ret = rte_timer_reset(&qconf->rx_timers[i], 0, PERIODICAL, lcore_id, 1007 &l2fwd_fwd_job, (void *)(uintptr_t)i); 1008 1009 if (ret < 0) { 1010 rte_exit(1, "Failed to reset lcore %u port %u job timer: %s", 1011 lcore_id, qconf->rx_port_list[i], rte_strerror(-ret)); 1012 } 1013 } 1014 } 1015 1016 if (timer_period) 1017 rte_eal_alarm_set(timer_period * MS_PER_S, show_stats_cb, NULL); 1018 else 1019 RTE_LOG(INFO, L2FWD, "Stats display disabled\n"); 1020 1021 /* launch per-lcore init on every lcore */ 1022 rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER); 1023 RTE_LCORE_FOREACH_SLAVE(lcore_id) { 1024 if (rte_eal_wait_lcore(lcore_id) < 0) 1025 return -1; 1026 } 1027 1028 return 0; 1029 } 1030