13998e2a0SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 23998e2a0SBruce Richardson * Copyright(c) 2010-2016 Intel Corporation 3af75078fSIntel */ 4af75078fSIntel 5af75078fSIntel #include <stdio.h> 6af75078fSIntel #include <stdlib.h> 7af75078fSIntel #include <string.h> 8af75078fSIntel #include <stdint.h> 9af75078fSIntel #include <inttypes.h> 10af75078fSIntel #include <sys/types.h> 11af75078fSIntel #include <sys/queue.h> 12af75078fSIntel #include <netinet/in.h> 13af75078fSIntel #include <setjmp.h> 14af75078fSIntel #include <stdarg.h> 15af75078fSIntel #include <ctype.h> 16af75078fSIntel #include <errno.h> 17af75078fSIntel #include <getopt.h> 1888908b61SZhihong Wang #include <signal.h> 1988908b61SZhihong Wang #include <stdbool.h> 20af75078fSIntel 21af75078fSIntel #include <rte_common.h> 22af75078fSIntel #include <rte_log.h> 23e2366e74STomasz Kulasek #include <rte_malloc.h> 24af75078fSIntel #include <rte_memory.h> 25af75078fSIntel #include <rte_memcpy.h> 26af75078fSIntel #include <rte_eal.h> 27af75078fSIntel #include <rte_launch.h> 28af75078fSIntel #include <rte_atomic.h> 29af75078fSIntel #include <rte_cycles.h> 30af75078fSIntel #include <rte_prefetch.h> 31af75078fSIntel #include <rte_lcore.h> 32af75078fSIntel #include <rte_per_lcore.h> 33af75078fSIntel #include <rte_branch_prediction.h> 34af75078fSIntel #include <rte_interrupts.h> 35af75078fSIntel #include <rte_random.h> 36af75078fSIntel #include <rte_debug.h> 37af75078fSIntel #include <rte_ether.h> 38af75078fSIntel #include <rte_ethdev.h> 39af75078fSIntel #include <rte_mempool.h> 40af75078fSIntel #include <rte_mbuf.h> 41af75078fSIntel 4288908b61SZhihong Wang static volatile bool force_quit; 4388908b61SZhihong Wang 44cf435a07SMaxime Coquelin /* MAC updating enabled by default */ 45cf435a07SMaxime Coquelin static int mac_updating = 1; 46cf435a07SMaxime Coquelin 47af75078fSIntel #define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1 48af75078fSIntel 49af75078fSIntel #define MAX_PKT_BURST 32 505c95261dSIntel #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */ 51b3e4d4e3SJerin Jacob #define MEMPOOL_CACHE_SIZE 256 52af75078fSIntel 53af75078fSIntel /* 54af75078fSIntel * Configurable number of RX/TX ring descriptors 55af75078fSIntel */ 56867a6c66SKevin Laatz #define RTE_TEST_RX_DESC_DEFAULT 1024 57867a6c66SKevin Laatz #define RTE_TEST_TX_DESC_DEFAULT 1024 58af75078fSIntel static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; 59af75078fSIntel static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; 60af75078fSIntel 61af75078fSIntel /* ethernet addresses of ports */ 626d13ea8eSOlivier Matz static struct rte_ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS]; 63af75078fSIntel 64af75078fSIntel /* mask of enabled ports */ 65af75078fSIntel static uint32_t l2fwd_enabled_port_mask = 0; 66af75078fSIntel 67af75078fSIntel /* list of enabled ports */ 681c17baf4SIntel static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS]; 69af75078fSIntel 70af75078fSIntel static unsigned int l2fwd_rx_queue_per_lcore = 1; 71af75078fSIntel 72af75078fSIntel #define MAX_RX_QUEUE_PER_LCORE 16 73af75078fSIntel #define MAX_TX_QUEUE_PER_PORT 16 74af75078fSIntel struct lcore_queue_conf { 7516ac9cf0SIntel unsigned n_rx_port; 7616ac9cf0SIntel unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE]; 77af75078fSIntel } __rte_cache_aligned; 78af75078fSIntel struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE]; 79af75078fSIntel 80e2366e74STomasz Kulasek static struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS]; 81e2366e74STomasz Kulasek 8275d7f266SShahaf Shuler static struct rte_eth_conf port_conf = { 83af75078fSIntel .rxmode = { 84af75078fSIntel .split_hdr_size = 0, 85af75078fSIntel }, 86af75078fSIntel .txmode = { 8732e7aa0bSIntel .mq_mode = ETH_MQ_TX_NONE, 88af75078fSIntel }, 89af75078fSIntel }; 90af75078fSIntel 91af75078fSIntel struct rte_mempool * l2fwd_pktmbuf_pool = NULL; 92af75078fSIntel 93af75078fSIntel /* Per-port statistics struct */ 94af75078fSIntel struct l2fwd_port_statistics { 95af75078fSIntel uint64_t tx; 96af75078fSIntel uint64_t rx; 97af75078fSIntel uint64_t dropped; 98af75078fSIntel } __rte_cache_aligned; 991c17baf4SIntel struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS]; 100af75078fSIntel 101af75078fSIntel #define MAX_TIMER_PERIOD 86400 /* 1 day max */ 1022412742cSJerin Jacob /* A tsc-based timer responsible for triggering statistics printout */ 1032412742cSJerin Jacob static uint64_t timer_period = 10; /* default period is 10 seconds */ 104af75078fSIntel 105af75078fSIntel /* Print out statistics on packets dropped */ 106af75078fSIntel static void 107af75078fSIntel print_stats(void) 108af75078fSIntel { 109af75078fSIntel uint64_t total_packets_dropped, total_packets_tx, total_packets_rx; 110af75078fSIntel unsigned portid; 111af75078fSIntel 112af75078fSIntel total_packets_dropped = 0; 113af75078fSIntel total_packets_tx = 0; 114af75078fSIntel total_packets_rx = 0; 115af75078fSIntel 116af75078fSIntel const char clr[] = { 27, '[', '2', 'J', '\0' }; 117af75078fSIntel const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' }; 118af75078fSIntel 119af75078fSIntel /* Clear screen and move to top left */ 120af75078fSIntel printf("%s%s", clr, topLeft); 121af75078fSIntel 122af75078fSIntel printf("\nPort statistics ===================================="); 123af75078fSIntel 1241c17baf4SIntel for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { 125af75078fSIntel /* skip disabled ports */ 126af75078fSIntel if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 127af75078fSIntel continue; 128af75078fSIntel printf("\nStatistics for port %u ------------------------------" 129af75078fSIntel "\nPackets sent: %24"PRIu64 130af75078fSIntel "\nPackets received: %20"PRIu64 131af75078fSIntel "\nPackets dropped: %21"PRIu64, 132af75078fSIntel portid, 133af75078fSIntel port_statistics[portid].tx, 134af75078fSIntel port_statistics[portid].rx, 135af75078fSIntel port_statistics[portid].dropped); 136af75078fSIntel 137af75078fSIntel total_packets_dropped += port_statistics[portid].dropped; 138af75078fSIntel total_packets_tx += port_statistics[portid].tx; 139af75078fSIntel total_packets_rx += port_statistics[portid].rx; 140af75078fSIntel } 141af75078fSIntel printf("\nAggregate statistics ===============================" 142af75078fSIntel "\nTotal packets sent: %18"PRIu64 143af75078fSIntel "\nTotal packets received: %14"PRIu64 144af75078fSIntel "\nTotal packets dropped: %15"PRIu64, 145af75078fSIntel total_packets_tx, 146af75078fSIntel total_packets_rx, 147af75078fSIntel total_packets_dropped); 148af75078fSIntel printf("\n====================================================\n"); 149af75078fSIntel } 150af75078fSIntel 151af75078fSIntel static void 152cf435a07SMaxime Coquelin l2fwd_mac_updating(struct rte_mbuf *m, unsigned dest_portid) 153af75078fSIntel { 1546d13ea8eSOlivier Matz struct rte_ether_hdr *eth; 155af75078fSIntel void *tmp; 156cf435a07SMaxime Coquelin 1576d13ea8eSOlivier Matz eth = rte_pktmbuf_mtod(m, struct rte_ether_hdr *); 158cf435a07SMaxime Coquelin 159cf435a07SMaxime Coquelin /* 02:00:00:00:00:xx */ 160cf435a07SMaxime Coquelin tmp = ð->d_addr.addr_bytes[0]; 161cf435a07SMaxime Coquelin *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dest_portid << 40); 162cf435a07SMaxime Coquelin 163cf435a07SMaxime Coquelin /* src addr */ 164538da7a1SOlivier Matz rte_ether_addr_copy(&l2fwd_ports_eth_addr[dest_portid], ð->s_addr); 165cf435a07SMaxime Coquelin } 166cf435a07SMaxime Coquelin 167cf435a07SMaxime Coquelin static void 168cf435a07SMaxime Coquelin l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid) 169cf435a07SMaxime Coquelin { 170af75078fSIntel unsigned dst_port; 171e2366e74STomasz Kulasek int sent; 172e2366e74STomasz Kulasek struct rte_eth_dev_tx_buffer *buffer; 173af75078fSIntel 174af75078fSIntel dst_port = l2fwd_dst_ports[portid]; 175af75078fSIntel 176cf435a07SMaxime Coquelin if (mac_updating) 177cf435a07SMaxime Coquelin l2fwd_mac_updating(m, dst_port); 178af75078fSIntel 179e2366e74STomasz Kulasek buffer = tx_buffer[dst_port]; 180e2366e74STomasz Kulasek sent = rte_eth_tx_buffer(dst_port, 0, buffer, m); 181e2366e74STomasz Kulasek if (sent) 182e2366e74STomasz Kulasek port_statistics[dst_port].tx += sent; 183af75078fSIntel } 184af75078fSIntel 185af75078fSIntel /* main processing loop */ 186af75078fSIntel static void 187af75078fSIntel l2fwd_main_loop(void) 188af75078fSIntel { 189af75078fSIntel struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; 190af75078fSIntel struct rte_mbuf *m; 191e2366e74STomasz Kulasek int sent; 192af75078fSIntel unsigned lcore_id; 1935c95261dSIntel uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc; 194af75078fSIntel unsigned i, j, portid, nb_rx; 195af75078fSIntel struct lcore_queue_conf *qconf; 196e2366e74STomasz Kulasek const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * 197e2366e74STomasz Kulasek BURST_TX_DRAIN_US; 198e2366e74STomasz Kulasek struct rte_eth_dev_tx_buffer *buffer; 199af75078fSIntel 2005c95261dSIntel prev_tsc = 0; 201af75078fSIntel timer_tsc = 0; 202af75078fSIntel 203af75078fSIntel lcore_id = rte_lcore_id(); 204af75078fSIntel qconf = &lcore_queue_conf[lcore_id]; 205af75078fSIntel 20616ac9cf0SIntel if (qconf->n_rx_port == 0) { 207af75078fSIntel RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id); 208cdfd5dbbSIntel return; 209af75078fSIntel } 210af75078fSIntel 211af75078fSIntel RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id); 212af75078fSIntel 21316ac9cf0SIntel for (i = 0; i < qconf->n_rx_port; i++) { 214af75078fSIntel 21516ac9cf0SIntel portid = qconf->rx_port_list[i]; 216af75078fSIntel RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id, 217af75078fSIntel portid); 218e2366e74STomasz Kulasek 219af75078fSIntel } 220af75078fSIntel 22188908b61SZhihong Wang while (!force_quit) { 222af75078fSIntel 223af75078fSIntel cur_tsc = rte_rdtsc(); 224af75078fSIntel 225af75078fSIntel /* 226af75078fSIntel * TX burst queue drain 227af75078fSIntel */ 228af75078fSIntel diff_tsc = cur_tsc - prev_tsc; 2295c95261dSIntel if (unlikely(diff_tsc > drain_tsc)) { 230af75078fSIntel 231e2366e74STomasz Kulasek for (i = 0; i < qconf->n_rx_port; i++) { 232e2366e74STomasz Kulasek 233e2366e74STomasz Kulasek portid = l2fwd_dst_ports[qconf->rx_port_list[i]]; 234e2366e74STomasz Kulasek buffer = tx_buffer[portid]; 235e2366e74STomasz Kulasek 236e2366e74STomasz Kulasek sent = rte_eth_tx_buffer_flush(portid, 0, buffer); 237e2366e74STomasz Kulasek if (sent) 238e2366e74STomasz Kulasek port_statistics[portid].tx += sent; 239e2366e74STomasz Kulasek 240af75078fSIntel } 241af75078fSIntel 242af75078fSIntel /* if timer is enabled */ 243af75078fSIntel if (timer_period > 0) { 244af75078fSIntel 245af75078fSIntel /* advance the timer */ 246af75078fSIntel timer_tsc += diff_tsc; 247af75078fSIntel 248af75078fSIntel /* if timer has reached its timeout */ 2492412742cSJerin Jacob if (unlikely(timer_tsc >= timer_period)) { 250af75078fSIntel 251af75078fSIntel /* do this only on master core */ 252af75078fSIntel if (lcore_id == rte_get_master_lcore()) { 253af75078fSIntel print_stats(); 254af75078fSIntel /* reset the timer */ 255af75078fSIntel timer_tsc = 0; 256af75078fSIntel } 257af75078fSIntel } 258af75078fSIntel } 259af75078fSIntel 260af75078fSIntel prev_tsc = cur_tsc; 261af75078fSIntel } 262af75078fSIntel 263af75078fSIntel /* 264af75078fSIntel * Read packet from RX queues 265af75078fSIntel */ 26616ac9cf0SIntel for (i = 0; i < qconf->n_rx_port; i++) { 267af75078fSIntel 26816ac9cf0SIntel portid = qconf->rx_port_list[i]; 269f8244c63SZhiyong Yang nb_rx = rte_eth_rx_burst(portid, 0, 270af75078fSIntel pkts_burst, MAX_PKT_BURST); 271af75078fSIntel 272af75078fSIntel port_statistics[portid].rx += nb_rx; 273af75078fSIntel 274af75078fSIntel for (j = 0; j < nb_rx; j++) { 275af75078fSIntel m = pkts_burst[j]; 276af75078fSIntel rte_prefetch0(rte_pktmbuf_mtod(m, void *)); 277af75078fSIntel l2fwd_simple_forward(m, portid); 278af75078fSIntel } 279af75078fSIntel } 280af75078fSIntel } 281af75078fSIntel } 282af75078fSIntel 283af75078fSIntel static int 284af75078fSIntel l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy) 285af75078fSIntel { 286af75078fSIntel l2fwd_main_loop(); 287af75078fSIntel return 0; 288af75078fSIntel } 289af75078fSIntel 290af75078fSIntel /* display usage */ 291af75078fSIntel static void 292af75078fSIntel l2fwd_usage(const char *prgname) 293af75078fSIntel { 294af75078fSIntel printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n" 295af75078fSIntel " -p PORTMASK: hexadecimal bitmask of ports to configure\n" 296af75078fSIntel " -q NQ: number of queue (=ports) per lcore (default is 1)\n" 297cf435a07SMaxime Coquelin " -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n" 298cf435a07SMaxime Coquelin " --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n" 299cf435a07SMaxime Coquelin " When enabled:\n" 300cf435a07SMaxime Coquelin " - The source MAC address is replaced by the TX port MAC address\n" 301cf435a07SMaxime Coquelin " - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n", 302af75078fSIntel prgname); 303af75078fSIntel } 304af75078fSIntel 305af75078fSIntel static int 306af75078fSIntel l2fwd_parse_portmask(const char *portmask) 307af75078fSIntel { 308af75078fSIntel char *end = NULL; 309af75078fSIntel unsigned long pm; 310af75078fSIntel 311af75078fSIntel /* parse hexadecimal string */ 312af75078fSIntel pm = strtoul(portmask, &end, 16); 313af75078fSIntel if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) 314af75078fSIntel return -1; 315af75078fSIntel 316af75078fSIntel if (pm == 0) 317af75078fSIntel return -1; 318af75078fSIntel 319af75078fSIntel return pm; 320af75078fSIntel } 321af75078fSIntel 322af75078fSIntel static unsigned int 323af75078fSIntel l2fwd_parse_nqueue(const char *q_arg) 324af75078fSIntel { 325af75078fSIntel char *end = NULL; 326af75078fSIntel unsigned long n; 327af75078fSIntel 328af75078fSIntel /* parse hexadecimal string */ 329af75078fSIntel n = strtoul(q_arg, &end, 10); 330af75078fSIntel if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 331af75078fSIntel return 0; 332af75078fSIntel if (n == 0) 333af75078fSIntel return 0; 334af75078fSIntel if (n >= MAX_RX_QUEUE_PER_LCORE) 335af75078fSIntel return 0; 336af75078fSIntel 337af75078fSIntel return n; 338af75078fSIntel } 339af75078fSIntel 340af75078fSIntel static int 341af75078fSIntel l2fwd_parse_timer_period(const char *q_arg) 342af75078fSIntel { 343af75078fSIntel char *end = NULL; 344af75078fSIntel int n; 345af75078fSIntel 346af75078fSIntel /* parse number string */ 347af75078fSIntel n = strtol(q_arg, &end, 10); 348af75078fSIntel if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 349af75078fSIntel return -1; 350af75078fSIntel if (n >= MAX_TIMER_PERIOD) 351af75078fSIntel return -1; 352af75078fSIntel 353af75078fSIntel return n; 354af75078fSIntel } 355af75078fSIntel 3566876790dSOlivier Matz static const char short_options[] = 3576876790dSOlivier Matz "p:" /* portmask */ 3586876790dSOlivier Matz "q:" /* number of queues */ 3596876790dSOlivier Matz "T:" /* timer period */ 3606876790dSOlivier Matz ; 3616876790dSOlivier Matz 3626876790dSOlivier Matz #define CMD_LINE_OPT_MAC_UPDATING "mac-updating" 3636876790dSOlivier Matz #define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating" 3646876790dSOlivier Matz 3656876790dSOlivier Matz enum { 3666876790dSOlivier Matz /* long options mapped to a short option */ 3676876790dSOlivier Matz 3686876790dSOlivier Matz /* first long only option value must be >= 256, so that we won't 3696876790dSOlivier Matz * conflict with short options */ 3706876790dSOlivier Matz CMD_LINE_OPT_MIN_NUM = 256, 3716876790dSOlivier Matz }; 3726876790dSOlivier Matz 3736876790dSOlivier Matz static const struct option lgopts[] = { 3746876790dSOlivier Matz { CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1}, 3756876790dSOlivier Matz { CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0}, 3766876790dSOlivier Matz {NULL, 0, 0, 0} 3776876790dSOlivier Matz }; 3786876790dSOlivier Matz 379af75078fSIntel /* Parse the argument given in the command line of the application */ 380af75078fSIntel static int 381af75078fSIntel l2fwd_parse_args(int argc, char **argv) 382af75078fSIntel { 3832412742cSJerin Jacob int opt, ret, timer_secs; 384af75078fSIntel char **argvopt; 385af75078fSIntel int option_index; 386af75078fSIntel char *prgname = argv[0]; 387af75078fSIntel 388af75078fSIntel argvopt = argv; 389af75078fSIntel 3906876790dSOlivier Matz while ((opt = getopt_long(argc, argvopt, short_options, 391af75078fSIntel lgopts, &option_index)) != EOF) { 392af75078fSIntel 393af75078fSIntel switch (opt) { 394af75078fSIntel /* portmask */ 395af75078fSIntel case 'p': 396af75078fSIntel l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg); 397af75078fSIntel if (l2fwd_enabled_port_mask == 0) { 398af75078fSIntel printf("invalid portmask\n"); 399af75078fSIntel l2fwd_usage(prgname); 400af75078fSIntel return -1; 401af75078fSIntel } 402af75078fSIntel break; 403af75078fSIntel 404af75078fSIntel /* nqueue */ 405af75078fSIntel case 'q': 406af75078fSIntel l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg); 407af75078fSIntel if (l2fwd_rx_queue_per_lcore == 0) { 408af75078fSIntel printf("invalid queue number\n"); 409af75078fSIntel l2fwd_usage(prgname); 410af75078fSIntel return -1; 411af75078fSIntel } 412af75078fSIntel break; 413af75078fSIntel 414af75078fSIntel /* timer period */ 415af75078fSIntel case 'T': 4162412742cSJerin Jacob timer_secs = l2fwd_parse_timer_period(optarg); 4172412742cSJerin Jacob if (timer_secs < 0) { 418af75078fSIntel printf("invalid timer period\n"); 419af75078fSIntel l2fwd_usage(prgname); 420af75078fSIntel return -1; 421af75078fSIntel } 4222412742cSJerin Jacob timer_period = timer_secs; 423af75078fSIntel break; 424af75078fSIntel 425af75078fSIntel /* long options */ 426af75078fSIntel case 0: 427cf435a07SMaxime Coquelin break; 428af75078fSIntel 429af75078fSIntel default: 430af75078fSIntel l2fwd_usage(prgname); 431af75078fSIntel return -1; 432af75078fSIntel } 433af75078fSIntel } 434af75078fSIntel 435af75078fSIntel if (optind >= 0) 436af75078fSIntel argv[optind-1] = prgname; 437af75078fSIntel 438af75078fSIntel ret = optind-1; 4399d5ca532SKeith Wiles optind = 1; /* reset getopt lib */ 440af75078fSIntel return ret; 441af75078fSIntel } 442af75078fSIntel 443d3641ae8SIntel /* Check the link status of all ports in up to 9s, and print them finally */ 444d3641ae8SIntel static void 4458728ccf3SThomas Monjalon check_all_ports_link_status(uint32_t port_mask) 446d3641ae8SIntel { 447d3641ae8SIntel #define CHECK_INTERVAL 100 /* 100ms */ 448d3641ae8SIntel #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ 449f8244c63SZhiyong Yang uint16_t portid; 450f8244c63SZhiyong Yang uint8_t count, all_ports_up, print_flag = 0; 451d3641ae8SIntel struct rte_eth_link link; 452d3641ae8SIntel 453d3641ae8SIntel printf("\nChecking link status"); 454d3641ae8SIntel fflush(stdout); 455d3641ae8SIntel for (count = 0; count <= MAX_CHECK_TIME; count++) { 45688908b61SZhihong Wang if (force_quit) 45788908b61SZhihong Wang return; 458d3641ae8SIntel all_ports_up = 1; 4598728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) { 46088908b61SZhihong Wang if (force_quit) 46188908b61SZhihong Wang return; 462d3641ae8SIntel if ((port_mask & (1 << portid)) == 0) 463d3641ae8SIntel continue; 464d3641ae8SIntel memset(&link, 0, sizeof(link)); 465d3641ae8SIntel rte_eth_link_get_nowait(portid, &link); 466d3641ae8SIntel /* print link status if flag set */ 467d3641ae8SIntel if (print_flag == 1) { 468d3641ae8SIntel if (link.link_status) 469f8244c63SZhiyong Yang printf( 470f8244c63SZhiyong Yang "Port%d Link Up. Speed %u Mbps - %s\n", 471f8244c63SZhiyong Yang portid, link.link_speed, 472d3641ae8SIntel (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? 473d3641ae8SIntel ("full-duplex") : ("half-duplex\n")); 474d3641ae8SIntel else 475f8244c63SZhiyong Yang printf("Port %d Link Down\n", portid); 476d3641ae8SIntel continue; 477d3641ae8SIntel } 478d3641ae8SIntel /* clear all_ports_up flag if any link down */ 47909419f23SThomas Monjalon if (link.link_status == ETH_LINK_DOWN) { 480d3641ae8SIntel all_ports_up = 0; 481d3641ae8SIntel break; 482d3641ae8SIntel } 483d3641ae8SIntel } 484d3641ae8SIntel /* after finally printing all link status, get out */ 485d3641ae8SIntel if (print_flag == 1) 486d3641ae8SIntel break; 487d3641ae8SIntel 488d3641ae8SIntel if (all_ports_up == 0) { 489d3641ae8SIntel printf("."); 490d3641ae8SIntel fflush(stdout); 491d3641ae8SIntel rte_delay_ms(CHECK_INTERVAL); 492d3641ae8SIntel } 493d3641ae8SIntel 494d3641ae8SIntel /* set the print_flag if all ports up or timeout */ 495d3641ae8SIntel if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { 496d3641ae8SIntel print_flag = 1; 497d3641ae8SIntel printf("done\n"); 498d3641ae8SIntel } 499d3641ae8SIntel } 500d3641ae8SIntel } 501d3641ae8SIntel 50288908b61SZhihong Wang static void 50388908b61SZhihong Wang signal_handler(int signum) 50488908b61SZhihong Wang { 50588908b61SZhihong Wang if (signum == SIGINT || signum == SIGTERM) { 50688908b61SZhihong Wang printf("\n\nSignal %d received, preparing to exit...\n", 50788908b61SZhihong Wang signum); 50888908b61SZhihong Wang force_quit = true; 50988908b61SZhihong Wang } 51088908b61SZhihong Wang } 51188908b61SZhihong Wang 512af75078fSIntel int 51398a16481SDavid Marchand main(int argc, char **argv) 514af75078fSIntel { 515af75078fSIntel struct lcore_queue_conf *qconf; 516af75078fSIntel int ret; 517f8244c63SZhiyong Yang uint16_t nb_ports; 5188728ccf3SThomas Monjalon uint16_t nb_ports_available = 0; 519f8244c63SZhiyong Yang uint16_t portid, last_port; 520af75078fSIntel unsigned lcore_id, rx_lcore_id; 521af75078fSIntel unsigned nb_ports_in_mask = 0; 5220b0ceb98SPavan Nikhilesh unsigned int nb_lcores = 0; 5230b0ceb98SPavan Nikhilesh unsigned int nb_mbufs; 524af75078fSIntel 525af75078fSIntel /* init EAL */ 526af75078fSIntel ret = rte_eal_init(argc, argv); 527af75078fSIntel if (ret < 0) 528af75078fSIntel rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n"); 529af75078fSIntel argc -= ret; 530af75078fSIntel argv += ret; 531af75078fSIntel 53288908b61SZhihong Wang force_quit = false; 53388908b61SZhihong Wang signal(SIGINT, signal_handler); 53488908b61SZhihong Wang signal(SIGTERM, signal_handler); 53588908b61SZhihong Wang 536af75078fSIntel /* parse application arguments (after the EAL ones) */ 537af75078fSIntel ret = l2fwd_parse_args(argc, argv); 538af75078fSIntel if (ret < 0) 539af75078fSIntel rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n"); 540af75078fSIntel 541cf435a07SMaxime Coquelin printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled"); 542cf435a07SMaxime Coquelin 5432412742cSJerin Jacob /* convert to number of cycles */ 5442412742cSJerin Jacob timer_period *= rte_get_timer_hz(); 5452412742cSJerin Jacob 546d9a42a69SThomas Monjalon nb_ports = rte_eth_dev_count_avail(); 547af75078fSIntel if (nb_ports == 0) 548af75078fSIntel rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n"); 549af75078fSIntel 55067265219SVipin Varghese /* check port mask to possible port mask */ 55167265219SVipin Varghese if (l2fwd_enabled_port_mask & ~((1 << nb_ports) - 1)) 55267265219SVipin Varghese rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n", 55367265219SVipin Varghese (1 << nb_ports) - 1); 55467265219SVipin Varghese 555af75078fSIntel /* reset l2fwd_dst_ports */ 5561c17baf4SIntel for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) 557af75078fSIntel l2fwd_dst_ports[portid] = 0; 558af75078fSIntel last_port = 0; 559af75078fSIntel 560af75078fSIntel /* 561af75078fSIntel * Each logical core is assigned a dedicated TX queue on each port. 562af75078fSIntel */ 5638728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) { 564af75078fSIntel /* skip ports that are not enabled */ 565af75078fSIntel if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 566af75078fSIntel continue; 567af75078fSIntel 568af75078fSIntel if (nb_ports_in_mask % 2) { 569af75078fSIntel l2fwd_dst_ports[portid] = last_port; 570af75078fSIntel l2fwd_dst_ports[last_port] = portid; 571af75078fSIntel } 572af75078fSIntel else 573af75078fSIntel last_port = portid; 574af75078fSIntel 575af75078fSIntel nb_ports_in_mask++; 576af75078fSIntel } 577f56d0815SIntel if (nb_ports_in_mask % 2) { 57816ac9cf0SIntel printf("Notice: odd number of ports in portmask.\n"); 57916ac9cf0SIntel l2fwd_dst_ports[last_port] = last_port; 580af75078fSIntel } 581af75078fSIntel 582af75078fSIntel rx_lcore_id = 0; 583af75078fSIntel qconf = NULL; 584af75078fSIntel 585af75078fSIntel /* Initialize the port/queue configuration of each logical core */ 5868728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) { 587af75078fSIntel /* skip ports that are not enabled */ 588af75078fSIntel if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 589af75078fSIntel continue; 590af75078fSIntel 591af75078fSIntel /* get the lcore_id for this port */ 592af75078fSIntel while (rte_lcore_is_enabled(rx_lcore_id) == 0 || 59316ac9cf0SIntel lcore_queue_conf[rx_lcore_id].n_rx_port == 594af75078fSIntel l2fwd_rx_queue_per_lcore) { 595af75078fSIntel rx_lcore_id++; 596af75078fSIntel if (rx_lcore_id >= RTE_MAX_LCORE) 597af75078fSIntel rte_exit(EXIT_FAILURE, "Not enough cores\n"); 598af75078fSIntel } 59916ac9cf0SIntel 6000b0ceb98SPavan Nikhilesh if (qconf != &lcore_queue_conf[rx_lcore_id]) { 601af75078fSIntel /* Assigned a new logical core in the loop above. */ 602af75078fSIntel qconf = &lcore_queue_conf[rx_lcore_id]; 6030b0ceb98SPavan Nikhilesh nb_lcores++; 6040b0ceb98SPavan Nikhilesh } 60516ac9cf0SIntel 60616ac9cf0SIntel qconf->rx_port_list[qconf->n_rx_port] = portid; 60716ac9cf0SIntel qconf->n_rx_port++; 608f8244c63SZhiyong Yang printf("Lcore %u: RX port %u\n", rx_lcore_id, portid); 609af75078fSIntel } 610af75078fSIntel 6110b0ceb98SPavan Nikhilesh nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST + 6120b0ceb98SPavan Nikhilesh nb_lcores * MEMPOOL_CACHE_SIZE), 8192U); 6130b0ceb98SPavan Nikhilesh 6140b0ceb98SPavan Nikhilesh /* create the mbuf pool */ 6150b0ceb98SPavan Nikhilesh l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs, 6160b0ceb98SPavan Nikhilesh MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, 6170b0ceb98SPavan Nikhilesh rte_socket_id()); 6180b0ceb98SPavan Nikhilesh if (l2fwd_pktmbuf_pool == NULL) 6190b0ceb98SPavan Nikhilesh rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n"); 6200b0ceb98SPavan Nikhilesh 621af75078fSIntel /* Initialise each port */ 6228728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) { 62375d7f266SShahaf Shuler struct rte_eth_rxconf rxq_conf; 62475d7f266SShahaf Shuler struct rte_eth_txconf txq_conf; 62575d7f266SShahaf Shuler struct rte_eth_conf local_port_conf = port_conf; 62675d7f266SShahaf Shuler struct rte_eth_dev_info dev_info; 62775d7f266SShahaf Shuler 628af75078fSIntel /* skip ports that are not enabled */ 629af75078fSIntel if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) { 630f8244c63SZhiyong Yang printf("Skipping disabled port %u\n", portid); 631af75078fSIntel continue; 632af75078fSIntel } 6338728ccf3SThomas Monjalon nb_ports_available++; 6348728ccf3SThomas Monjalon 635af75078fSIntel /* init port */ 636f8244c63SZhiyong Yang printf("Initializing port %u... ", portid); 637af75078fSIntel fflush(stdout); 638*089e5ed7SIvan Ilchenko 639*089e5ed7SIvan Ilchenko ret = rte_eth_dev_info_get(portid, &dev_info); 640*089e5ed7SIvan Ilchenko if (ret != 0) 641*089e5ed7SIvan Ilchenko rte_exit(EXIT_FAILURE, 642*089e5ed7SIvan Ilchenko "Error during getting device (port %u) info: %s\n", 643*089e5ed7SIvan Ilchenko portid, strerror(-ret)); 644*089e5ed7SIvan Ilchenko 64575d7f266SShahaf Shuler if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) 64675d7f266SShahaf Shuler local_port_conf.txmode.offloads |= 64775d7f266SShahaf Shuler DEV_TX_OFFLOAD_MBUF_FAST_FREE; 64875d7f266SShahaf Shuler ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf); 649af75078fSIntel if (ret < 0) 65016ac9cf0SIntel rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n", 651f8244c63SZhiyong Yang ret, portid); 652af75078fSIntel 65360efb44fSRoman Zhukov ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, 65460efb44fSRoman Zhukov &nb_txd); 65560efb44fSRoman Zhukov if (ret < 0) 65660efb44fSRoman Zhukov rte_exit(EXIT_FAILURE, 65760efb44fSRoman Zhukov "Cannot adjust number of descriptors: err=%d, port=%u\n", 658f8244c63SZhiyong Yang ret, portid); 65960efb44fSRoman Zhukov 660a974564bSIntel rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]); 661af75078fSIntel 662af75078fSIntel /* init one RX queue */ 663af75078fSIntel fflush(stdout); 66475d7f266SShahaf Shuler rxq_conf = dev_info.default_rxconf; 66575d7f266SShahaf Shuler rxq_conf.offloads = local_port_conf.rxmode.offloads; 666a974564bSIntel ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd, 66781f7ecd9SPablo de Lara rte_eth_dev_socket_id(portid), 66875d7f266SShahaf Shuler &rxq_conf, 669af75078fSIntel l2fwd_pktmbuf_pool); 670af75078fSIntel if (ret < 0) 671a974564bSIntel rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n", 672f8244c63SZhiyong Yang ret, portid); 673af75078fSIntel 674e60f71ebSIntel /* init one TX queue on each port */ 675af75078fSIntel fflush(stdout); 67675d7f266SShahaf Shuler txq_conf = dev_info.default_txconf; 67775d7f266SShahaf Shuler txq_conf.offloads = local_port_conf.txmode.offloads; 678a974564bSIntel ret = rte_eth_tx_queue_setup(portid, 0, nb_txd, 67981f7ecd9SPablo de Lara rte_eth_dev_socket_id(portid), 68075d7f266SShahaf Shuler &txq_conf); 681af75078fSIntel if (ret < 0) 68216ac9cf0SIntel rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n", 683f8244c63SZhiyong Yang ret, portid); 684af75078fSIntel 685e2366e74STomasz Kulasek /* Initialize TX buffers */ 686e2366e74STomasz Kulasek tx_buffer[portid] = rte_zmalloc_socket("tx_buffer", 687e2366e74STomasz Kulasek RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0, 688e2366e74STomasz Kulasek rte_eth_dev_socket_id(portid)); 689e2366e74STomasz Kulasek if (tx_buffer[portid] == NULL) 690e2366e74STomasz Kulasek rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n", 691f8244c63SZhiyong Yang portid); 692e2366e74STomasz Kulasek 693e2366e74STomasz Kulasek rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST); 694e2366e74STomasz Kulasek 695e2366e74STomasz Kulasek ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid], 696e2366e74STomasz Kulasek rte_eth_tx_buffer_count_callback, 697e2366e74STomasz Kulasek &port_statistics[portid].dropped); 698e2366e74STomasz Kulasek if (ret < 0) 699f8244c63SZhiyong Yang rte_exit(EXIT_FAILURE, 700f8244c63SZhiyong Yang "Cannot set error callback for tx buffer on port %u\n", 701f8244c63SZhiyong Yang portid); 702e2366e74STomasz Kulasek 703af75078fSIntel /* Start device */ 704a974564bSIntel ret = rte_eth_dev_start(portid); 705af75078fSIntel if (ret < 0) 70616ac9cf0SIntel rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n", 707f8244c63SZhiyong Yang ret, portid); 708af75078fSIntel 709d3641ae8SIntel printf("done: \n"); 710af75078fSIntel 711a974564bSIntel rte_eth_promiscuous_enable(portid); 712af75078fSIntel 713af75078fSIntel printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n", 714f8244c63SZhiyong Yang portid, 715af75078fSIntel l2fwd_ports_eth_addr[portid].addr_bytes[0], 716af75078fSIntel l2fwd_ports_eth_addr[portid].addr_bytes[1], 717af75078fSIntel l2fwd_ports_eth_addr[portid].addr_bytes[2], 718af75078fSIntel l2fwd_ports_eth_addr[portid].addr_bytes[3], 719af75078fSIntel l2fwd_ports_eth_addr[portid].addr_bytes[4], 720af75078fSIntel l2fwd_ports_eth_addr[portid].addr_bytes[5]); 721af75078fSIntel 722af75078fSIntel /* initialize port stats */ 723af75078fSIntel memset(&port_statistics, 0, sizeof(port_statistics)); 724af75078fSIntel } 725af75078fSIntel 726f56d0815SIntel if (!nb_ports_available) { 727f56d0815SIntel rte_exit(EXIT_FAILURE, 728f56d0815SIntel "All available ports are disabled. Please set portmask.\n"); 729f56d0815SIntel } 730f56d0815SIntel 7318728ccf3SThomas Monjalon check_all_ports_link_status(l2fwd_enabled_port_mask); 732d3641ae8SIntel 73388908b61SZhihong Wang ret = 0; 734af75078fSIntel /* launch per-lcore init on every lcore */ 735af75078fSIntel rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER); 736af75078fSIntel RTE_LCORE_FOREACH_SLAVE(lcore_id) { 73788908b61SZhihong Wang if (rte_eal_wait_lcore(lcore_id) < 0) { 73888908b61SZhihong Wang ret = -1; 73988908b61SZhihong Wang break; 74088908b61SZhihong Wang } 741af75078fSIntel } 742af75078fSIntel 7438728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) { 74488908b61SZhihong Wang if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 74588908b61SZhihong Wang continue; 74688908b61SZhihong Wang printf("Closing port %d...", portid); 74788908b61SZhihong Wang rte_eth_dev_stop(portid); 74888908b61SZhihong Wang rte_eth_dev_close(portid); 74988908b61SZhihong Wang printf(" Done\n"); 75088908b61SZhihong Wang } 75188908b61SZhihong Wang printf("Bye...\n"); 75288908b61SZhihong Wang 75388908b61SZhihong Wang return ret; 754af75078fSIntel } 755