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