xref: /dpdk/examples/distributor/main.c (revision f30a1bbd63f494f5ba623582d7e9166c817794a4)
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, &eth_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