1af75078fSIntel /*- 2af75078fSIntel * BSD LICENSE 3af75078fSIntel * 4b6df9fc8SIntel * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. 5af75078fSIntel * All rights reserved. 6af75078fSIntel * 7af75078fSIntel * Redistribution and use in source and binary forms, with or without 8af75078fSIntel * modification, are permitted provided that the following conditions 9af75078fSIntel * are met: 10af75078fSIntel * 11af75078fSIntel * * Redistributions of source code must retain the above copyright 12af75078fSIntel * notice, this list of conditions and the following disclaimer. 13af75078fSIntel * * Redistributions in binary form must reproduce the above copyright 14af75078fSIntel * notice, this list of conditions and the following disclaimer in 15af75078fSIntel * the documentation and/or other materials provided with the 16af75078fSIntel * distribution. 17af75078fSIntel * * Neither the name of Intel Corporation nor the names of its 18af75078fSIntel * contributors may be used to endorse or promote products derived 19af75078fSIntel * from this software without specific prior written permission. 20af75078fSIntel * 21af75078fSIntel * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22af75078fSIntel * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23af75078fSIntel * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24af75078fSIntel * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25af75078fSIntel * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26af75078fSIntel * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27af75078fSIntel * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28af75078fSIntel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29af75078fSIntel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30af75078fSIntel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31af75078fSIntel * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32af75078fSIntel */ 33af75078fSIntel 34af75078fSIntel #include <stdio.h> 35af75078fSIntel #include <stdlib.h> 36af75078fSIntel #include <string.h> 37af75078fSIntel #include <stdint.h> 38af75078fSIntel #include <inttypes.h> 39af75078fSIntel #include <sys/types.h> 40af75078fSIntel #include <sys/queue.h> 41af75078fSIntel #include <netinet/in.h> 42af75078fSIntel #include <setjmp.h> 43af75078fSIntel #include <stdarg.h> 44af75078fSIntel #include <ctype.h> 45af75078fSIntel #include <errno.h> 46af75078fSIntel #include <getopt.h> 47af75078fSIntel 48af75078fSIntel #include <rte_common.h> 49af75078fSIntel #include <rte_log.h> 50af75078fSIntel #include <rte_memory.h> 51af75078fSIntel #include <rte_memcpy.h> 52af75078fSIntel #include <rte_memzone.h> 53af75078fSIntel #include <rte_tailq.h> 54af75078fSIntel #include <rte_eal.h> 55af75078fSIntel #include <rte_per_lcore.h> 56af75078fSIntel #include <rte_launch.h> 57af75078fSIntel #include <rte_atomic.h> 58af75078fSIntel #include <rte_cycles.h> 59af75078fSIntel #include <rte_prefetch.h> 60af75078fSIntel #include <rte_lcore.h> 61af75078fSIntel #include <rte_per_lcore.h> 62af75078fSIntel #include <rte_branch_prediction.h> 63af75078fSIntel #include <rte_interrupts.h> 64af75078fSIntel #include <rte_pci.h> 65af75078fSIntel #include <rte_random.h> 66af75078fSIntel #include <rte_debug.h> 67af75078fSIntel #include <rte_ether.h> 68af75078fSIntel #include <rte_ethdev.h> 69af75078fSIntel #include <rte_ring.h> 70af75078fSIntel #include <rte_mempool.h> 71af75078fSIntel #include <rte_mbuf.h> 72af75078fSIntel 73af75078fSIntel #include "main.h" 74af75078fSIntel 75af75078fSIntel #define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1 76af75078fSIntel 77af75078fSIntel #define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) 78af75078fSIntel #define NB_MBUF 8192 79af75078fSIntel 80af75078fSIntel /* 81af75078fSIntel * RX and TX Prefetch, Host, and Write-back threshold values should be 82af75078fSIntel * carefully set for optimal performance. Consult the network 83af75078fSIntel * controller's datasheet and supporting DPDK documentation for guidance 84af75078fSIntel * on how these parameters should be set. 85af75078fSIntel */ 86af75078fSIntel #define RX_PTHRESH 8 /**< Default values of RX prefetch threshold reg. */ 87af75078fSIntel #define RX_HTHRESH 8 /**< Default values of RX host threshold reg. */ 88af75078fSIntel #define RX_WTHRESH 4 /**< Default values of RX write-back threshold reg. */ 89af75078fSIntel 90af75078fSIntel /* 91af75078fSIntel * These default values are optimized for use with the Intel(R) 82599 10 GbE 92af75078fSIntel * Controller and the DPDK ixgbe PMD. Consider using other values for other 93af75078fSIntel * network controllers and/or network drivers. 94af75078fSIntel */ 95af75078fSIntel #define TX_PTHRESH 36 /**< Default values of TX prefetch threshold reg. */ 96af75078fSIntel #define TX_HTHRESH 0 /**< Default values of TX host threshold reg. */ 97af75078fSIntel #define TX_WTHRESH 0 /**< Default values of TX write-back threshold reg. */ 98af75078fSIntel 99af75078fSIntel #define MAX_PKT_BURST 32 1005c95261dSIntel #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */ 101af75078fSIntel 102af75078fSIntel /* 103af75078fSIntel * Configurable number of RX/TX ring descriptors 104af75078fSIntel */ 105af75078fSIntel #define RTE_TEST_RX_DESC_DEFAULT 128 106af75078fSIntel #define RTE_TEST_TX_DESC_DEFAULT 512 107af75078fSIntel static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; 108af75078fSIntel static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; 109af75078fSIntel 110af75078fSIntel /* ethernet addresses of ports */ 1111c17baf4SIntel static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS]; 112af75078fSIntel 113af75078fSIntel /* mask of enabled ports */ 114af75078fSIntel static uint32_t l2fwd_enabled_port_mask = 0; 115af75078fSIntel 116af75078fSIntel /* list of enabled ports */ 1171c17baf4SIntel static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS]; 118af75078fSIntel 119af75078fSIntel static unsigned int l2fwd_rx_queue_per_lcore = 1; 120af75078fSIntel 121af75078fSIntel struct mbuf_table { 122af75078fSIntel unsigned len; 123af75078fSIntel struct rte_mbuf *m_table[MAX_PKT_BURST]; 124af75078fSIntel }; 125af75078fSIntel 126af75078fSIntel #define MAX_RX_QUEUE_PER_LCORE 16 127af75078fSIntel #define MAX_TX_QUEUE_PER_PORT 16 128af75078fSIntel struct lcore_queue_conf { 12916ac9cf0SIntel unsigned n_rx_port; 13016ac9cf0SIntel unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE]; 1311c17baf4SIntel struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS]; 132af75078fSIntel 133af75078fSIntel } __rte_cache_aligned; 134af75078fSIntel struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE]; 135af75078fSIntel 136af75078fSIntel static const struct rte_eth_conf port_conf = { 137af75078fSIntel .rxmode = { 138af75078fSIntel .split_hdr_size = 0, 139af75078fSIntel .header_split = 0, /**< Header Split disabled */ 140af75078fSIntel .hw_ip_checksum = 0, /**< IP checksum offload disabled */ 141af75078fSIntel .hw_vlan_filter = 0, /**< VLAN filtering disabled */ 142af75078fSIntel .jumbo_frame = 0, /**< Jumbo Frame Support disabled */ 143af75078fSIntel .hw_strip_crc = 0, /**< CRC stripped by hardware */ 144af75078fSIntel }, 145af75078fSIntel .txmode = { 14632e7aa0bSIntel .mq_mode = ETH_MQ_TX_NONE, 147af75078fSIntel }, 148af75078fSIntel }; 149af75078fSIntel 150af75078fSIntel static const struct rte_eth_rxconf rx_conf = { 151af75078fSIntel .rx_thresh = { 152af75078fSIntel .pthresh = RX_PTHRESH, 153af75078fSIntel .hthresh = RX_HTHRESH, 154af75078fSIntel .wthresh = RX_WTHRESH, 155af75078fSIntel }, 156af75078fSIntel }; 157af75078fSIntel 158af75078fSIntel static const struct rte_eth_txconf tx_conf = { 159af75078fSIntel .tx_thresh = { 160af75078fSIntel .pthresh = TX_PTHRESH, 161af75078fSIntel .hthresh = TX_HTHRESH, 162af75078fSIntel .wthresh = TX_WTHRESH, 163af75078fSIntel }, 164af75078fSIntel .tx_free_thresh = 0, /* Use PMD default values */ 165af75078fSIntel .tx_rs_thresh = 0, /* Use PMD default values */ 166af75078fSIntel }; 167af75078fSIntel 168af75078fSIntel struct rte_mempool * l2fwd_pktmbuf_pool = NULL; 169af75078fSIntel 170af75078fSIntel /* Per-port statistics struct */ 171af75078fSIntel struct l2fwd_port_statistics { 172af75078fSIntel uint64_t tx; 173af75078fSIntel uint64_t rx; 174af75078fSIntel uint64_t dropped; 175af75078fSIntel } __rte_cache_aligned; 1761c17baf4SIntel struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS]; 177af75078fSIntel 178af75078fSIntel /* A tsc-based timer responsible for triggering statistics printout */ 179af75078fSIntel #define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */ 180af75078fSIntel #define MAX_TIMER_PERIOD 86400 /* 1 day max */ 181af75078fSIntel static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000; /* default period is 10 seconds */ 182af75078fSIntel 183af75078fSIntel /* Print out statistics on packets dropped */ 184af75078fSIntel static void 185af75078fSIntel print_stats(void) 186af75078fSIntel { 187af75078fSIntel uint64_t total_packets_dropped, total_packets_tx, total_packets_rx; 188af75078fSIntel unsigned portid; 189af75078fSIntel 190af75078fSIntel total_packets_dropped = 0; 191af75078fSIntel total_packets_tx = 0; 192af75078fSIntel total_packets_rx = 0; 193af75078fSIntel 194af75078fSIntel const char clr[] = { 27, '[', '2', 'J', '\0' }; 195af75078fSIntel const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' }; 196af75078fSIntel 197af75078fSIntel /* Clear screen and move to top left */ 198af75078fSIntel printf("%s%s", clr, topLeft); 199af75078fSIntel 200af75078fSIntel printf("\nPort statistics ===================================="); 201af75078fSIntel 2021c17baf4SIntel for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { 203af75078fSIntel /* skip disabled ports */ 204af75078fSIntel if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 205af75078fSIntel continue; 206af75078fSIntel printf("\nStatistics for port %u ------------------------------" 207af75078fSIntel "\nPackets sent: %24"PRIu64 208af75078fSIntel "\nPackets received: %20"PRIu64 209af75078fSIntel "\nPackets dropped: %21"PRIu64, 210af75078fSIntel portid, 211af75078fSIntel port_statistics[portid].tx, 212af75078fSIntel port_statistics[portid].rx, 213af75078fSIntel port_statistics[portid].dropped); 214af75078fSIntel 215af75078fSIntel total_packets_dropped += port_statistics[portid].dropped; 216af75078fSIntel total_packets_tx += port_statistics[portid].tx; 217af75078fSIntel total_packets_rx += port_statistics[portid].rx; 218af75078fSIntel } 219af75078fSIntel printf("\nAggregate statistics ===============================" 220af75078fSIntel "\nTotal packets sent: %18"PRIu64 221af75078fSIntel "\nTotal packets received: %14"PRIu64 222af75078fSIntel "\nTotal packets dropped: %15"PRIu64, 223af75078fSIntel total_packets_tx, 224af75078fSIntel total_packets_rx, 225af75078fSIntel total_packets_dropped); 226af75078fSIntel printf("\n====================================================\n"); 227af75078fSIntel } 228af75078fSIntel 229*9787d22fSIntel /* Send the burst of packets on an output interface */ 230af75078fSIntel static int 231af75078fSIntel l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port) 232af75078fSIntel { 233af75078fSIntel struct rte_mbuf **m_table; 234af75078fSIntel unsigned ret; 23516ac9cf0SIntel unsigned queueid =0; 236af75078fSIntel 237af75078fSIntel m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table; 238af75078fSIntel 239af75078fSIntel ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n); 240af75078fSIntel port_statistics[port].tx += ret; 241af75078fSIntel if (unlikely(ret < n)) { 242af75078fSIntel port_statistics[port].dropped += (n - ret); 243af75078fSIntel do { 244af75078fSIntel rte_pktmbuf_free(m_table[ret]); 245af75078fSIntel } while (++ret < n); 246af75078fSIntel } 247af75078fSIntel 248af75078fSIntel return 0; 249af75078fSIntel } 250af75078fSIntel 251*9787d22fSIntel /* Enqueue packets for TX and prepare them to be sent */ 252af75078fSIntel static int 253af75078fSIntel l2fwd_send_packet(struct rte_mbuf *m, uint8_t port) 254af75078fSIntel { 255af75078fSIntel unsigned lcore_id, len; 256af75078fSIntel struct lcore_queue_conf *qconf; 257af75078fSIntel 258af75078fSIntel lcore_id = rte_lcore_id(); 259af75078fSIntel 260af75078fSIntel qconf = &lcore_queue_conf[lcore_id]; 261af75078fSIntel len = qconf->tx_mbufs[port].len; 262af75078fSIntel qconf->tx_mbufs[port].m_table[len] = m; 263af75078fSIntel len++; 264af75078fSIntel 265af75078fSIntel /* enough pkts to be sent */ 266af75078fSIntel if (unlikely(len == MAX_PKT_BURST)) { 267af75078fSIntel l2fwd_send_burst(qconf, MAX_PKT_BURST, port); 268af75078fSIntel len = 0; 269af75078fSIntel } 270af75078fSIntel 271af75078fSIntel qconf->tx_mbufs[port].len = len; 272af75078fSIntel return 0; 273af75078fSIntel } 274af75078fSIntel 275af75078fSIntel static void 276af75078fSIntel l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid) 277af75078fSIntel { 278af75078fSIntel struct ether_hdr *eth; 279af75078fSIntel void *tmp; 280af75078fSIntel unsigned dst_port; 281af75078fSIntel 282af75078fSIntel dst_port = l2fwd_dst_ports[portid]; 283af75078fSIntel eth = rte_pktmbuf_mtod(m, struct ether_hdr *); 284af75078fSIntel 28516ac9cf0SIntel /* 02:00:00:00:00:xx */ 286af75078fSIntel tmp = ð->d_addr.addr_bytes[0]; 28716ac9cf0SIntel *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40); 288af75078fSIntel 289af75078fSIntel /* src addr */ 290af75078fSIntel ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], ð->s_addr); 291af75078fSIntel 292af75078fSIntel l2fwd_send_packet(m, (uint8_t) dst_port); 293af75078fSIntel } 294af75078fSIntel 295af75078fSIntel /* main processing loop */ 296af75078fSIntel static void 297af75078fSIntel l2fwd_main_loop(void) 298af75078fSIntel { 299af75078fSIntel struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; 300af75078fSIntel struct rte_mbuf *m; 301af75078fSIntel unsigned lcore_id; 3025c95261dSIntel uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc; 303af75078fSIntel unsigned i, j, portid, nb_rx; 304af75078fSIntel struct lcore_queue_conf *qconf; 3055c95261dSIntel const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US; 306af75078fSIntel 3075c95261dSIntel prev_tsc = 0; 308af75078fSIntel timer_tsc = 0; 309af75078fSIntel 310af75078fSIntel lcore_id = rte_lcore_id(); 311af75078fSIntel qconf = &lcore_queue_conf[lcore_id]; 312af75078fSIntel 31316ac9cf0SIntel if (qconf->n_rx_port == 0) { 314af75078fSIntel RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id); 315cdfd5dbbSIntel return; 316af75078fSIntel } 317af75078fSIntel 318af75078fSIntel RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id); 319af75078fSIntel 32016ac9cf0SIntel for (i = 0; i < qconf->n_rx_port; i++) { 321af75078fSIntel 32216ac9cf0SIntel portid = qconf->rx_port_list[i]; 323af75078fSIntel RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id, 324af75078fSIntel portid); 325af75078fSIntel } 326af75078fSIntel 327af75078fSIntel while (1) { 328af75078fSIntel 329af75078fSIntel cur_tsc = rte_rdtsc(); 330af75078fSIntel 331af75078fSIntel /* 332af75078fSIntel * TX burst queue drain 333af75078fSIntel */ 334af75078fSIntel diff_tsc = cur_tsc - prev_tsc; 3355c95261dSIntel if (unlikely(diff_tsc > drain_tsc)) { 336af75078fSIntel 3371c17baf4SIntel for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { 338af75078fSIntel if (qconf->tx_mbufs[portid].len == 0) 339af75078fSIntel continue; 340af75078fSIntel l2fwd_send_burst(&lcore_queue_conf[lcore_id], 341af75078fSIntel qconf->tx_mbufs[portid].len, 342af75078fSIntel (uint8_t) portid); 343af75078fSIntel qconf->tx_mbufs[portid].len = 0; 344af75078fSIntel } 345af75078fSIntel 346af75078fSIntel /* if timer is enabled */ 347af75078fSIntel if (timer_period > 0) { 348af75078fSIntel 349af75078fSIntel /* advance the timer */ 350af75078fSIntel timer_tsc += diff_tsc; 351af75078fSIntel 352af75078fSIntel /* if timer has reached its timeout */ 353af75078fSIntel if (unlikely(timer_tsc >= (uint64_t) timer_period)) { 354af75078fSIntel 355af75078fSIntel /* do this only on master core */ 356af75078fSIntel if (lcore_id == rte_get_master_lcore()) { 357af75078fSIntel print_stats(); 358af75078fSIntel /* reset the timer */ 359af75078fSIntel timer_tsc = 0; 360af75078fSIntel } 361af75078fSIntel } 362af75078fSIntel } 363af75078fSIntel 364af75078fSIntel prev_tsc = cur_tsc; 365af75078fSIntel } 366af75078fSIntel 367af75078fSIntel /* 368af75078fSIntel * Read packet from RX queues 369af75078fSIntel */ 37016ac9cf0SIntel for (i = 0; i < qconf->n_rx_port; i++) { 371af75078fSIntel 37216ac9cf0SIntel portid = qconf->rx_port_list[i]; 373af75078fSIntel nb_rx = rte_eth_rx_burst((uint8_t) portid, 0, 374af75078fSIntel pkts_burst, MAX_PKT_BURST); 375af75078fSIntel 376af75078fSIntel port_statistics[portid].rx += nb_rx; 377af75078fSIntel 378af75078fSIntel for (j = 0; j < nb_rx; j++) { 379af75078fSIntel m = pkts_burst[j]; 380af75078fSIntel rte_prefetch0(rte_pktmbuf_mtod(m, void *)); 381af75078fSIntel l2fwd_simple_forward(m, portid); 382af75078fSIntel } 383af75078fSIntel } 384af75078fSIntel } 385af75078fSIntel } 386af75078fSIntel 387af75078fSIntel static int 388af75078fSIntel l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy) 389af75078fSIntel { 390af75078fSIntel l2fwd_main_loop(); 391af75078fSIntel return 0; 392af75078fSIntel } 393af75078fSIntel 394af75078fSIntel /* display usage */ 395af75078fSIntel static void 396af75078fSIntel l2fwd_usage(const char *prgname) 397af75078fSIntel { 398af75078fSIntel printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n" 399af75078fSIntel " -p PORTMASK: hexadecimal bitmask of ports to configure\n" 400af75078fSIntel " -q NQ: number of queue (=ports) per lcore (default is 1)\n" 401af75078fSIntel " -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n", 402af75078fSIntel prgname); 403af75078fSIntel } 404af75078fSIntel 405af75078fSIntel static int 406af75078fSIntel l2fwd_parse_portmask(const char *portmask) 407af75078fSIntel { 408af75078fSIntel char *end = NULL; 409af75078fSIntel unsigned long pm; 410af75078fSIntel 411af75078fSIntel /* parse hexadecimal string */ 412af75078fSIntel pm = strtoul(portmask, &end, 16); 413af75078fSIntel if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) 414af75078fSIntel return -1; 415af75078fSIntel 416af75078fSIntel if (pm == 0) 417af75078fSIntel return -1; 418af75078fSIntel 419af75078fSIntel return pm; 420af75078fSIntel } 421af75078fSIntel 422af75078fSIntel static unsigned int 423af75078fSIntel l2fwd_parse_nqueue(const char *q_arg) 424af75078fSIntel { 425af75078fSIntel char *end = NULL; 426af75078fSIntel unsigned long n; 427af75078fSIntel 428af75078fSIntel /* parse hexadecimal string */ 429af75078fSIntel n = strtoul(q_arg, &end, 10); 430af75078fSIntel if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 431af75078fSIntel return 0; 432af75078fSIntel if (n == 0) 433af75078fSIntel return 0; 434af75078fSIntel if (n >= MAX_RX_QUEUE_PER_LCORE) 435af75078fSIntel return 0; 436af75078fSIntel 437af75078fSIntel return n; 438af75078fSIntel } 439af75078fSIntel 440af75078fSIntel static int 441af75078fSIntel l2fwd_parse_timer_period(const char *q_arg) 442af75078fSIntel { 443af75078fSIntel char *end = NULL; 444af75078fSIntel int n; 445af75078fSIntel 446af75078fSIntel /* parse number string */ 447af75078fSIntel n = strtol(q_arg, &end, 10); 448af75078fSIntel if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 449af75078fSIntel return -1; 450af75078fSIntel if (n >= MAX_TIMER_PERIOD) 451af75078fSIntel return -1; 452af75078fSIntel 453af75078fSIntel return n; 454af75078fSIntel } 455af75078fSIntel 456af75078fSIntel /* Parse the argument given in the command line of the application */ 457af75078fSIntel static int 458af75078fSIntel l2fwd_parse_args(int argc, char **argv) 459af75078fSIntel { 460af75078fSIntel int opt, ret; 461af75078fSIntel char **argvopt; 462af75078fSIntel int option_index; 463af75078fSIntel char *prgname = argv[0]; 464af75078fSIntel static struct option lgopts[] = { 465af75078fSIntel {NULL, 0, 0, 0} 466af75078fSIntel }; 467af75078fSIntel 468af75078fSIntel argvopt = argv; 469af75078fSIntel 470af75078fSIntel while ((opt = getopt_long(argc, argvopt, "p:q:T:", 471af75078fSIntel lgopts, &option_index)) != EOF) { 472af75078fSIntel 473af75078fSIntel switch (opt) { 474af75078fSIntel /* portmask */ 475af75078fSIntel case 'p': 476af75078fSIntel l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg); 477af75078fSIntel if (l2fwd_enabled_port_mask == 0) { 478af75078fSIntel printf("invalid portmask\n"); 479af75078fSIntel l2fwd_usage(prgname); 480af75078fSIntel return -1; 481af75078fSIntel } 482af75078fSIntel break; 483af75078fSIntel 484af75078fSIntel /* nqueue */ 485af75078fSIntel case 'q': 486af75078fSIntel l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg); 487af75078fSIntel if (l2fwd_rx_queue_per_lcore == 0) { 488af75078fSIntel printf("invalid queue number\n"); 489af75078fSIntel l2fwd_usage(prgname); 490af75078fSIntel return -1; 491af75078fSIntel } 492af75078fSIntel break; 493af75078fSIntel 494af75078fSIntel /* timer period */ 495af75078fSIntel case 'T': 496af75078fSIntel timer_period = l2fwd_parse_timer_period(optarg) * 1000 * TIMER_MILLISECOND; 497af75078fSIntel if (timer_period < 0) { 498af75078fSIntel printf("invalid timer period\n"); 499af75078fSIntel l2fwd_usage(prgname); 500af75078fSIntel return -1; 501af75078fSIntel } 502af75078fSIntel break; 503af75078fSIntel 504af75078fSIntel /* long options */ 505af75078fSIntel case 0: 506af75078fSIntel l2fwd_usage(prgname); 507af75078fSIntel return -1; 508af75078fSIntel 509af75078fSIntel default: 510af75078fSIntel l2fwd_usage(prgname); 511af75078fSIntel return -1; 512af75078fSIntel } 513af75078fSIntel } 514af75078fSIntel 515af75078fSIntel if (optind >= 0) 516af75078fSIntel argv[optind-1] = prgname; 517af75078fSIntel 518af75078fSIntel ret = optind-1; 519af75078fSIntel optind = 0; /* reset getopt lib */ 520af75078fSIntel return ret; 521af75078fSIntel } 522af75078fSIntel 523d3641ae8SIntel /* Check the link status of all ports in up to 9s, and print them finally */ 524d3641ae8SIntel static void 525d3641ae8SIntel check_all_ports_link_status(uint8_t port_num, uint32_t port_mask) 526d3641ae8SIntel { 527d3641ae8SIntel #define CHECK_INTERVAL 100 /* 100ms */ 528d3641ae8SIntel #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ 529d3641ae8SIntel uint8_t portid, count, all_ports_up, print_flag = 0; 530d3641ae8SIntel struct rte_eth_link link; 531d3641ae8SIntel 532d3641ae8SIntel printf("\nChecking link status"); 533d3641ae8SIntel fflush(stdout); 534d3641ae8SIntel for (count = 0; count <= MAX_CHECK_TIME; count++) { 535d3641ae8SIntel all_ports_up = 1; 536d3641ae8SIntel for (portid = 0; portid < port_num; portid++) { 537d3641ae8SIntel if ((port_mask & (1 << portid)) == 0) 538d3641ae8SIntel continue; 539d3641ae8SIntel memset(&link, 0, sizeof(link)); 540d3641ae8SIntel rte_eth_link_get_nowait(portid, &link); 541d3641ae8SIntel /* print link status if flag set */ 542d3641ae8SIntel if (print_flag == 1) { 543d3641ae8SIntel if (link.link_status) 544d3641ae8SIntel printf("Port %d Link Up - speed %u " 545d3641ae8SIntel "Mbps - %s\n", (uint8_t)portid, 546d3641ae8SIntel (unsigned)link.link_speed, 547d3641ae8SIntel (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? 548d3641ae8SIntel ("full-duplex") : ("half-duplex\n")); 549d3641ae8SIntel else 550d3641ae8SIntel printf("Port %d Link Down\n", 551d3641ae8SIntel (uint8_t)portid); 552d3641ae8SIntel continue; 553d3641ae8SIntel } 554d3641ae8SIntel /* clear all_ports_up flag if any link down */ 555d3641ae8SIntel if (link.link_status == 0) { 556d3641ae8SIntel all_ports_up = 0; 557d3641ae8SIntel break; 558d3641ae8SIntel } 559d3641ae8SIntel } 560d3641ae8SIntel /* after finally printing all link status, get out */ 561d3641ae8SIntel if (print_flag == 1) 562d3641ae8SIntel break; 563d3641ae8SIntel 564d3641ae8SIntel if (all_ports_up == 0) { 565d3641ae8SIntel printf("."); 566d3641ae8SIntel fflush(stdout); 567d3641ae8SIntel rte_delay_ms(CHECK_INTERVAL); 568d3641ae8SIntel } 569d3641ae8SIntel 570d3641ae8SIntel /* set the print_flag if all ports up or timeout */ 571d3641ae8SIntel if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { 572d3641ae8SIntel print_flag = 1; 573d3641ae8SIntel printf("done\n"); 574d3641ae8SIntel } 575d3641ae8SIntel } 576d3641ae8SIntel } 577d3641ae8SIntel 578af75078fSIntel int 579af75078fSIntel MAIN(int argc, char **argv) 580af75078fSIntel { 581af75078fSIntel struct lcore_queue_conf *qconf; 582af75078fSIntel struct rte_eth_dev_info dev_info; 583af75078fSIntel int ret; 584a974564bSIntel uint8_t nb_ports; 585f56d0815SIntel uint8_t nb_ports_available; 586a974564bSIntel uint8_t portid, last_port; 587af75078fSIntel unsigned lcore_id, rx_lcore_id; 588af75078fSIntel unsigned nb_ports_in_mask = 0; 589af75078fSIntel 590af75078fSIntel /* init EAL */ 591af75078fSIntel ret = rte_eal_init(argc, argv); 592af75078fSIntel if (ret < 0) 593af75078fSIntel rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n"); 594af75078fSIntel argc -= ret; 595af75078fSIntel argv += ret; 596af75078fSIntel 597af75078fSIntel /* parse application arguments (after the EAL ones) */ 598af75078fSIntel ret = l2fwd_parse_args(argc, argv); 599af75078fSIntel if (ret < 0) 600af75078fSIntel rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n"); 601af75078fSIntel 602af75078fSIntel /* create the mbuf pool */ 603af75078fSIntel l2fwd_pktmbuf_pool = 604af75078fSIntel rte_mempool_create("mbuf_pool", NB_MBUF, 605af75078fSIntel MBUF_SIZE, 32, 606af75078fSIntel sizeof(struct rte_pktmbuf_pool_private), 607af75078fSIntel rte_pktmbuf_pool_init, NULL, 608af75078fSIntel rte_pktmbuf_init, NULL, 609e60f71ebSIntel rte_socket_id(), 0); 610af75078fSIntel if (l2fwd_pktmbuf_pool == NULL) 611af75078fSIntel rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n"); 612af75078fSIntel 613af75078fSIntel /* init driver(s) */ 61469d22b8eSIntel if (rte_pmd_init_all() < 0) 61569d22b8eSIntel rte_exit(EXIT_FAILURE, "Cannot init pmd\n"); 616af75078fSIntel 617af75078fSIntel if (rte_eal_pci_probe() < 0) 618af75078fSIntel rte_exit(EXIT_FAILURE, "Cannot probe PCI\n"); 619af75078fSIntel 620af75078fSIntel nb_ports = rte_eth_dev_count(); 621af75078fSIntel if (nb_ports == 0) 622af75078fSIntel rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n"); 623af75078fSIntel 6241c17baf4SIntel if (nb_ports > RTE_MAX_ETHPORTS) 6251c17baf4SIntel nb_ports = RTE_MAX_ETHPORTS; 626af75078fSIntel 627af75078fSIntel /* reset l2fwd_dst_ports */ 6281c17baf4SIntel for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) 629af75078fSIntel l2fwd_dst_ports[portid] = 0; 630af75078fSIntel last_port = 0; 631af75078fSIntel 632af75078fSIntel /* 633af75078fSIntel * Each logical core is assigned a dedicated TX queue on each port. 634af75078fSIntel */ 635af75078fSIntel for (portid = 0; portid < nb_ports; portid++) { 636af75078fSIntel /* skip ports that are not enabled */ 637af75078fSIntel if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 638af75078fSIntel continue; 639af75078fSIntel 640af75078fSIntel if (nb_ports_in_mask % 2) { 641af75078fSIntel l2fwd_dst_ports[portid] = last_port; 642af75078fSIntel l2fwd_dst_ports[last_port] = portid; 643af75078fSIntel } 644af75078fSIntel else 645af75078fSIntel last_port = portid; 646af75078fSIntel 647af75078fSIntel nb_ports_in_mask++; 648af75078fSIntel 649a974564bSIntel rte_eth_dev_info_get(portid, &dev_info); 650af75078fSIntel } 651f56d0815SIntel if (nb_ports_in_mask % 2) { 65216ac9cf0SIntel printf("Notice: odd number of ports in portmask.\n"); 65316ac9cf0SIntel l2fwd_dst_ports[last_port] = last_port; 654af75078fSIntel } 655af75078fSIntel 656af75078fSIntel rx_lcore_id = 0; 657af75078fSIntel qconf = NULL; 658af75078fSIntel 659af75078fSIntel /* Initialize the port/queue configuration of each logical core */ 660af75078fSIntel for (portid = 0; portid < nb_ports; portid++) { 661af75078fSIntel /* skip ports that are not enabled */ 662af75078fSIntel if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 663af75078fSIntel continue; 664af75078fSIntel 665af75078fSIntel /* get the lcore_id for this port */ 666af75078fSIntel while (rte_lcore_is_enabled(rx_lcore_id) == 0 || 66716ac9cf0SIntel lcore_queue_conf[rx_lcore_id].n_rx_port == 668af75078fSIntel l2fwd_rx_queue_per_lcore) { 669af75078fSIntel rx_lcore_id++; 670af75078fSIntel if (rx_lcore_id >= RTE_MAX_LCORE) 671af75078fSIntel rte_exit(EXIT_FAILURE, "Not enough cores\n"); 672af75078fSIntel } 67316ac9cf0SIntel 67416ac9cf0SIntel if (qconf != &lcore_queue_conf[rx_lcore_id]) 675af75078fSIntel /* Assigned a new logical core in the loop above. */ 676af75078fSIntel qconf = &lcore_queue_conf[rx_lcore_id]; 67716ac9cf0SIntel 67816ac9cf0SIntel qconf->rx_port_list[qconf->n_rx_port] = portid; 67916ac9cf0SIntel qconf->n_rx_port++; 680a974564bSIntel printf("Lcore %u: RX port %u\n", rx_lcore_id, (unsigned) portid); 681af75078fSIntel } 682af75078fSIntel 683f56d0815SIntel nb_ports_available = nb_ports; 684f56d0815SIntel 685af75078fSIntel /* Initialise each port */ 686af75078fSIntel for (portid = 0; portid < nb_ports; portid++) { 687af75078fSIntel /* skip ports that are not enabled */ 688af75078fSIntel if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) { 689a974564bSIntel printf("Skipping disabled port %u\n", (unsigned) portid); 690f56d0815SIntel nb_ports_available--; 691af75078fSIntel continue; 692af75078fSIntel } 693af75078fSIntel /* init port */ 694a974564bSIntel printf("Initializing port %u... ", (unsigned) portid); 695af75078fSIntel fflush(stdout); 696a974564bSIntel ret = rte_eth_dev_configure(portid, 1, 1, &port_conf); 697af75078fSIntel if (ret < 0) 69816ac9cf0SIntel rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n", 699a974564bSIntel ret, (unsigned) portid); 700af75078fSIntel 701a974564bSIntel rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]); 702af75078fSIntel 703af75078fSIntel /* init one RX queue */ 704af75078fSIntel fflush(stdout); 705a974564bSIntel ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd, 706a974564bSIntel rte_eth_dev_socket_id(portid), &rx_conf, 707af75078fSIntel l2fwd_pktmbuf_pool); 708af75078fSIntel if (ret < 0) 709a974564bSIntel rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n", 710a974564bSIntel ret, (unsigned) portid); 711af75078fSIntel 712e60f71ebSIntel /* init one TX queue on each port */ 713af75078fSIntel fflush(stdout); 714a974564bSIntel ret = rte_eth_tx_queue_setup(portid, 0, nb_txd, 715e60f71ebSIntel rte_eth_dev_socket_id(portid), &tx_conf); 716af75078fSIntel if (ret < 0) 71716ac9cf0SIntel rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n", 718a974564bSIntel ret, (unsigned) portid); 719af75078fSIntel 720af75078fSIntel /* Start device */ 721a974564bSIntel ret = rte_eth_dev_start(portid); 722af75078fSIntel if (ret < 0) 72316ac9cf0SIntel rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n", 724a974564bSIntel ret, (unsigned) portid); 725af75078fSIntel 726d3641ae8SIntel printf("done: \n"); 727af75078fSIntel 728a974564bSIntel rte_eth_promiscuous_enable(portid); 729af75078fSIntel 730af75078fSIntel printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n", 731a974564bSIntel (unsigned) portid, 732af75078fSIntel l2fwd_ports_eth_addr[portid].addr_bytes[0], 733af75078fSIntel l2fwd_ports_eth_addr[portid].addr_bytes[1], 734af75078fSIntel l2fwd_ports_eth_addr[portid].addr_bytes[2], 735af75078fSIntel l2fwd_ports_eth_addr[portid].addr_bytes[3], 736af75078fSIntel l2fwd_ports_eth_addr[portid].addr_bytes[4], 737af75078fSIntel l2fwd_ports_eth_addr[portid].addr_bytes[5]); 738af75078fSIntel 739af75078fSIntel /* initialize port stats */ 740af75078fSIntel memset(&port_statistics, 0, sizeof(port_statistics)); 741af75078fSIntel } 742af75078fSIntel 743f56d0815SIntel if (!nb_ports_available) { 744f56d0815SIntel rte_exit(EXIT_FAILURE, 745f56d0815SIntel "All available ports are disabled. Please set portmask.\n"); 746f56d0815SIntel } 747f56d0815SIntel 748a974564bSIntel check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask); 749d3641ae8SIntel 750af75078fSIntel /* launch per-lcore init on every lcore */ 751af75078fSIntel rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER); 752af75078fSIntel RTE_LCORE_FOREACH_SLAVE(lcore_id) { 753af75078fSIntel if (rte_eal_wait_lcore(lcore_id) < 0) 754af75078fSIntel return -1; 755af75078fSIntel } 756af75078fSIntel 757af75078fSIntel return 0; 758af75078fSIntel } 759d3641ae8SIntel 760