1d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2d30ea906Sjfb8856606 * Copyright(c) 2010-2017 Intel Corporation
3a9643ea8Slogwang */
4a9643ea8Slogwang
5a9643ea8Slogwang #include <stdint.h>
6a9643ea8Slogwang #include <inttypes.h>
7a9643ea8Slogwang #include <unistd.h>
8a9643ea8Slogwang #include <signal.h>
9a9643ea8Slogwang #include <getopt.h>
10a9643ea8Slogwang
11a9643ea8Slogwang #include <rte_eal.h>
12a9643ea8Slogwang #include <rte_ethdev.h>
13a9643ea8Slogwang #include <rte_cycles.h>
14a9643ea8Slogwang #include <rte_malloc.h>
15a9643ea8Slogwang #include <rte_debug.h>
16a9643ea8Slogwang #include <rte_prefetch.h>
17a9643ea8Slogwang #include <rte_distributor.h>
182bfe3f2eSlogwang #include <rte_pause.h>
194418919fSjohnjiang #include <rte_power.h>
20a9643ea8Slogwang
21d30ea906Sjfb8856606 #define RX_RING_SIZE 1024
22d30ea906Sjfb8856606 #define TX_RING_SIZE 1024
23a9643ea8Slogwang #define NUM_MBUFS ((64*1024)-1)
242bfe3f2eSlogwang #define MBUF_CACHE_SIZE 128
252bfe3f2eSlogwang #define BURST_SIZE 64
262bfe3f2eSlogwang #define SCHED_RX_RING_SZ 8192
272bfe3f2eSlogwang #define SCHED_TX_RING_SZ 65536
282bfe3f2eSlogwang #define BURST_SIZE_TX 32
29a9643ea8Slogwang
30a9643ea8Slogwang #define RTE_LOGTYPE_DISTRAPP RTE_LOGTYPE_USER1
31a9643ea8Slogwang
322bfe3f2eSlogwang #define ANSI_COLOR_RED "\x1b[31m"
332bfe3f2eSlogwang #define ANSI_COLOR_RESET "\x1b[0m"
342bfe3f2eSlogwang
35a9643ea8Slogwang /* mask of enabled ports */
36a9643ea8Slogwang static uint32_t enabled_port_mask;
37a9643ea8Slogwang volatile uint8_t quit_signal;
38a9643ea8Slogwang volatile uint8_t quit_signal_rx;
392bfe3f2eSlogwang volatile uint8_t quit_signal_dist;
402bfe3f2eSlogwang volatile uint8_t quit_signal_work;
414418919fSjohnjiang unsigned int power_lib_initialised;
42a9643ea8Slogwang
43a9643ea8Slogwang static volatile struct app_stats {
44a9643ea8Slogwang struct {
45a9643ea8Slogwang uint64_t rx_pkts;
46a9643ea8Slogwang uint64_t returned_pkts;
47a9643ea8Slogwang uint64_t enqueued_pkts;
482bfe3f2eSlogwang uint64_t enqdrop_pkts;
49a9643ea8Slogwang } rx __rte_cache_aligned;
502bfe3f2eSlogwang int pad1 __rte_cache_aligned;
512bfe3f2eSlogwang
522bfe3f2eSlogwang struct {
532bfe3f2eSlogwang uint64_t in_pkts;
542bfe3f2eSlogwang uint64_t ret_pkts;
552bfe3f2eSlogwang uint64_t sent_pkts;
562bfe3f2eSlogwang uint64_t enqdrop_pkts;
572bfe3f2eSlogwang } dist __rte_cache_aligned;
582bfe3f2eSlogwang int pad2 __rte_cache_aligned;
59a9643ea8Slogwang
60a9643ea8Slogwang struct {
61a9643ea8Slogwang uint64_t dequeue_pkts;
62a9643ea8Slogwang uint64_t tx_pkts;
632bfe3f2eSlogwang uint64_t enqdrop_pkts;
64a9643ea8Slogwang } tx __rte_cache_aligned;
652bfe3f2eSlogwang int pad3 __rte_cache_aligned;
662bfe3f2eSlogwang
672bfe3f2eSlogwang uint64_t worker_pkts[64] __rte_cache_aligned;
682bfe3f2eSlogwang
692bfe3f2eSlogwang int pad4 __rte_cache_aligned;
702bfe3f2eSlogwang
712bfe3f2eSlogwang uint64_t worker_bursts[64][8] __rte_cache_aligned;
722bfe3f2eSlogwang
732bfe3f2eSlogwang int pad5 __rte_cache_aligned;
742bfe3f2eSlogwang
752bfe3f2eSlogwang uint64_t port_rx_pkts[64] __rte_cache_aligned;
762bfe3f2eSlogwang uint64_t port_tx_pkts[64] __rte_cache_aligned;
77a9643ea8Slogwang } app_stats;
78a9643ea8Slogwang
792bfe3f2eSlogwang struct app_stats prev_app_stats;
802bfe3f2eSlogwang
81a9643ea8Slogwang static const struct rte_eth_conf port_conf_default = {
82a9643ea8Slogwang .rxmode = {
83a9643ea8Slogwang .mq_mode = ETH_MQ_RX_RSS,
844418919fSjohnjiang .max_rx_pkt_len = RTE_ETHER_MAX_LEN,
85a9643ea8Slogwang },
86a9643ea8Slogwang .txmode = {
87a9643ea8Slogwang .mq_mode = ETH_MQ_TX_NONE,
88a9643ea8Slogwang },
89a9643ea8Slogwang .rx_adv_conf = {
90a9643ea8Slogwang .rss_conf = {
91a9643ea8Slogwang .rss_hf = ETH_RSS_IP | ETH_RSS_UDP |
92a9643ea8Slogwang ETH_RSS_TCP | ETH_RSS_SCTP,
93a9643ea8Slogwang }
94a9643ea8Slogwang },
95a9643ea8Slogwang };
96a9643ea8Slogwang
97a9643ea8Slogwang struct output_buffer {
98a9643ea8Slogwang unsigned count;
99a9643ea8Slogwang struct rte_mbuf *mbufs[BURST_SIZE];
100a9643ea8Slogwang };
101a9643ea8Slogwang
1022bfe3f2eSlogwang static void print_stats(void);
1032bfe3f2eSlogwang
104a9643ea8Slogwang /*
105a9643ea8Slogwang * Initialises a given port using global settings and with the rx buffers
106a9643ea8Slogwang * coming from the mbuf_pool passed as parameter
107a9643ea8Slogwang */
108a9643ea8Slogwang static inline int
port_init(uint16_t port,struct rte_mempool * mbuf_pool)1092bfe3f2eSlogwang port_init(uint16_t port, struct rte_mempool *mbuf_pool)
110a9643ea8Slogwang {
111a9643ea8Slogwang struct rte_eth_conf port_conf = port_conf_default;
112a9643ea8Slogwang const uint16_t rxRings = 1, txRings = rte_lcore_count() - 1;
113a9643ea8Slogwang int retval;
114a9643ea8Slogwang uint16_t q;
1152bfe3f2eSlogwang uint16_t nb_rxd = RX_RING_SIZE;
1162bfe3f2eSlogwang uint16_t nb_txd = TX_RING_SIZE;
117d30ea906Sjfb8856606 struct rte_eth_dev_info dev_info;
118d30ea906Sjfb8856606 struct rte_eth_txconf txconf;
119a9643ea8Slogwang
120d30ea906Sjfb8856606 if (!rte_eth_dev_is_valid_port(port))
121a9643ea8Slogwang return -1;
122a9643ea8Slogwang
1234418919fSjohnjiang retval = rte_eth_dev_info_get(port, &dev_info);
1244418919fSjohnjiang if (retval != 0) {
1254418919fSjohnjiang printf("Error during getting device (port %u) info: %s\n",
1264418919fSjohnjiang port, strerror(-retval));
1274418919fSjohnjiang return retval;
1284418919fSjohnjiang }
1294418919fSjohnjiang
130d30ea906Sjfb8856606 if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
131d30ea906Sjfb8856606 port_conf.txmode.offloads |=
132d30ea906Sjfb8856606 DEV_TX_OFFLOAD_MBUF_FAST_FREE;
133d30ea906Sjfb8856606
134d30ea906Sjfb8856606 port_conf.rx_adv_conf.rss_conf.rss_hf &=
135d30ea906Sjfb8856606 dev_info.flow_type_rss_offloads;
136d30ea906Sjfb8856606 if (port_conf.rx_adv_conf.rss_conf.rss_hf !=
137d30ea906Sjfb8856606 port_conf_default.rx_adv_conf.rss_conf.rss_hf) {
138d30ea906Sjfb8856606 printf("Port %u modified RSS hash function based on hardware support,"
139d30ea906Sjfb8856606 "requested:%#"PRIx64" configured:%#"PRIx64"\n",
140d30ea906Sjfb8856606 port,
141d30ea906Sjfb8856606 port_conf_default.rx_adv_conf.rss_conf.rss_hf,
142d30ea906Sjfb8856606 port_conf.rx_adv_conf.rss_conf.rss_hf);
143d30ea906Sjfb8856606 }
144d30ea906Sjfb8856606
145a9643ea8Slogwang retval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf);
146a9643ea8Slogwang if (retval != 0)
147a9643ea8Slogwang return retval;
148a9643ea8Slogwang
1492bfe3f2eSlogwang retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd);
1502bfe3f2eSlogwang if (retval != 0)
1512bfe3f2eSlogwang return retval;
1522bfe3f2eSlogwang
153a9643ea8Slogwang for (q = 0; q < rxRings; q++) {
1542bfe3f2eSlogwang retval = rte_eth_rx_queue_setup(port, q, nb_rxd,
155a9643ea8Slogwang rte_eth_dev_socket_id(port),
156a9643ea8Slogwang NULL, mbuf_pool);
157a9643ea8Slogwang if (retval < 0)
158a9643ea8Slogwang return retval;
159a9643ea8Slogwang }
160a9643ea8Slogwang
161d30ea906Sjfb8856606 txconf = dev_info.default_txconf;
162d30ea906Sjfb8856606 txconf.offloads = port_conf.txmode.offloads;
163a9643ea8Slogwang for (q = 0; q < txRings; q++) {
1642bfe3f2eSlogwang retval = rte_eth_tx_queue_setup(port, q, nb_txd,
165a9643ea8Slogwang rte_eth_dev_socket_id(port),
166d30ea906Sjfb8856606 &txconf);
167a9643ea8Slogwang if (retval < 0)
168a9643ea8Slogwang return retval;
169a9643ea8Slogwang }
170a9643ea8Slogwang
171a9643ea8Slogwang retval = rte_eth_dev_start(port);
172a9643ea8Slogwang if (retval < 0)
173a9643ea8Slogwang return retval;
174a9643ea8Slogwang
175a9643ea8Slogwang struct rte_eth_link link;
1764418919fSjohnjiang do {
1774418919fSjohnjiang retval = rte_eth_link_get_nowait(port, &link);
1784418919fSjohnjiang if (retval < 0) {
1794418919fSjohnjiang printf("Failed link get (port %u): %s\n",
1804418919fSjohnjiang port, rte_strerror(-retval));
1814418919fSjohnjiang return retval;
1824418919fSjohnjiang } else if (link.link_status)
1834418919fSjohnjiang break;
1844418919fSjohnjiang
1852bfe3f2eSlogwang printf("Waiting for Link up on port %"PRIu16"\n", port);
186a9643ea8Slogwang sleep(1);
1874418919fSjohnjiang } while (!link.link_status);
188a9643ea8Slogwang
189a9643ea8Slogwang if (!link.link_status) {
1902bfe3f2eSlogwang printf("Link down on port %"PRIu16"\n", port);
191a9643ea8Slogwang return 0;
192a9643ea8Slogwang }
193a9643ea8Slogwang
1944418919fSjohnjiang struct rte_ether_addr addr;
1954418919fSjohnjiang retval = rte_eth_macaddr_get(port, &addr);
1964418919fSjohnjiang if (retval < 0) {
1974418919fSjohnjiang printf("Failed to get MAC address (port %u): %s\n",
1984418919fSjohnjiang port, rte_strerror(-retval));
1994418919fSjohnjiang return retval;
2004418919fSjohnjiang }
2014418919fSjohnjiang
202a9643ea8Slogwang printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
203a9643ea8Slogwang " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
2042bfe3f2eSlogwang port,
205a9643ea8Slogwang addr.addr_bytes[0], addr.addr_bytes[1],
206a9643ea8Slogwang addr.addr_bytes[2], addr.addr_bytes[3],
207a9643ea8Slogwang addr.addr_bytes[4], addr.addr_bytes[5]);
208a9643ea8Slogwang
2094418919fSjohnjiang retval = rte_eth_promiscuous_enable(port);
2104418919fSjohnjiang if (retval != 0)
2114418919fSjohnjiang return retval;
212a9643ea8Slogwang
213a9643ea8Slogwang return 0;
214a9643ea8Slogwang }
215a9643ea8Slogwang
216a9643ea8Slogwang struct lcore_params {
217a9643ea8Slogwang unsigned worker_id;
218a9643ea8Slogwang struct rte_distributor *d;
2192bfe3f2eSlogwang struct rte_ring *rx_dist_ring;
2202bfe3f2eSlogwang struct rte_ring *dist_tx_ring;
221a9643ea8Slogwang struct rte_mempool *mem_pool;
222a9643ea8Slogwang };
223a9643ea8Slogwang
224a9643ea8Slogwang static int
lcore_rx(struct lcore_params * p)225a9643ea8Slogwang lcore_rx(struct lcore_params *p)
226a9643ea8Slogwang {
227d30ea906Sjfb8856606 const uint16_t nb_ports = rte_eth_dev_count_avail();
228a9643ea8Slogwang const int socket_id = rte_socket_id();
2292bfe3f2eSlogwang uint16_t port;
2302bfe3f2eSlogwang struct rte_mbuf *bufs[BURST_SIZE*2];
231a9643ea8Slogwang
232d30ea906Sjfb8856606 RTE_ETH_FOREACH_DEV(port) {
233a9643ea8Slogwang /* skip ports that are not enabled */
234a9643ea8Slogwang if ((enabled_port_mask & (1 << port)) == 0)
235a9643ea8Slogwang continue;
236a9643ea8Slogwang
237a9643ea8Slogwang if (rte_eth_dev_socket_id(port) > 0 &&
238a9643ea8Slogwang rte_eth_dev_socket_id(port) != socket_id)
239a9643ea8Slogwang printf("WARNING, port %u is on remote NUMA node to "
240a9643ea8Slogwang "RX thread.\n\tPerformance will not "
241a9643ea8Slogwang "be optimal.\n", port);
242a9643ea8Slogwang }
243a9643ea8Slogwang
244a9643ea8Slogwang printf("\nCore %u doing packet RX.\n", rte_lcore_id());
245a9643ea8Slogwang port = 0;
246a9643ea8Slogwang while (!quit_signal_rx) {
247a9643ea8Slogwang
248a9643ea8Slogwang /* skip ports that are not enabled */
249a9643ea8Slogwang if ((enabled_port_mask & (1 << port)) == 0) {
250a9643ea8Slogwang if (++port == nb_ports)
251a9643ea8Slogwang port = 0;
252a9643ea8Slogwang continue;
253a9643ea8Slogwang }
254a9643ea8Slogwang const uint16_t nb_rx = rte_eth_rx_burst(port, 0, bufs,
255a9643ea8Slogwang BURST_SIZE);
256a9643ea8Slogwang if (unlikely(nb_rx == 0)) {
257a9643ea8Slogwang if (++port == nb_ports)
258a9643ea8Slogwang port = 0;
259a9643ea8Slogwang continue;
260a9643ea8Slogwang }
261a9643ea8Slogwang app_stats.rx.rx_pkts += nb_rx;
262a9643ea8Slogwang
2632bfe3f2eSlogwang /*
2642bfe3f2eSlogwang * You can run the distributor on the rx core with this code. Returned
2652bfe3f2eSlogwang * packets are then send straight to the tx core.
2662bfe3f2eSlogwang */
2672bfe3f2eSlogwang #if 0
268a9643ea8Slogwang rte_distributor_process(d, bufs, nb_rx);
2692bfe3f2eSlogwang const uint16_t nb_ret = rte_distributor_returned_pktsd,
270a9643ea8Slogwang bufs, BURST_SIZE*2);
2712bfe3f2eSlogwang
272a9643ea8Slogwang app_stats.rx.returned_pkts += nb_ret;
273a9643ea8Slogwang if (unlikely(nb_ret == 0)) {
274a9643ea8Slogwang if (++port == nb_ports)
275a9643ea8Slogwang port = 0;
276a9643ea8Slogwang continue;
277a9643ea8Slogwang }
278a9643ea8Slogwang
2792bfe3f2eSlogwang struct rte_ring *tx_ring = p->dist_tx_ring;
2802bfe3f2eSlogwang uint16_t sent = rte_ring_enqueue_burst(tx_ring,
2812bfe3f2eSlogwang (void *)bufs, nb_ret, NULL);
2822bfe3f2eSlogwang #else
2832bfe3f2eSlogwang uint16_t nb_ret = nb_rx;
2842bfe3f2eSlogwang /*
2852bfe3f2eSlogwang * Swap the following two lines if you want the rx traffic
2862bfe3f2eSlogwang * to go directly to tx, no distribution.
2872bfe3f2eSlogwang */
2882bfe3f2eSlogwang struct rte_ring *out_ring = p->rx_dist_ring;
2892bfe3f2eSlogwang /* struct rte_ring *out_ring = p->dist_tx_ring; */
2902bfe3f2eSlogwang
2912bfe3f2eSlogwang uint16_t sent = rte_ring_enqueue_burst(out_ring,
2922bfe3f2eSlogwang (void *)bufs, nb_ret, NULL);
2932bfe3f2eSlogwang #endif
2942bfe3f2eSlogwang
295a9643ea8Slogwang app_stats.rx.enqueued_pkts += sent;
296a9643ea8Slogwang if (unlikely(sent < nb_ret)) {
2972bfe3f2eSlogwang app_stats.rx.enqdrop_pkts += nb_ret - sent;
2982bfe3f2eSlogwang RTE_LOG_DP(DEBUG, DISTRAPP,
299a9643ea8Slogwang "%s:Packet loss due to full ring\n", __func__);
300a9643ea8Slogwang while (sent < nb_ret)
301a9643ea8Slogwang rte_pktmbuf_free(bufs[sent++]);
302a9643ea8Slogwang }
303a9643ea8Slogwang if (++port == nb_ports)
304a9643ea8Slogwang port = 0;
305a9643ea8Slogwang }
3064418919fSjohnjiang if (power_lib_initialised)
3074418919fSjohnjiang rte_power_exit(rte_lcore_id());
308a9643ea8Slogwang /* set worker & tx threads quit flag */
3092bfe3f2eSlogwang printf("\nCore %u exiting rx task.\n", rte_lcore_id());
310a9643ea8Slogwang quit_signal = 1;
311a9643ea8Slogwang return 0;
312a9643ea8Slogwang }
313a9643ea8Slogwang
314a9643ea8Slogwang static inline void
flush_one_port(struct output_buffer * outbuf,uint8_t outp)315a9643ea8Slogwang flush_one_port(struct output_buffer *outbuf, uint8_t outp)
316a9643ea8Slogwang {
3172bfe3f2eSlogwang unsigned int nb_tx = rte_eth_tx_burst(outp, 0,
3182bfe3f2eSlogwang outbuf->mbufs, outbuf->count);
3192bfe3f2eSlogwang app_stats.tx.tx_pkts += outbuf->count;
320a9643ea8Slogwang
321a9643ea8Slogwang if (unlikely(nb_tx < outbuf->count)) {
3222bfe3f2eSlogwang app_stats.tx.enqdrop_pkts += outbuf->count - nb_tx;
323a9643ea8Slogwang do {
324a9643ea8Slogwang rte_pktmbuf_free(outbuf->mbufs[nb_tx]);
325a9643ea8Slogwang } while (++nb_tx < outbuf->count);
326a9643ea8Slogwang }
327a9643ea8Slogwang outbuf->count = 0;
328a9643ea8Slogwang }
329a9643ea8Slogwang
330a9643ea8Slogwang static inline void
flush_all_ports(struct output_buffer * tx_buffers)331d30ea906Sjfb8856606 flush_all_ports(struct output_buffer *tx_buffers)
332a9643ea8Slogwang {
3332bfe3f2eSlogwang uint16_t outp;
3342bfe3f2eSlogwang
335d30ea906Sjfb8856606 RTE_ETH_FOREACH_DEV(outp) {
336a9643ea8Slogwang /* skip ports that are not enabled */
337a9643ea8Slogwang if ((enabled_port_mask & (1 << outp)) == 0)
338a9643ea8Slogwang continue;
339a9643ea8Slogwang
340a9643ea8Slogwang if (tx_buffers[outp].count == 0)
341a9643ea8Slogwang continue;
342a9643ea8Slogwang
343a9643ea8Slogwang flush_one_port(&tx_buffers[outp], outp);
344a9643ea8Slogwang }
345a9643ea8Slogwang }
346a9643ea8Slogwang
3472bfe3f2eSlogwang
3482bfe3f2eSlogwang
3492bfe3f2eSlogwang static int
lcore_distributor(struct lcore_params * p)3502bfe3f2eSlogwang lcore_distributor(struct lcore_params *p)
3512bfe3f2eSlogwang {
3522bfe3f2eSlogwang struct rte_ring *in_r = p->rx_dist_ring;
3532bfe3f2eSlogwang struct rte_ring *out_r = p->dist_tx_ring;
3542bfe3f2eSlogwang struct rte_mbuf *bufs[BURST_SIZE * 4];
3552bfe3f2eSlogwang struct rte_distributor *d = p->d;
3562bfe3f2eSlogwang
3572bfe3f2eSlogwang printf("\nCore %u acting as distributor core.\n", rte_lcore_id());
3582bfe3f2eSlogwang while (!quit_signal_dist) {
3592bfe3f2eSlogwang const uint16_t nb_rx = rte_ring_dequeue_burst(in_r,
3602bfe3f2eSlogwang (void *)bufs, BURST_SIZE*1, NULL);
3612bfe3f2eSlogwang if (nb_rx) {
3622bfe3f2eSlogwang app_stats.dist.in_pkts += nb_rx;
3632bfe3f2eSlogwang
3642bfe3f2eSlogwang /* Distribute the packets */
3652bfe3f2eSlogwang rte_distributor_process(d, bufs, nb_rx);
3662bfe3f2eSlogwang /* Handle Returns */
3672bfe3f2eSlogwang const uint16_t nb_ret =
3682bfe3f2eSlogwang rte_distributor_returned_pkts(d,
3692bfe3f2eSlogwang bufs, BURST_SIZE*2);
3702bfe3f2eSlogwang
3712bfe3f2eSlogwang if (unlikely(nb_ret == 0))
3722bfe3f2eSlogwang continue;
3732bfe3f2eSlogwang app_stats.dist.ret_pkts += nb_ret;
3742bfe3f2eSlogwang
3752bfe3f2eSlogwang uint16_t sent = rte_ring_enqueue_burst(out_r,
3762bfe3f2eSlogwang (void *)bufs, nb_ret, NULL);
3772bfe3f2eSlogwang app_stats.dist.sent_pkts += sent;
3782bfe3f2eSlogwang if (unlikely(sent < nb_ret)) {
3792bfe3f2eSlogwang app_stats.dist.enqdrop_pkts += nb_ret - sent;
3802bfe3f2eSlogwang RTE_LOG(DEBUG, DISTRAPP,
3812bfe3f2eSlogwang "%s:Packet loss due to full out ring\n",
3822bfe3f2eSlogwang __func__);
3832bfe3f2eSlogwang while (sent < nb_ret)
3842bfe3f2eSlogwang rte_pktmbuf_free(bufs[sent++]);
3852bfe3f2eSlogwang }
3862bfe3f2eSlogwang }
3872bfe3f2eSlogwang }
3882bfe3f2eSlogwang printf("\nCore %u exiting distributor task.\n", rte_lcore_id());
3892bfe3f2eSlogwang quit_signal_work = 1;
3904418919fSjohnjiang if (power_lib_initialised)
3914418919fSjohnjiang rte_power_exit(rte_lcore_id());
3922bfe3f2eSlogwang rte_distributor_flush(d);
3932bfe3f2eSlogwang /* Unblock any returns so workers can exit */
3942bfe3f2eSlogwang rte_distributor_clear_returns(d);
3952bfe3f2eSlogwang quit_signal_rx = 1;
3962bfe3f2eSlogwang return 0;
3972bfe3f2eSlogwang }
3982bfe3f2eSlogwang
3992bfe3f2eSlogwang
400a9643ea8Slogwang static int
lcore_tx(struct rte_ring * in_r)401a9643ea8Slogwang lcore_tx(struct rte_ring *in_r)
402a9643ea8Slogwang {
403a9643ea8Slogwang static struct output_buffer tx_buffers[RTE_MAX_ETHPORTS];
404a9643ea8Slogwang const int socket_id = rte_socket_id();
4052bfe3f2eSlogwang uint16_t port;
406a9643ea8Slogwang
407d30ea906Sjfb8856606 RTE_ETH_FOREACH_DEV(port) {
408a9643ea8Slogwang /* skip ports that are not enabled */
409a9643ea8Slogwang if ((enabled_port_mask & (1 << port)) == 0)
410a9643ea8Slogwang continue;
411a9643ea8Slogwang
412a9643ea8Slogwang if (rte_eth_dev_socket_id(port) > 0 &&
413a9643ea8Slogwang rte_eth_dev_socket_id(port) != socket_id)
414a9643ea8Slogwang printf("WARNING, port %u is on remote NUMA node to "
415a9643ea8Slogwang "TX thread.\n\tPerformance will not "
416a9643ea8Slogwang "be optimal.\n", port);
417a9643ea8Slogwang }
418a9643ea8Slogwang
419a9643ea8Slogwang printf("\nCore %u doing packet TX.\n", rte_lcore_id());
420a9643ea8Slogwang while (!quit_signal) {
421a9643ea8Slogwang
422d30ea906Sjfb8856606 RTE_ETH_FOREACH_DEV(port) {
423a9643ea8Slogwang /* skip ports that are not enabled */
424a9643ea8Slogwang if ((enabled_port_mask & (1 << port)) == 0)
425a9643ea8Slogwang continue;
426a9643ea8Slogwang
4272bfe3f2eSlogwang struct rte_mbuf *bufs[BURST_SIZE_TX];
428a9643ea8Slogwang const uint16_t nb_rx = rte_ring_dequeue_burst(in_r,
4292bfe3f2eSlogwang (void *)bufs, BURST_SIZE_TX, NULL);
430a9643ea8Slogwang app_stats.tx.dequeue_pkts += nb_rx;
431a9643ea8Slogwang
432a9643ea8Slogwang /* if we get no traffic, flush anything we have */
433a9643ea8Slogwang if (unlikely(nb_rx == 0)) {
434d30ea906Sjfb8856606 flush_all_ports(tx_buffers);
435a9643ea8Slogwang continue;
436a9643ea8Slogwang }
437a9643ea8Slogwang
438a9643ea8Slogwang /* for traffic we receive, queue it up for transmit */
439a9643ea8Slogwang uint16_t i;
440a9643ea8Slogwang rte_prefetch_non_temporal((void *)bufs[0]);
441a9643ea8Slogwang rte_prefetch_non_temporal((void *)bufs[1]);
442a9643ea8Slogwang rte_prefetch_non_temporal((void *)bufs[2]);
443a9643ea8Slogwang for (i = 0; i < nb_rx; i++) {
444a9643ea8Slogwang struct output_buffer *outbuf;
445a9643ea8Slogwang uint8_t outp;
446a9643ea8Slogwang rte_prefetch_non_temporal((void *)bufs[i + 3]);
447a9643ea8Slogwang /*
448a9643ea8Slogwang * workers should update in_port to hold the
449a9643ea8Slogwang * output port value
450a9643ea8Slogwang */
451a9643ea8Slogwang outp = bufs[i]->port;
452a9643ea8Slogwang /* skip ports that are not enabled */
453a9643ea8Slogwang if ((enabled_port_mask & (1 << outp)) == 0)
454a9643ea8Slogwang continue;
455a9643ea8Slogwang
456a9643ea8Slogwang outbuf = &tx_buffers[outp];
457a9643ea8Slogwang outbuf->mbufs[outbuf->count++] = bufs[i];
4582bfe3f2eSlogwang if (outbuf->count == BURST_SIZE_TX)
459a9643ea8Slogwang flush_one_port(outbuf, outp);
460a9643ea8Slogwang }
461a9643ea8Slogwang }
462a9643ea8Slogwang }
4634418919fSjohnjiang if (power_lib_initialised)
4644418919fSjohnjiang rte_power_exit(rte_lcore_id());
4652bfe3f2eSlogwang printf("\nCore %u exiting tx task.\n", rte_lcore_id());
466a9643ea8Slogwang return 0;
467a9643ea8Slogwang }
468a9643ea8Slogwang
469a9643ea8Slogwang static void
int_handler(int sig_num)470a9643ea8Slogwang int_handler(int sig_num)
471a9643ea8Slogwang {
472a9643ea8Slogwang printf("Exiting on signal %d\n", sig_num);
473a9643ea8Slogwang /* set quit flag for rx thread to exit */
4742bfe3f2eSlogwang quit_signal_dist = 1;
475a9643ea8Slogwang }
476a9643ea8Slogwang
477a9643ea8Slogwang static void
print_stats(void)478a9643ea8Slogwang print_stats(void)
479a9643ea8Slogwang {
480a9643ea8Slogwang struct rte_eth_stats eth_stats;
4812bfe3f2eSlogwang unsigned int i, j;
4822bfe3f2eSlogwang const unsigned int num_workers = rte_lcore_count() - 4;
483a9643ea8Slogwang
484d30ea906Sjfb8856606 RTE_ETH_FOREACH_DEV(i) {
485a9643ea8Slogwang rte_eth_stats_get(i, ð_stats);
4862bfe3f2eSlogwang app_stats.port_rx_pkts[i] = eth_stats.ipackets;
4872bfe3f2eSlogwang app_stats.port_tx_pkts[i] = eth_stats.opackets;
4882bfe3f2eSlogwang }
4892bfe3f2eSlogwang
4902bfe3f2eSlogwang printf("\n\nRX Thread:\n");
491d30ea906Sjfb8856606 RTE_ETH_FOREACH_DEV(i) {
4922bfe3f2eSlogwang printf("Port %u Pktsin : %5.2f\n", i,
4932bfe3f2eSlogwang (app_stats.port_rx_pkts[i] -
4942bfe3f2eSlogwang prev_app_stats.port_rx_pkts[i])/1000000.0);
4952bfe3f2eSlogwang prev_app_stats.port_rx_pkts[i] = app_stats.port_rx_pkts[i];
4962bfe3f2eSlogwang }
4972bfe3f2eSlogwang printf(" - Received: %5.2f\n",
4982bfe3f2eSlogwang (app_stats.rx.rx_pkts -
4992bfe3f2eSlogwang prev_app_stats.rx.rx_pkts)/1000000.0);
5002bfe3f2eSlogwang printf(" - Returned: %5.2f\n",
5012bfe3f2eSlogwang (app_stats.rx.returned_pkts -
5022bfe3f2eSlogwang prev_app_stats.rx.returned_pkts)/1000000.0);
5032bfe3f2eSlogwang printf(" - Enqueued: %5.2f\n",
5042bfe3f2eSlogwang (app_stats.rx.enqueued_pkts -
5052bfe3f2eSlogwang prev_app_stats.rx.enqueued_pkts)/1000000.0);
5062bfe3f2eSlogwang printf(" - Dropped: %s%5.2f%s\n", ANSI_COLOR_RED,
5072bfe3f2eSlogwang (app_stats.rx.enqdrop_pkts -
5082bfe3f2eSlogwang prev_app_stats.rx.enqdrop_pkts)/1000000.0,
5092bfe3f2eSlogwang ANSI_COLOR_RESET);
5102bfe3f2eSlogwang
5112bfe3f2eSlogwang printf("Distributor thread:\n");
5122bfe3f2eSlogwang printf(" - In: %5.2f\n",
5132bfe3f2eSlogwang (app_stats.dist.in_pkts -
5142bfe3f2eSlogwang prev_app_stats.dist.in_pkts)/1000000.0);
5152bfe3f2eSlogwang printf(" - Returned: %5.2f\n",
5162bfe3f2eSlogwang (app_stats.dist.ret_pkts -
5172bfe3f2eSlogwang prev_app_stats.dist.ret_pkts)/1000000.0);
5182bfe3f2eSlogwang printf(" - Sent: %5.2f\n",
5192bfe3f2eSlogwang (app_stats.dist.sent_pkts -
5202bfe3f2eSlogwang prev_app_stats.dist.sent_pkts)/1000000.0);
5212bfe3f2eSlogwang printf(" - Dropped %s%5.2f%s\n", ANSI_COLOR_RED,
5222bfe3f2eSlogwang (app_stats.dist.enqdrop_pkts -
5232bfe3f2eSlogwang prev_app_stats.dist.enqdrop_pkts)/1000000.0,
5242bfe3f2eSlogwang ANSI_COLOR_RESET);
5252bfe3f2eSlogwang
5262bfe3f2eSlogwang printf("TX thread:\n");
5272bfe3f2eSlogwang printf(" - Dequeued: %5.2f\n",
5282bfe3f2eSlogwang (app_stats.tx.dequeue_pkts -
5292bfe3f2eSlogwang prev_app_stats.tx.dequeue_pkts)/1000000.0);
530d30ea906Sjfb8856606 RTE_ETH_FOREACH_DEV(i) {
5312bfe3f2eSlogwang printf("Port %u Pktsout: %5.2f\n",
5322bfe3f2eSlogwang i, (app_stats.port_tx_pkts[i] -
5332bfe3f2eSlogwang prev_app_stats.port_tx_pkts[i])/1000000.0);
5342bfe3f2eSlogwang prev_app_stats.port_tx_pkts[i] = app_stats.port_tx_pkts[i];
5352bfe3f2eSlogwang }
5362bfe3f2eSlogwang printf(" - Transmitted: %5.2f\n",
5372bfe3f2eSlogwang (app_stats.tx.tx_pkts -
5382bfe3f2eSlogwang prev_app_stats.tx.tx_pkts)/1000000.0);
5392bfe3f2eSlogwang printf(" - Dropped: %s%5.2f%s\n", ANSI_COLOR_RED,
5402bfe3f2eSlogwang (app_stats.tx.enqdrop_pkts -
5412bfe3f2eSlogwang prev_app_stats.tx.enqdrop_pkts)/1000000.0,
5422bfe3f2eSlogwang ANSI_COLOR_RESET);
5432bfe3f2eSlogwang
5442bfe3f2eSlogwang prev_app_stats.rx.rx_pkts = app_stats.rx.rx_pkts;
5452bfe3f2eSlogwang prev_app_stats.rx.returned_pkts = app_stats.rx.returned_pkts;
5462bfe3f2eSlogwang prev_app_stats.rx.enqueued_pkts = app_stats.rx.enqueued_pkts;
5472bfe3f2eSlogwang prev_app_stats.rx.enqdrop_pkts = app_stats.rx.enqdrop_pkts;
5482bfe3f2eSlogwang prev_app_stats.dist.in_pkts = app_stats.dist.in_pkts;
5492bfe3f2eSlogwang prev_app_stats.dist.ret_pkts = app_stats.dist.ret_pkts;
5502bfe3f2eSlogwang prev_app_stats.dist.sent_pkts = app_stats.dist.sent_pkts;
5512bfe3f2eSlogwang prev_app_stats.dist.enqdrop_pkts = app_stats.dist.enqdrop_pkts;
5522bfe3f2eSlogwang prev_app_stats.tx.dequeue_pkts = app_stats.tx.dequeue_pkts;
5532bfe3f2eSlogwang prev_app_stats.tx.tx_pkts = app_stats.tx.tx_pkts;
5542bfe3f2eSlogwang prev_app_stats.tx.enqdrop_pkts = app_stats.tx.enqdrop_pkts;
5552bfe3f2eSlogwang
5562bfe3f2eSlogwang for (i = 0; i < num_workers; i++) {
5572bfe3f2eSlogwang printf("Worker %02u Pkts: %5.2f. Bursts(1-8): ", i,
5582bfe3f2eSlogwang (app_stats.worker_pkts[i] -
5592bfe3f2eSlogwang prev_app_stats.worker_pkts[i])/1000000.0);
5602bfe3f2eSlogwang for (j = 0; j < 8; j++) {
5612bfe3f2eSlogwang printf("%"PRIu64" ", app_stats.worker_bursts[i][j]);
5622bfe3f2eSlogwang app_stats.worker_bursts[i][j] = 0;
5632bfe3f2eSlogwang }
5642bfe3f2eSlogwang printf("\n");
5652bfe3f2eSlogwang prev_app_stats.worker_pkts[i] = app_stats.worker_pkts[i];
566a9643ea8Slogwang }
567a9643ea8Slogwang }
568a9643ea8Slogwang
569a9643ea8Slogwang static int
lcore_worker(struct lcore_params * p)570a9643ea8Slogwang lcore_worker(struct lcore_params *p)
571a9643ea8Slogwang {
572a9643ea8Slogwang struct rte_distributor *d = p->d;
573a9643ea8Slogwang const unsigned id = p->worker_id;
5742bfe3f2eSlogwang unsigned int num = 0;
5752bfe3f2eSlogwang unsigned int i;
5762bfe3f2eSlogwang
577a9643ea8Slogwang /*
578a9643ea8Slogwang * for single port, xor_val will be zero so we won't modify the output
579a9643ea8Slogwang * port, otherwise we send traffic from 0 to 1, 2 to 3, and vice versa
580a9643ea8Slogwang */
581d30ea906Sjfb8856606 const unsigned xor_val = (rte_eth_dev_count_avail() > 1);
5822bfe3f2eSlogwang struct rte_mbuf *buf[8] __rte_cache_aligned;
5832bfe3f2eSlogwang
5842bfe3f2eSlogwang for (i = 0; i < 8; i++)
5852bfe3f2eSlogwang buf[i] = NULL;
5862bfe3f2eSlogwang
5872bfe3f2eSlogwang app_stats.worker_pkts[p->worker_id] = 1;
588a9643ea8Slogwang
589a9643ea8Slogwang printf("\nCore %u acting as worker core.\n", rte_lcore_id());
5902bfe3f2eSlogwang while (!quit_signal_work) {
5912bfe3f2eSlogwang num = rte_distributor_get_pkt(d, id, buf, buf, num);
5922bfe3f2eSlogwang /* Do a little bit of work for each packet */
5932bfe3f2eSlogwang for (i = 0; i < num; i++) {
5942bfe3f2eSlogwang uint64_t t = rte_rdtsc()+100;
5952bfe3f2eSlogwang
5962bfe3f2eSlogwang while (rte_rdtsc() < t)
5972bfe3f2eSlogwang rte_pause();
5982bfe3f2eSlogwang buf[i]->port ^= xor_val;
5992bfe3f2eSlogwang }
6002bfe3f2eSlogwang
6012bfe3f2eSlogwang app_stats.worker_pkts[p->worker_id] += num;
6022bfe3f2eSlogwang if (num > 0)
6032bfe3f2eSlogwang app_stats.worker_bursts[p->worker_id][num-1]++;
604a9643ea8Slogwang }
6054418919fSjohnjiang if (power_lib_initialised)
6064418919fSjohnjiang rte_power_exit(rte_lcore_id());
6074418919fSjohnjiang rte_free(p);
608a9643ea8Slogwang return 0;
609a9643ea8Slogwang }
610a9643ea8Slogwang
6114418919fSjohnjiang static int
init_power_library(void)6124418919fSjohnjiang init_power_library(void)
6134418919fSjohnjiang {
6144418919fSjohnjiang int ret = 0, lcore_id;
615*2d9fd380Sjfb8856606 RTE_LCORE_FOREACH_WORKER(lcore_id) {
6164418919fSjohnjiang /* init power management library */
6174418919fSjohnjiang ret = rte_power_init(lcore_id);
6184418919fSjohnjiang if (ret) {
6194418919fSjohnjiang RTE_LOG(ERR, POWER,
6204418919fSjohnjiang "Library initialization failed on core %u\n",
6214418919fSjohnjiang lcore_id);
6224418919fSjohnjiang /*
6234418919fSjohnjiang * Return on first failure, we'll fall back
6244418919fSjohnjiang * to non-power operation
6254418919fSjohnjiang */
6264418919fSjohnjiang return ret;
6274418919fSjohnjiang }
6284418919fSjohnjiang }
6294418919fSjohnjiang return ret;
6304418919fSjohnjiang }
6314418919fSjohnjiang
632a9643ea8Slogwang /* display usage */
633a9643ea8Slogwang static void
print_usage(const char * prgname)634a9643ea8Slogwang print_usage(const char *prgname)
635a9643ea8Slogwang {
636a9643ea8Slogwang printf("%s [EAL options] -- -p PORTMASK\n"
637a9643ea8Slogwang " -p PORTMASK: hexadecimal bitmask of ports to configure\n",
638a9643ea8Slogwang prgname);
639a9643ea8Slogwang }
640a9643ea8Slogwang
641a9643ea8Slogwang static int
parse_portmask(const char * portmask)642a9643ea8Slogwang parse_portmask(const char *portmask)
643a9643ea8Slogwang {
644a9643ea8Slogwang char *end = NULL;
645a9643ea8Slogwang unsigned long pm;
646a9643ea8Slogwang
647a9643ea8Slogwang /* parse hexadecimal string */
648a9643ea8Slogwang pm = strtoul(portmask, &end, 16);
649a9643ea8Slogwang if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
650*2d9fd380Sjfb8856606 return 0;
651a9643ea8Slogwang
652a9643ea8Slogwang return pm;
653a9643ea8Slogwang }
654a9643ea8Slogwang
655a9643ea8Slogwang /* Parse the argument given in the command line of the application */
656a9643ea8Slogwang static int
parse_args(int argc,char ** argv)657a9643ea8Slogwang parse_args(int argc, char **argv)
658a9643ea8Slogwang {
659a9643ea8Slogwang int opt;
660a9643ea8Slogwang char **argvopt;
661a9643ea8Slogwang int option_index;
662a9643ea8Slogwang char *prgname = argv[0];
663a9643ea8Slogwang static struct option lgopts[] = {
664a9643ea8Slogwang {NULL, 0, 0, 0}
665a9643ea8Slogwang };
666a9643ea8Slogwang
667a9643ea8Slogwang argvopt = argv;
668a9643ea8Slogwang
669a9643ea8Slogwang while ((opt = getopt_long(argc, argvopt, "p:",
670a9643ea8Slogwang lgopts, &option_index)) != EOF) {
671a9643ea8Slogwang
672a9643ea8Slogwang switch (opt) {
673a9643ea8Slogwang /* portmask */
674a9643ea8Slogwang case 'p':
675a9643ea8Slogwang enabled_port_mask = parse_portmask(optarg);
676a9643ea8Slogwang if (enabled_port_mask == 0) {
677a9643ea8Slogwang printf("invalid portmask\n");
678a9643ea8Slogwang print_usage(prgname);
679a9643ea8Slogwang return -1;
680a9643ea8Slogwang }
681a9643ea8Slogwang break;
682a9643ea8Slogwang
683a9643ea8Slogwang default:
684a9643ea8Slogwang print_usage(prgname);
685a9643ea8Slogwang return -1;
686a9643ea8Slogwang }
687a9643ea8Slogwang }
688a9643ea8Slogwang
689a9643ea8Slogwang if (optind <= 1) {
690a9643ea8Slogwang print_usage(prgname);
691a9643ea8Slogwang return -1;
692a9643ea8Slogwang }
693a9643ea8Slogwang
694a9643ea8Slogwang argv[optind-1] = prgname;
695a9643ea8Slogwang
6962bfe3f2eSlogwang optind = 1; /* reset getopt lib */
697a9643ea8Slogwang return 0;
698a9643ea8Slogwang }
699a9643ea8Slogwang
700a9643ea8Slogwang /* Main function, does initialization and calls the per-lcore functions */
701a9643ea8Slogwang int
main(int argc,char * argv[])702a9643ea8Slogwang main(int argc, char *argv[])
703a9643ea8Slogwang {
704a9643ea8Slogwang struct rte_mempool *mbuf_pool;
705a9643ea8Slogwang struct rte_distributor *d;
7062bfe3f2eSlogwang struct rte_ring *dist_tx_ring;
7072bfe3f2eSlogwang struct rte_ring *rx_dist_ring;
7084418919fSjohnjiang struct rte_power_core_capabilities lcore_cap;
7094418919fSjohnjiang unsigned int lcore_id, worker_id = 0;
7104418919fSjohnjiang int distr_core_id = -1, rx_core_id = -1, tx_core_id = -1;
711a9643ea8Slogwang unsigned nb_ports;
7122bfe3f2eSlogwang uint16_t portid;
7132bfe3f2eSlogwang uint16_t nb_ports_available;
7142bfe3f2eSlogwang uint64_t t, freq;
715a9643ea8Slogwang
716a9643ea8Slogwang /* catch ctrl-c so we can print on exit */
717a9643ea8Slogwang signal(SIGINT, int_handler);
718a9643ea8Slogwang
719a9643ea8Slogwang /* init EAL */
720a9643ea8Slogwang int ret = rte_eal_init(argc, argv);
721a9643ea8Slogwang if (ret < 0)
722a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
723a9643ea8Slogwang argc -= ret;
724a9643ea8Slogwang argv += ret;
725a9643ea8Slogwang
726a9643ea8Slogwang /* parse application arguments (after the EAL ones) */
727a9643ea8Slogwang ret = parse_args(argc, argv);
728a9643ea8Slogwang if (ret < 0)
729a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Invalid distributor parameters\n");
730a9643ea8Slogwang
7312bfe3f2eSlogwang if (rte_lcore_count() < 5)
732a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Error, This application needs at "
7332bfe3f2eSlogwang "least 5 logical cores to run:\n"
7342bfe3f2eSlogwang "1 lcore for stats (can be core 0)\n"
7352bfe3f2eSlogwang "1 lcore for packet RX\n"
7362bfe3f2eSlogwang "1 lcore for distribution\n"
737a9643ea8Slogwang "1 lcore for packet TX\n"
738a9643ea8Slogwang "and at least 1 lcore for worker threads\n");
739a9643ea8Slogwang
7404418919fSjohnjiang if (init_power_library() == 0)
7414418919fSjohnjiang power_lib_initialised = 1;
7424418919fSjohnjiang
743d30ea906Sjfb8856606 nb_ports = rte_eth_dev_count_avail();
744a9643ea8Slogwang if (nb_ports == 0)
745a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Error: no ethernet ports detected\n");
746a9643ea8Slogwang if (nb_ports != 1 && (nb_ports & 1))
747a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Error: number of ports must be even, except "
748a9643ea8Slogwang "when using a single port\n");
749a9643ea8Slogwang
750a9643ea8Slogwang mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL",
751a9643ea8Slogwang NUM_MBUFS * nb_ports, MBUF_CACHE_SIZE, 0,
752a9643ea8Slogwang RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
753a9643ea8Slogwang if (mbuf_pool == NULL)
754a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
755a9643ea8Slogwang nb_ports_available = nb_ports;
756a9643ea8Slogwang
757a9643ea8Slogwang /* initialize all ports */
758d30ea906Sjfb8856606 RTE_ETH_FOREACH_DEV(portid) {
759a9643ea8Slogwang /* skip ports that are not enabled */
760a9643ea8Slogwang if ((enabled_port_mask & (1 << portid)) == 0) {
761a9643ea8Slogwang printf("\nSkipping disabled port %d\n", portid);
762a9643ea8Slogwang nb_ports_available--;
763a9643ea8Slogwang continue;
764a9643ea8Slogwang }
765a9643ea8Slogwang /* init port */
7662bfe3f2eSlogwang printf("Initializing port %u... done\n", portid);
767a9643ea8Slogwang
768a9643ea8Slogwang if (port_init(portid, mbuf_pool) != 0)
7692bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Cannot initialize port %u\n",
770a9643ea8Slogwang portid);
771a9643ea8Slogwang }
772a9643ea8Slogwang
773a9643ea8Slogwang if (!nb_ports_available) {
774a9643ea8Slogwang rte_exit(EXIT_FAILURE,
775a9643ea8Slogwang "All available ports are disabled. Please set portmask.\n");
776a9643ea8Slogwang }
777a9643ea8Slogwang
778a9643ea8Slogwang d = rte_distributor_create("PKT_DIST", rte_socket_id(),
7792bfe3f2eSlogwang rte_lcore_count() - 4,
7802bfe3f2eSlogwang RTE_DIST_ALG_BURST);
781a9643ea8Slogwang if (d == NULL)
782a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Cannot create distributor\n");
783a9643ea8Slogwang
784a9643ea8Slogwang /*
7852bfe3f2eSlogwang * scheduler ring is read by the transmitter core, and written to
7862bfe3f2eSlogwang * by scheduler core
787a9643ea8Slogwang */
7882bfe3f2eSlogwang dist_tx_ring = rte_ring_create("Output_ring", SCHED_TX_RING_SZ,
7892bfe3f2eSlogwang rte_socket_id(), RING_F_SC_DEQ | RING_F_SP_ENQ);
7902bfe3f2eSlogwang if (dist_tx_ring == NULL)
7912bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Cannot create output ring\n");
7922bfe3f2eSlogwang
7932bfe3f2eSlogwang rx_dist_ring = rte_ring_create("Input_ring", SCHED_RX_RING_SZ,
7942bfe3f2eSlogwang rte_socket_id(), RING_F_SC_DEQ | RING_F_SP_ENQ);
7952bfe3f2eSlogwang if (rx_dist_ring == NULL)
796a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Cannot create output ring\n");
797a9643ea8Slogwang
7984418919fSjohnjiang if (power_lib_initialised) {
7994418919fSjohnjiang /*
8004418919fSjohnjiang * Here we'll pre-assign lcore ids to the rx, tx and
8014418919fSjohnjiang * distributor workloads if there's higher frequency
8024418919fSjohnjiang * on those cores e.g. if Turbo Boost is enabled.
8034418919fSjohnjiang * It's also worth mentioning that it will assign cores in a
8044418919fSjohnjiang * specific order, so that if there's less than three
8054418919fSjohnjiang * available, the higher frequency cores will go to the
8064418919fSjohnjiang * distributor first, then rx, then tx.
8074418919fSjohnjiang */
808*2d9fd380Sjfb8856606 RTE_LCORE_FOREACH_WORKER(lcore_id) {
8094418919fSjohnjiang
8104418919fSjohnjiang rte_power_get_capabilities(lcore_id, &lcore_cap);
8114418919fSjohnjiang
8124418919fSjohnjiang if (lcore_cap.priority != 1)
8134418919fSjohnjiang continue;
8144418919fSjohnjiang
8154418919fSjohnjiang if (distr_core_id < 0) {
8164418919fSjohnjiang distr_core_id = lcore_id;
8174418919fSjohnjiang printf("Distributor on priority core %d\n",
8182bfe3f2eSlogwang lcore_id);
8194418919fSjohnjiang continue;
8204418919fSjohnjiang }
8214418919fSjohnjiang if (rx_core_id < 0) {
8224418919fSjohnjiang rx_core_id = lcore_id;
8234418919fSjohnjiang printf("Rx on priority core %d\n",
8244418919fSjohnjiang lcore_id);
8254418919fSjohnjiang continue;
8264418919fSjohnjiang }
8274418919fSjohnjiang if (tx_core_id < 0) {
8284418919fSjohnjiang tx_core_id = lcore_id;
8294418919fSjohnjiang printf("Tx on priority core %d\n",
8304418919fSjohnjiang lcore_id);
8314418919fSjohnjiang continue;
8324418919fSjohnjiang }
8334418919fSjohnjiang }
8344418919fSjohnjiang }
8354418919fSjohnjiang
8364418919fSjohnjiang /*
8374418919fSjohnjiang * If there's any of the key workloads left without an lcore_id
8384418919fSjohnjiang * after the high performing core assignment above, pre-assign
8394418919fSjohnjiang * them here.
8404418919fSjohnjiang */
841*2d9fd380Sjfb8856606 RTE_LCORE_FOREACH_WORKER(lcore_id) {
8424418919fSjohnjiang if (lcore_id == (unsigned int)distr_core_id ||
8434418919fSjohnjiang lcore_id == (unsigned int)rx_core_id ||
8444418919fSjohnjiang lcore_id == (unsigned int)tx_core_id)
8454418919fSjohnjiang continue;
8464418919fSjohnjiang if (distr_core_id < 0) {
8474418919fSjohnjiang distr_core_id = lcore_id;
8484418919fSjohnjiang printf("Distributor on core %d\n", lcore_id);
8494418919fSjohnjiang continue;
8504418919fSjohnjiang }
8514418919fSjohnjiang if (rx_core_id < 0) {
8524418919fSjohnjiang rx_core_id = lcore_id;
8534418919fSjohnjiang printf("Rx on core %d\n", lcore_id);
8544418919fSjohnjiang continue;
8554418919fSjohnjiang }
8564418919fSjohnjiang if (tx_core_id < 0) {
8574418919fSjohnjiang tx_core_id = lcore_id;
8584418919fSjohnjiang printf("Tx on core %d\n", lcore_id);
8594418919fSjohnjiang continue;
8604418919fSjohnjiang }
8614418919fSjohnjiang }
8624418919fSjohnjiang
8634418919fSjohnjiang printf(" tx id %d, dist id %d, rx id %d\n",
8644418919fSjohnjiang tx_core_id,
8654418919fSjohnjiang distr_core_id,
8664418919fSjohnjiang rx_core_id);
8674418919fSjohnjiang
8684418919fSjohnjiang /*
8694418919fSjohnjiang * Kick off all the worker threads first, avoiding the pre-assigned
8704418919fSjohnjiang * lcore_ids for tx, rx and distributor workloads.
8714418919fSjohnjiang */
872*2d9fd380Sjfb8856606 RTE_LCORE_FOREACH_WORKER(lcore_id) {
8734418919fSjohnjiang if (lcore_id == (unsigned int)distr_core_id ||
8744418919fSjohnjiang lcore_id == (unsigned int)rx_core_id ||
8754418919fSjohnjiang lcore_id == (unsigned int)tx_core_id)
8764418919fSjohnjiang continue;
8774418919fSjohnjiang printf("Starting thread %d as worker, lcore_id %d\n",
8782bfe3f2eSlogwang worker_id, lcore_id);
8792bfe3f2eSlogwang struct lcore_params *p =
8802bfe3f2eSlogwang rte_malloc(NULL, sizeof(*p), 0);
8812bfe3f2eSlogwang if (!p)
8822bfe3f2eSlogwang rte_panic("malloc failure\n");
8834418919fSjohnjiang *p = (struct lcore_params){worker_id++, d, rx_dist_ring,
8842bfe3f2eSlogwang dist_tx_ring, mbuf_pool};
885a9643ea8Slogwang
886a9643ea8Slogwang rte_eal_remote_launch((lcore_function_t *)lcore_worker,
887a9643ea8Slogwang p, lcore_id);
888a9643ea8Slogwang }
8894418919fSjohnjiang
8904418919fSjohnjiang /* Start tx core */
8914418919fSjohnjiang rte_eal_remote_launch((lcore_function_t *)lcore_tx,
8924418919fSjohnjiang dist_tx_ring, tx_core_id);
8934418919fSjohnjiang
8944418919fSjohnjiang /* Start distributor core */
8954418919fSjohnjiang struct lcore_params *pd =
8964418919fSjohnjiang rte_malloc(NULL, sizeof(*pd), 0);
8974418919fSjohnjiang if (!pd)
8984418919fSjohnjiang rte_panic("malloc failure\n");
8994418919fSjohnjiang *pd = (struct lcore_params){worker_id++, d,
9004418919fSjohnjiang rx_dist_ring, dist_tx_ring, mbuf_pool};
9014418919fSjohnjiang rte_eal_remote_launch(
9024418919fSjohnjiang (lcore_function_t *)lcore_distributor,
9034418919fSjohnjiang pd, distr_core_id);
9044418919fSjohnjiang
9054418919fSjohnjiang /* Start rx core */
9064418919fSjohnjiang struct lcore_params *pr =
9074418919fSjohnjiang rte_malloc(NULL, sizeof(*pr), 0);
9084418919fSjohnjiang if (!pr)
9094418919fSjohnjiang rte_panic("malloc failure\n");
9104418919fSjohnjiang *pr = (struct lcore_params){worker_id++, d, rx_dist_ring,
9114418919fSjohnjiang dist_tx_ring, mbuf_pool};
9124418919fSjohnjiang rte_eal_remote_launch((lcore_function_t *)lcore_rx,
9134418919fSjohnjiang pr, rx_core_id);
914a9643ea8Slogwang
9152bfe3f2eSlogwang freq = rte_get_timer_hz();
9162bfe3f2eSlogwang t = rte_rdtsc() + freq;
9172bfe3f2eSlogwang while (!quit_signal_dist) {
9182bfe3f2eSlogwang if (t < rte_rdtsc()) {
9192bfe3f2eSlogwang print_stats();
9202bfe3f2eSlogwang t = rte_rdtsc() + freq;
9212bfe3f2eSlogwang }
9222bfe3f2eSlogwang usleep(1000);
9232bfe3f2eSlogwang }
924a9643ea8Slogwang
925*2d9fd380Sjfb8856606 RTE_LCORE_FOREACH_WORKER(lcore_id) {
926a9643ea8Slogwang if (rte_eal_wait_lcore(lcore_id) < 0)
927a9643ea8Slogwang return -1;
928a9643ea8Slogwang }
929a9643ea8Slogwang
930a9643ea8Slogwang print_stats();
9314418919fSjohnjiang
9324418919fSjohnjiang rte_free(pd);
9334418919fSjohnjiang rte_free(pr);
9344418919fSjohnjiang
935a9643ea8Slogwang return 0;
936a9643ea8Slogwang }
937