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 <setjmp.h> 13af75078fSIntel #include <stdarg.h> 14af75078fSIntel #include <ctype.h> 15af75078fSIntel #include <errno.h> 16af75078fSIntel #include <getopt.h> 1788908b61SZhihong Wang #include <signal.h> 1888908b61SZhihong Wang #include <stdbool.h> 19af75078fSIntel 20af75078fSIntel #include <rte_common.h> 21af75078fSIntel #include <rte_log.h> 22e2366e74STomasz Kulasek #include <rte_malloc.h> 23af75078fSIntel #include <rte_memory.h> 24af75078fSIntel #include <rte_memcpy.h> 25af75078fSIntel #include <rte_eal.h> 26af75078fSIntel #include <rte_launch.h> 27af75078fSIntel #include <rte_atomic.h> 28af75078fSIntel #include <rte_cycles.h> 29af75078fSIntel #include <rte_prefetch.h> 30af75078fSIntel #include <rte_lcore.h> 31af75078fSIntel #include <rte_per_lcore.h> 32af75078fSIntel #include <rte_branch_prediction.h> 33af75078fSIntel #include <rte_interrupts.h> 34af75078fSIntel #include <rte_random.h> 35af75078fSIntel #include <rte_debug.h> 36af75078fSIntel #include <rte_ether.h> 37af75078fSIntel #include <rte_ethdev.h> 38af75078fSIntel #include <rte_mempool.h> 39af75078fSIntel #include <rte_mbuf.h> 40fa19eb20SVamsi Attunuru #include <rte_string_fns.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 70fa19eb20SVamsi Attunuru struct port_pair_params { 71fa19eb20SVamsi Attunuru #define NUM_PORTS 2 72fa19eb20SVamsi Attunuru uint16_t port[NUM_PORTS]; 73fa19eb20SVamsi Attunuru } __rte_cache_aligned; 74fa19eb20SVamsi Attunuru 75fa19eb20SVamsi Attunuru static struct port_pair_params port_pair_params_array[RTE_MAX_ETHPORTS / 2]; 76fa19eb20SVamsi Attunuru static struct port_pair_params *port_pair_params; 77fa19eb20SVamsi Attunuru static uint16_t nb_port_pair_params; 78fa19eb20SVamsi Attunuru 79af75078fSIntel static unsigned int l2fwd_rx_queue_per_lcore = 1; 80af75078fSIntel 81af75078fSIntel #define MAX_RX_QUEUE_PER_LCORE 16 82af75078fSIntel #define MAX_TX_QUEUE_PER_PORT 16 83af75078fSIntel struct lcore_queue_conf { 8416ac9cf0SIntel unsigned n_rx_port; 8516ac9cf0SIntel unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE]; 86af75078fSIntel } __rte_cache_aligned; 87af75078fSIntel struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE]; 88af75078fSIntel 89e2366e74STomasz Kulasek static struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS]; 90e2366e74STomasz Kulasek 9175d7f266SShahaf Shuler static struct rte_eth_conf port_conf = { 92af75078fSIntel .rxmode = { 93af75078fSIntel .split_hdr_size = 0, 94af75078fSIntel }, 95af75078fSIntel .txmode = { 9632e7aa0bSIntel .mq_mode = ETH_MQ_TX_NONE, 97af75078fSIntel }, 98af75078fSIntel }; 99af75078fSIntel 100af75078fSIntel struct rte_mempool * l2fwd_pktmbuf_pool = NULL; 101af75078fSIntel 102af75078fSIntel /* Per-port statistics struct */ 103af75078fSIntel struct l2fwd_port_statistics { 104af75078fSIntel uint64_t tx; 105af75078fSIntel uint64_t rx; 106af75078fSIntel uint64_t dropped; 107af75078fSIntel } __rte_cache_aligned; 1081c17baf4SIntel struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS]; 109af75078fSIntel 110af75078fSIntel #define MAX_TIMER_PERIOD 86400 /* 1 day max */ 1112412742cSJerin Jacob /* A tsc-based timer responsible for triggering statistics printout */ 1122412742cSJerin Jacob static uint64_t timer_period = 10; /* default period is 10 seconds */ 113af75078fSIntel 114af75078fSIntel /* Print out statistics on packets dropped */ 115af75078fSIntel static void 116af75078fSIntel print_stats(void) 117af75078fSIntel { 118af75078fSIntel uint64_t total_packets_dropped, total_packets_tx, total_packets_rx; 119af75078fSIntel unsigned portid; 120af75078fSIntel 121af75078fSIntel total_packets_dropped = 0; 122af75078fSIntel total_packets_tx = 0; 123af75078fSIntel total_packets_rx = 0; 124af75078fSIntel 125af75078fSIntel const char clr[] = { 27, '[', '2', 'J', '\0' }; 126af75078fSIntel const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' }; 127af75078fSIntel 128af75078fSIntel /* Clear screen and move to top left */ 129af75078fSIntel printf("%s%s", clr, topLeft); 130af75078fSIntel 131af75078fSIntel printf("\nPort statistics ===================================="); 132af75078fSIntel 1331c17baf4SIntel for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { 134af75078fSIntel /* skip disabled ports */ 135af75078fSIntel if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 136af75078fSIntel continue; 137af75078fSIntel printf("\nStatistics for port %u ------------------------------" 138af75078fSIntel "\nPackets sent: %24"PRIu64 139af75078fSIntel "\nPackets received: %20"PRIu64 140af75078fSIntel "\nPackets dropped: %21"PRIu64, 141af75078fSIntel portid, 142af75078fSIntel port_statistics[portid].tx, 143af75078fSIntel port_statistics[portid].rx, 144af75078fSIntel port_statistics[portid].dropped); 145af75078fSIntel 146af75078fSIntel total_packets_dropped += port_statistics[portid].dropped; 147af75078fSIntel total_packets_tx += port_statistics[portid].tx; 148af75078fSIntel total_packets_rx += port_statistics[portid].rx; 149af75078fSIntel } 150af75078fSIntel printf("\nAggregate statistics ===============================" 151af75078fSIntel "\nTotal packets sent: %18"PRIu64 152af75078fSIntel "\nTotal packets received: %14"PRIu64 153af75078fSIntel "\nTotal packets dropped: %15"PRIu64, 154af75078fSIntel total_packets_tx, 155af75078fSIntel total_packets_rx, 156af75078fSIntel total_packets_dropped); 157af75078fSIntel printf("\n====================================================\n"); 1583ee6f706SGeorgiy Levashov 1593ee6f706SGeorgiy Levashov fflush(stdout); 160af75078fSIntel } 161af75078fSIntel 162af75078fSIntel static void 163cf435a07SMaxime Coquelin l2fwd_mac_updating(struct rte_mbuf *m, unsigned dest_portid) 164af75078fSIntel { 1656d13ea8eSOlivier Matz struct rte_ether_hdr *eth; 166af75078fSIntel void *tmp; 167cf435a07SMaxime Coquelin 1686d13ea8eSOlivier Matz eth = rte_pktmbuf_mtod(m, struct rte_ether_hdr *); 169cf435a07SMaxime Coquelin 170cf435a07SMaxime Coquelin /* 02:00:00:00:00:xx */ 171cf435a07SMaxime Coquelin tmp = ð->d_addr.addr_bytes[0]; 172cf435a07SMaxime Coquelin *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dest_portid << 40); 173cf435a07SMaxime Coquelin 174cf435a07SMaxime Coquelin /* src addr */ 175538da7a1SOlivier Matz rte_ether_addr_copy(&l2fwd_ports_eth_addr[dest_portid], ð->s_addr); 176cf435a07SMaxime Coquelin } 177cf435a07SMaxime Coquelin 178cf435a07SMaxime Coquelin static void 179cf435a07SMaxime Coquelin l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid) 180cf435a07SMaxime Coquelin { 181af75078fSIntel unsigned dst_port; 182e2366e74STomasz Kulasek int sent; 183e2366e74STomasz Kulasek struct rte_eth_dev_tx_buffer *buffer; 184af75078fSIntel 185af75078fSIntel dst_port = l2fwd_dst_ports[portid]; 186af75078fSIntel 187cf435a07SMaxime Coquelin if (mac_updating) 188cf435a07SMaxime Coquelin l2fwd_mac_updating(m, dst_port); 189af75078fSIntel 190e2366e74STomasz Kulasek buffer = tx_buffer[dst_port]; 191e2366e74STomasz Kulasek sent = rte_eth_tx_buffer(dst_port, 0, buffer, m); 192e2366e74STomasz Kulasek if (sent) 193e2366e74STomasz Kulasek port_statistics[dst_port].tx += sent; 194af75078fSIntel } 195af75078fSIntel 196af75078fSIntel /* main processing loop */ 197af75078fSIntel static void 198af75078fSIntel l2fwd_main_loop(void) 199af75078fSIntel { 200af75078fSIntel struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; 201af75078fSIntel struct rte_mbuf *m; 202e2366e74STomasz Kulasek int sent; 203af75078fSIntel unsigned lcore_id; 2045c95261dSIntel uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc; 205af75078fSIntel unsigned i, j, portid, nb_rx; 206af75078fSIntel struct lcore_queue_conf *qconf; 207e2366e74STomasz Kulasek const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * 208e2366e74STomasz Kulasek BURST_TX_DRAIN_US; 209e2366e74STomasz Kulasek struct rte_eth_dev_tx_buffer *buffer; 210af75078fSIntel 2115c95261dSIntel prev_tsc = 0; 212af75078fSIntel timer_tsc = 0; 213af75078fSIntel 214af75078fSIntel lcore_id = rte_lcore_id(); 215af75078fSIntel qconf = &lcore_queue_conf[lcore_id]; 216af75078fSIntel 21716ac9cf0SIntel if (qconf->n_rx_port == 0) { 218af75078fSIntel RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id); 219cdfd5dbbSIntel return; 220af75078fSIntel } 221af75078fSIntel 222af75078fSIntel RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id); 223af75078fSIntel 22416ac9cf0SIntel for (i = 0; i < qconf->n_rx_port; i++) { 225af75078fSIntel 22616ac9cf0SIntel portid = qconf->rx_port_list[i]; 227af75078fSIntel RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id, 228af75078fSIntel portid); 229e2366e74STomasz Kulasek 230af75078fSIntel } 231af75078fSIntel 23288908b61SZhihong Wang while (!force_quit) { 233af75078fSIntel 234af75078fSIntel cur_tsc = rte_rdtsc(); 235af75078fSIntel 236af75078fSIntel /* 237af75078fSIntel * TX burst queue drain 238af75078fSIntel */ 239af75078fSIntel diff_tsc = cur_tsc - prev_tsc; 2405c95261dSIntel if (unlikely(diff_tsc > drain_tsc)) { 241af75078fSIntel 242e2366e74STomasz Kulasek for (i = 0; i < qconf->n_rx_port; i++) { 243e2366e74STomasz Kulasek 244e2366e74STomasz Kulasek portid = l2fwd_dst_ports[qconf->rx_port_list[i]]; 245e2366e74STomasz Kulasek buffer = tx_buffer[portid]; 246e2366e74STomasz Kulasek 247e2366e74STomasz Kulasek sent = rte_eth_tx_buffer_flush(portid, 0, buffer); 248e2366e74STomasz Kulasek if (sent) 249e2366e74STomasz Kulasek port_statistics[portid].tx += sent; 250e2366e74STomasz Kulasek 251af75078fSIntel } 252af75078fSIntel 253af75078fSIntel /* if timer is enabled */ 254af75078fSIntel if (timer_period > 0) { 255af75078fSIntel 256af75078fSIntel /* advance the timer */ 257af75078fSIntel timer_tsc += diff_tsc; 258af75078fSIntel 259af75078fSIntel /* if timer has reached its timeout */ 2602412742cSJerin Jacob if (unlikely(timer_tsc >= timer_period)) { 261af75078fSIntel 262cb056611SStephen Hemminger /* do this only on main core */ 263cb056611SStephen Hemminger if (lcore_id == rte_get_main_lcore()) { 264af75078fSIntel print_stats(); 265af75078fSIntel /* reset the timer */ 266af75078fSIntel timer_tsc = 0; 267af75078fSIntel } 268af75078fSIntel } 269af75078fSIntel } 270af75078fSIntel 271af75078fSIntel prev_tsc = cur_tsc; 272af75078fSIntel } 273af75078fSIntel 274af75078fSIntel /* 275af75078fSIntel * Read packet from RX queues 276af75078fSIntel */ 27716ac9cf0SIntel for (i = 0; i < qconf->n_rx_port; i++) { 278af75078fSIntel 27916ac9cf0SIntel portid = qconf->rx_port_list[i]; 280f8244c63SZhiyong Yang nb_rx = rte_eth_rx_burst(portid, 0, 281af75078fSIntel pkts_burst, MAX_PKT_BURST); 282af75078fSIntel 283af75078fSIntel port_statistics[portid].rx += nb_rx; 284af75078fSIntel 285af75078fSIntel for (j = 0; j < nb_rx; j++) { 286af75078fSIntel m = pkts_burst[j]; 287af75078fSIntel rte_prefetch0(rte_pktmbuf_mtod(m, void *)); 288af75078fSIntel l2fwd_simple_forward(m, portid); 289af75078fSIntel } 290af75078fSIntel } 291af75078fSIntel } 292af75078fSIntel } 293af75078fSIntel 294af75078fSIntel static int 295f2fc83b4SThomas Monjalon l2fwd_launch_one_lcore(__rte_unused void *dummy) 296af75078fSIntel { 297af75078fSIntel l2fwd_main_loop(); 298af75078fSIntel return 0; 299af75078fSIntel } 300af75078fSIntel 301af75078fSIntel /* display usage */ 302af75078fSIntel static void 303af75078fSIntel l2fwd_usage(const char *prgname) 304af75078fSIntel { 305af75078fSIntel printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n" 306af75078fSIntel " -p PORTMASK: hexadecimal bitmask of ports to configure\n" 307af75078fSIntel " -q NQ: number of queue (=ports) per lcore (default is 1)\n" 308cf435a07SMaxime Coquelin " -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n" 309cf435a07SMaxime Coquelin " --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n" 310cf435a07SMaxime Coquelin " When enabled:\n" 311cf435a07SMaxime Coquelin " - The source MAC address is replaced by the TX port MAC address\n" 312fa19eb20SVamsi Attunuru " - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n" 313fa19eb20SVamsi Attunuru " --portmap: Configure forwarding port pair mapping\n" 314fa19eb20SVamsi Attunuru " Default: alternate port pairs\n\n", 315af75078fSIntel prgname); 316af75078fSIntel } 317af75078fSIntel 318af75078fSIntel static int 319af75078fSIntel l2fwd_parse_portmask(const char *portmask) 320af75078fSIntel { 321af75078fSIntel char *end = NULL; 322af75078fSIntel unsigned long pm; 323af75078fSIntel 324af75078fSIntel /* parse hexadecimal string */ 325af75078fSIntel pm = strtoul(portmask, &end, 16); 326af75078fSIntel if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) 327ce6b8c31SSarosh Arif return 0; 328af75078fSIntel 329af75078fSIntel return pm; 330af75078fSIntel } 331af75078fSIntel 332fa19eb20SVamsi Attunuru static int 333fa19eb20SVamsi Attunuru l2fwd_parse_port_pair_config(const char *q_arg) 334fa19eb20SVamsi Attunuru { 335fa19eb20SVamsi Attunuru enum fieldnames { 336fa19eb20SVamsi Attunuru FLD_PORT1 = 0, 337fa19eb20SVamsi Attunuru FLD_PORT2, 338fa19eb20SVamsi Attunuru _NUM_FLD 339fa19eb20SVamsi Attunuru }; 340fa19eb20SVamsi Attunuru unsigned long int_fld[_NUM_FLD]; 341fa19eb20SVamsi Attunuru const char *p, *p0 = q_arg; 342fa19eb20SVamsi Attunuru char *str_fld[_NUM_FLD]; 343fa19eb20SVamsi Attunuru unsigned int size; 344fa19eb20SVamsi Attunuru char s[256]; 345fa19eb20SVamsi Attunuru char *end; 346fa19eb20SVamsi Attunuru int i; 347fa19eb20SVamsi Attunuru 348fa19eb20SVamsi Attunuru nb_port_pair_params = 0; 349fa19eb20SVamsi Attunuru 350fa19eb20SVamsi Attunuru while ((p = strchr(p0, '(')) != NULL) { 351fa19eb20SVamsi Attunuru ++p; 352fa19eb20SVamsi Attunuru p0 = strchr(p, ')'); 353fa19eb20SVamsi Attunuru if (p0 == NULL) 354fa19eb20SVamsi Attunuru return -1; 355fa19eb20SVamsi Attunuru 356fa19eb20SVamsi Attunuru size = p0 - p; 357fa19eb20SVamsi Attunuru if (size >= sizeof(s)) 358fa19eb20SVamsi Attunuru return -1; 359fa19eb20SVamsi Attunuru 360fa19eb20SVamsi Attunuru memcpy(s, p, size); 361fa19eb20SVamsi Attunuru s[size] = '\0'; 362fa19eb20SVamsi Attunuru if (rte_strsplit(s, sizeof(s), str_fld, 363fa19eb20SVamsi Attunuru _NUM_FLD, ',') != _NUM_FLD) 364fa19eb20SVamsi Attunuru return -1; 365fa19eb20SVamsi Attunuru for (i = 0; i < _NUM_FLD; i++) { 366fa19eb20SVamsi Attunuru errno = 0; 367fa19eb20SVamsi Attunuru int_fld[i] = strtoul(str_fld[i], &end, 0); 368fa19eb20SVamsi Attunuru if (errno != 0 || end == str_fld[i] || 369fa19eb20SVamsi Attunuru int_fld[i] >= RTE_MAX_ETHPORTS) 370fa19eb20SVamsi Attunuru return -1; 371fa19eb20SVamsi Attunuru } 372fa19eb20SVamsi Attunuru if (nb_port_pair_params >= RTE_MAX_ETHPORTS/2) { 373fa19eb20SVamsi Attunuru printf("exceeded max number of port pair params: %hu\n", 374fa19eb20SVamsi Attunuru nb_port_pair_params); 375fa19eb20SVamsi Attunuru return -1; 376fa19eb20SVamsi Attunuru } 377fa19eb20SVamsi Attunuru port_pair_params_array[nb_port_pair_params].port[0] = 378fa19eb20SVamsi Attunuru (uint16_t)int_fld[FLD_PORT1]; 379fa19eb20SVamsi Attunuru port_pair_params_array[nb_port_pair_params].port[1] = 380fa19eb20SVamsi Attunuru (uint16_t)int_fld[FLD_PORT2]; 381fa19eb20SVamsi Attunuru ++nb_port_pair_params; 382fa19eb20SVamsi Attunuru } 383fa19eb20SVamsi Attunuru port_pair_params = port_pair_params_array; 384fa19eb20SVamsi Attunuru return 0; 385fa19eb20SVamsi Attunuru } 386fa19eb20SVamsi Attunuru 387af75078fSIntel static unsigned int 388af75078fSIntel l2fwd_parse_nqueue(const char *q_arg) 389af75078fSIntel { 390af75078fSIntel char *end = NULL; 391af75078fSIntel unsigned long n; 392af75078fSIntel 393af75078fSIntel /* parse hexadecimal string */ 394af75078fSIntel n = strtoul(q_arg, &end, 10); 395af75078fSIntel if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 396af75078fSIntel return 0; 397af75078fSIntel if (n == 0) 398af75078fSIntel return 0; 399af75078fSIntel if (n >= MAX_RX_QUEUE_PER_LCORE) 400af75078fSIntel return 0; 401af75078fSIntel 402af75078fSIntel return n; 403af75078fSIntel } 404af75078fSIntel 405af75078fSIntel static int 406af75078fSIntel l2fwd_parse_timer_period(const char *q_arg) 407af75078fSIntel { 408af75078fSIntel char *end = NULL; 409af75078fSIntel int n; 410af75078fSIntel 411af75078fSIntel /* parse number string */ 412af75078fSIntel n = strtol(q_arg, &end, 10); 413af75078fSIntel if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 414af75078fSIntel return -1; 415af75078fSIntel if (n >= MAX_TIMER_PERIOD) 416af75078fSIntel return -1; 417af75078fSIntel 418af75078fSIntel return n; 419af75078fSIntel } 420af75078fSIntel 4216876790dSOlivier Matz static const char short_options[] = 4226876790dSOlivier Matz "p:" /* portmask */ 4236876790dSOlivier Matz "q:" /* number of queues */ 4246876790dSOlivier Matz "T:" /* timer period */ 4256876790dSOlivier Matz ; 4266876790dSOlivier Matz 4276876790dSOlivier Matz #define CMD_LINE_OPT_MAC_UPDATING "mac-updating" 4286876790dSOlivier Matz #define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating" 429fa19eb20SVamsi Attunuru #define CMD_LINE_OPT_PORTMAP_CONFIG "portmap" 4306876790dSOlivier Matz 4316876790dSOlivier Matz enum { 4326876790dSOlivier Matz /* long options mapped to a short option */ 4336876790dSOlivier Matz 4346876790dSOlivier Matz /* first long only option value must be >= 256, so that we won't 4356876790dSOlivier Matz * conflict with short options */ 436*bbbe38a6SChenglian Sun CMD_LINE_OPT_MAC_UPDATING_NUM = 256, 437*bbbe38a6SChenglian Sun CMD_LINE_OPT_NO_MAC_UPDATING_NUM, 438fa19eb20SVamsi Attunuru CMD_LINE_OPT_PORTMAP_NUM, 4396876790dSOlivier Matz }; 4406876790dSOlivier Matz 4416876790dSOlivier Matz static const struct option lgopts[] = { 442*bbbe38a6SChenglian Sun { CMD_LINE_OPT_MAC_UPDATING, no_argument, 0, 443*bbbe38a6SChenglian Sun CMD_LINE_OPT_MAC_UPDATING_NUM}, 444*bbbe38a6SChenglian Sun { CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, 0, 445*bbbe38a6SChenglian Sun CMD_LINE_OPT_NO_MAC_UPDATING_NUM}, 446fa19eb20SVamsi Attunuru { CMD_LINE_OPT_PORTMAP_CONFIG, 1, 0, CMD_LINE_OPT_PORTMAP_NUM}, 4476876790dSOlivier Matz {NULL, 0, 0, 0} 4486876790dSOlivier Matz }; 4496876790dSOlivier Matz 450af75078fSIntel /* Parse the argument given in the command line of the application */ 451af75078fSIntel static int 452af75078fSIntel l2fwd_parse_args(int argc, char **argv) 453af75078fSIntel { 4542412742cSJerin Jacob int opt, ret, timer_secs; 455af75078fSIntel char **argvopt; 456af75078fSIntel int option_index; 457af75078fSIntel char *prgname = argv[0]; 458af75078fSIntel 459af75078fSIntel argvopt = argv; 460fa19eb20SVamsi Attunuru port_pair_params = NULL; 461af75078fSIntel 4626876790dSOlivier Matz while ((opt = getopt_long(argc, argvopt, short_options, 463af75078fSIntel lgopts, &option_index)) != EOF) { 464af75078fSIntel 465af75078fSIntel switch (opt) { 466af75078fSIntel /* portmask */ 467af75078fSIntel case 'p': 468af75078fSIntel l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg); 469af75078fSIntel if (l2fwd_enabled_port_mask == 0) { 470af75078fSIntel printf("invalid portmask\n"); 471af75078fSIntel l2fwd_usage(prgname); 472af75078fSIntel return -1; 473af75078fSIntel } 474af75078fSIntel break; 475af75078fSIntel 476af75078fSIntel /* nqueue */ 477af75078fSIntel case 'q': 478af75078fSIntel l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg); 479af75078fSIntel if (l2fwd_rx_queue_per_lcore == 0) { 480af75078fSIntel printf("invalid queue number\n"); 481af75078fSIntel l2fwd_usage(prgname); 482af75078fSIntel return -1; 483af75078fSIntel } 484af75078fSIntel break; 485af75078fSIntel 486af75078fSIntel /* timer period */ 487af75078fSIntel case 'T': 4882412742cSJerin Jacob timer_secs = l2fwd_parse_timer_period(optarg); 4892412742cSJerin Jacob if (timer_secs < 0) { 490af75078fSIntel printf("invalid timer period\n"); 491af75078fSIntel l2fwd_usage(prgname); 492af75078fSIntel return -1; 493af75078fSIntel } 4942412742cSJerin Jacob timer_period = timer_secs; 495af75078fSIntel break; 496af75078fSIntel 497af75078fSIntel /* long options */ 498fa19eb20SVamsi Attunuru case CMD_LINE_OPT_PORTMAP_NUM: 499fa19eb20SVamsi Attunuru ret = l2fwd_parse_port_pair_config(optarg); 500fa19eb20SVamsi Attunuru if (ret) { 501fa19eb20SVamsi Attunuru fprintf(stderr, "Invalid config\n"); 502fa19eb20SVamsi Attunuru l2fwd_usage(prgname); 503fa19eb20SVamsi Attunuru return -1; 504fa19eb20SVamsi Attunuru } 505cf435a07SMaxime Coquelin break; 506af75078fSIntel 507*bbbe38a6SChenglian Sun case CMD_LINE_OPT_MAC_UPDATING_NUM: 508*bbbe38a6SChenglian Sun mac_updating = 1; 509*bbbe38a6SChenglian Sun break; 510*bbbe38a6SChenglian Sun 511*bbbe38a6SChenglian Sun case CMD_LINE_OPT_NO_MAC_UPDATING_NUM: 512*bbbe38a6SChenglian Sun mac_updating = 0; 513*bbbe38a6SChenglian Sun break; 514*bbbe38a6SChenglian Sun 515af75078fSIntel default: 516af75078fSIntel l2fwd_usage(prgname); 517af75078fSIntel return -1; 518af75078fSIntel } 519af75078fSIntel } 520af75078fSIntel 521af75078fSIntel if (optind >= 0) 522af75078fSIntel argv[optind-1] = prgname; 523af75078fSIntel 524af75078fSIntel ret = optind-1; 5259d5ca532SKeith Wiles optind = 1; /* reset getopt lib */ 526af75078fSIntel return ret; 527af75078fSIntel } 528af75078fSIntel 529fa19eb20SVamsi Attunuru /* 530fa19eb20SVamsi Attunuru * Check port pair config with enabled port mask, 531fa19eb20SVamsi Attunuru * and for valid port pair combinations. 532fa19eb20SVamsi Attunuru */ 533fa19eb20SVamsi Attunuru static int 534fa19eb20SVamsi Attunuru check_port_pair_config(void) 535fa19eb20SVamsi Attunuru { 536fa19eb20SVamsi Attunuru uint32_t port_pair_config_mask = 0; 537fa19eb20SVamsi Attunuru uint32_t port_pair_mask = 0; 538fa19eb20SVamsi Attunuru uint16_t index, i, portid; 539fa19eb20SVamsi Attunuru 540fa19eb20SVamsi Attunuru for (index = 0; index < nb_port_pair_params; index++) { 541fa19eb20SVamsi Attunuru port_pair_mask = 0; 542fa19eb20SVamsi Attunuru 543fa19eb20SVamsi Attunuru for (i = 0; i < NUM_PORTS; i++) { 544fa19eb20SVamsi Attunuru portid = port_pair_params[index].port[i]; 545fa19eb20SVamsi Attunuru if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) { 546fa19eb20SVamsi Attunuru printf("port %u is not enabled in port mask\n", 547fa19eb20SVamsi Attunuru portid); 548fa19eb20SVamsi Attunuru return -1; 549fa19eb20SVamsi Attunuru } 550fa19eb20SVamsi Attunuru if (!rte_eth_dev_is_valid_port(portid)) { 551fa19eb20SVamsi Attunuru printf("port %u is not present on the board\n", 552fa19eb20SVamsi Attunuru portid); 553fa19eb20SVamsi Attunuru return -1; 554fa19eb20SVamsi Attunuru } 555fa19eb20SVamsi Attunuru 556fa19eb20SVamsi Attunuru port_pair_mask |= 1 << portid; 557fa19eb20SVamsi Attunuru } 558fa19eb20SVamsi Attunuru 559fa19eb20SVamsi Attunuru if (port_pair_config_mask & port_pair_mask) { 560fa19eb20SVamsi Attunuru printf("port %u is used in other port pairs\n", portid); 561fa19eb20SVamsi Attunuru return -1; 562fa19eb20SVamsi Attunuru } 563fa19eb20SVamsi Attunuru port_pair_config_mask |= port_pair_mask; 564fa19eb20SVamsi Attunuru } 565fa19eb20SVamsi Attunuru 566fa19eb20SVamsi Attunuru l2fwd_enabled_port_mask &= port_pair_config_mask; 567fa19eb20SVamsi Attunuru 568fa19eb20SVamsi Attunuru return 0; 569fa19eb20SVamsi Attunuru } 570fa19eb20SVamsi Attunuru 571d3641ae8SIntel /* Check the link status of all ports in up to 9s, and print them finally */ 572d3641ae8SIntel static void 5738728ccf3SThomas Monjalon check_all_ports_link_status(uint32_t port_mask) 574d3641ae8SIntel { 575d3641ae8SIntel #define CHECK_INTERVAL 100 /* 100ms */ 576d3641ae8SIntel #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ 577f8244c63SZhiyong Yang uint16_t portid; 578f8244c63SZhiyong Yang uint8_t count, all_ports_up, print_flag = 0; 579d3641ae8SIntel struct rte_eth_link link; 58022e5c73bSIgor Romanov int ret; 581db4e8135SIvan Dyukov char link_status_text[RTE_ETH_LINK_MAX_STR_LEN]; 582d3641ae8SIntel 583d3641ae8SIntel printf("\nChecking link status"); 584d3641ae8SIntel fflush(stdout); 585d3641ae8SIntel for (count = 0; count <= MAX_CHECK_TIME; count++) { 58688908b61SZhihong Wang if (force_quit) 58788908b61SZhihong Wang return; 588d3641ae8SIntel all_ports_up = 1; 5898728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) { 59088908b61SZhihong Wang if (force_quit) 59188908b61SZhihong Wang return; 592d3641ae8SIntel if ((port_mask & (1 << portid)) == 0) 593d3641ae8SIntel continue; 594d3641ae8SIntel memset(&link, 0, sizeof(link)); 59522e5c73bSIgor Romanov ret = rte_eth_link_get_nowait(portid, &link); 59622e5c73bSIgor Romanov if (ret < 0) { 59722e5c73bSIgor Romanov all_ports_up = 0; 59822e5c73bSIgor Romanov if (print_flag == 1) 59922e5c73bSIgor Romanov printf("Port %u link get failed: %s\n", 60022e5c73bSIgor Romanov portid, rte_strerror(-ret)); 60122e5c73bSIgor Romanov continue; 60222e5c73bSIgor Romanov } 603d3641ae8SIntel /* print link status if flag set */ 604d3641ae8SIntel if (print_flag == 1) { 605db4e8135SIvan Dyukov rte_eth_link_to_str(link_status_text, 606db4e8135SIvan Dyukov sizeof(link_status_text), &link); 607db4e8135SIvan Dyukov printf("Port %d %s\n", portid, 608db4e8135SIvan Dyukov link_status_text); 609d3641ae8SIntel continue; 610d3641ae8SIntel } 611d3641ae8SIntel /* clear all_ports_up flag if any link down */ 61209419f23SThomas Monjalon if (link.link_status == ETH_LINK_DOWN) { 613d3641ae8SIntel all_ports_up = 0; 614d3641ae8SIntel break; 615d3641ae8SIntel } 616d3641ae8SIntel } 617d3641ae8SIntel /* after finally printing all link status, get out */ 618d3641ae8SIntel if (print_flag == 1) 619d3641ae8SIntel break; 620d3641ae8SIntel 621d3641ae8SIntel if (all_ports_up == 0) { 622d3641ae8SIntel printf("."); 623d3641ae8SIntel fflush(stdout); 624d3641ae8SIntel rte_delay_ms(CHECK_INTERVAL); 625d3641ae8SIntel } 626d3641ae8SIntel 627d3641ae8SIntel /* set the print_flag if all ports up or timeout */ 628d3641ae8SIntel if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { 629d3641ae8SIntel print_flag = 1; 630d3641ae8SIntel printf("done\n"); 631d3641ae8SIntel } 632d3641ae8SIntel } 633d3641ae8SIntel } 634d3641ae8SIntel 63588908b61SZhihong Wang static void 63688908b61SZhihong Wang signal_handler(int signum) 63788908b61SZhihong Wang { 63888908b61SZhihong Wang if (signum == SIGINT || signum == SIGTERM) { 63988908b61SZhihong Wang printf("\n\nSignal %d received, preparing to exit...\n", 64088908b61SZhihong Wang signum); 64188908b61SZhihong Wang force_quit = true; 64288908b61SZhihong Wang } 64388908b61SZhihong Wang } 64488908b61SZhihong Wang 645af75078fSIntel int 64698a16481SDavid Marchand main(int argc, char **argv) 647af75078fSIntel { 648af75078fSIntel struct lcore_queue_conf *qconf; 649af75078fSIntel int ret; 650f8244c63SZhiyong Yang uint16_t nb_ports; 6518728ccf3SThomas Monjalon uint16_t nb_ports_available = 0; 652f8244c63SZhiyong Yang uint16_t portid, last_port; 653af75078fSIntel unsigned lcore_id, rx_lcore_id; 654af75078fSIntel unsigned nb_ports_in_mask = 0; 6550b0ceb98SPavan Nikhilesh unsigned int nb_lcores = 0; 6560b0ceb98SPavan Nikhilesh unsigned int nb_mbufs; 657af75078fSIntel 658af75078fSIntel /* init EAL */ 659af75078fSIntel ret = rte_eal_init(argc, argv); 660af75078fSIntel if (ret < 0) 661af75078fSIntel rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n"); 662af75078fSIntel argc -= ret; 663af75078fSIntel argv += ret; 664af75078fSIntel 66588908b61SZhihong Wang force_quit = false; 66688908b61SZhihong Wang signal(SIGINT, signal_handler); 66788908b61SZhihong Wang signal(SIGTERM, signal_handler); 66888908b61SZhihong Wang 669af75078fSIntel /* parse application arguments (after the EAL ones) */ 670af75078fSIntel ret = l2fwd_parse_args(argc, argv); 671af75078fSIntel if (ret < 0) 672af75078fSIntel rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n"); 673af75078fSIntel 674cf435a07SMaxime Coquelin printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled"); 675cf435a07SMaxime Coquelin 6762412742cSJerin Jacob /* convert to number of cycles */ 6772412742cSJerin Jacob timer_period *= rte_get_timer_hz(); 6782412742cSJerin Jacob 679d9a42a69SThomas Monjalon nb_ports = rte_eth_dev_count_avail(); 680af75078fSIntel if (nb_ports == 0) 681af75078fSIntel rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n"); 682af75078fSIntel 683fa19eb20SVamsi Attunuru if (port_pair_params != NULL) { 684fa19eb20SVamsi Attunuru if (check_port_pair_config() < 0) 685fa19eb20SVamsi Attunuru rte_exit(EXIT_FAILURE, "Invalid port pair config\n"); 686fa19eb20SVamsi Attunuru } 687fa19eb20SVamsi Attunuru 68867265219SVipin Varghese /* check port mask to possible port mask */ 68967265219SVipin Varghese if (l2fwd_enabled_port_mask & ~((1 << nb_ports) - 1)) 69067265219SVipin Varghese rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n", 69167265219SVipin Varghese (1 << nb_ports) - 1); 69267265219SVipin Varghese 693af75078fSIntel /* reset l2fwd_dst_ports */ 6941c17baf4SIntel for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) 695af75078fSIntel l2fwd_dst_ports[portid] = 0; 696af75078fSIntel last_port = 0; 697af75078fSIntel 698fa19eb20SVamsi Attunuru /* populate destination port details */ 699fa19eb20SVamsi Attunuru if (port_pair_params != NULL) { 700fa19eb20SVamsi Attunuru uint16_t idx, p; 701fa19eb20SVamsi Attunuru 702fa19eb20SVamsi Attunuru for (idx = 0; idx < (nb_port_pair_params << 1); idx++) { 703fa19eb20SVamsi Attunuru p = idx & 1; 704fa19eb20SVamsi Attunuru portid = port_pair_params[idx >> 1].port[p]; 705fa19eb20SVamsi Attunuru l2fwd_dst_ports[portid] = 706fa19eb20SVamsi Attunuru port_pair_params[idx >> 1].port[p ^ 1]; 707fa19eb20SVamsi Attunuru } 708fa19eb20SVamsi Attunuru } else { 7098728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) { 710af75078fSIntel /* skip ports that are not enabled */ 711af75078fSIntel if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 712af75078fSIntel continue; 713af75078fSIntel 714af75078fSIntel if (nb_ports_in_mask % 2) { 715af75078fSIntel l2fwd_dst_ports[portid] = last_port; 716af75078fSIntel l2fwd_dst_ports[last_port] = portid; 717fa19eb20SVamsi Attunuru } else { 718af75078fSIntel last_port = portid; 719fa19eb20SVamsi Attunuru } 720af75078fSIntel 721af75078fSIntel nb_ports_in_mask++; 722af75078fSIntel } 723f56d0815SIntel if (nb_ports_in_mask % 2) { 72416ac9cf0SIntel printf("Notice: odd number of ports in portmask.\n"); 72516ac9cf0SIntel l2fwd_dst_ports[last_port] = last_port; 726af75078fSIntel } 727fa19eb20SVamsi Attunuru } 728af75078fSIntel 729af75078fSIntel rx_lcore_id = 0; 730af75078fSIntel qconf = NULL; 731af75078fSIntel 732af75078fSIntel /* Initialize the port/queue configuration of each logical core */ 7338728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) { 734af75078fSIntel /* skip ports that are not enabled */ 735af75078fSIntel if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 736af75078fSIntel continue; 737af75078fSIntel 738af75078fSIntel /* get the lcore_id for this port */ 739af75078fSIntel while (rte_lcore_is_enabled(rx_lcore_id) == 0 || 74016ac9cf0SIntel lcore_queue_conf[rx_lcore_id].n_rx_port == 741af75078fSIntel l2fwd_rx_queue_per_lcore) { 742af75078fSIntel rx_lcore_id++; 743af75078fSIntel if (rx_lcore_id >= RTE_MAX_LCORE) 744af75078fSIntel rte_exit(EXIT_FAILURE, "Not enough cores\n"); 745af75078fSIntel } 74616ac9cf0SIntel 7470b0ceb98SPavan Nikhilesh if (qconf != &lcore_queue_conf[rx_lcore_id]) { 748af75078fSIntel /* Assigned a new logical core in the loop above. */ 749af75078fSIntel qconf = &lcore_queue_conf[rx_lcore_id]; 7500b0ceb98SPavan Nikhilesh nb_lcores++; 7510b0ceb98SPavan Nikhilesh } 75216ac9cf0SIntel 75316ac9cf0SIntel qconf->rx_port_list[qconf->n_rx_port] = portid; 75416ac9cf0SIntel qconf->n_rx_port++; 755fa19eb20SVamsi Attunuru printf("Lcore %u: RX port %u TX port %u\n", rx_lcore_id, 756fa19eb20SVamsi Attunuru portid, l2fwd_dst_ports[portid]); 757af75078fSIntel } 758af75078fSIntel 7590b0ceb98SPavan Nikhilesh nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST + 7600b0ceb98SPavan Nikhilesh nb_lcores * MEMPOOL_CACHE_SIZE), 8192U); 7610b0ceb98SPavan Nikhilesh 7620b0ceb98SPavan Nikhilesh /* create the mbuf pool */ 7630b0ceb98SPavan Nikhilesh l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs, 7640b0ceb98SPavan Nikhilesh MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, 7650b0ceb98SPavan Nikhilesh rte_socket_id()); 7660b0ceb98SPavan Nikhilesh if (l2fwd_pktmbuf_pool == NULL) 7670b0ceb98SPavan Nikhilesh rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n"); 7680b0ceb98SPavan Nikhilesh 769af75078fSIntel /* Initialise each port */ 7708728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) { 77175d7f266SShahaf Shuler struct rte_eth_rxconf rxq_conf; 77275d7f266SShahaf Shuler struct rte_eth_txconf txq_conf; 77375d7f266SShahaf Shuler struct rte_eth_conf local_port_conf = port_conf; 77475d7f266SShahaf Shuler struct rte_eth_dev_info dev_info; 77575d7f266SShahaf Shuler 776af75078fSIntel /* skip ports that are not enabled */ 777af75078fSIntel if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) { 778f8244c63SZhiyong Yang printf("Skipping disabled port %u\n", portid); 779af75078fSIntel continue; 780af75078fSIntel } 7818728ccf3SThomas Monjalon nb_ports_available++; 7828728ccf3SThomas Monjalon 783af75078fSIntel /* init port */ 784f8244c63SZhiyong Yang printf("Initializing port %u... ", portid); 785af75078fSIntel fflush(stdout); 786089e5ed7SIvan Ilchenko 787089e5ed7SIvan Ilchenko ret = rte_eth_dev_info_get(portid, &dev_info); 788089e5ed7SIvan Ilchenko if (ret != 0) 789089e5ed7SIvan Ilchenko rte_exit(EXIT_FAILURE, 790089e5ed7SIvan Ilchenko "Error during getting device (port %u) info: %s\n", 791089e5ed7SIvan Ilchenko portid, strerror(-ret)); 792089e5ed7SIvan Ilchenko 79375d7f266SShahaf Shuler if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) 79475d7f266SShahaf Shuler local_port_conf.txmode.offloads |= 79575d7f266SShahaf Shuler DEV_TX_OFFLOAD_MBUF_FAST_FREE; 79675d7f266SShahaf Shuler ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf); 797af75078fSIntel if (ret < 0) 79816ac9cf0SIntel rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n", 799f8244c63SZhiyong Yang ret, portid); 800af75078fSIntel 80160efb44fSRoman Zhukov ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, 80260efb44fSRoman Zhukov &nb_txd); 80360efb44fSRoman Zhukov if (ret < 0) 80460efb44fSRoman Zhukov rte_exit(EXIT_FAILURE, 80560efb44fSRoman Zhukov "Cannot adjust number of descriptors: err=%d, port=%u\n", 806f8244c63SZhiyong Yang ret, portid); 80760efb44fSRoman Zhukov 80870febdcfSIgor Romanov ret = rte_eth_macaddr_get(portid, 80970febdcfSIgor Romanov &l2fwd_ports_eth_addr[portid]); 81070febdcfSIgor Romanov if (ret < 0) 81170febdcfSIgor Romanov rte_exit(EXIT_FAILURE, 81270febdcfSIgor Romanov "Cannot get MAC address: err=%d, port=%u\n", 81370febdcfSIgor Romanov ret, portid); 814af75078fSIntel 815af75078fSIntel /* init one RX queue */ 816af75078fSIntel fflush(stdout); 81775d7f266SShahaf Shuler rxq_conf = dev_info.default_rxconf; 81875d7f266SShahaf Shuler rxq_conf.offloads = local_port_conf.rxmode.offloads; 819a974564bSIntel ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd, 82081f7ecd9SPablo de Lara rte_eth_dev_socket_id(portid), 82175d7f266SShahaf Shuler &rxq_conf, 822af75078fSIntel l2fwd_pktmbuf_pool); 823af75078fSIntel if (ret < 0) 824a974564bSIntel rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n", 825f8244c63SZhiyong Yang ret, portid); 826af75078fSIntel 827e60f71ebSIntel /* init one TX queue on each port */ 828af75078fSIntel fflush(stdout); 82975d7f266SShahaf Shuler txq_conf = dev_info.default_txconf; 83075d7f266SShahaf Shuler txq_conf.offloads = local_port_conf.txmode.offloads; 831a974564bSIntel ret = rte_eth_tx_queue_setup(portid, 0, nb_txd, 83281f7ecd9SPablo de Lara rte_eth_dev_socket_id(portid), 83375d7f266SShahaf Shuler &txq_conf); 834af75078fSIntel if (ret < 0) 83516ac9cf0SIntel rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n", 836f8244c63SZhiyong Yang ret, portid); 837af75078fSIntel 838e2366e74STomasz Kulasek /* Initialize TX buffers */ 839e2366e74STomasz Kulasek tx_buffer[portid] = rte_zmalloc_socket("tx_buffer", 840e2366e74STomasz Kulasek RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0, 841e2366e74STomasz Kulasek rte_eth_dev_socket_id(portid)); 842e2366e74STomasz Kulasek if (tx_buffer[portid] == NULL) 843e2366e74STomasz Kulasek rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n", 844f8244c63SZhiyong Yang portid); 845e2366e74STomasz Kulasek 846e2366e74STomasz Kulasek rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST); 847e2366e74STomasz Kulasek 848e2366e74STomasz Kulasek ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid], 849e2366e74STomasz Kulasek rte_eth_tx_buffer_count_callback, 850e2366e74STomasz Kulasek &port_statistics[portid].dropped); 851e2366e74STomasz Kulasek if (ret < 0) 852f8244c63SZhiyong Yang rte_exit(EXIT_FAILURE, 853f8244c63SZhiyong Yang "Cannot set error callback for tx buffer on port %u\n", 854f8244c63SZhiyong Yang portid); 855e2366e74STomasz Kulasek 8569731df2eSPavan Nikhilesh ret = rte_eth_dev_set_ptypes(portid, RTE_PTYPE_UNKNOWN, NULL, 8579731df2eSPavan Nikhilesh 0); 8589731df2eSPavan Nikhilesh if (ret < 0) 8599731df2eSPavan Nikhilesh printf("Port %u, Failed to disable Ptype parsing\n", 8609731df2eSPavan Nikhilesh portid); 861af75078fSIntel /* Start device */ 862a974564bSIntel ret = rte_eth_dev_start(portid); 863af75078fSIntel if (ret < 0) 86416ac9cf0SIntel rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n", 865f8244c63SZhiyong Yang ret, portid); 866af75078fSIntel 867d3641ae8SIntel printf("done: \n"); 868af75078fSIntel 869f430bbceSIvan Ilchenko ret = rte_eth_promiscuous_enable(portid); 870f430bbceSIvan Ilchenko if (ret != 0) 871f430bbceSIvan Ilchenko rte_exit(EXIT_FAILURE, 872f430bbceSIvan Ilchenko "rte_eth_promiscuous_enable:err=%s, port=%u\n", 873f430bbceSIvan Ilchenko rte_strerror(-ret), portid); 874af75078fSIntel 875af75078fSIntel printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n", 876f8244c63SZhiyong Yang portid, 877af75078fSIntel l2fwd_ports_eth_addr[portid].addr_bytes[0], 878af75078fSIntel l2fwd_ports_eth_addr[portid].addr_bytes[1], 879af75078fSIntel l2fwd_ports_eth_addr[portid].addr_bytes[2], 880af75078fSIntel l2fwd_ports_eth_addr[portid].addr_bytes[3], 881af75078fSIntel l2fwd_ports_eth_addr[portid].addr_bytes[4], 882af75078fSIntel l2fwd_ports_eth_addr[portid].addr_bytes[5]); 883af75078fSIntel 884af75078fSIntel /* initialize port stats */ 885af75078fSIntel memset(&port_statistics, 0, sizeof(port_statistics)); 886af75078fSIntel } 887af75078fSIntel 888f56d0815SIntel if (!nb_ports_available) { 889f56d0815SIntel rte_exit(EXIT_FAILURE, 890f56d0815SIntel "All available ports are disabled. Please set portmask.\n"); 891f56d0815SIntel } 892f56d0815SIntel 8938728ccf3SThomas Monjalon check_all_ports_link_status(l2fwd_enabled_port_mask); 894d3641ae8SIntel 89588908b61SZhihong Wang ret = 0; 896af75078fSIntel /* launch per-lcore init on every lcore */ 897cb056611SStephen Hemminger rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MAIN); 898cb056611SStephen Hemminger RTE_LCORE_FOREACH_WORKER(lcore_id) { 89988908b61SZhihong Wang if (rte_eal_wait_lcore(lcore_id) < 0) { 90088908b61SZhihong Wang ret = -1; 90188908b61SZhihong Wang break; 90288908b61SZhihong Wang } 903af75078fSIntel } 904af75078fSIntel 9058728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) { 90688908b61SZhihong Wang if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 90788908b61SZhihong Wang continue; 90888908b61SZhihong Wang printf("Closing port %d...", portid); 909b55efbabSIvan Ilchenko ret = rte_eth_dev_stop(portid); 910b55efbabSIvan Ilchenko if (ret != 0) 911b55efbabSIvan Ilchenko printf("rte_eth_dev_stop: err=%d, port=%d\n", 912b55efbabSIvan Ilchenko ret, portid); 91388908b61SZhihong Wang rte_eth_dev_close(portid); 91488908b61SZhihong Wang printf(" Done\n"); 91588908b61SZhihong Wang } 91610aa3757SChengchang Tang 91710aa3757SChengchang Tang /* clean up the EAL */ 91810aa3757SChengchang Tang rte_eal_cleanup(); 91988908b61SZhihong Wang printf("Bye...\n"); 92088908b61SZhihong Wang 92188908b61SZhihong Wang return ret; 922af75078fSIntel } 923