13998e2a0SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 23998e2a0SBruce Richardson * Copyright(c) 2010-2017 Intel Corporation 307db4a97SReshma Pattan */ 407db4a97SReshma Pattan 507db4a97SReshma Pattan #include <stdint.h> 672b452c5SDmitry Kozlyuk #include <stdlib.h> 707db4a97SReshma Pattan #include <inttypes.h> 807db4a97SReshma Pattan #include <unistd.h> 907db4a97SReshma Pattan #include <signal.h> 1007db4a97SReshma Pattan #include <getopt.h> 1107db4a97SReshma Pattan 1207db4a97SReshma Pattan #include <rte_eal.h> 1307db4a97SReshma Pattan #include <rte_ethdev.h> 1407db4a97SReshma Pattan #include <rte_cycles.h> 1507db4a97SReshma Pattan #include <rte_malloc.h> 1607db4a97SReshma Pattan #include <rte_debug.h> 1764502fabSJerin Jacob #include <rte_prefetch.h> 1807db4a97SReshma Pattan #include <rte_distributor.h> 19577329e6SJerin Jacob #include <rte_pause.h> 20*f30a1bbdSSivaprasad Tummala #include <rte_power_cpufreq.h> 2107db4a97SReshma Pattan 22867a6c66SKevin Laatz #define RX_RING_SIZE 1024 23867a6c66SKevin Laatz #define TX_RING_SIZE 1024 2407db4a97SReshma Pattan #define NUM_MBUFS ((64*1024)-1) 25fce56395SDavid Hunt #define MBUF_CACHE_SIZE 128 26fce56395SDavid Hunt #define BURST_SIZE 64 274a7f40c0SDavid Hunt #define SCHED_RX_RING_SZ 8192 284a7f40c0SDavid Hunt #define SCHED_TX_RING_SZ 65536 29fce56395SDavid Hunt #define BURST_SIZE_TX 32 3007db4a97SReshma Pattan 3107db4a97SReshma Pattan #define RTE_LOGTYPE_DISTRAPP RTE_LOGTYPE_USER1 3207db4a97SReshma Pattan 33eecb8128SDavid Hunt #define ANSI_COLOR_RED "\x1b[31m" 34eecb8128SDavid Hunt #define ANSI_COLOR_RESET "\x1b[0m" 35eecb8128SDavid Hunt 3607db4a97SReshma Pattan /* mask of enabled ports */ 3707db4a97SReshma Pattan static uint32_t enabled_port_mask; 3807db4a97SReshma Pattan volatile uint8_t quit_signal; 3907db4a97SReshma Pattan volatile uint8_t quit_signal_rx; 40eecb8128SDavid Hunt volatile uint8_t quit_signal_dist; 419872251dSDavid Hunt volatile uint8_t quit_signal_work; 42f73477e2SDavid Hunt unsigned int power_lib_initialised; 433429d6ddSAbdullah Ömer Yamaç bool enable_lcore_rx_distributor; 443429d6ddSAbdullah Ömer Yamaç unsigned int num_workers; 4507db4a97SReshma Pattan 4607db4a97SReshma Pattan static volatile struct app_stats { 477e06c0deSTyler Retzlaff alignas(RTE_CACHE_LINE_SIZE) struct { 4807db4a97SReshma Pattan uint64_t rx_pkts; 4907db4a97SReshma Pattan uint64_t returned_pkts; 5007db4a97SReshma Pattan uint64_t enqueued_pkts; 51eecb8128SDavid Hunt uint64_t enqdrop_pkts; 527e06c0deSTyler Retzlaff } rx; 537e06c0deSTyler Retzlaff alignas(RTE_CACHE_LINE_SIZE) int pad1; 54eecb8128SDavid Hunt 557e06c0deSTyler Retzlaff alignas(RTE_CACHE_LINE_SIZE) struct { 56eecb8128SDavid Hunt uint64_t in_pkts; 57eecb8128SDavid Hunt uint64_t ret_pkts; 58eecb8128SDavid Hunt uint64_t sent_pkts; 59eecb8128SDavid Hunt uint64_t enqdrop_pkts; 607e06c0deSTyler Retzlaff } dist; 617e06c0deSTyler Retzlaff alignas(RTE_CACHE_LINE_SIZE) int pad2; 6207db4a97SReshma Pattan 637e06c0deSTyler Retzlaff alignas(RTE_CACHE_LINE_SIZE) struct { 6407db4a97SReshma Pattan uint64_t dequeue_pkts; 6507db4a97SReshma Pattan uint64_t tx_pkts; 66eecb8128SDavid Hunt uint64_t enqdrop_pkts; 677e06c0deSTyler Retzlaff } tx; 687e06c0deSTyler Retzlaff alignas(RTE_CACHE_LINE_SIZE) int pad3; 69eecb8128SDavid Hunt 707e06c0deSTyler Retzlaff alignas(RTE_CACHE_LINE_SIZE) uint64_t worker_pkts[64]; 71eecb8128SDavid Hunt 727e06c0deSTyler Retzlaff alignas(RTE_CACHE_LINE_SIZE) int pad4; 73eecb8128SDavid Hunt 747e06c0deSTyler Retzlaff alignas(RTE_CACHE_LINE_SIZE) uint64_t worker_bursts[64][8]; 75eecb8128SDavid Hunt 767e06c0deSTyler Retzlaff alignas(RTE_CACHE_LINE_SIZE) int pad5; 77eecb8128SDavid Hunt 787e06c0deSTyler Retzlaff alignas(RTE_CACHE_LINE_SIZE) uint64_t port_rx_pkts[64]; 797e06c0deSTyler Retzlaff alignas(RTE_CACHE_LINE_SIZE) uint64_t port_tx_pkts[64]; 8007db4a97SReshma Pattan } app_stats; 8107db4a97SReshma Pattan 82eecb8128SDavid Hunt struct app_stats prev_app_stats; 83eecb8128SDavid Hunt 8407db4a97SReshma Pattan static const struct rte_eth_conf port_conf_default = { 8507db4a97SReshma Pattan .rxmode = { 86295968d1SFerruh Yigit .mq_mode = RTE_ETH_MQ_RX_RSS, 8707db4a97SReshma Pattan }, 8807db4a97SReshma Pattan .txmode = { 89295968d1SFerruh Yigit .mq_mode = RTE_ETH_MQ_TX_NONE, 9007db4a97SReshma Pattan }, 9107db4a97SReshma Pattan .rx_adv_conf = { 9207db4a97SReshma Pattan .rss_conf = { 93295968d1SFerruh Yigit .rss_hf = RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | 94295968d1SFerruh Yigit RTE_ETH_RSS_TCP | RTE_ETH_RSS_SCTP, 9507db4a97SReshma Pattan } 9607db4a97SReshma Pattan }, 9707db4a97SReshma Pattan }; 9807db4a97SReshma Pattan 9907db4a97SReshma Pattan struct output_buffer { 10007db4a97SReshma Pattan unsigned count; 10107db4a97SReshma Pattan struct rte_mbuf *mbufs[BURST_SIZE]; 10207db4a97SReshma Pattan }; 10307db4a97SReshma Pattan 104eecb8128SDavid Hunt static void print_stats(void); 105eecb8128SDavid Hunt 10607db4a97SReshma Pattan /* 10707db4a97SReshma Pattan * Initialises a given port using global settings and with the rx buffers 10807db4a97SReshma Pattan * coming from the mbuf_pool passed as parameter 10907db4a97SReshma Pattan */ 11007db4a97SReshma Pattan static inline int 111f8244c63SZhiyong Yang port_init(uint16_t port, struct rte_mempool *mbuf_pool) 11207db4a97SReshma Pattan { 11307db4a97SReshma Pattan struct rte_eth_conf port_conf = port_conf_default; 114e7f6d128SHonnappa Nagarahalli const uint16_t rxRings = 1, txRings = 1; 11507db4a97SReshma Pattan int retval; 11607db4a97SReshma Pattan uint16_t q; 11760efb44fSRoman Zhukov uint16_t nb_rxd = RX_RING_SIZE; 11860efb44fSRoman Zhukov uint16_t nb_txd = TX_RING_SIZE; 119f8f0012dSShahaf Shuler struct rte_eth_dev_info dev_info; 120f8f0012dSShahaf Shuler struct rte_eth_txconf txconf; 12107db4a97SReshma Pattan 122a9dbe180SThomas Monjalon if (!rte_eth_dev_is_valid_port(port)) 12307db4a97SReshma Pattan return -1; 12407db4a97SReshma Pattan 125089e5ed7SIvan Ilchenko retval = rte_eth_dev_info_get(port, &dev_info); 126089e5ed7SIvan Ilchenko if (retval != 0) { 127089e5ed7SIvan Ilchenko printf("Error during getting device (port %u) info: %s\n", 128089e5ed7SIvan Ilchenko port, strerror(-retval)); 129089e5ed7SIvan Ilchenko return retval; 130089e5ed7SIvan Ilchenko } 131089e5ed7SIvan Ilchenko 132295968d1SFerruh Yigit if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE) 133f8f0012dSShahaf Shuler port_conf.txmode.offloads |= 134295968d1SFerruh Yigit RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE; 135f8f0012dSShahaf Shuler 1364f5701f2SFerruh Yigit port_conf.rx_adv_conf.rss_conf.rss_hf &= 1374f5701f2SFerruh Yigit dev_info.flow_type_rss_offloads; 1384f5701f2SFerruh Yigit if (port_conf.rx_adv_conf.rss_conf.rss_hf != 1394f5701f2SFerruh Yigit port_conf_default.rx_adv_conf.rss_conf.rss_hf) { 1404f5701f2SFerruh Yigit printf("Port %u modified RSS hash function based on hardware support," 1414f5701f2SFerruh Yigit "requested:%#"PRIx64" configured:%#"PRIx64"\n", 1424f5701f2SFerruh Yigit port, 1434f5701f2SFerruh Yigit port_conf_default.rx_adv_conf.rss_conf.rss_hf, 1444f5701f2SFerruh Yigit port_conf.rx_adv_conf.rss_conf.rss_hf); 1454f5701f2SFerruh Yigit } 1464f5701f2SFerruh Yigit 14707db4a97SReshma Pattan retval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf); 14807db4a97SReshma Pattan if (retval != 0) 14907db4a97SReshma Pattan return retval; 15007db4a97SReshma Pattan 15160efb44fSRoman Zhukov retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd); 15260efb44fSRoman Zhukov if (retval != 0) 15360efb44fSRoman Zhukov return retval; 15460efb44fSRoman Zhukov 15507db4a97SReshma Pattan for (q = 0; q < rxRings; q++) { 15660efb44fSRoman Zhukov retval = rte_eth_rx_queue_setup(port, q, nb_rxd, 15707db4a97SReshma Pattan rte_eth_dev_socket_id(port), 15807db4a97SReshma Pattan NULL, mbuf_pool); 15907db4a97SReshma Pattan if (retval < 0) 16007db4a97SReshma Pattan return retval; 16107db4a97SReshma Pattan } 16207db4a97SReshma Pattan 163f8f0012dSShahaf Shuler txconf = dev_info.default_txconf; 164f8f0012dSShahaf Shuler txconf.offloads = port_conf.txmode.offloads; 16507db4a97SReshma Pattan for (q = 0; q < txRings; q++) { 16660efb44fSRoman Zhukov retval = rte_eth_tx_queue_setup(port, q, nb_txd, 16707db4a97SReshma Pattan rte_eth_dev_socket_id(port), 168f8f0012dSShahaf Shuler &txconf); 16907db4a97SReshma Pattan if (retval < 0) 17007db4a97SReshma Pattan return retval; 17107db4a97SReshma Pattan } 17207db4a97SReshma Pattan 17307db4a97SReshma Pattan retval = rte_eth_dev_start(port); 17407db4a97SReshma Pattan if (retval < 0) 17507db4a97SReshma Pattan return retval; 17607db4a97SReshma Pattan 17707db4a97SReshma Pattan struct rte_eth_link link; 17822e5c73bSIgor Romanov do { 17922e5c73bSIgor Romanov retval = rte_eth_link_get_nowait(port, &link); 18022e5c73bSIgor Romanov if (retval < 0) { 18122e5c73bSIgor Romanov printf("Failed link get (port %u): %s\n", 18222e5c73bSIgor Romanov port, rte_strerror(-retval)); 18322e5c73bSIgor Romanov return retval; 18422e5c73bSIgor Romanov } else if (link.link_status) 18522e5c73bSIgor Romanov break; 18622e5c73bSIgor Romanov 187f8244c63SZhiyong Yang printf("Waiting for Link up on port %"PRIu16"\n", port); 18807db4a97SReshma Pattan sleep(1); 18922e5c73bSIgor Romanov } while (!link.link_status); 19007db4a97SReshma Pattan 19107db4a97SReshma Pattan if (!link.link_status) { 192f8244c63SZhiyong Yang printf("Link down on port %"PRIu16"\n", port); 19307db4a97SReshma Pattan return 0; 19407db4a97SReshma Pattan } 19507db4a97SReshma Pattan 1966d13ea8eSOlivier Matz struct rte_ether_addr addr; 19770febdcfSIgor Romanov retval = rte_eth_macaddr_get(port, &addr); 19870febdcfSIgor Romanov if (retval < 0) { 19970febdcfSIgor Romanov printf("Failed to get MAC address (port %u): %s\n", 20070febdcfSIgor Romanov port, rte_strerror(-retval)); 20170febdcfSIgor Romanov return retval; 20270febdcfSIgor Romanov } 20370febdcfSIgor Romanov 20407db4a97SReshma Pattan printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8 20507db4a97SReshma Pattan " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n", 206a7db3afcSAman Deep Singh port, RTE_ETHER_ADDR_BYTES(&addr)); 20707db4a97SReshma Pattan 208f430bbceSIvan Ilchenko retval = rte_eth_promiscuous_enable(port); 209f430bbceSIvan Ilchenko if (retval != 0) 210f430bbceSIvan Ilchenko return retval; 21107db4a97SReshma Pattan 21207db4a97SReshma Pattan return 0; 21307db4a97SReshma Pattan } 21407db4a97SReshma Pattan 21507db4a97SReshma Pattan struct lcore_params { 21607db4a97SReshma Pattan unsigned worker_id; 21707db4a97SReshma Pattan struct rte_distributor *d; 2184a7f40c0SDavid Hunt struct rte_ring *rx_dist_ring; 2194a7f40c0SDavid Hunt struct rte_ring *dist_tx_ring; 22007db4a97SReshma Pattan struct rte_mempool *mem_pool; 22107db4a97SReshma Pattan }; 22207db4a97SReshma Pattan 223d532ddccSMarcin Kerlin static int 22407db4a97SReshma Pattan lcore_rx(struct lcore_params *p) 22507db4a97SReshma Pattan { 226d9a42a69SThomas Monjalon const uint16_t nb_ports = rte_eth_dev_count_avail(); 22707db4a97SReshma Pattan const int socket_id = rte_socket_id(); 22847523597SZhiyong Yang uint16_t port; 229fce56395SDavid Hunt struct rte_mbuf *bufs[BURST_SIZE*2]; 23007db4a97SReshma Pattan 2318728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(port) { 23207db4a97SReshma Pattan /* skip ports that are not enabled */ 23307db4a97SReshma Pattan if ((enabled_port_mask & (1 << port)) == 0) 23407db4a97SReshma Pattan continue; 23507db4a97SReshma Pattan 2367dcd73e3SOlivier Matz if (rte_eth_dev_socket_id(port) >= 0 && 23707db4a97SReshma Pattan rte_eth_dev_socket_id(port) != socket_id) 23807db4a97SReshma Pattan printf("WARNING, port %u is on remote NUMA node to " 23907db4a97SReshma Pattan "RX thread.\n\tPerformance will not " 24007db4a97SReshma Pattan "be optimal.\n", port); 24107db4a97SReshma Pattan } 24207db4a97SReshma Pattan 24307db4a97SReshma Pattan printf("\nCore %u doing packet RX.\n", rte_lcore_id()); 24407db4a97SReshma Pattan port = 0; 24507db4a97SReshma Pattan while (!quit_signal_rx) { 24607db4a97SReshma Pattan 24707db4a97SReshma Pattan /* skip ports that are not enabled */ 24807db4a97SReshma Pattan if ((enabled_port_mask & (1 << port)) == 0) { 24907db4a97SReshma Pattan if (++port == nb_ports) 25007db4a97SReshma Pattan port = 0; 25107db4a97SReshma Pattan continue; 25207db4a97SReshma Pattan } 25307db4a97SReshma Pattan const uint16_t nb_rx = rte_eth_rx_burst(port, 0, bufs, 25407db4a97SReshma Pattan BURST_SIZE); 2552b41fac5SReshma Pattan if (unlikely(nb_rx == 0)) { 2562b41fac5SReshma Pattan if (++port == nb_ports) 2572b41fac5SReshma Pattan port = 0; 2582b41fac5SReshma Pattan continue; 2592b41fac5SReshma Pattan } 26007db4a97SReshma Pattan app_stats.rx.rx_pkts += nb_rx; 26107db4a97SReshma Pattan 2624a7f40c0SDavid Hunt /* 2633429d6ddSAbdullah Ömer Yamaç * Swap the following two lines if you want the rx traffic 2643429d6ddSAbdullah Ömer Yamaç * to go directly to tx, no distribution. 2653429d6ddSAbdullah Ömer Yamaç */ 2663429d6ddSAbdullah Ömer Yamaç struct rte_ring *out_ring = p->rx_dist_ring; 2673429d6ddSAbdullah Ömer Yamaç /* struct rte_ring *out_ring = p->dist_tx_ring; */ 2683429d6ddSAbdullah Ömer Yamaç 2693429d6ddSAbdullah Ömer Yamaç uint16_t sent = rte_ring_enqueue_burst(out_ring, 2703429d6ddSAbdullah Ömer Yamaç (void *)bufs, nb_rx, NULL); 2713429d6ddSAbdullah Ömer Yamaç 2723429d6ddSAbdullah Ömer Yamaç app_stats.rx.enqueued_pkts += sent; 2733429d6ddSAbdullah Ömer Yamaç if (unlikely(sent < nb_rx)) { 2743429d6ddSAbdullah Ömer Yamaç app_stats.rx.enqdrop_pkts += nb_rx - sent; 2753429d6ddSAbdullah Ömer Yamaç RTE_LOG_DP(DEBUG, DISTRAPP, 2763429d6ddSAbdullah Ömer Yamaç "%s:Packet loss due to full ring\n", __func__); 2773429d6ddSAbdullah Ömer Yamaç while (sent < nb_rx) 2783429d6ddSAbdullah Ömer Yamaç rte_pktmbuf_free(bufs[sent++]); 2793429d6ddSAbdullah Ömer Yamaç } 2803429d6ddSAbdullah Ömer Yamaç if (++port == nb_ports) 2813429d6ddSAbdullah Ömer Yamaç port = 0; 2823429d6ddSAbdullah Ömer Yamaç } 2833429d6ddSAbdullah Ömer Yamaç if (power_lib_initialised) 2843429d6ddSAbdullah Ömer Yamaç rte_power_exit(rte_lcore_id()); 2853429d6ddSAbdullah Ömer Yamaç printf("\nCore %u exiting rx task.\n", rte_lcore_id()); 2863429d6ddSAbdullah Ömer Yamaç /* set distributor threads quit flag */ 2873429d6ddSAbdullah Ömer Yamaç quit_signal_dist = 1; 2883429d6ddSAbdullah Ömer Yamaç return 0; 2893429d6ddSAbdullah Ömer Yamaç } 2903429d6ddSAbdullah Ömer Yamaç 2913429d6ddSAbdullah Ömer Yamaç static int 2923429d6ddSAbdullah Ömer Yamaç lcore_rx_and_distributor(struct lcore_params *p) 2933429d6ddSAbdullah Ömer Yamaç { 2943429d6ddSAbdullah Ömer Yamaç struct rte_distributor *d = p->d; 2953429d6ddSAbdullah Ömer Yamaç const uint16_t nb_ports = rte_eth_dev_count_avail(); 2963429d6ddSAbdullah Ömer Yamaç const int socket_id = rte_socket_id(); 2973429d6ddSAbdullah Ömer Yamaç uint16_t port; 2983429d6ddSAbdullah Ömer Yamaç struct rte_mbuf *bufs[BURST_SIZE*2]; 2993429d6ddSAbdullah Ömer Yamaç 3003429d6ddSAbdullah Ömer Yamaç RTE_ETH_FOREACH_DEV(port) { 3013429d6ddSAbdullah Ömer Yamaç /* skip ports that are not enabled */ 3023429d6ddSAbdullah Ömer Yamaç if ((enabled_port_mask & (1 << port)) == 0) 3033429d6ddSAbdullah Ömer Yamaç continue; 3043429d6ddSAbdullah Ömer Yamaç 3053429d6ddSAbdullah Ömer Yamaç if (rte_eth_dev_socket_id(port) > 0 && 3063429d6ddSAbdullah Ömer Yamaç rte_eth_dev_socket_id(port) != socket_id) 3073429d6ddSAbdullah Ömer Yamaç printf("WARNING, port %u is on remote NUMA node to " 3083429d6ddSAbdullah Ömer Yamaç "RX thread.\n\tPerformance will not " 3093429d6ddSAbdullah Ömer Yamaç "be optimal.\n", port); 3103429d6ddSAbdullah Ömer Yamaç } 3113429d6ddSAbdullah Ömer Yamaç 3123429d6ddSAbdullah Ömer Yamaç printf("\nCore %u doing packet RX and Distributor.\n", rte_lcore_id()); 3133429d6ddSAbdullah Ömer Yamaç port = 0; 3143429d6ddSAbdullah Ömer Yamaç while (!quit_signal_rx) { 3153429d6ddSAbdullah Ömer Yamaç 3163429d6ddSAbdullah Ömer Yamaç /* skip ports that are not enabled */ 3173429d6ddSAbdullah Ömer Yamaç if ((enabled_port_mask & (1 << port)) == 0) { 3183429d6ddSAbdullah Ömer Yamaç if (++port == nb_ports) 3193429d6ddSAbdullah Ömer Yamaç port = 0; 3203429d6ddSAbdullah Ömer Yamaç continue; 3213429d6ddSAbdullah Ömer Yamaç } 3223429d6ddSAbdullah Ömer Yamaç const uint16_t nb_rx = rte_eth_rx_burst(port, 0, bufs, 3233429d6ddSAbdullah Ömer Yamaç BURST_SIZE); 3243429d6ddSAbdullah Ömer Yamaç if (unlikely(nb_rx == 0)) { 3253429d6ddSAbdullah Ömer Yamaç if (++port == nb_ports) 3263429d6ddSAbdullah Ömer Yamaç port = 0; 3273429d6ddSAbdullah Ömer Yamaç continue; 3283429d6ddSAbdullah Ömer Yamaç } 3293429d6ddSAbdullah Ömer Yamaç app_stats.rx.rx_pkts += nb_rx; 3303429d6ddSAbdullah Ömer Yamaç 3313429d6ddSAbdullah Ömer Yamaç /* 3323429d6ddSAbdullah Ömer Yamaç * Run the distributor on the rx core. Returned 3334a7f40c0SDavid Hunt * packets are then send straight to the tx core. 3344a7f40c0SDavid Hunt */ 3353429d6ddSAbdullah Ömer Yamaç rte_distributor_process(d, bufs, nb_rx); 3363429d6ddSAbdullah Ömer Yamaç const uint16_t nb_ret = rte_distributor_returned_pkts(d, 33707db4a97SReshma Pattan bufs, BURST_SIZE*2); 3384a7f40c0SDavid Hunt 33907db4a97SReshma Pattan app_stats.rx.returned_pkts += nb_ret; 3402b41fac5SReshma Pattan if (unlikely(nb_ret == 0)) { 3412b41fac5SReshma Pattan if (++port == nb_ports) 3422b41fac5SReshma Pattan port = 0; 34307db4a97SReshma Pattan continue; 3442b41fac5SReshma Pattan } 34507db4a97SReshma Pattan 3464a7f40c0SDavid Hunt struct rte_ring *tx_ring = p->dist_tx_ring; 3474a7f40c0SDavid Hunt uint16_t sent = rte_ring_enqueue_burst(tx_ring, 34814fbffb0SBruce Richardson (void *)bufs, nb_ret, NULL); 3494a7f40c0SDavid Hunt 35007db4a97SReshma Pattan app_stats.rx.enqueued_pkts += sent; 35107db4a97SReshma Pattan if (unlikely(sent < nb_ret)) { 352fce56395SDavid Hunt app_stats.rx.enqdrop_pkts += nb_ret - sent; 3535d8f0bafSOlivier Matz RTE_LOG_DP(DEBUG, DISTRAPP, 3541f49ec15SThomas Monjalon "%s:Packet loss due to full ring\n", __func__); 35507db4a97SReshma Pattan while (sent < nb_ret) 35607db4a97SReshma Pattan rte_pktmbuf_free(bufs[sent++]); 35707db4a97SReshma Pattan } 35807db4a97SReshma Pattan if (++port == nb_ports) 35907db4a97SReshma Pattan port = 0; 36007db4a97SReshma Pattan } 361f73477e2SDavid Hunt if (power_lib_initialised) 362f73477e2SDavid Hunt rte_power_exit(rte_lcore_id()); 3634a7f40c0SDavid Hunt printf("\nCore %u exiting rx task.\n", rte_lcore_id()); 3643429d6ddSAbdullah Ömer Yamaç /* set tx threads quit flag */ 36507db4a97SReshma Pattan quit_signal = 1; 3663429d6ddSAbdullah Ömer Yamaç /* set worker threads quit flag */ 3673429d6ddSAbdullah Ömer Yamaç quit_signal_work = 1; 3683429d6ddSAbdullah Ömer Yamaç rte_distributor_flush(d); 3693429d6ddSAbdullah Ömer Yamaç /* Unblock any returns so workers can exit */ 3703429d6ddSAbdullah Ömer Yamaç rte_distributor_clear_returns(d); 37107db4a97SReshma Pattan return 0; 37207db4a97SReshma Pattan } 37307db4a97SReshma Pattan 37407db4a97SReshma Pattan static inline void 37507db4a97SReshma Pattan flush_one_port(struct output_buffer *outbuf, uint8_t outp) 37607db4a97SReshma Pattan { 377fce56395SDavid Hunt unsigned int nb_tx = rte_eth_tx_burst(outp, 0, 378fce56395SDavid Hunt outbuf->mbufs, outbuf->count); 379fce56395SDavid Hunt app_stats.tx.tx_pkts += outbuf->count; 38007db4a97SReshma Pattan 38107db4a97SReshma Pattan if (unlikely(nb_tx < outbuf->count)) { 382fce56395SDavid Hunt app_stats.tx.enqdrop_pkts += outbuf->count - nb_tx; 38307db4a97SReshma Pattan do { 38407db4a97SReshma Pattan rte_pktmbuf_free(outbuf->mbufs[nb_tx]); 38507db4a97SReshma Pattan } while (++nb_tx < outbuf->count); 38607db4a97SReshma Pattan } 38707db4a97SReshma Pattan outbuf->count = 0; 38807db4a97SReshma Pattan } 38907db4a97SReshma Pattan 39007db4a97SReshma Pattan static inline void 3918728ccf3SThomas Monjalon flush_all_ports(struct output_buffer *tx_buffers) 39207db4a97SReshma Pattan { 393f8244c63SZhiyong Yang uint16_t outp; 394fce56395SDavid Hunt 3958728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(outp) { 39607db4a97SReshma Pattan /* skip ports that are not enabled */ 39707db4a97SReshma Pattan if ((enabled_port_mask & (1 << outp)) == 0) 39807db4a97SReshma Pattan continue; 39907db4a97SReshma Pattan 40007db4a97SReshma Pattan if (tx_buffers[outp].count == 0) 40107db4a97SReshma Pattan continue; 40207db4a97SReshma Pattan 40307db4a97SReshma Pattan flush_one_port(&tx_buffers[outp], outp); 40407db4a97SReshma Pattan } 40507db4a97SReshma Pattan } 40607db4a97SReshma Pattan 4074a7f40c0SDavid Hunt 4084a7f40c0SDavid Hunt 4094a7f40c0SDavid Hunt static int 4104a7f40c0SDavid Hunt lcore_distributor(struct lcore_params *p) 4114a7f40c0SDavid Hunt { 4124a7f40c0SDavid Hunt struct rte_ring *in_r = p->rx_dist_ring; 4134a7f40c0SDavid Hunt struct rte_ring *out_r = p->dist_tx_ring; 4144a7f40c0SDavid Hunt struct rte_mbuf *bufs[BURST_SIZE * 4]; 4154a7f40c0SDavid Hunt struct rte_distributor *d = p->d; 4164a7f40c0SDavid Hunt 4174a7f40c0SDavid Hunt printf("\nCore %u acting as distributor core.\n", rte_lcore_id()); 4184a7f40c0SDavid Hunt while (!quit_signal_dist) { 4194a7f40c0SDavid Hunt const uint16_t nb_rx = rte_ring_dequeue_burst(in_r, 420ecaed092SBruce Richardson (void *)bufs, BURST_SIZE*1, NULL); 4214a7f40c0SDavid Hunt if (nb_rx) { 4224a7f40c0SDavid Hunt app_stats.dist.in_pkts += nb_rx; 4234a7f40c0SDavid Hunt 4244a7f40c0SDavid Hunt /* Distribute the packets */ 4254a7f40c0SDavid Hunt rte_distributor_process(d, bufs, nb_rx); 4264a7f40c0SDavid Hunt /* Handle Returns */ 4274a7f40c0SDavid Hunt const uint16_t nb_ret = 4284a7f40c0SDavid Hunt rte_distributor_returned_pkts(d, 4294a7f40c0SDavid Hunt bufs, BURST_SIZE*2); 4304a7f40c0SDavid Hunt 4314a7f40c0SDavid Hunt if (unlikely(nb_ret == 0)) 4324a7f40c0SDavid Hunt continue; 4334a7f40c0SDavid Hunt app_stats.dist.ret_pkts += nb_ret; 4344a7f40c0SDavid Hunt 4354a7f40c0SDavid Hunt uint16_t sent = rte_ring_enqueue_burst(out_r, 43614fbffb0SBruce Richardson (void *)bufs, nb_ret, NULL); 4374a7f40c0SDavid Hunt app_stats.dist.sent_pkts += sent; 4384a7f40c0SDavid Hunt if (unlikely(sent < nb_ret)) { 4394a7f40c0SDavid Hunt app_stats.dist.enqdrop_pkts += nb_ret - sent; 4404a7f40c0SDavid Hunt RTE_LOG(DEBUG, DISTRAPP, 4414a7f40c0SDavid Hunt "%s:Packet loss due to full out ring\n", 4424a7f40c0SDavid Hunt __func__); 4434a7f40c0SDavid Hunt while (sent < nb_ret) 4444a7f40c0SDavid Hunt rte_pktmbuf_free(bufs[sent++]); 4454a7f40c0SDavid Hunt } 4464a7f40c0SDavid Hunt } 4474a7f40c0SDavid Hunt } 448f73477e2SDavid Hunt if (power_lib_initialised) 449f73477e2SDavid Hunt rte_power_exit(rte_lcore_id()); 4503429d6ddSAbdullah Ömer Yamaç printf("\nCore %u exiting distributor task.\n", rte_lcore_id()); 4513429d6ddSAbdullah Ömer Yamaç /* set tx threads quit flag */ 4523429d6ddSAbdullah Ömer Yamaç quit_signal = 1; 4533429d6ddSAbdullah Ömer Yamaç /* set worker threads quit flag */ 4543429d6ddSAbdullah Ömer Yamaç quit_signal_work = 1; 4554a7f40c0SDavid Hunt rte_distributor_flush(d); 4564a7f40c0SDavid Hunt /* Unblock any returns so workers can exit */ 4574a7f40c0SDavid Hunt rte_distributor_clear_returns(d); 4584a7f40c0SDavid Hunt return 0; 4594a7f40c0SDavid Hunt } 4604a7f40c0SDavid Hunt 4614a7f40c0SDavid Hunt 46207db4a97SReshma Pattan static int 46307db4a97SReshma Pattan lcore_tx(struct rte_ring *in_r) 46407db4a97SReshma Pattan { 46507db4a97SReshma Pattan static struct output_buffer tx_buffers[RTE_MAX_ETHPORTS]; 46607db4a97SReshma Pattan const int socket_id = rte_socket_id(); 467f8244c63SZhiyong Yang uint16_t port; 46807db4a97SReshma Pattan 4698728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(port) { 47007db4a97SReshma Pattan /* skip ports that are not enabled */ 47107db4a97SReshma Pattan if ((enabled_port_mask & (1 << port)) == 0) 47207db4a97SReshma Pattan continue; 47307db4a97SReshma Pattan 4747dcd73e3SOlivier Matz if (rte_eth_dev_socket_id(port) >= 0 && 47507db4a97SReshma Pattan rte_eth_dev_socket_id(port) != socket_id) 47607db4a97SReshma Pattan printf("WARNING, port %u is on remote NUMA node to " 47707db4a97SReshma Pattan "TX thread.\n\tPerformance will not " 47807db4a97SReshma Pattan "be optimal.\n", port); 47907db4a97SReshma Pattan } 48007db4a97SReshma Pattan 48107db4a97SReshma Pattan printf("\nCore %u doing packet TX.\n", rte_lcore_id()); 48207db4a97SReshma Pattan while (!quit_signal) { 48307db4a97SReshma Pattan 4848728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(port) { 48507db4a97SReshma Pattan /* skip ports that are not enabled */ 48607db4a97SReshma Pattan if ((enabled_port_mask & (1 << port)) == 0) 48707db4a97SReshma Pattan continue; 48807db4a97SReshma Pattan 489fce56395SDavid Hunt struct rte_mbuf *bufs[BURST_SIZE_TX]; 49007db4a97SReshma Pattan const uint16_t nb_rx = rte_ring_dequeue_burst(in_r, 491ecaed092SBruce Richardson (void *)bufs, BURST_SIZE_TX, NULL); 49207db4a97SReshma Pattan app_stats.tx.dequeue_pkts += nb_rx; 49307db4a97SReshma Pattan 49407db4a97SReshma Pattan /* if we get no traffic, flush anything we have */ 49507db4a97SReshma Pattan if (unlikely(nb_rx == 0)) { 4968728ccf3SThomas Monjalon flush_all_ports(tx_buffers); 49707db4a97SReshma Pattan continue; 49807db4a97SReshma Pattan } 49907db4a97SReshma Pattan 50007db4a97SReshma Pattan /* for traffic we receive, queue it up for transmit */ 50107db4a97SReshma Pattan uint16_t i; 50264502fabSJerin Jacob rte_prefetch_non_temporal((void *)bufs[0]); 50364502fabSJerin Jacob rte_prefetch_non_temporal((void *)bufs[1]); 50464502fabSJerin Jacob rte_prefetch_non_temporal((void *)bufs[2]); 50507db4a97SReshma Pattan for (i = 0; i < nb_rx; i++) { 50607db4a97SReshma Pattan struct output_buffer *outbuf; 50707db4a97SReshma Pattan uint8_t outp; 50864502fabSJerin Jacob rte_prefetch_non_temporal((void *)bufs[i + 3]); 50907db4a97SReshma Pattan /* 51007db4a97SReshma Pattan * workers should update in_port to hold the 51107db4a97SReshma Pattan * output port value 51207db4a97SReshma Pattan */ 51307db4a97SReshma Pattan outp = bufs[i]->port; 51407db4a97SReshma Pattan /* skip ports that are not enabled */ 51507db4a97SReshma Pattan if ((enabled_port_mask & (1 << outp)) == 0) 51607db4a97SReshma Pattan continue; 51707db4a97SReshma Pattan 51807db4a97SReshma Pattan outbuf = &tx_buffers[outp]; 51907db4a97SReshma Pattan outbuf->mbufs[outbuf->count++] = bufs[i]; 520fce56395SDavid Hunt if (outbuf->count == BURST_SIZE_TX) 52107db4a97SReshma Pattan flush_one_port(outbuf, outp); 52207db4a97SReshma Pattan } 52307db4a97SReshma Pattan } 52407db4a97SReshma Pattan } 525f73477e2SDavid Hunt if (power_lib_initialised) 526f73477e2SDavid Hunt rte_power_exit(rte_lcore_id()); 527fce56395SDavid Hunt printf("\nCore %u exiting tx task.\n", rte_lcore_id()); 52807db4a97SReshma Pattan return 0; 52907db4a97SReshma Pattan } 53007db4a97SReshma Pattan 53107db4a97SReshma Pattan static void 53207db4a97SReshma Pattan int_handler(int sig_num) 53307db4a97SReshma Pattan { 53407db4a97SReshma Pattan printf("Exiting on signal %d\n", sig_num); 53507db4a97SReshma Pattan /* set quit flag for rx thread to exit */ 5363429d6ddSAbdullah Ömer Yamaç quit_signal_rx = 1; 53707db4a97SReshma Pattan } 53807db4a97SReshma Pattan 53907db4a97SReshma Pattan static void 54007db4a97SReshma Pattan print_stats(void) 54107db4a97SReshma Pattan { 54207db4a97SReshma Pattan struct rte_eth_stats eth_stats; 543eecb8128SDavid Hunt unsigned int i, j; 54407db4a97SReshma Pattan 5458728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(i) { 54607db4a97SReshma Pattan rte_eth_stats_get(i, ð_stats); 547eecb8128SDavid Hunt app_stats.port_rx_pkts[i] = eth_stats.ipackets; 548eecb8128SDavid Hunt app_stats.port_tx_pkts[i] = eth_stats.opackets; 549eecb8128SDavid Hunt } 550eecb8128SDavid Hunt 551eecb8128SDavid Hunt printf("\n\nRX Thread:\n"); 5528728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(i) { 553eecb8128SDavid Hunt printf("Port %u Pktsin : %5.2f\n", i, 554eecb8128SDavid Hunt (app_stats.port_rx_pkts[i] - 555eecb8128SDavid Hunt prev_app_stats.port_rx_pkts[i])/1000000.0); 556eecb8128SDavid Hunt prev_app_stats.port_rx_pkts[i] = app_stats.port_rx_pkts[i]; 557eecb8128SDavid Hunt } 558eecb8128SDavid Hunt printf(" - Received: %5.2f\n", 559eecb8128SDavid Hunt (app_stats.rx.rx_pkts - 560eecb8128SDavid Hunt prev_app_stats.rx.rx_pkts)/1000000.0); 561eecb8128SDavid Hunt printf(" - Returned: %5.2f\n", 562eecb8128SDavid Hunt (app_stats.rx.returned_pkts - 563eecb8128SDavid Hunt prev_app_stats.rx.returned_pkts)/1000000.0); 564eecb8128SDavid Hunt printf(" - Enqueued: %5.2f\n", 565eecb8128SDavid Hunt (app_stats.rx.enqueued_pkts - 566eecb8128SDavid Hunt prev_app_stats.rx.enqueued_pkts)/1000000.0); 567eecb8128SDavid Hunt printf(" - Dropped: %s%5.2f%s\n", ANSI_COLOR_RED, 568eecb8128SDavid Hunt (app_stats.rx.enqdrop_pkts - 569eecb8128SDavid Hunt prev_app_stats.rx.enqdrop_pkts)/1000000.0, 570eecb8128SDavid Hunt ANSI_COLOR_RESET); 571eecb8128SDavid Hunt 5723429d6ddSAbdullah Ömer Yamaç if (!enable_lcore_rx_distributor) { 573eecb8128SDavid Hunt printf("Distributor thread:\n"); 574eecb8128SDavid Hunt printf(" - In: %5.2f\n", 575eecb8128SDavid Hunt (app_stats.dist.in_pkts - 576eecb8128SDavid Hunt prev_app_stats.dist.in_pkts)/1000000.0); 577eecb8128SDavid Hunt printf(" - Returned: %5.2f\n", 578eecb8128SDavid Hunt (app_stats.dist.ret_pkts - 579eecb8128SDavid Hunt prev_app_stats.dist.ret_pkts)/1000000.0); 580eecb8128SDavid Hunt printf(" - Sent: %5.2f\n", 581eecb8128SDavid Hunt (app_stats.dist.sent_pkts - 582eecb8128SDavid Hunt prev_app_stats.dist.sent_pkts)/1000000.0); 583eecb8128SDavid Hunt printf(" - Dropped %s%5.2f%s\n", ANSI_COLOR_RED, 584eecb8128SDavid Hunt (app_stats.dist.enqdrop_pkts - 585eecb8128SDavid Hunt prev_app_stats.dist.enqdrop_pkts)/1000000.0, 586eecb8128SDavid Hunt ANSI_COLOR_RESET); 5873429d6ddSAbdullah Ömer Yamaç } 588eecb8128SDavid Hunt 589eecb8128SDavid Hunt printf("TX thread:\n"); 590eecb8128SDavid Hunt printf(" - Dequeued: %5.2f\n", 591eecb8128SDavid Hunt (app_stats.tx.dequeue_pkts - 592eecb8128SDavid Hunt prev_app_stats.tx.dequeue_pkts)/1000000.0); 5938728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(i) { 594eecb8128SDavid Hunt printf("Port %u Pktsout: %5.2f\n", 595eecb8128SDavid Hunt i, (app_stats.port_tx_pkts[i] - 596eecb8128SDavid Hunt prev_app_stats.port_tx_pkts[i])/1000000.0); 597eecb8128SDavid Hunt prev_app_stats.port_tx_pkts[i] = app_stats.port_tx_pkts[i]; 598eecb8128SDavid Hunt } 599eecb8128SDavid Hunt printf(" - Transmitted: %5.2f\n", 600eecb8128SDavid Hunt (app_stats.tx.tx_pkts - 601eecb8128SDavid Hunt prev_app_stats.tx.tx_pkts)/1000000.0); 602eecb8128SDavid Hunt printf(" - Dropped: %s%5.2f%s\n", ANSI_COLOR_RED, 603eecb8128SDavid Hunt (app_stats.tx.enqdrop_pkts - 604eecb8128SDavid Hunt prev_app_stats.tx.enqdrop_pkts)/1000000.0, 605eecb8128SDavid Hunt ANSI_COLOR_RESET); 606eecb8128SDavid Hunt 607eecb8128SDavid Hunt prev_app_stats.rx.rx_pkts = app_stats.rx.rx_pkts; 608eecb8128SDavid Hunt prev_app_stats.rx.returned_pkts = app_stats.rx.returned_pkts; 609eecb8128SDavid Hunt prev_app_stats.rx.enqueued_pkts = app_stats.rx.enqueued_pkts; 610eecb8128SDavid Hunt prev_app_stats.rx.enqdrop_pkts = app_stats.rx.enqdrop_pkts; 611eecb8128SDavid Hunt prev_app_stats.dist.in_pkts = app_stats.dist.in_pkts; 612eecb8128SDavid Hunt prev_app_stats.dist.ret_pkts = app_stats.dist.ret_pkts; 613eecb8128SDavid Hunt prev_app_stats.dist.sent_pkts = app_stats.dist.sent_pkts; 614eecb8128SDavid Hunt prev_app_stats.dist.enqdrop_pkts = app_stats.dist.enqdrop_pkts; 615eecb8128SDavid Hunt prev_app_stats.tx.dequeue_pkts = app_stats.tx.dequeue_pkts; 616eecb8128SDavid Hunt prev_app_stats.tx.tx_pkts = app_stats.tx.tx_pkts; 617eecb8128SDavid Hunt prev_app_stats.tx.enqdrop_pkts = app_stats.tx.enqdrop_pkts; 618eecb8128SDavid Hunt 619eecb8128SDavid Hunt for (i = 0; i < num_workers; i++) { 620eecb8128SDavid Hunt printf("Worker %02u Pkts: %5.2f. Bursts(1-8): ", i, 621eecb8128SDavid Hunt (app_stats.worker_pkts[i] - 622eecb8128SDavid Hunt prev_app_stats.worker_pkts[i])/1000000.0); 623eecb8128SDavid Hunt for (j = 0; j < 8; j++) { 624eecb8128SDavid Hunt printf("%"PRIu64" ", app_stats.worker_bursts[i][j]); 625eecb8128SDavid Hunt app_stats.worker_bursts[i][j] = 0; 626eecb8128SDavid Hunt } 627eecb8128SDavid Hunt printf("\n"); 628eecb8128SDavid Hunt prev_app_stats.worker_pkts[i] = app_stats.worker_pkts[i]; 62907db4a97SReshma Pattan } 63007db4a97SReshma Pattan } 63107db4a97SReshma Pattan 63207db4a97SReshma Pattan static int 63307db4a97SReshma Pattan lcore_worker(struct lcore_params *p) 63407db4a97SReshma Pattan { 63507db4a97SReshma Pattan struct rte_distributor *d = p->d; 63607db4a97SReshma Pattan const unsigned id = p->worker_id; 637c0de0eb8SDavid Hunt unsigned int num = 0; 638c0de0eb8SDavid Hunt unsigned int i; 639c0de0eb8SDavid Hunt 64007db4a97SReshma Pattan /* 64107db4a97SReshma Pattan * for single port, xor_val will be zero so we won't modify the output 64207db4a97SReshma Pattan * port, otherwise we send traffic from 0 to 1, 2 to 3, and vice versa 64307db4a97SReshma Pattan */ 644d9a42a69SThomas Monjalon const unsigned xor_val = (rte_eth_dev_count_avail() > 1); 6457e06c0deSTyler Retzlaff alignas(RTE_CACHE_LINE_SIZE) struct rte_mbuf *buf[8]; 646c0de0eb8SDavid Hunt 647c0de0eb8SDavid Hunt for (i = 0; i < 8; i++) 648c0de0eb8SDavid Hunt buf[i] = NULL; 64907db4a97SReshma Pattan 650fce56395SDavid Hunt app_stats.worker_pkts[p->worker_id] = 1; 651fce56395SDavid Hunt 65207db4a97SReshma Pattan printf("\nCore %u acting as worker core.\n", rte_lcore_id()); 6534a7f40c0SDavid Hunt while (!quit_signal_work) { 654c0de0eb8SDavid Hunt num = rte_distributor_get_pkt(d, id, buf, buf, num); 655c0de0eb8SDavid Hunt /* Do a little bit of work for each packet */ 656c0de0eb8SDavid Hunt for (i = 0; i < num; i++) { 657c0de0eb8SDavid Hunt uint64_t t = rte_rdtsc()+100; 658c0de0eb8SDavid Hunt 659c0de0eb8SDavid Hunt while (rte_rdtsc() < t) 660c0de0eb8SDavid Hunt rte_pause(); 661c0de0eb8SDavid Hunt buf[i]->port ^= xor_val; 662c0de0eb8SDavid Hunt } 663fce56395SDavid Hunt 664fce56395SDavid Hunt app_stats.worker_pkts[p->worker_id] += num; 665fce56395SDavid Hunt if (num > 0) 666fce56395SDavid Hunt app_stats.worker_bursts[p->worker_id][num-1]++; 66707db4a97SReshma Pattan } 668f73477e2SDavid Hunt if (power_lib_initialised) 669f73477e2SDavid Hunt rte_power_exit(rte_lcore_id()); 670f73477e2SDavid Hunt rte_free(p); 67107db4a97SReshma Pattan return 0; 67207db4a97SReshma Pattan } 67307db4a97SReshma Pattan 674f73477e2SDavid Hunt static int 675f73477e2SDavid Hunt init_power_library(void) 676f73477e2SDavid Hunt { 677f73477e2SDavid Hunt int ret = 0, lcore_id; 678cb056611SStephen Hemminger RTE_LCORE_FOREACH_WORKER(lcore_id) { 679f73477e2SDavid Hunt /* init power management library */ 680f73477e2SDavid Hunt ret = rte_power_init(lcore_id); 681f73477e2SDavid Hunt if (ret) { 6828bae59edSStephen Hemminger fprintf(stderr, 683f73477e2SDavid Hunt "Library initialization failed on core %u\n", 684f73477e2SDavid Hunt lcore_id); 685f73477e2SDavid Hunt /* 686f73477e2SDavid Hunt * Return on first failure, we'll fall back 687f73477e2SDavid Hunt * to non-power operation 688f73477e2SDavid Hunt */ 689f73477e2SDavid Hunt return ret; 690f73477e2SDavid Hunt } 691f73477e2SDavid Hunt } 692f73477e2SDavid Hunt return ret; 693f73477e2SDavid Hunt } 694f73477e2SDavid Hunt 69507db4a97SReshma Pattan /* display usage */ 69607db4a97SReshma Pattan static void 69707db4a97SReshma Pattan print_usage(const char *prgname) 69807db4a97SReshma Pattan { 6993429d6ddSAbdullah Ömer Yamaç printf("%s [EAL options] -- -p PORTMASK [-c]\n" 7003429d6ddSAbdullah Ömer Yamaç " -p PORTMASK: hexadecimal bitmask of ports to configure\n" 7013429d6ddSAbdullah Ömer Yamaç " -c: Combines the RX core with the distribution core\n", 70207db4a97SReshma Pattan prgname); 70307db4a97SReshma Pattan } 70407db4a97SReshma Pattan 70507db4a97SReshma Pattan static int 70607db4a97SReshma Pattan parse_portmask(const char *portmask) 70707db4a97SReshma Pattan { 70807db4a97SReshma Pattan char *end = NULL; 70907db4a97SReshma Pattan unsigned long pm; 71007db4a97SReshma Pattan 71107db4a97SReshma Pattan /* parse hexadecimal string */ 71207db4a97SReshma Pattan pm = strtoul(portmask, &end, 16); 71307db4a97SReshma Pattan if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) 714ce6b8c31SSarosh Arif return 0; 71507db4a97SReshma Pattan 71607db4a97SReshma Pattan return pm; 71707db4a97SReshma Pattan } 71807db4a97SReshma Pattan 71907db4a97SReshma Pattan /* Parse the argument given in the command line of the application */ 72007db4a97SReshma Pattan static int 72107db4a97SReshma Pattan parse_args(int argc, char **argv) 72207db4a97SReshma Pattan { 72307db4a97SReshma Pattan int opt; 72407db4a97SReshma Pattan char **argvopt; 72507db4a97SReshma Pattan int option_index; 72607db4a97SReshma Pattan char *prgname = argv[0]; 72707db4a97SReshma Pattan static struct option lgopts[] = { 72807db4a97SReshma Pattan {NULL, 0, 0, 0} 72907db4a97SReshma Pattan }; 73007db4a97SReshma Pattan 73107db4a97SReshma Pattan argvopt = argv; 7323429d6ddSAbdullah Ömer Yamaç enable_lcore_rx_distributor = false; 7333429d6ddSAbdullah Ömer Yamaç while ((opt = getopt_long(argc, argvopt, "cp:", 73407db4a97SReshma Pattan lgopts, &option_index)) != EOF) { 73507db4a97SReshma Pattan 73607db4a97SReshma Pattan switch (opt) { 73707db4a97SReshma Pattan /* portmask */ 73807db4a97SReshma Pattan case 'p': 73907db4a97SReshma Pattan enabled_port_mask = parse_portmask(optarg); 74007db4a97SReshma Pattan if (enabled_port_mask == 0) { 74107db4a97SReshma Pattan printf("invalid portmask\n"); 74207db4a97SReshma Pattan print_usage(prgname); 74307db4a97SReshma Pattan return -1; 74407db4a97SReshma Pattan } 74507db4a97SReshma Pattan break; 74607db4a97SReshma Pattan 7473429d6ddSAbdullah Ömer Yamaç case 'c': 7483429d6ddSAbdullah Ömer Yamaç enable_lcore_rx_distributor = true; 7493429d6ddSAbdullah Ömer Yamaç break; 7503429d6ddSAbdullah Ömer Yamaç 75107db4a97SReshma Pattan default: 75207db4a97SReshma Pattan print_usage(prgname); 75307db4a97SReshma Pattan return -1; 75407db4a97SReshma Pattan } 75507db4a97SReshma Pattan } 75607db4a97SReshma Pattan 75707db4a97SReshma Pattan if (optind <= 1) { 75807db4a97SReshma Pattan print_usage(prgname); 75907db4a97SReshma Pattan return -1; 76007db4a97SReshma Pattan } 76107db4a97SReshma Pattan 76207db4a97SReshma Pattan argv[optind-1] = prgname; 76307db4a97SReshma Pattan 7649d5ca532SKeith Wiles optind = 1; /* reset getopt lib */ 76507db4a97SReshma Pattan return 0; 76607db4a97SReshma Pattan } 76707db4a97SReshma Pattan 76807db4a97SReshma Pattan /* Main function, does initialization and calls the per-lcore functions */ 76907db4a97SReshma Pattan int 77098a16481SDavid Marchand main(int argc, char *argv[]) 77107db4a97SReshma Pattan { 77207db4a97SReshma Pattan struct rte_mempool *mbuf_pool; 77307db4a97SReshma Pattan struct rte_distributor *d; 7744a7f40c0SDavid Hunt struct rte_ring *dist_tx_ring; 7754a7f40c0SDavid Hunt struct rte_ring *rx_dist_ring; 776f73477e2SDavid Hunt struct rte_power_core_capabilities lcore_cap; 777f73477e2SDavid Hunt unsigned int lcore_id, worker_id = 0; 778f73477e2SDavid Hunt int distr_core_id = -1, rx_core_id = -1, tx_core_id = -1; 77907db4a97SReshma Pattan unsigned nb_ports; 7803429d6ddSAbdullah Ömer Yamaç unsigned int min_cores; 781f8244c63SZhiyong Yang uint16_t portid; 782f8244c63SZhiyong Yang uint16_t nb_ports_available; 783eecb8128SDavid Hunt uint64_t t, freq; 78407db4a97SReshma Pattan 78507db4a97SReshma Pattan /* catch ctrl-c so we can print on exit */ 78607db4a97SReshma Pattan signal(SIGINT, int_handler); 78707db4a97SReshma Pattan 78807db4a97SReshma Pattan /* init EAL */ 78907db4a97SReshma Pattan int ret = rte_eal_init(argc, argv); 79007db4a97SReshma Pattan if (ret < 0) 79107db4a97SReshma Pattan rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); 79207db4a97SReshma Pattan argc -= ret; 79307db4a97SReshma Pattan argv += ret; 79407db4a97SReshma Pattan 79507db4a97SReshma Pattan /* parse application arguments (after the EAL ones) */ 79607db4a97SReshma Pattan ret = parse_args(argc, argv); 79707db4a97SReshma Pattan if (ret < 0) 79807db4a97SReshma Pattan rte_exit(EXIT_FAILURE, "Invalid distributor parameters\n"); 79907db4a97SReshma Pattan 8003429d6ddSAbdullah Ömer Yamaç if (enable_lcore_rx_distributor) { 8013429d6ddSAbdullah Ömer Yamaç /* RX and distributor combined, 3 fixed function cores (stat, TX, at least 1 worker) */ 8023429d6ddSAbdullah Ömer Yamaç min_cores = 4; 8033429d6ddSAbdullah Ömer Yamaç num_workers = rte_lcore_count() - 3; 8043429d6ddSAbdullah Ömer Yamaç } else { 8053429d6ddSAbdullah Ömer Yamaç /* separate RX and distributor, 3 fixed function cores (stat, TX, at least 1 worker) */ 8063429d6ddSAbdullah Ömer Yamaç min_cores = 5; 8073429d6ddSAbdullah Ömer Yamaç num_workers = rte_lcore_count() - 4; 8083429d6ddSAbdullah Ömer Yamaç } 8093429d6ddSAbdullah Ömer Yamaç 8103429d6ddSAbdullah Ömer Yamaç if (rte_lcore_count() < min_cores) 81107db4a97SReshma Pattan rte_exit(EXIT_FAILURE, "Error, This application needs at " 8123429d6ddSAbdullah Ömer Yamaç "least 4 logical cores to run:\n" 813e80046e5SDavid Hunt "1 lcore for stats (can be core 0)\n" 8143429d6ddSAbdullah Ömer Yamaç "1 or 2 lcore for packet RX and distribution\n" 81507db4a97SReshma Pattan "1 lcore for packet TX\n" 81607db4a97SReshma Pattan "and at least 1 lcore for worker threads\n"); 81707db4a97SReshma Pattan 818f73477e2SDavid Hunt if (init_power_library() == 0) 819f73477e2SDavid Hunt power_lib_initialised = 1; 820f73477e2SDavid Hunt 821d9a42a69SThomas Monjalon nb_ports = rte_eth_dev_count_avail(); 82207db4a97SReshma Pattan if (nb_ports == 0) 82307db4a97SReshma Pattan rte_exit(EXIT_FAILURE, "Error: no ethernet ports detected\n"); 82407db4a97SReshma Pattan if (nb_ports != 1 && (nb_ports & 1)) 82507db4a97SReshma Pattan rte_exit(EXIT_FAILURE, "Error: number of ports must be even, except " 82607db4a97SReshma Pattan "when using a single port\n"); 82707db4a97SReshma Pattan 828ea0c20eaSOlivier Matz mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", 829824cb29cSKonstantin Ananyev NUM_MBUFS * nb_ports, MBUF_CACHE_SIZE, 0, 830824cb29cSKonstantin Ananyev RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); 83107db4a97SReshma Pattan if (mbuf_pool == NULL) 83207db4a97SReshma Pattan rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n"); 83307db4a97SReshma Pattan nb_ports_available = nb_ports; 83407db4a97SReshma Pattan 83507db4a97SReshma Pattan /* initialize all ports */ 8368728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) { 83707db4a97SReshma Pattan /* skip ports that are not enabled */ 83807db4a97SReshma Pattan if ((enabled_port_mask & (1 << portid)) == 0) { 83907db4a97SReshma Pattan printf("\nSkipping disabled port %d\n", portid); 84007db4a97SReshma Pattan nb_ports_available--; 84107db4a97SReshma Pattan continue; 84207db4a97SReshma Pattan } 84307db4a97SReshma Pattan /* init port */ 844f8244c63SZhiyong Yang printf("Initializing port %u... done\n", portid); 84507db4a97SReshma Pattan 84607db4a97SReshma Pattan if (port_init(portid, mbuf_pool) != 0) 847f8244c63SZhiyong Yang rte_exit(EXIT_FAILURE, "Cannot initialize port %u\n", 84807db4a97SReshma Pattan portid); 84907db4a97SReshma Pattan } 85007db4a97SReshma Pattan 85107db4a97SReshma Pattan if (!nb_ports_available) { 85207db4a97SReshma Pattan rte_exit(EXIT_FAILURE, 85307db4a97SReshma Pattan "All available ports are disabled. Please set portmask.\n"); 85407db4a97SReshma Pattan } 85507db4a97SReshma Pattan 85607db4a97SReshma Pattan d = rte_distributor_create("PKT_DIST", rte_socket_id(), 8573429d6ddSAbdullah Ömer Yamaç num_workers, 858c0de0eb8SDavid Hunt RTE_DIST_ALG_BURST); 85907db4a97SReshma Pattan if (d == NULL) 86007db4a97SReshma Pattan rte_exit(EXIT_FAILURE, "Cannot create distributor\n"); 86107db4a97SReshma Pattan 86207db4a97SReshma Pattan /* 8634a7f40c0SDavid Hunt * scheduler ring is read by the transmitter core, and written to 8644a7f40c0SDavid Hunt * by scheduler core 86507db4a97SReshma Pattan */ 8664a7f40c0SDavid Hunt dist_tx_ring = rte_ring_create("Output_ring", SCHED_TX_RING_SZ, 8674a7f40c0SDavid Hunt rte_socket_id(), RING_F_SC_DEQ | RING_F_SP_ENQ); 8684a7f40c0SDavid Hunt if (dist_tx_ring == NULL) 8694a7f40c0SDavid Hunt rte_exit(EXIT_FAILURE, "Cannot create output ring\n"); 8704a7f40c0SDavid Hunt 8714a7f40c0SDavid Hunt rx_dist_ring = rte_ring_create("Input_ring", SCHED_RX_RING_SZ, 8724a7f40c0SDavid Hunt rte_socket_id(), RING_F_SC_DEQ | RING_F_SP_ENQ); 8734a7f40c0SDavid Hunt if (rx_dist_ring == NULL) 87407db4a97SReshma Pattan rte_exit(EXIT_FAILURE, "Cannot create output ring\n"); 87507db4a97SReshma Pattan 876f73477e2SDavid Hunt if (power_lib_initialised) { 877f73477e2SDavid Hunt /* 878f73477e2SDavid Hunt * Here we'll pre-assign lcore ids to the rx, tx and 879f73477e2SDavid Hunt * distributor workloads if there's higher frequency 880f73477e2SDavid Hunt * on those cores e.g. if Turbo Boost is enabled. 881f73477e2SDavid Hunt * It's also worth mentioning that it will assign cores in a 882f73477e2SDavid Hunt * specific order, so that if there's less than three 883f73477e2SDavid Hunt * available, the higher frequency cores will go to the 884f73477e2SDavid Hunt * distributor first, then rx, then tx. 885f73477e2SDavid Hunt */ 886cb056611SStephen Hemminger RTE_LCORE_FOREACH_WORKER(lcore_id) { 887f73477e2SDavid Hunt 888f73477e2SDavid Hunt rte_power_get_capabilities(lcore_id, &lcore_cap); 889f73477e2SDavid Hunt 890f73477e2SDavid Hunt if (lcore_cap.priority != 1) 891f73477e2SDavid Hunt continue; 892f73477e2SDavid Hunt 8933429d6ddSAbdullah Ömer Yamaç if (distr_core_id < 0 && !enable_lcore_rx_distributor) { 894f73477e2SDavid Hunt distr_core_id = lcore_id; 895f73477e2SDavid Hunt printf("Distributor on priority core %d\n", 8964a7f40c0SDavid Hunt lcore_id); 897f73477e2SDavid Hunt continue; 898f73477e2SDavid Hunt } 899f73477e2SDavid Hunt if (rx_core_id < 0) { 900f73477e2SDavid Hunt rx_core_id = lcore_id; 901f73477e2SDavid Hunt printf("Rx on priority core %d\n", 902f73477e2SDavid Hunt lcore_id); 903f73477e2SDavid Hunt continue; 904f73477e2SDavid Hunt } 905f73477e2SDavid Hunt if (tx_core_id < 0) { 906f73477e2SDavid Hunt tx_core_id = lcore_id; 907f73477e2SDavid Hunt printf("Tx on priority core %d\n", 908f73477e2SDavid Hunt lcore_id); 909f73477e2SDavid Hunt continue; 910f73477e2SDavid Hunt } 911f73477e2SDavid Hunt } 912f73477e2SDavid Hunt } 913f73477e2SDavid Hunt 914f73477e2SDavid Hunt /* 915f73477e2SDavid Hunt * If there's any of the key workloads left without an lcore_id 916f73477e2SDavid Hunt * after the high performing core assignment above, pre-assign 917f73477e2SDavid Hunt * them here. 918f73477e2SDavid Hunt */ 919cb056611SStephen Hemminger RTE_LCORE_FOREACH_WORKER(lcore_id) { 920f73477e2SDavid Hunt if (lcore_id == (unsigned int)distr_core_id || 921f73477e2SDavid Hunt lcore_id == (unsigned int)rx_core_id || 922f73477e2SDavid Hunt lcore_id == (unsigned int)tx_core_id) 923f73477e2SDavid Hunt continue; 9243429d6ddSAbdullah Ömer Yamaç if (distr_core_id < 0 && !enable_lcore_rx_distributor) { 925f73477e2SDavid Hunt distr_core_id = lcore_id; 926f73477e2SDavid Hunt printf("Distributor on core %d\n", lcore_id); 927f73477e2SDavid Hunt continue; 928f73477e2SDavid Hunt } 929f73477e2SDavid Hunt if (rx_core_id < 0) { 930f73477e2SDavid Hunt rx_core_id = lcore_id; 931f73477e2SDavid Hunt printf("Rx on core %d\n", lcore_id); 932f73477e2SDavid Hunt continue; 933f73477e2SDavid Hunt } 934f73477e2SDavid Hunt if (tx_core_id < 0) { 935f73477e2SDavid Hunt tx_core_id = lcore_id; 936f73477e2SDavid Hunt printf("Tx on core %d\n", lcore_id); 937f73477e2SDavid Hunt continue; 938f73477e2SDavid Hunt } 939f73477e2SDavid Hunt } 940f73477e2SDavid Hunt 9413429d6ddSAbdullah Ömer Yamaç if (enable_lcore_rx_distributor) 9423429d6ddSAbdullah Ömer Yamaç printf(" tx id %d, rx id %d\n", 9433429d6ddSAbdullah Ömer Yamaç tx_core_id, 9443429d6ddSAbdullah Ömer Yamaç rx_core_id); 9453429d6ddSAbdullah Ömer Yamaç else 946f73477e2SDavid Hunt printf(" tx id %d, dist id %d, rx id %d\n", 947f73477e2SDavid Hunt tx_core_id, 948f73477e2SDavid Hunt distr_core_id, 949f73477e2SDavid Hunt rx_core_id); 950f73477e2SDavid Hunt 951f73477e2SDavid Hunt /* 952f73477e2SDavid Hunt * Kick off all the worker threads first, avoiding the pre-assigned 953f73477e2SDavid Hunt * lcore_ids for tx, rx and distributor workloads. 954f73477e2SDavid Hunt */ 955cb056611SStephen Hemminger RTE_LCORE_FOREACH_WORKER(lcore_id) { 956f73477e2SDavid Hunt if (lcore_id == (unsigned int)distr_core_id || 957f73477e2SDavid Hunt lcore_id == (unsigned int)rx_core_id || 958f73477e2SDavid Hunt lcore_id == (unsigned int)tx_core_id) 959f73477e2SDavid Hunt continue; 960f73477e2SDavid Hunt printf("Starting thread %d as worker, lcore_id %d\n", 961fce56395SDavid Hunt worker_id, lcore_id); 9624a7f40c0SDavid Hunt struct lcore_params *p = 9634a7f40c0SDavid Hunt rte_malloc(NULL, sizeof(*p), 0); 9644a7f40c0SDavid Hunt if (!p) 9654a7f40c0SDavid Hunt rte_panic("malloc failure\n"); 966f73477e2SDavid Hunt *p = (struct lcore_params){worker_id++, d, rx_dist_ring, 9674a7f40c0SDavid Hunt dist_tx_ring, mbuf_pool}; 96807db4a97SReshma Pattan 96907db4a97SReshma Pattan rte_eal_remote_launch((lcore_function_t *)lcore_worker, 97007db4a97SReshma Pattan p, lcore_id); 97107db4a97SReshma Pattan } 972f73477e2SDavid Hunt 973f73477e2SDavid Hunt /* Start tx core */ 974f73477e2SDavid Hunt rte_eal_remote_launch((lcore_function_t *)lcore_tx, 975f73477e2SDavid Hunt dist_tx_ring, tx_core_id); 976f73477e2SDavid Hunt 977f73477e2SDavid Hunt /* Start distributor core */ 9783429d6ddSAbdullah Ömer Yamaç struct lcore_params *pd = NULL; 9793429d6ddSAbdullah Ömer Yamaç if (!enable_lcore_rx_distributor) { 9803429d6ddSAbdullah Ömer Yamaç pd = rte_malloc(NULL, sizeof(*pd), 0); 981f73477e2SDavid Hunt if (!pd) 982f73477e2SDavid Hunt rte_panic("malloc failure\n"); 983f73477e2SDavid Hunt *pd = (struct lcore_params){worker_id++, d, 984f73477e2SDavid Hunt rx_dist_ring, dist_tx_ring, mbuf_pool}; 9853429d6ddSAbdullah Ömer Yamaç rte_eal_remote_launch((lcore_function_t *)lcore_distributor, 986f73477e2SDavid Hunt pd, distr_core_id); 9873429d6ddSAbdullah Ömer Yamaç } 988f73477e2SDavid Hunt 989f73477e2SDavid Hunt /* Start rx core */ 990f73477e2SDavid Hunt struct lcore_params *pr = 991f73477e2SDavid Hunt rte_malloc(NULL, sizeof(*pr), 0); 992f73477e2SDavid Hunt if (!pr) 993f73477e2SDavid Hunt rte_panic("malloc failure\n"); 994f73477e2SDavid Hunt *pr = (struct lcore_params){worker_id++, d, rx_dist_ring, 995f73477e2SDavid Hunt dist_tx_ring, mbuf_pool}; 9963429d6ddSAbdullah Ömer Yamaç if (enable_lcore_rx_distributor) 9973429d6ddSAbdullah Ömer Yamaç rte_eal_remote_launch((lcore_function_t *)lcore_rx_and_distributor, 9983429d6ddSAbdullah Ömer Yamaç pr, rx_core_id); 9993429d6ddSAbdullah Ömer Yamaç else 1000f73477e2SDavid Hunt rte_eal_remote_launch((lcore_function_t *)lcore_rx, 1001f73477e2SDavid Hunt pr, rx_core_id); 100207db4a97SReshma Pattan 1003eecb8128SDavid Hunt freq = rte_get_timer_hz(); 1004eecb8128SDavid Hunt t = rte_rdtsc() + freq; 10053429d6ddSAbdullah Ömer Yamaç while (!quit_signal) { 1006eecb8128SDavid Hunt if (t < rte_rdtsc()) { 1007eecb8128SDavid Hunt print_stats(); 1008eecb8128SDavid Hunt t = rte_rdtsc() + freq; 1009eecb8128SDavid Hunt } 1010eecb8128SDavid Hunt usleep(1000); 1011eecb8128SDavid Hunt } 1012eecb8128SDavid Hunt 1013cb056611SStephen Hemminger RTE_LCORE_FOREACH_WORKER(lcore_id) { 101407db4a97SReshma Pattan if (rte_eal_wait_lcore(lcore_id) < 0) 101507db4a97SReshma Pattan return -1; 101607db4a97SReshma Pattan } 101707db4a97SReshma Pattan 101807db4a97SReshma Pattan print_stats(); 1019f73477e2SDavid Hunt 1020f73477e2SDavid Hunt rte_free(pd); 1021f73477e2SDavid Hunt rte_free(pr); 1022f73477e2SDavid Hunt 102310aa3757SChengchang Tang /* clean up the EAL */ 102410aa3757SChengchang Tang rte_eal_cleanup(); 102510aa3757SChengchang Tang 102607db4a97SReshma Pattan return 0; 102707db4a97SReshma Pattan } 1028