xref: /dpdk/examples/l3fwd-power/main.c (revision 089e5ed727a15da2729cfee9b63533dd120bd04c)
13998e2a0SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
2f88e7c17SRadu Nicolau  * Copyright(c) 2010-2018 Intel Corporation
3d7937e2eSIntel  */
4d7937e2eSIntel 
5d7937e2eSIntel #include <stdio.h>
6d7937e2eSIntel #include <stdlib.h>
7d7937e2eSIntel #include <stdint.h>
8d7937e2eSIntel #include <inttypes.h>
9d7937e2eSIntel #include <sys/types.h>
10d7937e2eSIntel #include <string.h>
11d7937e2eSIntel #include <sys/queue.h>
12d7937e2eSIntel #include <stdarg.h>
13d7937e2eSIntel #include <errno.h>
14d7937e2eSIntel #include <getopt.h>
15d7937e2eSIntel #include <unistd.h>
16d7937e2eSIntel #include <signal.h>
17609e7984SReshma Pattan #include <math.h>
18d7937e2eSIntel 
19d7937e2eSIntel #include <rte_common.h>
20d7937e2eSIntel #include <rte_byteorder.h>
21d7937e2eSIntel #include <rte_log.h>
22e2366e74STomasz Kulasek #include <rte_malloc.h>
23d7937e2eSIntel #include <rte_memory.h>
24d7937e2eSIntel #include <rte_memcpy.h>
25d7937e2eSIntel #include <rte_eal.h>
26d7937e2eSIntel #include <rte_launch.h>
27d7937e2eSIntel #include <rte_atomic.h>
28d7937e2eSIntel #include <rte_cycles.h>
29d7937e2eSIntel #include <rte_prefetch.h>
30d7937e2eSIntel #include <rte_lcore.h>
31d7937e2eSIntel #include <rte_per_lcore.h>
32d7937e2eSIntel #include <rte_branch_prediction.h>
33d7937e2eSIntel #include <rte_interrupts.h>
34d7937e2eSIntel #include <rte_random.h>
35d7937e2eSIntel #include <rte_debug.h>
36d7937e2eSIntel #include <rte_ether.h>
37d7937e2eSIntel #include <rte_ethdev.h>
38d7937e2eSIntel #include <rte_mempool.h>
39d7937e2eSIntel #include <rte_mbuf.h>
40d7937e2eSIntel #include <rte_ip.h>
41d7937e2eSIntel #include <rte_tcp.h>
42d7937e2eSIntel #include <rte_udp.h>
43d7937e2eSIntel #include <rte_string_fns.h>
44d7937e2eSIntel #include <rte_timer.h>
45d7937e2eSIntel #include <rte_power.h>
46aee3bc79SCunming Liang #include <rte_spinlock.h>
47a137d012SLiang Ma #include <rte_power_empty_poll.h>
48609e7984SReshma Pattan #include <rte_metrics.h>
49d7937e2eSIntel 
50f88e7c17SRadu Nicolau #include "perf_core.h"
51f88e7c17SRadu Nicolau #include "main.h"
52f88e7c17SRadu Nicolau 
53d7937e2eSIntel #define RTE_LOGTYPE_L3FWD_POWER RTE_LOGTYPE_USER1
54d7937e2eSIntel 
55d7937e2eSIntel #define MAX_PKT_BURST 32
56d7937e2eSIntel 
57aee3bc79SCunming Liang #define MIN_ZERO_POLL_COUNT 10
58d7937e2eSIntel 
59d7937e2eSIntel /* 100 ms interval */
60d7937e2eSIntel #define TIMER_NUMBER_PER_SECOND           10
61a137d012SLiang Ma /* (10ms) */
62a137d012SLiang Ma #define INTERVALS_PER_SECOND             100
63d7937e2eSIntel /* 100000 us */
64d7937e2eSIntel #define SCALING_PERIOD                    (1000000/TIMER_NUMBER_PER_SECOND)
65d7937e2eSIntel #define SCALING_DOWN_TIME_RATIO_THRESHOLD 0.25
66d7937e2eSIntel 
67d7937e2eSIntel #define APP_LOOKUP_EXACT_MATCH          0
68d7937e2eSIntel #define APP_LOOKUP_LPM                  1
69d7937e2eSIntel #define DO_RFC_1812_CHECKS
70d7937e2eSIntel 
71d7937e2eSIntel #ifndef APP_LOOKUP_METHOD
72d7937e2eSIntel #define APP_LOOKUP_METHOD             APP_LOOKUP_LPM
73d7937e2eSIntel #endif
74d7937e2eSIntel 
75d7937e2eSIntel #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
76d7937e2eSIntel #include <rte_hash.h>
77d7937e2eSIntel #elif (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
78d7937e2eSIntel #include <rte_lpm.h>
79d7937e2eSIntel #else
80d7937e2eSIntel #error "APP_LOOKUP_METHOD set to incorrect value"
81d7937e2eSIntel #endif
82d7937e2eSIntel 
83d7937e2eSIntel #ifndef IPv6_BYTES
84d7937e2eSIntel #define IPv6_BYTES_FMT "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"\
85d7937e2eSIntel                        "%02x%02x:%02x%02x:%02x%02x:%02x%02x"
86d7937e2eSIntel #define IPv6_BYTES(addr) \
87d7937e2eSIntel 	addr[0],  addr[1], addr[2],  addr[3], \
88d7937e2eSIntel 	addr[4],  addr[5], addr[6],  addr[7], \
89d7937e2eSIntel 	addr[8],  addr[9], addr[10], addr[11],\
90d7937e2eSIntel 	addr[12], addr[13],addr[14], addr[15]
91d7937e2eSIntel #endif
92d7937e2eSIntel 
93d7937e2eSIntel #define MAX_JUMBO_PKT_LEN  9600
94d7937e2eSIntel 
95d7937e2eSIntel #define IPV6_ADDR_LEN 16
96d7937e2eSIntel 
97d7937e2eSIntel #define MEMPOOL_CACHE_SIZE 256
98d7937e2eSIntel 
99d7937e2eSIntel /*
100d7937e2eSIntel  * This expression is used to calculate the number of mbufs needed depending on
101d7937e2eSIntel  * user input, taking into account memory for rx and tx hardware rings, cache
102d7937e2eSIntel  * per lcore and mtable per port per lcore. RTE_MAX is used to ensure that
103d7937e2eSIntel  * NB_MBUF never goes below a minimum value of 8192.
104d7937e2eSIntel  */
105d7937e2eSIntel 
106d7937e2eSIntel #define NB_MBUF RTE_MAX	( \
10760efb44fSRoman Zhukov 	(nb_ports*nb_rx_queue*nb_rxd + \
108d7937e2eSIntel 	nb_ports*nb_lcores*MAX_PKT_BURST + \
10960efb44fSRoman Zhukov 	nb_ports*n_tx_queue*nb_txd + \
110d7937e2eSIntel 	nb_lcores*MEMPOOL_CACHE_SIZE), \
111d7937e2eSIntel 	(unsigned)8192)
112d7937e2eSIntel 
113d7937e2eSIntel #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
114d7937e2eSIntel 
115d7937e2eSIntel #define NB_SOCKETS 8
116d7937e2eSIntel 
117d7937e2eSIntel /* Configure how many packets ahead to prefetch, when reading packets */
118d7937e2eSIntel #define PREFETCH_OFFSET	3
119d7937e2eSIntel 
120d7937e2eSIntel /*
121d7937e2eSIntel  * Configurable number of RX/TX ring descriptors
122d7937e2eSIntel  */
123867a6c66SKevin Laatz #define RTE_TEST_RX_DESC_DEFAULT 1024
124867a6c66SKevin Laatz #define RTE_TEST_TX_DESC_DEFAULT 1024
125a137d012SLiang Ma 
126a137d012SLiang Ma /*
127a137d012SLiang Ma  * These two thresholds were decided on by running the training algorithm on
128a137d012SLiang Ma  * a 2.5GHz Xeon. These defaults can be overridden by supplying non-zero values
129a137d012SLiang Ma  * for the med_threshold and high_threshold parameters on the command line.
130a137d012SLiang Ma  */
131a137d012SLiang Ma #define EMPTY_POLL_MED_THRESHOLD 350000UL
132a137d012SLiang Ma #define EMPTY_POLL_HGH_THRESHOLD 580000UL
133a137d012SLiang Ma 
134a137d012SLiang Ma 
135a137d012SLiang Ma 
136d7937e2eSIntel static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
137d7937e2eSIntel static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
138d7937e2eSIntel 
139d7937e2eSIntel /* ethernet addresses of ports */
1406d13ea8eSOlivier Matz static struct rte_ether_addr ports_eth_addr[RTE_MAX_ETHPORTS];
141d7937e2eSIntel 
142aee3bc79SCunming Liang /* ethernet addresses of ports */
143aee3bc79SCunming Liang static rte_spinlock_t locks[RTE_MAX_ETHPORTS];
144aee3bc79SCunming Liang 
145d7937e2eSIntel /* mask of enabled ports */
146d7937e2eSIntel static uint32_t enabled_port_mask = 0;
147d7937e2eSIntel /* Ports set in promiscuous mode off by default. */
148d7937e2eSIntel static int promiscuous_on = 0;
149d7937e2eSIntel /* NUMA is enabled by default. */
150d7937e2eSIntel static int numa_on = 1;
151609e7984SReshma Pattan static bool empty_poll_stop;
152a137d012SLiang Ma static bool empty_poll_train;
153609e7984SReshma Pattan volatile bool quit_signal;
154a137d012SLiang Ma static struct  ep_params *ep_params;
155a137d012SLiang Ma static struct  ep_policy policy;
156a137d012SLiang Ma static long  ep_med_edpi, ep_hgh_edpi;
157609e7984SReshma Pattan /* timer to update telemetry every 500ms */
158609e7984SReshma Pattan static struct rte_timer telemetry_timer;
159609e7984SReshma Pattan 
160609e7984SReshma Pattan /* stats index returned by metrics lib */
161609e7984SReshma Pattan int telstats_index;
162609e7984SReshma Pattan 
163609e7984SReshma Pattan struct telstats_name {
164609e7984SReshma Pattan 	char name[RTE_ETH_XSTATS_NAME_SIZE];
165609e7984SReshma Pattan };
166609e7984SReshma Pattan 
167609e7984SReshma Pattan /* telemetry stats to be reported */
168609e7984SReshma Pattan const struct telstats_name telstats_strings[] = {
169609e7984SReshma Pattan 	{"empty_poll"},
170609e7984SReshma Pattan 	{"full_poll"},
171609e7984SReshma Pattan 	{"busy_percent"}
172609e7984SReshma Pattan };
173609e7984SReshma Pattan 
174609e7984SReshma Pattan /* core busyness in percentage */
175609e7984SReshma Pattan enum busy_rate {
176609e7984SReshma Pattan 	ZERO = 0,
177609e7984SReshma Pattan 	PARTIAL = 50,
178609e7984SReshma Pattan 	FULL = 100
179609e7984SReshma Pattan };
180609e7984SReshma Pattan 
181609e7984SReshma Pattan /* reference poll count to measure core busyness */
182609e7984SReshma Pattan #define DEFAULT_COUNT 10000
183609e7984SReshma Pattan /*
184609e7984SReshma Pattan  * reference CYCLES to be used to
185609e7984SReshma Pattan  * measure core busyness based on poll count
186609e7984SReshma Pattan  */
187609e7984SReshma Pattan #define MIN_CYCLES  1500000ULL
188b55d8fecSDavid Hunt #define MAX_CYCLES 22000000ULL
189609e7984SReshma Pattan 
190609e7984SReshma Pattan /* (500ms) */
191609e7984SReshma Pattan #define TELEMETRY_INTERVALS_PER_SEC 2
192a137d012SLiang Ma 
19382bea466SJianfeng Tan static int parse_ptype; /**< Parse packet type using rx callback, and */
19482bea466SJianfeng Tan 			/**< disabled by default */
195d7937e2eSIntel 
196609e7984SReshma Pattan enum appmode {
197609e7984SReshma Pattan 	APP_MODE_LEGACY = 0,
198609e7984SReshma Pattan 	APP_MODE_EMPTY_POLL,
199609e7984SReshma Pattan 	APP_MODE_TELEMETRY
200609e7984SReshma Pattan };
201609e7984SReshma Pattan 
202609e7984SReshma Pattan enum appmode app_mode;
203609e7984SReshma Pattan 
204d7937e2eSIntel enum freq_scale_hint_t
205d7937e2eSIntel {
206d7937e2eSIntel 	FREQ_LOWER    =      -1,
207d7937e2eSIntel 	FREQ_CURRENT  =       0,
208d7937e2eSIntel 	FREQ_HIGHER   =       1,
209d7937e2eSIntel 	FREQ_HIGHEST  =       2
210d7937e2eSIntel };
211d7937e2eSIntel 
212d7937e2eSIntel struct lcore_rx_queue {
213f8244c63SZhiyong Yang 	uint16_t port_id;
214d7937e2eSIntel 	uint8_t queue_id;
215d7937e2eSIntel 	enum freq_scale_hint_t freq_up_hint;
216d7937e2eSIntel 	uint32_t zero_rx_packet_count;
217d7937e2eSIntel 	uint32_t idle_hint;
218d7937e2eSIntel } __rte_cache_aligned;
219d7937e2eSIntel 
220d7937e2eSIntel #define MAX_RX_QUEUE_PER_LCORE 16
221d7937e2eSIntel #define MAX_TX_QUEUE_PER_PORT RTE_MAX_ETHPORTS
222d7937e2eSIntel #define MAX_RX_QUEUE_PER_PORT 128
223d7937e2eSIntel 
224aee3bc79SCunming Liang #define MAX_RX_QUEUE_INTERRUPT_PER_PORT 16
225aee3bc79SCunming Liang 
226aee3bc79SCunming Liang 
227f88e7c17SRadu Nicolau struct lcore_params lcore_params_array[MAX_LCORE_PARAMS];
228d7937e2eSIntel static struct lcore_params lcore_params_array_default[] = {
229d7937e2eSIntel 	{0, 0, 2},
230d7937e2eSIntel 	{0, 1, 2},
231d7937e2eSIntel 	{0, 2, 2},
232d7937e2eSIntel 	{1, 0, 2},
233d7937e2eSIntel 	{1, 1, 2},
234d7937e2eSIntel 	{1, 2, 2},
235d7937e2eSIntel 	{2, 0, 2},
236d7937e2eSIntel 	{3, 0, 3},
237d7937e2eSIntel 	{3, 1, 3},
238d7937e2eSIntel };
239d7937e2eSIntel 
240f88e7c17SRadu Nicolau struct lcore_params *lcore_params = lcore_params_array_default;
241f88e7c17SRadu Nicolau uint16_t nb_lcore_params = sizeof(lcore_params_array_default) /
242d7937e2eSIntel 				sizeof(lcore_params_array_default[0]);
243d7937e2eSIntel 
244d7937e2eSIntel static struct rte_eth_conf port_conf = {
245d7937e2eSIntel 	.rxmode = {
24613c4ebd6SBruce Richardson 		.mq_mode        = ETH_MQ_RX_RSS,
24735b2d13fSOlivier Matz 		.max_rx_pkt_len = RTE_ETHER_MAX_LEN,
248d7937e2eSIntel 		.split_hdr_size = 0,
249323e7b66SFerruh Yigit 		.offloads = DEV_RX_OFFLOAD_CHECKSUM,
250d7937e2eSIntel 	},
251d7937e2eSIntel 	.rx_adv_conf = {
252d7937e2eSIntel 		.rss_conf = {
253d7937e2eSIntel 			.rss_key = NULL,
254aee3bc79SCunming Liang 			.rss_hf = ETH_RSS_UDP,
255d7937e2eSIntel 		},
256d7937e2eSIntel 	},
257d7937e2eSIntel 	.txmode = {
258aee3bc79SCunming Liang 		.mq_mode = ETH_MQ_TX_NONE,
259aee3bc79SCunming Liang 	},
260aee3bc79SCunming Liang 	.intr_conf = {
261aee3bc79SCunming Liang 		.rxq = 1,
262d7937e2eSIntel 	},
263d7937e2eSIntel };
264d7937e2eSIntel 
265d7937e2eSIntel static struct rte_mempool * pktmbuf_pool[NB_SOCKETS];
266d7937e2eSIntel 
267d7937e2eSIntel 
268d7937e2eSIntel #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
269d7937e2eSIntel 
270193f9ec5SBruce Richardson #ifdef RTE_ARCH_X86
271d7937e2eSIntel #include <rte_hash_crc.h>
272d7937e2eSIntel #define DEFAULT_HASH_FUNC       rte_hash_crc
273d7937e2eSIntel #else
274d7937e2eSIntel #include <rte_jhash.h>
275d7937e2eSIntel #define DEFAULT_HASH_FUNC       rte_jhash
276d7937e2eSIntel #endif
277d7937e2eSIntel 
278d7937e2eSIntel struct ipv4_5tuple {
279d7937e2eSIntel 	uint32_t ip_dst;
280d7937e2eSIntel 	uint32_t ip_src;
281d7937e2eSIntel 	uint16_t port_dst;
282d7937e2eSIntel 	uint16_t port_src;
283d7937e2eSIntel 	uint8_t  proto;
284d7937e2eSIntel } __attribute__((__packed__));
285d7937e2eSIntel 
286d7937e2eSIntel struct ipv6_5tuple {
287d7937e2eSIntel 	uint8_t  ip_dst[IPV6_ADDR_LEN];
288d7937e2eSIntel 	uint8_t  ip_src[IPV6_ADDR_LEN];
289d7937e2eSIntel 	uint16_t port_dst;
290d7937e2eSIntel 	uint16_t port_src;
291d7937e2eSIntel 	uint8_t  proto;
292d7937e2eSIntel } __attribute__((__packed__));
293d7937e2eSIntel 
294d7937e2eSIntel struct ipv4_l3fwd_route {
295d7937e2eSIntel 	struct ipv4_5tuple key;
296d7937e2eSIntel 	uint8_t if_out;
297d7937e2eSIntel };
298d7937e2eSIntel 
299d7937e2eSIntel struct ipv6_l3fwd_route {
300d7937e2eSIntel 	struct ipv6_5tuple key;
301d7937e2eSIntel 	uint8_t if_out;
302d7937e2eSIntel };
303d7937e2eSIntel 
304d7937e2eSIntel static struct ipv4_l3fwd_route ipv4_l3fwd_route_array[] = {
3050c9da755SDavid Marchand 	{{RTE_IPV4(100,10,0,1), RTE_IPV4(200,10,0,1), 101, 11, IPPROTO_TCP}, 0},
3060c9da755SDavid Marchand 	{{RTE_IPV4(100,20,0,2), RTE_IPV4(200,20,0,2), 102, 12, IPPROTO_TCP}, 1},
3070c9da755SDavid Marchand 	{{RTE_IPV4(100,30,0,3), RTE_IPV4(200,30,0,3), 103, 13, IPPROTO_TCP}, 2},
3080c9da755SDavid Marchand 	{{RTE_IPV4(100,40,0,4), RTE_IPV4(200,40,0,4), 104, 14, IPPROTO_TCP}, 3},
309d7937e2eSIntel };
310d7937e2eSIntel 
311d7937e2eSIntel static struct ipv6_l3fwd_route ipv6_l3fwd_route_array[] = {
312d7937e2eSIntel 	{
313d7937e2eSIntel 		{
314d7937e2eSIntel 			{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315d7937e2eSIntel 			 0x02, 0x1b, 0x21, 0xff, 0xfe, 0x91, 0x38, 0x05},
316d7937e2eSIntel 			{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
317d7937e2eSIntel 			 0x02, 0x1e, 0x67, 0xff, 0xfe, 0x0d, 0xb6, 0x0a},
318d7937e2eSIntel 			 1, 10, IPPROTO_UDP
319d7937e2eSIntel 		}, 4
320d7937e2eSIntel 	},
321d7937e2eSIntel };
322d7937e2eSIntel 
323d7937e2eSIntel typedef struct rte_hash lookup_struct_t;
324d7937e2eSIntel static lookup_struct_t *ipv4_l3fwd_lookup_struct[NB_SOCKETS];
325d7937e2eSIntel static lookup_struct_t *ipv6_l3fwd_lookup_struct[NB_SOCKETS];
326d7937e2eSIntel 
327d7937e2eSIntel #define L3FWD_HASH_ENTRIES	1024
328d7937e2eSIntel 
329d7937e2eSIntel #define IPV4_L3FWD_NUM_ROUTES \
330d7937e2eSIntel 	(sizeof(ipv4_l3fwd_route_array) / sizeof(ipv4_l3fwd_route_array[0]))
331d7937e2eSIntel 
332d7937e2eSIntel #define IPV6_L3FWD_NUM_ROUTES \
333d7937e2eSIntel 	(sizeof(ipv6_l3fwd_route_array) / sizeof(ipv6_l3fwd_route_array[0]))
334d7937e2eSIntel 
335f8244c63SZhiyong Yang static uint16_t ipv4_l3fwd_out_if[L3FWD_HASH_ENTRIES] __rte_cache_aligned;
336f8244c63SZhiyong Yang static uint16_t ipv6_l3fwd_out_if[L3FWD_HASH_ENTRIES] __rte_cache_aligned;
337d7937e2eSIntel #endif
338d7937e2eSIntel 
339d7937e2eSIntel #if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
340d7937e2eSIntel struct ipv4_l3fwd_route {
341d7937e2eSIntel 	uint32_t ip;
342d7937e2eSIntel 	uint8_t  depth;
343d7937e2eSIntel 	uint8_t  if_out;
344d7937e2eSIntel };
345d7937e2eSIntel 
346d7937e2eSIntel static struct ipv4_l3fwd_route ipv4_l3fwd_route_array[] = {
3470c9da755SDavid Marchand 	{RTE_IPV4(1,1,1,0), 24, 0},
3480c9da755SDavid Marchand 	{RTE_IPV4(2,1,1,0), 24, 1},
3490c9da755SDavid Marchand 	{RTE_IPV4(3,1,1,0), 24, 2},
3500c9da755SDavid Marchand 	{RTE_IPV4(4,1,1,0), 24, 3},
3510c9da755SDavid Marchand 	{RTE_IPV4(5,1,1,0), 24, 4},
3520c9da755SDavid Marchand 	{RTE_IPV4(6,1,1,0), 24, 5},
3530c9da755SDavid Marchand 	{RTE_IPV4(7,1,1,0), 24, 6},
3540c9da755SDavid Marchand 	{RTE_IPV4(8,1,1,0), 24, 7},
355d7937e2eSIntel };
356d7937e2eSIntel 
357d7937e2eSIntel #define IPV4_L3FWD_NUM_ROUTES \
358d7937e2eSIntel 	(sizeof(ipv4_l3fwd_route_array) / sizeof(ipv4_l3fwd_route_array[0]))
359d7937e2eSIntel 
360d7937e2eSIntel #define IPV4_L3FWD_LPM_MAX_RULES     1024
361d7937e2eSIntel 
362d7937e2eSIntel typedef struct rte_lpm lookup_struct_t;
363d7937e2eSIntel static lookup_struct_t *ipv4_l3fwd_lookup_struct[NB_SOCKETS];
364d7937e2eSIntel #endif
365d7937e2eSIntel 
366d7937e2eSIntel struct lcore_conf {
367d7937e2eSIntel 	uint16_t n_rx_queue;
368d7937e2eSIntel 	struct lcore_rx_queue rx_queue_list[MAX_RX_QUEUE_PER_LCORE];
369e2366e74STomasz Kulasek 	uint16_t n_tx_port;
370e2366e74STomasz Kulasek 	uint16_t tx_port_id[RTE_MAX_ETHPORTS];
371d7937e2eSIntel 	uint16_t tx_queue_id[RTE_MAX_ETHPORTS];
372e2366e74STomasz Kulasek 	struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
373d7937e2eSIntel 	lookup_struct_t * ipv4_lookup_struct;
374d7937e2eSIntel 	lookup_struct_t * ipv6_lookup_struct;
375d7937e2eSIntel } __rte_cache_aligned;
376d7937e2eSIntel 
377d7937e2eSIntel struct lcore_stats {
378d7937e2eSIntel 	/* total sleep time in ms since last frequency scaling down */
379d7937e2eSIntel 	uint32_t sleep_time;
380d7937e2eSIntel 	/* number of long sleep recently */
381d7937e2eSIntel 	uint32_t nb_long_sleep;
382d7937e2eSIntel 	/* freq. scaling up trend */
383d7937e2eSIntel 	uint32_t trend;
384d7937e2eSIntel 	/* total packet processed recently */
385d7937e2eSIntel 	uint64_t nb_rx_processed;
386d7937e2eSIntel 	/* total iterations looped recently */
387d7937e2eSIntel 	uint64_t nb_iteration_looped;
388609e7984SReshma Pattan 	/*
389609e7984SReshma Pattan 	 * Represents empty and non empty polls
390609e7984SReshma Pattan 	 * of rte_eth_rx_burst();
391609e7984SReshma Pattan 	 * ep_nep[0] holds non empty polls
392609e7984SReshma Pattan 	 * i.e. 0 < nb_rx <= MAX_BURST
393609e7984SReshma Pattan 	 * ep_nep[1] holds empty polls.
394609e7984SReshma Pattan 	 * i.e. nb_rx == 0
395609e7984SReshma Pattan 	 */
396609e7984SReshma Pattan 	uint64_t ep_nep[2];
397609e7984SReshma Pattan 	/*
398609e7984SReshma Pattan 	 * Represents full and empty+partial
399609e7984SReshma Pattan 	 * polls of rte_eth_rx_burst();
400609e7984SReshma Pattan 	 * ep_nep[0] holds empty+partial polls.
401609e7984SReshma Pattan 	 * i.e. 0 <= nb_rx < MAX_BURST
402609e7984SReshma Pattan 	 * ep_nep[1] holds full polls
403609e7984SReshma Pattan 	 * i.e. nb_rx == MAX_BURST
404609e7984SReshma Pattan 	 */
405609e7984SReshma Pattan 	uint64_t fp_nfp[2];
406609e7984SReshma Pattan 	enum busy_rate br;
407609e7984SReshma Pattan 	rte_spinlock_t telemetry_lock;
408d7937e2eSIntel } __rte_cache_aligned;
409d7937e2eSIntel 
410d7937e2eSIntel static struct lcore_conf lcore_conf[RTE_MAX_LCORE] __rte_cache_aligned;
411d7937e2eSIntel static struct lcore_stats stats[RTE_MAX_LCORE] __rte_cache_aligned;
412d7937e2eSIntel static struct rte_timer power_timers[RTE_MAX_LCORE];
413d7937e2eSIntel 
414d7937e2eSIntel static inline uint32_t power_idle_heuristic(uint32_t zero_rx_packet_count);
415d7937e2eSIntel static inline enum freq_scale_hint_t power_freq_scaleup_heuristic( \
416f8244c63SZhiyong Yang 		unsigned int lcore_id, uint16_t port_id, uint16_t queue_id);
417d7937e2eSIntel 
418a137d012SLiang Ma 
419a137d012SLiang Ma /*
420a137d012SLiang Ma  * These defaults are using the max frequency index (1), a medium index (9)
421a137d012SLiang Ma  * and a typical low frequency index (14). These can be adjusted to use
422a137d012SLiang Ma  * different indexes using the relevant command line parameters.
423a137d012SLiang Ma  */
424a137d012SLiang Ma static uint8_t  freq_tlb[] = {14, 9, 1};
425a137d012SLiang Ma 
426a137d012SLiang Ma static int is_done(void)
427a137d012SLiang Ma {
428609e7984SReshma Pattan 	return quit_signal;
429a137d012SLiang Ma }
430a137d012SLiang Ma 
431d7937e2eSIntel /* exit signal handler */
432d7937e2eSIntel static void
433d7937e2eSIntel signal_exit_now(int sigtype)
434d7937e2eSIntel {
435d7937e2eSIntel 	unsigned lcore_id;
4368728ccf3SThomas Monjalon 	unsigned int portid;
437d7937e2eSIntel 	int ret;
438d7937e2eSIntel 
439d7937e2eSIntel 	if (sigtype == SIGINT) {
440609e7984SReshma Pattan 		if (app_mode == APP_MODE_EMPTY_POLL ||
441609e7984SReshma Pattan 				app_mode == APP_MODE_TELEMETRY)
442609e7984SReshma Pattan 			quit_signal = true;
443a137d012SLiang Ma 
444a137d012SLiang Ma 
445d7937e2eSIntel 		for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
446d7937e2eSIntel 			if (rte_lcore_is_enabled(lcore_id) == 0)
447d7937e2eSIntel 				continue;
448d7937e2eSIntel 
449d7937e2eSIntel 			/* init power management library */
450d7937e2eSIntel 			ret = rte_power_exit(lcore_id);
451d7937e2eSIntel 			if (ret)
452d7937e2eSIntel 				rte_exit(EXIT_FAILURE, "Power management "
453d7937e2eSIntel 					"library de-initialization failed on "
454d7937e2eSIntel 							"core%u\n", lcore_id);
455d7937e2eSIntel 		}
456e2a6f124SJianfeng Tan 
457609e7984SReshma Pattan 		if (app_mode != APP_MODE_EMPTY_POLL) {
4588728ccf3SThomas Monjalon 			RTE_ETH_FOREACH_DEV(portid) {
459e2a6f124SJianfeng Tan 				if ((enabled_port_mask & (1 << portid)) == 0)
460e2a6f124SJianfeng Tan 					continue;
461e2a6f124SJianfeng Tan 
462e2a6f124SJianfeng Tan 				rte_eth_dev_stop(portid);
463e2a6f124SJianfeng Tan 				rte_eth_dev_close(portid);
464e2a6f124SJianfeng Tan 			}
465d7937e2eSIntel 		}
466a137d012SLiang Ma 	}
467d7937e2eSIntel 
468609e7984SReshma Pattan 	if (app_mode != APP_MODE_EMPTY_POLL)
469d7937e2eSIntel 		rte_exit(EXIT_SUCCESS, "User forced exit\n");
470d7937e2eSIntel }
471d7937e2eSIntel 
472d7937e2eSIntel /*  Freqency scale down timer callback */
473d7937e2eSIntel static void
474d7937e2eSIntel power_timer_cb(__attribute__((unused)) struct rte_timer *tim,
475d7937e2eSIntel 			  __attribute__((unused)) void *arg)
476d7937e2eSIntel {
477d7937e2eSIntel 	uint64_t hz;
478d7937e2eSIntel 	float sleep_time_ratio;
479d7937e2eSIntel 	unsigned lcore_id = rte_lcore_id();
480d7937e2eSIntel 
481d7937e2eSIntel 	/* accumulate total execution time in us when callback is invoked */
482d7937e2eSIntel 	sleep_time_ratio = (float)(stats[lcore_id].sleep_time) /
483d7937e2eSIntel 					(float)SCALING_PERIOD;
484d7937e2eSIntel 	/**
485d7937e2eSIntel 	 * check whether need to scale down frequency a step if it sleep a lot.
486d7937e2eSIntel 	 */
487aee3bc79SCunming Liang 	if (sleep_time_ratio >= SCALING_DOWN_TIME_RATIO_THRESHOLD) {
488aee3bc79SCunming Liang 		if (rte_power_freq_down)
489d7937e2eSIntel 			rte_power_freq_down(lcore_id);
490aee3bc79SCunming Liang 	}
491d7937e2eSIntel 	else if ( (unsigned)(stats[lcore_id].nb_rx_processed /
492aee3bc79SCunming Liang 		stats[lcore_id].nb_iteration_looped) < MAX_PKT_BURST) {
493d7937e2eSIntel 		/**
494d7937e2eSIntel 		 * scale down a step if average packet per iteration less
495d7937e2eSIntel 		 * than expectation.
496d7937e2eSIntel 		 */
497aee3bc79SCunming Liang 		if (rte_power_freq_down)
498d7937e2eSIntel 			rte_power_freq_down(lcore_id);
499aee3bc79SCunming Liang 	}
500d7937e2eSIntel 
501d7937e2eSIntel 	/**
502d7937e2eSIntel 	 * initialize another timer according to current frequency to ensure
503d7937e2eSIntel 	 * timer interval is relatively fixed.
504d7937e2eSIntel 	 */
505d7937e2eSIntel 	hz = rte_get_timer_hz();
506d7937e2eSIntel 	rte_timer_reset(&power_timers[lcore_id], hz/TIMER_NUMBER_PER_SECOND,
507d7937e2eSIntel 				SINGLE, lcore_id, power_timer_cb, NULL);
508d7937e2eSIntel 
509d7937e2eSIntel 	stats[lcore_id].nb_rx_processed = 0;
510d7937e2eSIntel 	stats[lcore_id].nb_iteration_looped = 0;
511d7937e2eSIntel 
512d7937e2eSIntel 	stats[lcore_id].sleep_time = 0;
513d7937e2eSIntel }
514d7937e2eSIntel 
515d7937e2eSIntel /* Enqueue a single packet, and send burst if queue is filled */
516d7937e2eSIntel static inline int
51747523597SZhiyong Yang send_single_packet(struct rte_mbuf *m, uint16_t port)
518d7937e2eSIntel {
519d7937e2eSIntel 	uint32_t lcore_id;
520d7937e2eSIntel 	struct lcore_conf *qconf;
521d7937e2eSIntel 
522d7937e2eSIntel 	lcore_id = rte_lcore_id();
523d7937e2eSIntel 	qconf = &lcore_conf[lcore_id];
524d7937e2eSIntel 
525e2366e74STomasz Kulasek 	rte_eth_tx_buffer(port, qconf->tx_queue_id[port],
526e2366e74STomasz Kulasek 			qconf->tx_buffer[port], m);
527d7937e2eSIntel 
528d7937e2eSIntel 	return 0;
529d7937e2eSIntel }
530d7937e2eSIntel 
531d7937e2eSIntel #ifdef DO_RFC_1812_CHECKS
532d7937e2eSIntel static inline int
533a7c528e5SOlivier Matz is_valid_ipv4_pkt(struct rte_ipv4_hdr *pkt, uint32_t link_len)
534d7937e2eSIntel {
535d7937e2eSIntel 	/* From http://www.rfc-editor.org/rfc/rfc1812.txt section 5.2.2 */
536d7937e2eSIntel 	/*
537d7937e2eSIntel 	 * 1. The packet length reported by the Link Layer must be large
538d7937e2eSIntel 	 * enough to hold the minimum length legal IP datagram (20 bytes).
539d7937e2eSIntel 	 */
540a7c528e5SOlivier Matz 	if (link_len < sizeof(struct rte_ipv4_hdr))
541d7937e2eSIntel 		return -1;
542d7937e2eSIntel 
543d7937e2eSIntel 	/* 2. The IP checksum must be correct. */
544d7937e2eSIntel 	/* this is checked in H/W */
545d7937e2eSIntel 
546d7937e2eSIntel 	/*
547d7937e2eSIntel 	 * 3. The IP version number must be 4. If the version number is not 4
548d7937e2eSIntel 	 * then the packet may be another version of IP, such as IPng or
549d7937e2eSIntel 	 * ST-II.
550d7937e2eSIntel 	 */
551d7937e2eSIntel 	if (((pkt->version_ihl) >> 4) != 4)
552d7937e2eSIntel 		return -3;
553d7937e2eSIntel 	/*
554d7937e2eSIntel 	 * 4. The IP header length field must be large enough to hold the
555d7937e2eSIntel 	 * minimum length legal IP datagram (20 bytes = 5 words).
556d7937e2eSIntel 	 */
557d7937e2eSIntel 	if ((pkt->version_ihl & 0xf) < 5)
558d7937e2eSIntel 		return -4;
559d7937e2eSIntel 
560d7937e2eSIntel 	/*
561d7937e2eSIntel 	 * 5. The IP total length field must be large enough to hold the IP
562d7937e2eSIntel 	 * datagram header, whose length is specified in the IP header length
563d7937e2eSIntel 	 * field.
564d7937e2eSIntel 	 */
565a7c528e5SOlivier Matz 	if (rte_cpu_to_be_16(pkt->total_length) < sizeof(struct rte_ipv4_hdr))
566d7937e2eSIntel 		return -5;
567d7937e2eSIntel 
568d7937e2eSIntel 	return 0;
569d7937e2eSIntel }
570d7937e2eSIntel #endif
571d7937e2eSIntel 
572d7937e2eSIntel #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
573d7937e2eSIntel static void
574d7937e2eSIntel print_ipv4_key(struct ipv4_5tuple key)
575d7937e2eSIntel {
576d7937e2eSIntel 	printf("IP dst = %08x, IP src = %08x, port dst = %d, port src = %d, "
577d7937e2eSIntel 		"proto = %d\n", (unsigned)key.ip_dst, (unsigned)key.ip_src,
578d7937e2eSIntel 				key.port_dst, key.port_src, key.proto);
579d7937e2eSIntel }
580d7937e2eSIntel static void
581d7937e2eSIntel print_ipv6_key(struct ipv6_5tuple key)
582d7937e2eSIntel {
583d7937e2eSIntel 	printf( "IP dst = " IPv6_BYTES_FMT ", IP src = " IPv6_BYTES_FMT ", "
584d7937e2eSIntel 	        "port dst = %d, port src = %d, proto = %d\n",
585d7937e2eSIntel 	        IPv6_BYTES(key.ip_dst), IPv6_BYTES(key.ip_src),
586d7937e2eSIntel 	        key.port_dst, key.port_src, key.proto);
587d7937e2eSIntel }
588d7937e2eSIntel 
589f8244c63SZhiyong Yang static inline uint16_t
590a7c528e5SOlivier Matz get_ipv4_dst_port(struct rte_ipv4_hdr *ipv4_hdr, uint16_t portid,
591d7937e2eSIntel 		lookup_struct_t * ipv4_l3fwd_lookup_struct)
592d7937e2eSIntel {
593d7937e2eSIntel 	struct ipv4_5tuple key;
594f41b5156SOlivier Matz 	struct rte_tcp_hdr *tcp;
595e73e3547SOlivier Matz 	struct rte_udp_hdr *udp;
596d7937e2eSIntel 	int ret = 0;
597d7937e2eSIntel 
598d7937e2eSIntel 	key.ip_dst = rte_be_to_cpu_32(ipv4_hdr->dst_addr);
599d7937e2eSIntel 	key.ip_src = rte_be_to_cpu_32(ipv4_hdr->src_addr);
600d7937e2eSIntel 	key.proto = ipv4_hdr->next_proto_id;
601d7937e2eSIntel 
602d7937e2eSIntel 	switch (ipv4_hdr->next_proto_id) {
603d7937e2eSIntel 	case IPPROTO_TCP:
604f41b5156SOlivier Matz 		tcp = (struct rte_tcp_hdr *)((unsigned char *)ipv4_hdr +
605a7c528e5SOlivier Matz 					sizeof(struct rte_ipv4_hdr));
606d7937e2eSIntel 		key.port_dst = rte_be_to_cpu_16(tcp->dst_port);
607d7937e2eSIntel 		key.port_src = rte_be_to_cpu_16(tcp->src_port);
608d7937e2eSIntel 		break;
609d7937e2eSIntel 
610d7937e2eSIntel 	case IPPROTO_UDP:
611e73e3547SOlivier Matz 		udp = (struct rte_udp_hdr *)((unsigned char *)ipv4_hdr +
612a7c528e5SOlivier Matz 					sizeof(struct rte_ipv4_hdr));
613d7937e2eSIntel 		key.port_dst = rte_be_to_cpu_16(udp->dst_port);
614d7937e2eSIntel 		key.port_src = rte_be_to_cpu_16(udp->src_port);
615d7937e2eSIntel 		break;
616d7937e2eSIntel 
617d7937e2eSIntel 	default:
618d7937e2eSIntel 		key.port_dst = 0;
619d7937e2eSIntel 		key.port_src = 0;
620d7937e2eSIntel 		break;
621d7937e2eSIntel 	}
622d7937e2eSIntel 
623d7937e2eSIntel 	/* Find destination port */
624d7937e2eSIntel 	ret = rte_hash_lookup(ipv4_l3fwd_lookup_struct, (const void *)&key);
625f8244c63SZhiyong Yang 	return ((ret < 0) ? portid : ipv4_l3fwd_out_if[ret]);
626d7937e2eSIntel }
627d7937e2eSIntel 
628f8244c63SZhiyong Yang static inline uint16_t
629a7c528e5SOlivier Matz get_ipv6_dst_port(struct rte_ipv6_hdr *ipv6_hdr, uint16_t portid,
630d7937e2eSIntel 			lookup_struct_t *ipv6_l3fwd_lookup_struct)
631d7937e2eSIntel {
632d7937e2eSIntel 	struct ipv6_5tuple key;
633f41b5156SOlivier Matz 	struct rte_tcp_hdr *tcp;
634e73e3547SOlivier Matz 	struct rte_udp_hdr *udp;
635d7937e2eSIntel 	int ret = 0;
636d7937e2eSIntel 
637d7937e2eSIntel 	memcpy(key.ip_dst, ipv6_hdr->dst_addr, IPV6_ADDR_LEN);
638d7937e2eSIntel 	memcpy(key.ip_src, ipv6_hdr->src_addr, IPV6_ADDR_LEN);
639d7937e2eSIntel 
640d7937e2eSIntel 	key.proto = ipv6_hdr->proto;
641d7937e2eSIntel 
642d7937e2eSIntel 	switch (ipv6_hdr->proto) {
643d7937e2eSIntel 	case IPPROTO_TCP:
644f41b5156SOlivier Matz 		tcp = (struct rte_tcp_hdr *)((unsigned char *) ipv6_hdr +
645a7c528e5SOlivier Matz 					sizeof(struct rte_ipv6_hdr));
646d7937e2eSIntel 		key.port_dst = rte_be_to_cpu_16(tcp->dst_port);
647d7937e2eSIntel 		key.port_src = rte_be_to_cpu_16(tcp->src_port);
648d7937e2eSIntel 		break;
649d7937e2eSIntel 
650d7937e2eSIntel 	case IPPROTO_UDP:
651e73e3547SOlivier Matz 		udp = (struct rte_udp_hdr *)((unsigned char *) ipv6_hdr +
652a7c528e5SOlivier Matz 					sizeof(struct rte_ipv6_hdr));
653d7937e2eSIntel 		key.port_dst = rte_be_to_cpu_16(udp->dst_port);
654d7937e2eSIntel 		key.port_src = rte_be_to_cpu_16(udp->src_port);
655d7937e2eSIntel 		break;
656d7937e2eSIntel 
657d7937e2eSIntel 	default:
658d7937e2eSIntel 		key.port_dst = 0;
659d7937e2eSIntel 		key.port_src = 0;
660d7937e2eSIntel 		break;
661d7937e2eSIntel 	}
662d7937e2eSIntel 
663d7937e2eSIntel 	/* Find destination port */
664d7937e2eSIntel 	ret = rte_hash_lookup(ipv6_l3fwd_lookup_struct, (const void *)&key);
665f8244c63SZhiyong Yang 	return ((ret < 0) ? portid : ipv6_l3fwd_out_if[ret]);
666d7937e2eSIntel }
667d7937e2eSIntel #endif
668d7937e2eSIntel 
669d7937e2eSIntel #if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
670f8244c63SZhiyong Yang static inline uint16_t
671a7c528e5SOlivier Matz get_ipv4_dst_port(struct rte_ipv4_hdr *ipv4_hdr, uint16_t portid,
672d7937e2eSIntel 		lookup_struct_t *ipv4_l3fwd_lookup_struct)
673d7937e2eSIntel {
674dc81ebbaSMichal Kobylinski 	uint32_t next_hop;
675d7937e2eSIntel 
676f8244c63SZhiyong Yang 	return ((rte_lpm_lookup(ipv4_l3fwd_lookup_struct,
677d7937e2eSIntel 			rte_be_to_cpu_32(ipv4_hdr->dst_addr), &next_hop) == 0)?
678d7937e2eSIntel 			next_hop : portid);
679d7937e2eSIntel }
680d7937e2eSIntel #endif
681d7937e2eSIntel 
682d7937e2eSIntel static inline void
68382bea466SJianfeng Tan parse_ptype_one(struct rte_mbuf *m)
68482bea466SJianfeng Tan {
6856d13ea8eSOlivier Matz 	struct rte_ether_hdr *eth_hdr;
68682bea466SJianfeng Tan 	uint32_t packet_type = RTE_PTYPE_UNKNOWN;
68782bea466SJianfeng Tan 	uint16_t ether_type;
68882bea466SJianfeng Tan 
6896d13ea8eSOlivier Matz 	eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
69082bea466SJianfeng Tan 	ether_type = eth_hdr->ether_type;
6910c9da755SDavid Marchand 	if (ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4))
69282bea466SJianfeng Tan 		packet_type |= RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
6930c9da755SDavid Marchand 	else if (ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6))
69482bea466SJianfeng Tan 		packet_type |= RTE_PTYPE_L3_IPV6_EXT_UNKNOWN;
69582bea466SJianfeng Tan 
69682bea466SJianfeng Tan 	m->packet_type = packet_type;
69782bea466SJianfeng Tan }
69882bea466SJianfeng Tan 
69982bea466SJianfeng Tan static uint16_t
700f8244c63SZhiyong Yang cb_parse_ptype(uint16_t port __rte_unused, uint16_t queue __rte_unused,
70182bea466SJianfeng Tan 	       struct rte_mbuf *pkts[], uint16_t nb_pkts,
70282bea466SJianfeng Tan 	       uint16_t max_pkts __rte_unused,
70382bea466SJianfeng Tan 	       void *user_param __rte_unused)
70482bea466SJianfeng Tan {
70582bea466SJianfeng Tan 	unsigned int i;
70682bea466SJianfeng Tan 
70782bea466SJianfeng Tan 	for (i = 0; i < nb_pkts; ++i)
70882bea466SJianfeng Tan 		parse_ptype_one(pkts[i]);
70982bea466SJianfeng Tan 
71082bea466SJianfeng Tan 	return nb_pkts;
71182bea466SJianfeng Tan }
71282bea466SJianfeng Tan 
71382bea466SJianfeng Tan static int
714f8244c63SZhiyong Yang add_cb_parse_ptype(uint16_t portid, uint16_t queueid)
71582bea466SJianfeng Tan {
71682bea466SJianfeng Tan 	printf("Port %d: softly parse packet type info\n", portid);
71782bea466SJianfeng Tan 	if (rte_eth_add_rx_callback(portid, queueid, cb_parse_ptype, NULL))
71882bea466SJianfeng Tan 		return 0;
71982bea466SJianfeng Tan 
72082bea466SJianfeng Tan 	printf("Failed to add rx callback: port=%d\n", portid);
72182bea466SJianfeng Tan 	return -1;
72282bea466SJianfeng Tan }
72382bea466SJianfeng Tan 
72482bea466SJianfeng Tan static inline void
72547523597SZhiyong Yang l3fwd_simple_forward(struct rte_mbuf *m, uint16_t portid,
726d7937e2eSIntel 				struct lcore_conf *qconf)
727d7937e2eSIntel {
7286d13ea8eSOlivier Matz 	struct rte_ether_hdr *eth_hdr;
729a7c528e5SOlivier Matz 	struct rte_ipv4_hdr *ipv4_hdr;
730d7937e2eSIntel 	void *d_addr_bytes;
731f8244c63SZhiyong Yang 	uint16_t dst_port;
732d7937e2eSIntel 
7336d13ea8eSOlivier Matz 	eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
734d7937e2eSIntel 
7353c0184ccSHelin Zhang 	if (RTE_ETH_IS_IPV4_HDR(m->packet_type)) {
736d7937e2eSIntel 		/* Handle IPv4 headers.*/
737d7937e2eSIntel 		ipv4_hdr =
738a7c528e5SOlivier Matz 			rte_pktmbuf_mtod_offset(m, struct rte_ipv4_hdr *,
7396d13ea8eSOlivier Matz 						sizeof(struct rte_ether_hdr));
740d7937e2eSIntel 
741d7937e2eSIntel #ifdef DO_RFC_1812_CHECKS
742d7937e2eSIntel 		/* Check to make sure the packet is valid (RFC1812) */
743ea672a8bSOlivier Matz 		if (is_valid_ipv4_pkt(ipv4_hdr, m->pkt_len) < 0) {
744d7937e2eSIntel 			rte_pktmbuf_free(m);
745d7937e2eSIntel 			return;
746d7937e2eSIntel 		}
747d7937e2eSIntel #endif
748d7937e2eSIntel 
749d7937e2eSIntel 		dst_port = get_ipv4_dst_port(ipv4_hdr, portid,
750d7937e2eSIntel 					qconf->ipv4_lookup_struct);
751d7937e2eSIntel 		if (dst_port >= RTE_MAX_ETHPORTS ||
752d7937e2eSIntel 				(enabled_port_mask & 1 << dst_port) == 0)
753d7937e2eSIntel 			dst_port = portid;
754d7937e2eSIntel 
755d7937e2eSIntel 		/* 02:00:00:00:00:xx */
756d7937e2eSIntel 		d_addr_bytes = &eth_hdr->d_addr.addr_bytes[0];
757d7937e2eSIntel 		*((uint64_t *)d_addr_bytes) =
758d7937e2eSIntel 			0x000000000002 + ((uint64_t)dst_port << 40);
759d7937e2eSIntel 
760d7937e2eSIntel #ifdef DO_RFC_1812_CHECKS
761d7937e2eSIntel 		/* Update time to live and header checksum */
762d7937e2eSIntel 		--(ipv4_hdr->time_to_live);
763d7937e2eSIntel 		++(ipv4_hdr->hdr_checksum);
764d7937e2eSIntel #endif
765d7937e2eSIntel 
766d7937e2eSIntel 		/* src addr */
767538da7a1SOlivier Matz 		rte_ether_addr_copy(&ports_eth_addr[dst_port],
768538da7a1SOlivier Matz 				&eth_hdr->s_addr);
769d7937e2eSIntel 
770d7937e2eSIntel 		send_single_packet(m, dst_port);
7713c0184ccSHelin Zhang 	} else if (RTE_ETH_IS_IPV6_HDR(m->packet_type)) {
772d7937e2eSIntel 		/* Handle IPv6 headers.*/
773d7937e2eSIntel #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
774a7c528e5SOlivier Matz 		struct rte_ipv6_hdr *ipv6_hdr;
775d7937e2eSIntel 
776d7937e2eSIntel 		ipv6_hdr =
777a7c528e5SOlivier Matz 			rte_pktmbuf_mtod_offset(m, struct rte_ipv6_hdr *,
7786d13ea8eSOlivier Matz 						sizeof(struct rte_ether_hdr));
779d7937e2eSIntel 
780d7937e2eSIntel 		dst_port = get_ipv6_dst_port(ipv6_hdr, portid,
781d7937e2eSIntel 					qconf->ipv6_lookup_struct);
782d7937e2eSIntel 
783d7937e2eSIntel 		if (dst_port >= RTE_MAX_ETHPORTS ||
784d7937e2eSIntel 				(enabled_port_mask & 1 << dst_port) == 0)
785d7937e2eSIntel 			dst_port = portid;
786d7937e2eSIntel 
787d7937e2eSIntel 		/* 02:00:00:00:00:xx */
788d7937e2eSIntel 		d_addr_bytes = &eth_hdr->d_addr.addr_bytes[0];
789d7937e2eSIntel 		*((uint64_t *)d_addr_bytes) =
790d7937e2eSIntel 			0x000000000002 + ((uint64_t)dst_port << 40);
791d7937e2eSIntel 
792d7937e2eSIntel 		/* src addr */
793538da7a1SOlivier Matz 		rte_ether_addr_copy(&ports_eth_addr[dst_port],
794538da7a1SOlivier Matz 				&eth_hdr->s_addr);
795d7937e2eSIntel 
796d7937e2eSIntel 		send_single_packet(m, dst_port);
797d7937e2eSIntel #else
798d7937e2eSIntel 		/* We don't currently handle IPv6 packets in LPM mode. */
799d7937e2eSIntel 		rte_pktmbuf_free(m);
800d7937e2eSIntel #endif
801bec2f7dfSShaopeng He 	} else
802bec2f7dfSShaopeng He 		rte_pktmbuf_free(m);
803d7937e2eSIntel 
804d7937e2eSIntel }
805d7937e2eSIntel 
806aee3bc79SCunming Liang #define MINIMUM_SLEEP_TIME         1
807aee3bc79SCunming Liang #define SUSPEND_THRESHOLD          300
808d7937e2eSIntel 
809d7937e2eSIntel static inline uint32_t
810d7937e2eSIntel power_idle_heuristic(uint32_t zero_rx_packet_count)
811d7937e2eSIntel {
812aee3bc79SCunming Liang 	/* If zero count is less than 100,  sleep 1us */
813aee3bc79SCunming Liang 	if (zero_rx_packet_count < SUSPEND_THRESHOLD)
814aee3bc79SCunming Liang 		return MINIMUM_SLEEP_TIME;
815aee3bc79SCunming Liang 	/* If zero count is less than 1000, sleep 100 us which is the
816aee3bc79SCunming Liang 		minimum latency switching from C3/C6 to C0
817aee3bc79SCunming Liang 	*/
818aee3bc79SCunming Liang 	else
819aee3bc79SCunming Liang 		return SUSPEND_THRESHOLD;
820d7937e2eSIntel }
821d7937e2eSIntel 
822d7937e2eSIntel static inline enum freq_scale_hint_t
823b451aa39SIntel power_freq_scaleup_heuristic(unsigned lcore_id,
824f8244c63SZhiyong Yang 			     uint16_t port_id,
825b451aa39SIntel 			     uint16_t queue_id)
826d7937e2eSIntel {
82747d834baSNikhil Agarwal 	uint32_t rxq_count = rte_eth_rx_queue_count(port_id, queue_id);
828d7937e2eSIntel /**
829d7937e2eSIntel  * HW Rx queue size is 128 by default, Rx burst read at maximum 32 entries
830d7937e2eSIntel  * per iteration
831d7937e2eSIntel  */
832d7937e2eSIntel #define FREQ_GEAR1_RX_PACKET_THRESHOLD             MAX_PKT_BURST
833b451aa39SIntel #define FREQ_GEAR2_RX_PACKET_THRESHOLD             (MAX_PKT_BURST*2)
834b451aa39SIntel #define FREQ_GEAR3_RX_PACKET_THRESHOLD             (MAX_PKT_BURST*3)
835d7937e2eSIntel #define FREQ_UP_TREND1_ACC   1
836d7937e2eSIntel #define FREQ_UP_TREND2_ACC   100
837d7937e2eSIntel #define FREQ_UP_THRESHOLD    10000
838d7937e2eSIntel 
83947d834baSNikhil Agarwal 	if (likely(rxq_count > FREQ_GEAR3_RX_PACKET_THRESHOLD)) {
840d7937e2eSIntel 		stats[lcore_id].trend = 0;
841d7937e2eSIntel 		return FREQ_HIGHEST;
84247d834baSNikhil Agarwal 	} else if (likely(rxq_count > FREQ_GEAR2_RX_PACKET_THRESHOLD))
843d7937e2eSIntel 		stats[lcore_id].trend += FREQ_UP_TREND2_ACC;
84447d834baSNikhil Agarwal 	else if (likely(rxq_count > FREQ_GEAR1_RX_PACKET_THRESHOLD))
845d7937e2eSIntel 		stats[lcore_id].trend += FREQ_UP_TREND1_ACC;
846d7937e2eSIntel 
847b451aa39SIntel 	if (likely(stats[lcore_id].trend > FREQ_UP_THRESHOLD)) {
848d7937e2eSIntel 		stats[lcore_id].trend = 0;
849d7937e2eSIntel 		return FREQ_HIGHER;
850d7937e2eSIntel 	}
851d7937e2eSIntel 
852d7937e2eSIntel 	return FREQ_CURRENT;
853d7937e2eSIntel }
854d7937e2eSIntel 
855aee3bc79SCunming Liang /**
856aee3bc79SCunming Liang  * force polling thread sleep until one-shot rx interrupt triggers
857aee3bc79SCunming Liang  * @param port_id
858aee3bc79SCunming Liang  *  Port id.
859aee3bc79SCunming Liang  * @param queue_id
860aee3bc79SCunming Liang  *  Rx queue id.
861aee3bc79SCunming Liang  * @return
862aee3bc79SCunming Liang  *  0 on success
863aee3bc79SCunming Liang  */
864aee3bc79SCunming Liang static int
865aee3bc79SCunming Liang sleep_until_rx_interrupt(int num)
866aee3bc79SCunming Liang {
867aee3bc79SCunming Liang 	struct rte_epoll_event event[num];
868aee3bc79SCunming Liang 	int n, i;
869f8244c63SZhiyong Yang 	uint16_t port_id;
870f8244c63SZhiyong Yang 	uint8_t queue_id;
871aee3bc79SCunming Liang 	void *data;
872aee3bc79SCunming Liang 
873aee3bc79SCunming Liang 	RTE_LOG(INFO, L3FWD_POWER,
874aee3bc79SCunming Liang 		"lcore %u sleeps until interrupt triggers\n",
875aee3bc79SCunming Liang 		rte_lcore_id());
876aee3bc79SCunming Liang 
877aee3bc79SCunming Liang 	n = rte_epoll_wait(RTE_EPOLL_PER_THREAD, event, num, -1);
878aee3bc79SCunming Liang 	for (i = 0; i < n; i++) {
879aee3bc79SCunming Liang 		data = event[i].epdata.data;
880aee3bc79SCunming Liang 		port_id = ((uintptr_t)data) >> CHAR_BIT;
881aee3bc79SCunming Liang 		queue_id = ((uintptr_t)data) &
882aee3bc79SCunming Liang 			RTE_LEN2MASK(CHAR_BIT, uint8_t);
883b736d647SYong Liu 		rte_eth_dev_rx_intr_disable(port_id, queue_id);
884aee3bc79SCunming Liang 		RTE_LOG(INFO, L3FWD_POWER,
885aee3bc79SCunming Liang 			"lcore %u is waked up from rx interrupt on"
886aee3bc79SCunming Liang 			" port %d queue %d\n",
887aee3bc79SCunming Liang 			rte_lcore_id(), port_id, queue_id);
888aee3bc79SCunming Liang 	}
889aee3bc79SCunming Liang 
890aee3bc79SCunming Liang 	return 0;
891aee3bc79SCunming Liang }
892aee3bc79SCunming Liang 
893aee3bc79SCunming Liang static void turn_on_intr(struct lcore_conf *qconf)
894aee3bc79SCunming Liang {
895aee3bc79SCunming Liang 	int i;
896aee3bc79SCunming Liang 	struct lcore_rx_queue *rx_queue;
897f8244c63SZhiyong Yang 	uint8_t queue_id;
898f8244c63SZhiyong Yang 	uint16_t port_id;
899aee3bc79SCunming Liang 
900aee3bc79SCunming Liang 	for (i = 0; i < qconf->n_rx_queue; ++i) {
901aee3bc79SCunming Liang 		rx_queue = &(qconf->rx_queue_list[i]);
902aee3bc79SCunming Liang 		port_id = rx_queue->port_id;
903aee3bc79SCunming Liang 		queue_id = rx_queue->queue_id;
904aee3bc79SCunming Liang 
905aee3bc79SCunming Liang 		rte_spinlock_lock(&(locks[port_id]));
906aee3bc79SCunming Liang 		rte_eth_dev_rx_intr_enable(port_id, queue_id);
907aee3bc79SCunming Liang 		rte_spinlock_unlock(&(locks[port_id]));
908aee3bc79SCunming Liang 	}
909aee3bc79SCunming Liang }
910aee3bc79SCunming Liang 
911aee3bc79SCunming Liang static int event_register(struct lcore_conf *qconf)
912aee3bc79SCunming Liang {
913aee3bc79SCunming Liang 	struct lcore_rx_queue *rx_queue;
914f8244c63SZhiyong Yang 	uint8_t queueid;
915f8244c63SZhiyong Yang 	uint16_t portid;
916aee3bc79SCunming Liang 	uint32_t data;
917aee3bc79SCunming Liang 	int ret;
918aee3bc79SCunming Liang 	int i;
919aee3bc79SCunming Liang 
920aee3bc79SCunming Liang 	for (i = 0; i < qconf->n_rx_queue; ++i) {
921aee3bc79SCunming Liang 		rx_queue = &(qconf->rx_queue_list[i]);
922aee3bc79SCunming Liang 		portid = rx_queue->port_id;
923aee3bc79SCunming Liang 		queueid = rx_queue->queue_id;
924aee3bc79SCunming Liang 		data = portid << CHAR_BIT | queueid;
925aee3bc79SCunming Liang 
926aee3bc79SCunming Liang 		ret = rte_eth_dev_rx_intr_ctl_q(portid, queueid,
927aee3bc79SCunming Liang 						RTE_EPOLL_PER_THREAD,
928aee3bc79SCunming Liang 						RTE_INTR_EVENT_ADD,
929aee3bc79SCunming Liang 						(void *)((uintptr_t)data));
930aee3bc79SCunming Liang 		if (ret)
931aee3bc79SCunming Liang 			return ret;
932aee3bc79SCunming Liang 	}
933aee3bc79SCunming Liang 
934aee3bc79SCunming Liang 	return 0;
935aee3bc79SCunming Liang }
936a137d012SLiang Ma /* main processing loop */
937a137d012SLiang Ma static int
938609e7984SReshma Pattan main_telemetry_loop(__attribute__((unused)) void *dummy)
939609e7984SReshma Pattan {
940609e7984SReshma Pattan 	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
941609e7984SReshma Pattan 	unsigned int lcore_id;
942609e7984SReshma Pattan 	uint64_t prev_tsc, diff_tsc, cur_tsc, prev_tel_tsc;
943609e7984SReshma Pattan 	int i, j, nb_rx;
944609e7984SReshma Pattan 	uint8_t queueid;
945609e7984SReshma Pattan 	uint16_t portid;
946609e7984SReshma Pattan 	struct lcore_conf *qconf;
947609e7984SReshma Pattan 	struct lcore_rx_queue *rx_queue;
948609e7984SReshma Pattan 	uint64_t ep_nep[2] = {0}, fp_nfp[2] = {0};
949609e7984SReshma Pattan 	uint64_t poll_count;
950609e7984SReshma Pattan 	enum busy_rate br;
951609e7984SReshma Pattan 
952609e7984SReshma Pattan 	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) /
953609e7984SReshma Pattan 					US_PER_S * BURST_TX_DRAIN_US;
954609e7984SReshma Pattan 
955609e7984SReshma Pattan 	poll_count = 0;
956609e7984SReshma Pattan 	prev_tsc = 0;
957609e7984SReshma Pattan 	prev_tel_tsc = 0;
958609e7984SReshma Pattan 
959609e7984SReshma Pattan 	lcore_id = rte_lcore_id();
960609e7984SReshma Pattan 	qconf = &lcore_conf[lcore_id];
961609e7984SReshma Pattan 
962609e7984SReshma Pattan 	if (qconf->n_rx_queue == 0) {
963609e7984SReshma Pattan 		RTE_LOG(INFO, L3FWD_POWER, "lcore %u has nothing to do\n",
964609e7984SReshma Pattan 			lcore_id);
965609e7984SReshma Pattan 		return 0;
966609e7984SReshma Pattan 	}
967609e7984SReshma Pattan 
968609e7984SReshma Pattan 	RTE_LOG(INFO, L3FWD_POWER, "entering main telemetry loop on lcore %u\n",
969609e7984SReshma Pattan 		lcore_id);
970609e7984SReshma Pattan 
971609e7984SReshma Pattan 	for (i = 0; i < qconf->n_rx_queue; i++) {
972609e7984SReshma Pattan 		portid = qconf->rx_queue_list[i].port_id;
973609e7984SReshma Pattan 		queueid = qconf->rx_queue_list[i].queue_id;
974609e7984SReshma Pattan 		RTE_LOG(INFO, L3FWD_POWER, " -- lcoreid=%u portid=%u "
975609e7984SReshma Pattan 			"rxqueueid=%hhu\n", lcore_id, portid, queueid);
976609e7984SReshma Pattan 	}
977609e7984SReshma Pattan 
978609e7984SReshma Pattan 	while (!is_done()) {
979609e7984SReshma Pattan 
980609e7984SReshma Pattan 		cur_tsc = rte_rdtsc();
981609e7984SReshma Pattan 		/*
982609e7984SReshma Pattan 		 * TX burst queue drain
983609e7984SReshma Pattan 		 */
984609e7984SReshma Pattan 		diff_tsc = cur_tsc - prev_tsc;
985609e7984SReshma Pattan 		if (unlikely(diff_tsc > drain_tsc)) {
986609e7984SReshma Pattan 			for (i = 0; i < qconf->n_tx_port; ++i) {
987609e7984SReshma Pattan 				portid = qconf->tx_port_id[i];
988609e7984SReshma Pattan 				rte_eth_tx_buffer_flush(portid,
989609e7984SReshma Pattan 						qconf->tx_queue_id[portid],
990609e7984SReshma Pattan 						qconf->tx_buffer[portid]);
991609e7984SReshma Pattan 			}
992609e7984SReshma Pattan 			prev_tsc = cur_tsc;
993609e7984SReshma Pattan 		}
994609e7984SReshma Pattan 
995609e7984SReshma Pattan 		/*
996609e7984SReshma Pattan 		 * Read packet from RX queues
997609e7984SReshma Pattan 		 */
998609e7984SReshma Pattan 		for (i = 0; i < qconf->n_rx_queue; ++i) {
999609e7984SReshma Pattan 			rx_queue = &(qconf->rx_queue_list[i]);
1000609e7984SReshma Pattan 			portid = rx_queue->port_id;
1001609e7984SReshma Pattan 			queueid = rx_queue->queue_id;
1002609e7984SReshma Pattan 
1003609e7984SReshma Pattan 			nb_rx = rte_eth_rx_burst(portid, queueid, pkts_burst,
1004609e7984SReshma Pattan 								MAX_PKT_BURST);
1005609e7984SReshma Pattan 			ep_nep[nb_rx == 0]++;
1006609e7984SReshma Pattan 			fp_nfp[nb_rx == MAX_PKT_BURST]++;
1007609e7984SReshma Pattan 			poll_count++;
1008609e7984SReshma Pattan 			if (unlikely(nb_rx == 0))
1009609e7984SReshma Pattan 				continue;
1010609e7984SReshma Pattan 
1011609e7984SReshma Pattan 			/* Prefetch first packets */
1012609e7984SReshma Pattan 			for (j = 0; j < PREFETCH_OFFSET && j < nb_rx; j++) {
1013609e7984SReshma Pattan 				rte_prefetch0(rte_pktmbuf_mtod(
1014609e7984SReshma Pattan 						pkts_burst[j], void *));
1015609e7984SReshma Pattan 			}
1016609e7984SReshma Pattan 
1017609e7984SReshma Pattan 			/* Prefetch and forward already prefetched packets */
1018609e7984SReshma Pattan 			for (j = 0; j < (nb_rx - PREFETCH_OFFSET); j++) {
1019609e7984SReshma Pattan 				rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[
1020609e7984SReshma Pattan 						j + PREFETCH_OFFSET], void *));
1021609e7984SReshma Pattan 				l3fwd_simple_forward(pkts_burst[j], portid,
1022609e7984SReshma Pattan 								qconf);
1023609e7984SReshma Pattan 			}
1024609e7984SReshma Pattan 
1025609e7984SReshma Pattan 			/* Forward remaining prefetched packets */
1026609e7984SReshma Pattan 			for (; j < nb_rx; j++) {
1027609e7984SReshma Pattan 				l3fwd_simple_forward(pkts_burst[j], portid,
1028609e7984SReshma Pattan 								qconf);
1029609e7984SReshma Pattan 			}
1030609e7984SReshma Pattan 		}
1031609e7984SReshma Pattan 		if (unlikely(poll_count >= DEFAULT_COUNT)) {
1032609e7984SReshma Pattan 			diff_tsc = cur_tsc - prev_tel_tsc;
1033609e7984SReshma Pattan 			if (diff_tsc >= MAX_CYCLES) {
1034609e7984SReshma Pattan 				br = FULL;
1035609e7984SReshma Pattan 			} else if (diff_tsc > MIN_CYCLES &&
1036609e7984SReshma Pattan 					diff_tsc < MAX_CYCLES) {
1037b55d8fecSDavid Hunt 				br = (diff_tsc * 100) / MAX_CYCLES;
1038609e7984SReshma Pattan 			} else {
1039609e7984SReshma Pattan 				br = ZERO;
1040609e7984SReshma Pattan 			}
1041609e7984SReshma Pattan 			poll_count = 0;
1042609e7984SReshma Pattan 			prev_tel_tsc = cur_tsc;
1043609e7984SReshma Pattan 			/* update stats for telemetry */
1044609e7984SReshma Pattan 			rte_spinlock_lock(&stats[lcore_id].telemetry_lock);
1045609e7984SReshma Pattan 			stats[lcore_id].ep_nep[0] = ep_nep[0];
1046609e7984SReshma Pattan 			stats[lcore_id].ep_nep[1] = ep_nep[1];
1047609e7984SReshma Pattan 			stats[lcore_id].fp_nfp[0] = fp_nfp[0];
1048609e7984SReshma Pattan 			stats[lcore_id].fp_nfp[1] = fp_nfp[1];
1049609e7984SReshma Pattan 			stats[lcore_id].br = br;
1050609e7984SReshma Pattan 			rte_spinlock_unlock(&stats[lcore_id].telemetry_lock);
1051609e7984SReshma Pattan 		}
1052609e7984SReshma Pattan 	}
1053609e7984SReshma Pattan 
1054609e7984SReshma Pattan 	return 0;
1055609e7984SReshma Pattan }
1056609e7984SReshma Pattan /* main processing loop */
1057609e7984SReshma Pattan static int
1058a137d012SLiang Ma main_empty_poll_loop(__attribute__((unused)) void *dummy)
1059a137d012SLiang Ma {
1060a137d012SLiang Ma 	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
1061a137d012SLiang Ma 	unsigned int lcore_id;
1062a137d012SLiang Ma 	uint64_t prev_tsc, diff_tsc, cur_tsc;
1063a137d012SLiang Ma 	int i, j, nb_rx;
1064a137d012SLiang Ma 	uint8_t queueid;
1065a137d012SLiang Ma 	uint16_t portid;
1066a137d012SLiang Ma 	struct lcore_conf *qconf;
1067a137d012SLiang Ma 	struct lcore_rx_queue *rx_queue;
1068aee3bc79SCunming Liang 
1069a137d012SLiang Ma 	const uint64_t drain_tsc =
1070a137d012SLiang Ma 		(rte_get_tsc_hz() + US_PER_S - 1) /
1071a137d012SLiang Ma 		US_PER_S * BURST_TX_DRAIN_US;
1072a137d012SLiang Ma 
1073a137d012SLiang Ma 	prev_tsc = 0;
1074a137d012SLiang Ma 
1075a137d012SLiang Ma 	lcore_id = rte_lcore_id();
1076a137d012SLiang Ma 	qconf = &lcore_conf[lcore_id];
1077a137d012SLiang Ma 
1078a137d012SLiang Ma 	if (qconf->n_rx_queue == 0) {
1079a137d012SLiang Ma 		RTE_LOG(INFO, L3FWD_POWER, "lcore %u has nothing to do\n",
1080a137d012SLiang Ma 			lcore_id);
1081a137d012SLiang Ma 		return 0;
1082a137d012SLiang Ma 	}
1083a137d012SLiang Ma 
1084a137d012SLiang Ma 	for (i = 0; i < qconf->n_rx_queue; i++) {
1085a137d012SLiang Ma 		portid = qconf->rx_queue_list[i].port_id;
1086a137d012SLiang Ma 		queueid = qconf->rx_queue_list[i].queue_id;
1087a137d012SLiang Ma 		RTE_LOG(INFO, L3FWD_POWER, " -- lcoreid=%u portid=%u "
1088a137d012SLiang Ma 				"rxqueueid=%hhu\n", lcore_id, portid, queueid);
1089a137d012SLiang Ma 	}
1090a137d012SLiang Ma 
1091a137d012SLiang Ma 	while (!is_done()) {
1092a137d012SLiang Ma 		stats[lcore_id].nb_iteration_looped++;
1093a137d012SLiang Ma 
1094a137d012SLiang Ma 		cur_tsc = rte_rdtsc();
1095a137d012SLiang Ma 		/*
1096a137d012SLiang Ma 		 * TX burst queue drain
1097a137d012SLiang Ma 		 */
1098a137d012SLiang Ma 		diff_tsc = cur_tsc - prev_tsc;
1099a137d012SLiang Ma 		if (unlikely(diff_tsc > drain_tsc)) {
1100a137d012SLiang Ma 			for (i = 0; i < qconf->n_tx_port; ++i) {
1101a137d012SLiang Ma 				portid = qconf->tx_port_id[i];
1102a137d012SLiang Ma 				rte_eth_tx_buffer_flush(portid,
1103a137d012SLiang Ma 						qconf->tx_queue_id[portid],
1104a137d012SLiang Ma 						qconf->tx_buffer[portid]);
1105a137d012SLiang Ma 			}
1106a137d012SLiang Ma 			prev_tsc = cur_tsc;
1107a137d012SLiang Ma 		}
1108a137d012SLiang Ma 
1109a137d012SLiang Ma 		/*
1110a137d012SLiang Ma 		 * Read packet from RX queues
1111a137d012SLiang Ma 		 */
1112a137d012SLiang Ma 		for (i = 0; i < qconf->n_rx_queue; ++i) {
1113a137d012SLiang Ma 			rx_queue = &(qconf->rx_queue_list[i]);
1114a137d012SLiang Ma 			rx_queue->idle_hint = 0;
1115a137d012SLiang Ma 			portid = rx_queue->port_id;
1116a137d012SLiang Ma 			queueid = rx_queue->queue_id;
1117a137d012SLiang Ma 
1118a137d012SLiang Ma 			nb_rx = rte_eth_rx_burst(portid, queueid, pkts_burst,
1119a137d012SLiang Ma 					MAX_PKT_BURST);
1120a137d012SLiang Ma 
1121a137d012SLiang Ma 			stats[lcore_id].nb_rx_processed += nb_rx;
1122a137d012SLiang Ma 
1123a137d012SLiang Ma 			if (nb_rx == 0) {
1124a137d012SLiang Ma 
1125a137d012SLiang Ma 				rte_power_empty_poll_stat_update(lcore_id);
1126a137d012SLiang Ma 
1127a137d012SLiang Ma 				continue;
1128a137d012SLiang Ma 			} else {
1129a137d012SLiang Ma 				rte_power_poll_stat_update(lcore_id, nb_rx);
1130a137d012SLiang Ma 			}
1131a137d012SLiang Ma 
1132a137d012SLiang Ma 
1133a137d012SLiang Ma 			/* Prefetch first packets */
1134a137d012SLiang Ma 			for (j = 0; j < PREFETCH_OFFSET && j < nb_rx; j++) {
1135a137d012SLiang Ma 				rte_prefetch0(rte_pktmbuf_mtod(
1136a137d012SLiang Ma 							pkts_burst[j], void *));
1137a137d012SLiang Ma 			}
1138a137d012SLiang Ma 
1139a137d012SLiang Ma 			/* Prefetch and forward already prefetched packets */
1140a137d012SLiang Ma 			for (j = 0; j < (nb_rx - PREFETCH_OFFSET); j++) {
1141a137d012SLiang Ma 				rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[
1142a137d012SLiang Ma 							j + PREFETCH_OFFSET],
1143a137d012SLiang Ma 							void *));
1144a137d012SLiang Ma 				l3fwd_simple_forward(pkts_burst[j], portid,
1145a137d012SLiang Ma 						qconf);
1146a137d012SLiang Ma 			}
1147a137d012SLiang Ma 
1148a137d012SLiang Ma 			/* Forward remaining prefetched packets */
1149a137d012SLiang Ma 			for (; j < nb_rx; j++) {
1150a137d012SLiang Ma 				l3fwd_simple_forward(pkts_burst[j], portid,
1151a137d012SLiang Ma 						qconf);
1152a137d012SLiang Ma 			}
1153a137d012SLiang Ma 
1154a137d012SLiang Ma 		}
1155a137d012SLiang Ma 
1156a137d012SLiang Ma 	}
1157a137d012SLiang Ma 
1158a137d012SLiang Ma 	return 0;
1159a137d012SLiang Ma }
1160d7937e2eSIntel /* main processing loop */
1161d7937e2eSIntel static int
1162d7937e2eSIntel main_loop(__attribute__((unused)) void *dummy)
1163d7937e2eSIntel {
1164d7937e2eSIntel 	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
1165d7937e2eSIntel 	unsigned lcore_id;
116663de7e6eSNikhil Agarwal 	uint64_t prev_tsc, diff_tsc, cur_tsc, tim_res_tsc, hz;
1167d7937e2eSIntel 	uint64_t prev_tsc_power = 0, cur_tsc_power, diff_tsc_power;
1168d7937e2eSIntel 	int i, j, nb_rx;
1169f8244c63SZhiyong Yang 	uint8_t queueid;
1170f8244c63SZhiyong Yang 	uint16_t portid;
1171d7937e2eSIntel 	struct lcore_conf *qconf;
1172d7937e2eSIntel 	struct lcore_rx_queue *rx_queue;
1173d7937e2eSIntel 	enum freq_scale_hint_t lcore_scaleup_hint;
1174d7937e2eSIntel 	uint32_t lcore_rx_idle_count = 0;
1175d7937e2eSIntel 	uint32_t lcore_idle_hint = 0;
1176aee3bc79SCunming Liang 	int intr_en = 0;
1177d7937e2eSIntel 
1178d7937e2eSIntel 	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;
1179d7937e2eSIntel 
1180d7937e2eSIntel 	prev_tsc = 0;
118163de7e6eSNikhil Agarwal 	hz = rte_get_timer_hz();
118263de7e6eSNikhil Agarwal 	tim_res_tsc = hz/TIMER_NUMBER_PER_SECOND;
1183d7937e2eSIntel 
1184d7937e2eSIntel 	lcore_id = rte_lcore_id();
1185d7937e2eSIntel 	qconf = &lcore_conf[lcore_id];
1186d7937e2eSIntel 
1187d7937e2eSIntel 	if (qconf->n_rx_queue == 0) {
1188d7937e2eSIntel 		RTE_LOG(INFO, L3FWD_POWER, "lcore %u has nothing to do\n", lcore_id);
1189d7937e2eSIntel 		return 0;
1190d7937e2eSIntel 	}
1191d7937e2eSIntel 
1192d7937e2eSIntel 	RTE_LOG(INFO, L3FWD_POWER, "entering main loop on lcore %u\n", lcore_id);
1193d7937e2eSIntel 
1194d7937e2eSIntel 	for (i = 0; i < qconf->n_rx_queue; i++) {
1195d7937e2eSIntel 		portid = qconf->rx_queue_list[i].port_id;
1196d7937e2eSIntel 		queueid = qconf->rx_queue_list[i].queue_id;
1197f8244c63SZhiyong Yang 		RTE_LOG(INFO, L3FWD_POWER, " -- lcoreid=%u portid=%u "
1198d7937e2eSIntel 			"rxqueueid=%hhu\n", lcore_id, portid, queueid);
1199d7937e2eSIntel 	}
1200d7937e2eSIntel 
1201aee3bc79SCunming Liang 	/* add into event wait list */
1202aee3bc79SCunming Liang 	if (event_register(qconf) == 0)
1203aee3bc79SCunming Liang 		intr_en = 1;
1204aee3bc79SCunming Liang 	else
1205aee3bc79SCunming Liang 		RTE_LOG(INFO, L3FWD_POWER, "RX interrupt won't enable.\n");
1206aee3bc79SCunming Liang 
1207d7937e2eSIntel 	while (1) {
1208d7937e2eSIntel 		stats[lcore_id].nb_iteration_looped++;
1209d7937e2eSIntel 
1210d7937e2eSIntel 		cur_tsc = rte_rdtsc();
1211d7937e2eSIntel 		cur_tsc_power = cur_tsc;
1212d7937e2eSIntel 
1213d7937e2eSIntel 		/*
1214d7937e2eSIntel 		 * TX burst queue drain
1215d7937e2eSIntel 		 */
1216d7937e2eSIntel 		diff_tsc = cur_tsc - prev_tsc;
1217d7937e2eSIntel 		if (unlikely(diff_tsc > drain_tsc)) {
1218e2366e74STomasz Kulasek 			for (i = 0; i < qconf->n_tx_port; ++i) {
1219e2366e74STomasz Kulasek 				portid = qconf->tx_port_id[i];
1220e2366e74STomasz Kulasek 				rte_eth_tx_buffer_flush(portid,
1221e2366e74STomasz Kulasek 						qconf->tx_queue_id[portid],
1222e2366e74STomasz Kulasek 						qconf->tx_buffer[portid]);
1223d7937e2eSIntel 			}
1224d7937e2eSIntel 			prev_tsc = cur_tsc;
1225d7937e2eSIntel 		}
1226d7937e2eSIntel 
1227d7937e2eSIntel 		diff_tsc_power = cur_tsc_power - prev_tsc_power;
122863de7e6eSNikhil Agarwal 		if (diff_tsc_power > tim_res_tsc) {
1229d7937e2eSIntel 			rte_timer_manage();
1230d7937e2eSIntel 			prev_tsc_power = cur_tsc_power;
1231d7937e2eSIntel 		}
1232d7937e2eSIntel 
1233aee3bc79SCunming Liang start_rx:
1234d7937e2eSIntel 		/*
1235d7937e2eSIntel 		 * Read packet from RX queues
1236d7937e2eSIntel 		 */
1237d7937e2eSIntel 		lcore_scaleup_hint = FREQ_CURRENT;
1238d7937e2eSIntel 		lcore_rx_idle_count = 0;
1239d7937e2eSIntel 		for (i = 0; i < qconf->n_rx_queue; ++i) {
1240d7937e2eSIntel 			rx_queue = &(qconf->rx_queue_list[i]);
1241d7937e2eSIntel 			rx_queue->idle_hint = 0;
1242d7937e2eSIntel 			portid = rx_queue->port_id;
1243d7937e2eSIntel 			queueid = rx_queue->queue_id;
1244d7937e2eSIntel 
1245d7937e2eSIntel 			nb_rx = rte_eth_rx_burst(portid, queueid, pkts_burst,
1246d7937e2eSIntel 								MAX_PKT_BURST);
1247aee3bc79SCunming Liang 
1248d7937e2eSIntel 			stats[lcore_id].nb_rx_processed += nb_rx;
1249d7937e2eSIntel 			if (unlikely(nb_rx == 0)) {
1250d7937e2eSIntel 				/**
1251d7937e2eSIntel 				 * no packet received from rx queue, try to
1252d7937e2eSIntel 				 * sleep for a while forcing CPU enter deeper
1253d7937e2eSIntel 				 * C states.
1254d7937e2eSIntel 				 */
1255d7937e2eSIntel 				rx_queue->zero_rx_packet_count++;
1256d7937e2eSIntel 
1257d7937e2eSIntel 				if (rx_queue->zero_rx_packet_count <=
1258d7937e2eSIntel 							MIN_ZERO_POLL_COUNT)
1259d7937e2eSIntel 					continue;
1260d7937e2eSIntel 
1261d7937e2eSIntel 				rx_queue->idle_hint = power_idle_heuristic(\
1262d7937e2eSIntel 					rx_queue->zero_rx_packet_count);
1263d7937e2eSIntel 				lcore_rx_idle_count++;
1264d7937e2eSIntel 			} else {
1265d7937e2eSIntel 				rx_queue->zero_rx_packet_count = 0;
1266d7937e2eSIntel 
1267d7937e2eSIntel 				/**
1268d7937e2eSIntel 				 * do not scale up frequency immediately as
1269d7937e2eSIntel 				 * user to kernel space communication is costly
1270d7937e2eSIntel 				 * which might impact packet I/O for received
1271d7937e2eSIntel 				 * packets.
1272d7937e2eSIntel 				 */
1273d7937e2eSIntel 				rx_queue->freq_up_hint =
1274d7937e2eSIntel 					power_freq_scaleup_heuristic(lcore_id,
1275b451aa39SIntel 							portid, queueid);
1276d7937e2eSIntel 			}
1277d7937e2eSIntel 
1278d7937e2eSIntel 			/* Prefetch first packets */
1279d7937e2eSIntel 			for (j = 0; j < PREFETCH_OFFSET && j < nb_rx; j++) {
1280d7937e2eSIntel 				rte_prefetch0(rte_pktmbuf_mtod(
1281d7937e2eSIntel 						pkts_burst[j], void *));
1282d7937e2eSIntel 			}
1283d7937e2eSIntel 
1284d7937e2eSIntel 			/* Prefetch and forward already prefetched packets */
1285d7937e2eSIntel 			for (j = 0; j < (nb_rx - PREFETCH_OFFSET); j++) {
1286d7937e2eSIntel 				rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[
1287d7937e2eSIntel 						j + PREFETCH_OFFSET], void *));
1288d7937e2eSIntel 				l3fwd_simple_forward(pkts_burst[j], portid,
1289d7937e2eSIntel 								qconf);
1290d7937e2eSIntel 			}
1291d7937e2eSIntel 
1292d7937e2eSIntel 			/* Forward remaining prefetched packets */
1293d7937e2eSIntel 			for (; j < nb_rx; j++) {
1294d7937e2eSIntel 				l3fwd_simple_forward(pkts_burst[j], portid,
1295d7937e2eSIntel 								qconf);
1296d7937e2eSIntel 			}
1297d7937e2eSIntel 		}
1298d7937e2eSIntel 
1299d7937e2eSIntel 		if (likely(lcore_rx_idle_count != qconf->n_rx_queue)) {
1300d7937e2eSIntel 			for (i = 1, lcore_scaleup_hint =
1301d7937e2eSIntel 				qconf->rx_queue_list[0].freq_up_hint;
1302d7937e2eSIntel 					i < qconf->n_rx_queue; ++i) {
1303d7937e2eSIntel 				rx_queue = &(qconf->rx_queue_list[i]);
1304d7937e2eSIntel 				if (rx_queue->freq_up_hint >
1305d7937e2eSIntel 						lcore_scaleup_hint)
1306d7937e2eSIntel 					lcore_scaleup_hint =
1307d7937e2eSIntel 						rx_queue->freq_up_hint;
1308d7937e2eSIntel 			}
1309d7937e2eSIntel 
1310aee3bc79SCunming Liang 			if (lcore_scaleup_hint == FREQ_HIGHEST) {
1311aee3bc79SCunming Liang 				if (rte_power_freq_max)
1312d7937e2eSIntel 					rte_power_freq_max(lcore_id);
1313aee3bc79SCunming Liang 			} else if (lcore_scaleup_hint == FREQ_HIGHER) {
1314aee3bc79SCunming Liang 				if (rte_power_freq_up)
1315d7937e2eSIntel 					rte_power_freq_up(lcore_id);
1316aee3bc79SCunming Liang 			}
1317d7937e2eSIntel 		} else {
1318d7937e2eSIntel 			/**
1319d7937e2eSIntel 			 * All Rx queues empty in recent consecutive polls,
1320d7937e2eSIntel 			 * sleep in a conservative manner, meaning sleep as
1321d7937e2eSIntel 			 * less as possible.
1322d7937e2eSIntel 			 */
1323d7937e2eSIntel 			for (i = 1, lcore_idle_hint =
1324d7937e2eSIntel 				qconf->rx_queue_list[0].idle_hint;
1325d7937e2eSIntel 					i < qconf->n_rx_queue; ++i) {
1326d7937e2eSIntel 				rx_queue = &(qconf->rx_queue_list[i]);
1327d7937e2eSIntel 				if (rx_queue->idle_hint < lcore_idle_hint)
1328d7937e2eSIntel 					lcore_idle_hint = rx_queue->idle_hint;
1329d7937e2eSIntel 			}
1330d7937e2eSIntel 
1331aee3bc79SCunming Liang 			if (lcore_idle_hint < SUSPEND_THRESHOLD)
1332d7937e2eSIntel 				/**
1333d7937e2eSIntel 				 * execute "pause" instruction to avoid context
1334aee3bc79SCunming Liang 				 * switch which generally take hundred of
1335aee3bc79SCunming Liang 				 * microseconds for short sleep.
1336d7937e2eSIntel 				 */
1337d7937e2eSIntel 				rte_delay_us(lcore_idle_hint);
1338aee3bc79SCunming Liang 			else {
1339aee3bc79SCunming Liang 				/* suspend until rx interrupt trigges */
1340aee3bc79SCunming Liang 				if (intr_en) {
1341aee3bc79SCunming Liang 					turn_on_intr(qconf);
1342aee3bc79SCunming Liang 					sleep_until_rx_interrupt(
1343aee3bc79SCunming Liang 						qconf->n_rx_queue);
13444ffc0a88SNikhil Agarwal 					/**
13454ffc0a88SNikhil Agarwal 					 * start receiving packets immediately
13464ffc0a88SNikhil Agarwal 					 */
1347aee3bc79SCunming Liang 					goto start_rx;
1348aee3bc79SCunming Liang 				}
13494ffc0a88SNikhil Agarwal 			}
1350d7937e2eSIntel 			stats[lcore_id].sleep_time += lcore_idle_hint;
1351d7937e2eSIntel 		}
1352d7937e2eSIntel 	}
1353d7937e2eSIntel }
1354d7937e2eSIntel 
1355d7937e2eSIntel static int
1356d7937e2eSIntel check_lcore_params(void)
1357d7937e2eSIntel {
1358d7937e2eSIntel 	uint8_t queue, lcore;
1359d7937e2eSIntel 	uint16_t i;
1360d7937e2eSIntel 	int socketid;
1361d7937e2eSIntel 
1362d7937e2eSIntel 	for (i = 0; i < nb_lcore_params; ++i) {
1363d7937e2eSIntel 		queue = lcore_params[i].queue_id;
1364d7937e2eSIntel 		if (queue >= MAX_RX_QUEUE_PER_PORT) {
1365d7937e2eSIntel 			printf("invalid queue number: %hhu\n", queue);
1366d7937e2eSIntel 			return -1;
1367d7937e2eSIntel 		}
1368d7937e2eSIntel 		lcore = lcore_params[i].lcore_id;
1369d7937e2eSIntel 		if (!rte_lcore_is_enabled(lcore)) {
1370d7937e2eSIntel 			printf("error: lcore %hhu is not enabled in lcore "
1371d7937e2eSIntel 							"mask\n", lcore);
1372d7937e2eSIntel 			return -1;
1373d7937e2eSIntel 		}
1374d7937e2eSIntel 		if ((socketid = rte_lcore_to_socket_id(lcore) != 0) &&
1375d7937e2eSIntel 							(numa_on == 0)) {
1376d7937e2eSIntel 			printf("warning: lcore %hhu is on socket %d with numa "
1377d7937e2eSIntel 						"off\n", lcore, socketid);
1378d7937e2eSIntel 		}
1379609e7984SReshma Pattan 		if (app_mode == APP_MODE_TELEMETRY && lcore == rte_lcore_id()) {
1380609e7984SReshma Pattan 			printf("cannot enable master core %d in config for telemetry mode\n",
1381609e7984SReshma Pattan 				rte_lcore_id());
1382609e7984SReshma Pattan 			return -1;
1383609e7984SReshma Pattan 		}
1384d7937e2eSIntel 	}
1385d7937e2eSIntel 	return 0;
1386d7937e2eSIntel }
1387d7937e2eSIntel 
1388d7937e2eSIntel static int
1389a9dbe180SThomas Monjalon check_port_config(void)
1390d7937e2eSIntel {
1391d7937e2eSIntel 	unsigned portid;
1392d7937e2eSIntel 	uint16_t i;
1393d7937e2eSIntel 
1394d7937e2eSIntel 	for (i = 0; i < nb_lcore_params; ++i) {
1395d7937e2eSIntel 		portid = lcore_params[i].port_id;
1396d7937e2eSIntel 		if ((enabled_port_mask & (1 << portid)) == 0) {
1397d7937e2eSIntel 			printf("port %u is not enabled in port mask\n",
1398d7937e2eSIntel 								portid);
1399d7937e2eSIntel 			return -1;
1400d7937e2eSIntel 		}
1401a9dbe180SThomas Monjalon 		if (!rte_eth_dev_is_valid_port(portid)) {
1402d7937e2eSIntel 			printf("port %u is not present on the board\n",
1403d7937e2eSIntel 								portid);
1404d7937e2eSIntel 			return -1;
1405d7937e2eSIntel 		}
1406d7937e2eSIntel 	}
1407d7937e2eSIntel 	return 0;
1408d7937e2eSIntel }
1409d7937e2eSIntel 
1410d7937e2eSIntel static uint8_t
141147523597SZhiyong Yang get_port_n_rx_queues(const uint16_t port)
1412d7937e2eSIntel {
1413d7937e2eSIntel 	int queue = -1;
1414d7937e2eSIntel 	uint16_t i;
1415d7937e2eSIntel 
1416d7937e2eSIntel 	for (i = 0; i < nb_lcore_params; ++i) {
1417d7937e2eSIntel 		if (lcore_params[i].port_id == port &&
1418d7937e2eSIntel 				lcore_params[i].queue_id > queue)
1419d7937e2eSIntel 			queue = lcore_params[i].queue_id;
1420d7937e2eSIntel 	}
1421d7937e2eSIntel 	return (uint8_t)(++queue);
1422d7937e2eSIntel }
1423d7937e2eSIntel 
1424d7937e2eSIntel static int
1425d7937e2eSIntel init_lcore_rx_queues(void)
1426d7937e2eSIntel {
1427d7937e2eSIntel 	uint16_t i, nb_rx_queue;
1428d7937e2eSIntel 	uint8_t lcore;
1429d7937e2eSIntel 
1430d7937e2eSIntel 	for (i = 0; i < nb_lcore_params; ++i) {
1431d7937e2eSIntel 		lcore = lcore_params[i].lcore_id;
1432d7937e2eSIntel 		nb_rx_queue = lcore_conf[lcore].n_rx_queue;
1433d7937e2eSIntel 		if (nb_rx_queue >= MAX_RX_QUEUE_PER_LCORE) {
1434d7937e2eSIntel 			printf("error: too many queues (%u) for lcore: %u\n",
1435d7937e2eSIntel 				(unsigned)nb_rx_queue + 1, (unsigned)lcore);
1436d7937e2eSIntel 			return -1;
1437d7937e2eSIntel 		} else {
1438d7937e2eSIntel 			lcore_conf[lcore].rx_queue_list[nb_rx_queue].port_id =
1439d7937e2eSIntel 				lcore_params[i].port_id;
1440d7937e2eSIntel 			lcore_conf[lcore].rx_queue_list[nb_rx_queue].queue_id =
1441d7937e2eSIntel 				lcore_params[i].queue_id;
1442d7937e2eSIntel 			lcore_conf[lcore].n_rx_queue++;
1443d7937e2eSIntel 		}
1444d7937e2eSIntel 	}
1445d7937e2eSIntel 	return 0;
1446d7937e2eSIntel }
1447d7937e2eSIntel 
1448d7937e2eSIntel /* display usage */
1449d7937e2eSIntel static void
1450d7937e2eSIntel print_usage(const char *prgname)
1451d7937e2eSIntel {
1452d7937e2eSIntel 	printf ("%s [EAL options] -- -p PORTMASK -P"
1453d7937e2eSIntel 		"  [--config (port,queue,lcore)[,(port,queue,lcore]]"
1454f88e7c17SRadu Nicolau 		"  [--high-perf-cores CORELIST"
1455f88e7c17SRadu Nicolau 		"  [--perf-config (port,queue,hi_perf,lcore_index)[,(port,queue,hi_perf,lcore_index]]"
1456d7937e2eSIntel 		"  [--enable-jumbo [--max-pkt-len PKTLEN]]\n"
1457d7937e2eSIntel 		"  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
1458d7937e2eSIntel 		"  -P : enable promiscuous mode\n"
1459d7937e2eSIntel 		"  --config (port,queue,lcore): rx queues configuration\n"
1460f88e7c17SRadu Nicolau 		"  --high-perf-cores CORELIST: list of high performance cores\n"
1461f88e7c17SRadu Nicolau 		"  --perf-config: similar as config, cores specified as indices"
1462f88e7c17SRadu Nicolau 		" for bins containing high or regular performance cores\n"
1463d7937e2eSIntel 		"  --no-numa: optional, disable numa awareness\n"
1464d7937e2eSIntel 		"  --enable-jumbo: enable jumbo frame"
146582bea466SJianfeng Tan 		" which max packet len is PKTLEN in decimal (64-9600)\n"
1466a137d012SLiang Ma 		"  --parse-ptype: parse packet type by software\n"
1467a137d012SLiang Ma 		"  --empty-poll: enable empty poll detection"
1468609e7984SReshma Pattan 		" follow (training_flag, high_threshold, med_threshold)\n"
1469609e7984SReshma Pattan 		" --telemetry: enable telemetry mode, to update"
1470609e7984SReshma Pattan 		" empty polls, full polls, and core busyness to telemetry\n",
1471d7937e2eSIntel 		prgname);
1472d7937e2eSIntel }
1473d7937e2eSIntel 
1474d7937e2eSIntel static int parse_max_pkt_len(const char *pktlen)
1475d7937e2eSIntel {
1476d7937e2eSIntel 	char *end = NULL;
1477d7937e2eSIntel 	unsigned long len;
1478d7937e2eSIntel 
1479d7937e2eSIntel 	/* parse decimal string */
1480d7937e2eSIntel 	len = strtoul(pktlen, &end, 10);
1481d7937e2eSIntel 	if ((pktlen[0] == '\0') || (end == NULL) || (*end != '\0'))
1482d7937e2eSIntel 		return -1;
1483d7937e2eSIntel 
1484d7937e2eSIntel 	if (len == 0)
1485d7937e2eSIntel 		return -1;
1486d7937e2eSIntel 
1487d7937e2eSIntel 	return len;
1488d7937e2eSIntel }
1489d7937e2eSIntel 
1490d7937e2eSIntel static int
1491d7937e2eSIntel parse_portmask(const char *portmask)
1492d7937e2eSIntel {
1493d7937e2eSIntel 	char *end = NULL;
1494d7937e2eSIntel 	unsigned long pm;
1495d7937e2eSIntel 
1496d7937e2eSIntel 	/* parse hexadecimal string */
1497d7937e2eSIntel 	pm = strtoul(portmask, &end, 16);
1498d7937e2eSIntel 	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
1499d7937e2eSIntel 		return -1;
1500d7937e2eSIntel 
1501d7937e2eSIntel 	if (pm == 0)
1502d7937e2eSIntel 		return -1;
1503d7937e2eSIntel 
1504d7937e2eSIntel 	return pm;
1505d7937e2eSIntel }
1506d7937e2eSIntel 
1507d7937e2eSIntel static int
1508d7937e2eSIntel parse_config(const char *q_arg)
1509d7937e2eSIntel {
1510d7937e2eSIntel 	char s[256];
1511d7937e2eSIntel 	const char *p, *p0 = q_arg;
1512d7937e2eSIntel 	char *end;
1513d7937e2eSIntel 	enum fieldnames {
1514d7937e2eSIntel 		FLD_PORT = 0,
1515d7937e2eSIntel 		FLD_QUEUE,
1516d7937e2eSIntel 		FLD_LCORE,
1517d7937e2eSIntel 		_NUM_FLD
1518d7937e2eSIntel 	};
1519d7937e2eSIntel 	unsigned long int_fld[_NUM_FLD];
1520d7937e2eSIntel 	char *str_fld[_NUM_FLD];
1521d7937e2eSIntel 	int i;
1522d7937e2eSIntel 	unsigned size;
1523d7937e2eSIntel 
1524d7937e2eSIntel 	nb_lcore_params = 0;
1525d7937e2eSIntel 
1526d7937e2eSIntel 	while ((p = strchr(p0,'(')) != NULL) {
1527d7937e2eSIntel 		++p;
1528d7937e2eSIntel 		if((p0 = strchr(p,')')) == NULL)
1529d7937e2eSIntel 			return -1;
1530d7937e2eSIntel 
1531d7937e2eSIntel 		size = p0 - p;
1532d7937e2eSIntel 		if(size >= sizeof(s))
1533d7937e2eSIntel 			return -1;
1534d7937e2eSIntel 
15356f41fe75SStephen Hemminger 		snprintf(s, sizeof(s), "%.*s", size, p);
1536d7937e2eSIntel 		if (rte_strsplit(s, sizeof(s), str_fld, _NUM_FLD, ',') !=
1537d7937e2eSIntel 								_NUM_FLD)
1538d7937e2eSIntel 			return -1;
1539d7937e2eSIntel 		for (i = 0; i < _NUM_FLD; i++){
1540d7937e2eSIntel 			errno = 0;
1541d7937e2eSIntel 			int_fld[i] = strtoul(str_fld[i], &end, 0);
1542d7937e2eSIntel 			if (errno != 0 || end == str_fld[i] || int_fld[i] >
1543d7937e2eSIntel 									255)
1544d7937e2eSIntel 				return -1;
1545d7937e2eSIntel 		}
1546d7937e2eSIntel 		if (nb_lcore_params >= MAX_LCORE_PARAMS) {
1547d7937e2eSIntel 			printf("exceeded max number of lcore params: %hu\n",
1548d7937e2eSIntel 				nb_lcore_params);
1549d7937e2eSIntel 			return -1;
1550d7937e2eSIntel 		}
1551d7937e2eSIntel 		lcore_params_array[nb_lcore_params].port_id =
1552d7937e2eSIntel 				(uint8_t)int_fld[FLD_PORT];
1553d7937e2eSIntel 		lcore_params_array[nb_lcore_params].queue_id =
1554d7937e2eSIntel 				(uint8_t)int_fld[FLD_QUEUE];
1555d7937e2eSIntel 		lcore_params_array[nb_lcore_params].lcore_id =
1556d7937e2eSIntel 				(uint8_t)int_fld[FLD_LCORE];
1557d7937e2eSIntel 		++nb_lcore_params;
1558d7937e2eSIntel 	}
1559d7937e2eSIntel 	lcore_params = lcore_params_array;
1560d7937e2eSIntel 
1561d7937e2eSIntel 	return 0;
1562d7937e2eSIntel }
1563a137d012SLiang Ma static int
1564a137d012SLiang Ma parse_ep_config(const char *q_arg)
1565a137d012SLiang Ma {
1566a137d012SLiang Ma 	char s[256];
1567a137d012SLiang Ma 	const char *p = q_arg;
1568a137d012SLiang Ma 	char *end;
1569a137d012SLiang Ma 	int  num_arg;
1570d7937e2eSIntel 
1571a137d012SLiang Ma 	char *str_fld[3];
1572a137d012SLiang Ma 
1573a137d012SLiang Ma 	int training_flag;
1574a137d012SLiang Ma 	int med_edpi;
1575a137d012SLiang Ma 	int hgh_edpi;
1576a137d012SLiang Ma 
1577a137d012SLiang Ma 	ep_med_edpi = EMPTY_POLL_MED_THRESHOLD;
1578a137d012SLiang Ma 	ep_hgh_edpi = EMPTY_POLL_MED_THRESHOLD;
1579a137d012SLiang Ma 
1580f9acaf84SBruce Richardson 	strlcpy(s, p, sizeof(s));
1581a137d012SLiang Ma 
1582a137d012SLiang Ma 	num_arg = rte_strsplit(s, sizeof(s), str_fld, 3, ',');
1583a137d012SLiang Ma 
1584a137d012SLiang Ma 	empty_poll_train = false;
1585a137d012SLiang Ma 
1586a137d012SLiang Ma 	if (num_arg == 0)
1587a137d012SLiang Ma 		return 0;
1588a137d012SLiang Ma 
1589a137d012SLiang Ma 	if (num_arg == 3) {
1590a137d012SLiang Ma 
1591a137d012SLiang Ma 		training_flag = strtoul(str_fld[0], &end, 0);
1592a137d012SLiang Ma 		med_edpi = strtoul(str_fld[1], &end, 0);
1593a137d012SLiang Ma 		hgh_edpi = strtoul(str_fld[2], &end, 0);
1594a137d012SLiang Ma 
1595a137d012SLiang Ma 		if (training_flag == 1)
1596a137d012SLiang Ma 			empty_poll_train = true;
1597a137d012SLiang Ma 
1598a137d012SLiang Ma 		if (med_edpi > 0)
1599a137d012SLiang Ma 			ep_med_edpi = med_edpi;
1600a137d012SLiang Ma 
1601a137d012SLiang Ma 		if (med_edpi > 0)
1602a137d012SLiang Ma 			ep_hgh_edpi = hgh_edpi;
1603a137d012SLiang Ma 
1604a137d012SLiang Ma 	} else {
1605a137d012SLiang Ma 
1606a137d012SLiang Ma 		return -1;
1607a137d012SLiang Ma 	}
1608a137d012SLiang Ma 
1609a137d012SLiang Ma 	return 0;
1610a137d012SLiang Ma 
1611a137d012SLiang Ma }
161282bea466SJianfeng Tan #define CMD_LINE_OPT_PARSE_PTYPE "parse-ptype"
1613609e7984SReshma Pattan #define CMD_LINE_OPT_TELEMETRY "telemetry"
161482bea466SJianfeng Tan 
1615d7937e2eSIntel /* Parse the argument given in the command line of the application */
1616d7937e2eSIntel static int
1617d7937e2eSIntel parse_args(int argc, char **argv)
1618d7937e2eSIntel {
1619d7937e2eSIntel 	int opt, ret;
1620d7937e2eSIntel 	char **argvopt;
1621d7937e2eSIntel 	int option_index;
1622a137d012SLiang Ma 	uint32_t limit;
1623d7937e2eSIntel 	char *prgname = argv[0];
1624d7937e2eSIntel 	static struct option lgopts[] = {
1625d7937e2eSIntel 		{"config", 1, 0, 0},
1626f88e7c17SRadu Nicolau 		{"perf-config", 1, 0, 0},
1627f88e7c17SRadu Nicolau 		{"high-perf-cores", 1, 0, 0},
1628d7937e2eSIntel 		{"no-numa", 0, 0, 0},
1629d7937e2eSIntel 		{"enable-jumbo", 0, 0, 0},
1630a137d012SLiang Ma 		{"empty-poll", 1, 0, 0},
163182bea466SJianfeng Tan 		{CMD_LINE_OPT_PARSE_PTYPE, 0, 0, 0},
1632609e7984SReshma Pattan 		{CMD_LINE_OPT_TELEMETRY, 0, 0, 0},
1633d7937e2eSIntel 		{NULL, 0, 0, 0}
1634d7937e2eSIntel 	};
1635d7937e2eSIntel 
1636d7937e2eSIntel 	argvopt = argv;
1637d7937e2eSIntel 
1638a137d012SLiang Ma 	while ((opt = getopt_long(argc, argvopt, "p:l:m:h:P",
1639d7937e2eSIntel 				lgopts, &option_index)) != EOF) {
1640d7937e2eSIntel 
1641d7937e2eSIntel 		switch (opt) {
1642d7937e2eSIntel 		/* portmask */
1643d7937e2eSIntel 		case 'p':
1644d7937e2eSIntel 			enabled_port_mask = parse_portmask(optarg);
1645d7937e2eSIntel 			if (enabled_port_mask == 0) {
1646d7937e2eSIntel 				printf("invalid portmask\n");
1647d7937e2eSIntel 				print_usage(prgname);
1648d7937e2eSIntel 				return -1;
1649d7937e2eSIntel 			}
1650d7937e2eSIntel 			break;
1651d7937e2eSIntel 		case 'P':
1652d7937e2eSIntel 			printf("Promiscuous mode selected\n");
1653d7937e2eSIntel 			promiscuous_on = 1;
1654d7937e2eSIntel 			break;
1655a137d012SLiang Ma 		case 'l':
1656a137d012SLiang Ma 			limit = parse_max_pkt_len(optarg);
1657a137d012SLiang Ma 			freq_tlb[LOW] = limit;
1658a137d012SLiang Ma 			break;
1659a137d012SLiang Ma 		case 'm':
1660a137d012SLiang Ma 			limit = parse_max_pkt_len(optarg);
1661a137d012SLiang Ma 			freq_tlb[MED] = limit;
1662a137d012SLiang Ma 			break;
1663a137d012SLiang Ma 		case 'h':
1664a137d012SLiang Ma 			limit = parse_max_pkt_len(optarg);
1665a137d012SLiang Ma 			freq_tlb[HGH] = limit;
1666a137d012SLiang Ma 			break;
1667d7937e2eSIntel 		/* long options */
1668d7937e2eSIntel 		case 0:
1669d7937e2eSIntel 			if (!strncmp(lgopts[option_index].name, "config", 6)) {
1670d7937e2eSIntel 				ret = parse_config(optarg);
1671d7937e2eSIntel 				if (ret) {
1672d7937e2eSIntel 					printf("invalid config\n");
1673d7937e2eSIntel 					print_usage(prgname);
1674d7937e2eSIntel 					return -1;
1675d7937e2eSIntel 				}
1676d7937e2eSIntel 			}
1677d7937e2eSIntel 
1678d7937e2eSIntel 			if (!strncmp(lgopts[option_index].name,
1679f88e7c17SRadu Nicolau 					"perf-config", 11)) {
1680f88e7c17SRadu Nicolau 				ret = parse_perf_config(optarg);
1681f88e7c17SRadu Nicolau 				if (ret) {
1682f88e7c17SRadu Nicolau 					printf("invalid perf-config\n");
1683f88e7c17SRadu Nicolau 					print_usage(prgname);
1684f88e7c17SRadu Nicolau 					return -1;
1685f88e7c17SRadu Nicolau 				}
1686f88e7c17SRadu Nicolau 			}
1687f88e7c17SRadu Nicolau 
1688f88e7c17SRadu Nicolau 			if (!strncmp(lgopts[option_index].name,
1689f88e7c17SRadu Nicolau 					"high-perf-cores", 15)) {
1690f88e7c17SRadu Nicolau 				ret = parse_perf_core_list(optarg);
1691f88e7c17SRadu Nicolau 				if (ret) {
1692f88e7c17SRadu Nicolau 					printf("invalid high-perf-cores\n");
1693f88e7c17SRadu Nicolau 					print_usage(prgname);
1694f88e7c17SRadu Nicolau 					return -1;
1695f88e7c17SRadu Nicolau 				}
1696f88e7c17SRadu Nicolau 			}
1697f88e7c17SRadu Nicolau 
1698f88e7c17SRadu Nicolau 			if (!strncmp(lgopts[option_index].name,
1699d7937e2eSIntel 						"no-numa", 7)) {
1700d7937e2eSIntel 				printf("numa is disabled \n");
1701d7937e2eSIntel 				numa_on = 0;
1702d7937e2eSIntel 			}
1703d7937e2eSIntel 
1704d7937e2eSIntel 			if (!strncmp(lgopts[option_index].name,
1705a137d012SLiang Ma 						"empty-poll", 10)) {
1706609e7984SReshma Pattan 				if (app_mode == APP_MODE_TELEMETRY) {
1707609e7984SReshma Pattan 					printf(" empty-poll cannot be enabled as telemetry mode is enabled\n");
1708609e7984SReshma Pattan 					return -1;
1709609e7984SReshma Pattan 				}
1710609e7984SReshma Pattan 				app_mode = APP_MODE_EMPTY_POLL;
1711a137d012SLiang Ma 				ret = parse_ep_config(optarg);
1712a137d012SLiang Ma 
1713a137d012SLiang Ma 				if (ret) {
1714a137d012SLiang Ma 					printf("invalid empty poll config\n");
1715a137d012SLiang Ma 					print_usage(prgname);
1716a137d012SLiang Ma 					return -1;
1717a137d012SLiang Ma 				}
1718609e7984SReshma Pattan 				printf("empty-poll is enabled\n");
1719609e7984SReshma Pattan 			}
1720a137d012SLiang Ma 
1721609e7984SReshma Pattan 			if (!strncmp(lgopts[option_index].name,
1722609e7984SReshma Pattan 					CMD_LINE_OPT_TELEMETRY,
1723609e7984SReshma Pattan 					sizeof(CMD_LINE_OPT_TELEMETRY))) {
1724609e7984SReshma Pattan 				if (app_mode == APP_MODE_EMPTY_POLL) {
1725609e7984SReshma Pattan 					printf("telemetry mode cannot be enabled as empty poll mode is enabled\n");
1726609e7984SReshma Pattan 					return -1;
1727609e7984SReshma Pattan 				}
1728609e7984SReshma Pattan 				app_mode = APP_MODE_TELEMETRY;
1729609e7984SReshma Pattan 				printf("telemetry mode is enabled\n");
1730a137d012SLiang Ma 			}
1731a137d012SLiang Ma 
1732a137d012SLiang Ma 			if (!strncmp(lgopts[option_index].name,
1733d7937e2eSIntel 					"enable-jumbo", 12)) {
1734d7937e2eSIntel 				struct option lenopts =
1735d7937e2eSIntel 					{"max-pkt-len", required_argument, \
1736d7937e2eSIntel 									0, 0};
1737d7937e2eSIntel 
1738d7937e2eSIntel 				printf("jumbo frame is enabled \n");
173940df1d7aSShahaf Shuler 				port_conf.rxmode.offloads |=
174040df1d7aSShahaf Shuler 						DEV_RX_OFFLOAD_JUMBO_FRAME;
174140df1d7aSShahaf Shuler 				port_conf.txmode.offloads |=
174240df1d7aSShahaf Shuler 						DEV_TX_OFFLOAD_MULTI_SEGS;
1743d7937e2eSIntel 
1744d7937e2eSIntel 				/**
1745d7937e2eSIntel 				 * if no max-pkt-len set, use the default value
174635b2d13fSOlivier Matz 				 * RTE_ETHER_MAX_LEN
1747d7937e2eSIntel 				 */
1748d7937e2eSIntel 				if (0 == getopt_long(argc, argvopt, "",
1749d7937e2eSIntel 						&lenopts, &option_index)) {
1750d7937e2eSIntel 					ret = parse_max_pkt_len(optarg);
1751d7937e2eSIntel 					if ((ret < 64) ||
1752d7937e2eSIntel 						(ret > MAX_JUMBO_PKT_LEN)){
1753d7937e2eSIntel 						printf("invalid packet "
1754d7937e2eSIntel 								"length\n");
1755d7937e2eSIntel 						print_usage(prgname);
1756d7937e2eSIntel 						return -1;
1757d7937e2eSIntel 					}
1758d7937e2eSIntel 					port_conf.rxmode.max_rx_pkt_len = ret;
1759d7937e2eSIntel 				}
1760d7937e2eSIntel 				printf("set jumbo frame "
1761d7937e2eSIntel 					"max packet length to %u\n",
1762d7937e2eSIntel 				(unsigned int)port_conf.rxmode.max_rx_pkt_len);
1763d7937e2eSIntel 			}
1764d7937e2eSIntel 
176582bea466SJianfeng Tan 			if (!strncmp(lgopts[option_index].name,
176682bea466SJianfeng Tan 				     CMD_LINE_OPT_PARSE_PTYPE,
176782bea466SJianfeng Tan 				     sizeof(CMD_LINE_OPT_PARSE_PTYPE))) {
176882bea466SJianfeng Tan 				printf("soft parse-ptype is enabled\n");
176982bea466SJianfeng Tan 				parse_ptype = 1;
177082bea466SJianfeng Tan 			}
177182bea466SJianfeng Tan 
1772d7937e2eSIntel 			break;
1773d7937e2eSIntel 
1774d7937e2eSIntel 		default:
1775d7937e2eSIntel 			print_usage(prgname);
1776d7937e2eSIntel 			return -1;
1777d7937e2eSIntel 		}
1778d7937e2eSIntel 	}
1779d7937e2eSIntel 
1780d7937e2eSIntel 	if (optind >= 0)
1781d7937e2eSIntel 		argv[optind-1] = prgname;
1782d7937e2eSIntel 
1783d7937e2eSIntel 	ret = optind-1;
17849d5ca532SKeith Wiles 	optind = 1; /* reset getopt lib */
1785d7937e2eSIntel 	return ret;
1786d7937e2eSIntel }
1787d7937e2eSIntel 
1788d7937e2eSIntel static void
17896d13ea8eSOlivier Matz print_ethaddr(const char *name, const struct rte_ether_addr *eth_addr)
1790d7937e2eSIntel {
179135b2d13fSOlivier Matz 	char buf[RTE_ETHER_ADDR_FMT_SIZE];
179235b2d13fSOlivier Matz 	rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr);
1793ec3d82dbSCunming Liang 	printf("%s%s", name, buf);
1794d7937e2eSIntel }
1795d7937e2eSIntel 
1796d7937e2eSIntel #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
1797d7937e2eSIntel static void
1798d7937e2eSIntel setup_hash(int socketid)
1799d7937e2eSIntel {
1800d7937e2eSIntel 	struct rte_hash_parameters ipv4_l3fwd_hash_params = {
1801d7937e2eSIntel 		.name = NULL,
1802d7937e2eSIntel 		.entries = L3FWD_HASH_ENTRIES,
1803d7937e2eSIntel 		.key_len = sizeof(struct ipv4_5tuple),
1804d7937e2eSIntel 		.hash_func = DEFAULT_HASH_FUNC,
1805d7937e2eSIntel 		.hash_func_init_val = 0,
1806d7937e2eSIntel 	};
1807d7937e2eSIntel 
1808d7937e2eSIntel 	struct rte_hash_parameters ipv6_l3fwd_hash_params = {
1809d7937e2eSIntel 		.name = NULL,
1810d7937e2eSIntel 		.entries = L3FWD_HASH_ENTRIES,
1811d7937e2eSIntel 		.key_len = sizeof(struct ipv6_5tuple),
1812d7937e2eSIntel 		.hash_func = DEFAULT_HASH_FUNC,
1813d7937e2eSIntel 		.hash_func_init_val = 0,
1814d7937e2eSIntel 	};
1815d7937e2eSIntel 
1816d7937e2eSIntel 	unsigned i;
1817d7937e2eSIntel 	int ret;
1818d7937e2eSIntel 	char s[64];
1819d7937e2eSIntel 
1820d7937e2eSIntel 	/* create ipv4 hash */
1821a5cf3924SThomas Monjalon 	snprintf(s, sizeof(s), "ipv4_l3fwd_hash_%d", socketid);
1822d7937e2eSIntel 	ipv4_l3fwd_hash_params.name = s;
1823d7937e2eSIntel 	ipv4_l3fwd_hash_params.socket_id = socketid;
1824d7937e2eSIntel 	ipv4_l3fwd_lookup_struct[socketid] =
1825d7937e2eSIntel 		rte_hash_create(&ipv4_l3fwd_hash_params);
1826d7937e2eSIntel 	if (ipv4_l3fwd_lookup_struct[socketid] == NULL)
1827d7937e2eSIntel 		rte_exit(EXIT_FAILURE, "Unable to create the l3fwd hash on "
1828d7937e2eSIntel 				"socket %d\n", socketid);
1829d7937e2eSIntel 
1830d7937e2eSIntel 	/* create ipv6 hash */
1831a5cf3924SThomas Monjalon 	snprintf(s, sizeof(s), "ipv6_l3fwd_hash_%d", socketid);
1832d7937e2eSIntel 	ipv6_l3fwd_hash_params.name = s;
1833d7937e2eSIntel 	ipv6_l3fwd_hash_params.socket_id = socketid;
1834d7937e2eSIntel 	ipv6_l3fwd_lookup_struct[socketid] =
1835d7937e2eSIntel 		rte_hash_create(&ipv6_l3fwd_hash_params);
1836d7937e2eSIntel 	if (ipv6_l3fwd_lookup_struct[socketid] == NULL)
1837d7937e2eSIntel 		rte_exit(EXIT_FAILURE, "Unable to create the l3fwd hash on "
1838d7937e2eSIntel 				"socket %d\n", socketid);
1839d7937e2eSIntel 
1840d7937e2eSIntel 
1841d7937e2eSIntel 	/* populate the ipv4 hash */
1842d7937e2eSIntel 	for (i = 0; i < IPV4_L3FWD_NUM_ROUTES; i++) {
1843d7937e2eSIntel 		ret = rte_hash_add_key (ipv4_l3fwd_lookup_struct[socketid],
1844d7937e2eSIntel 				(void *) &ipv4_l3fwd_route_array[i].key);
1845d7937e2eSIntel 		if (ret < 0) {
1846d7937e2eSIntel 			rte_exit(EXIT_FAILURE, "Unable to add entry %u to the"
1847d7937e2eSIntel 				"l3fwd hash on socket %d\n", i, socketid);
1848d7937e2eSIntel 		}
1849d7937e2eSIntel 		ipv4_l3fwd_out_if[ret] = ipv4_l3fwd_route_array[i].if_out;
1850d7937e2eSIntel 		printf("Hash: Adding key\n");
1851d7937e2eSIntel 		print_ipv4_key(ipv4_l3fwd_route_array[i].key);
1852d7937e2eSIntel 	}
1853d7937e2eSIntel 
1854d7937e2eSIntel 	/* populate the ipv6 hash */
1855d7937e2eSIntel 	for (i = 0; i < IPV6_L3FWD_NUM_ROUTES; i++) {
1856d7937e2eSIntel 		ret = rte_hash_add_key (ipv6_l3fwd_lookup_struct[socketid],
1857d7937e2eSIntel 				(void *) &ipv6_l3fwd_route_array[i].key);
1858d7937e2eSIntel 		if (ret < 0) {
1859d7937e2eSIntel 			rte_exit(EXIT_FAILURE, "Unable to add entry %u to the"
1860d7937e2eSIntel 				"l3fwd hash on socket %d\n", i, socketid);
1861d7937e2eSIntel 		}
1862d7937e2eSIntel 		ipv6_l3fwd_out_if[ret] = ipv6_l3fwd_route_array[i].if_out;
1863d7937e2eSIntel 		printf("Hash: Adding key\n");
1864d7937e2eSIntel 		print_ipv6_key(ipv6_l3fwd_route_array[i].key);
1865d7937e2eSIntel 	}
1866d7937e2eSIntel }
1867d7937e2eSIntel #endif
1868d7937e2eSIntel 
1869d7937e2eSIntel #if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
1870d7937e2eSIntel static void
1871d7937e2eSIntel setup_lpm(int socketid)
1872d7937e2eSIntel {
1873d7937e2eSIntel 	unsigned i;
1874d7937e2eSIntel 	int ret;
1875d7937e2eSIntel 	char s[64];
1876d7937e2eSIntel 
1877d7937e2eSIntel 	/* create the LPM table */
1878f1f72618SMichal Kobylinski 	struct rte_lpm_config lpm_ipv4_config;
1879f1f72618SMichal Kobylinski 
1880f1f72618SMichal Kobylinski 	lpm_ipv4_config.max_rules = IPV4_L3FWD_LPM_MAX_RULES;
1881f1f72618SMichal Kobylinski 	lpm_ipv4_config.number_tbl8s = 256;
1882f1f72618SMichal Kobylinski 	lpm_ipv4_config.flags = 0;
1883f1f72618SMichal Kobylinski 
18846f41fe75SStephen Hemminger 	snprintf(s, sizeof(s), "IPV4_L3FWD_LPM_%d", socketid);
1885f1f72618SMichal Kobylinski 	ipv4_l3fwd_lookup_struct[socketid] =
1886f1f72618SMichal Kobylinski 			rte_lpm_create(s, socketid, &lpm_ipv4_config);
1887d7937e2eSIntel 	if (ipv4_l3fwd_lookup_struct[socketid] == NULL)
1888d7937e2eSIntel 		rte_exit(EXIT_FAILURE, "Unable to create the l3fwd LPM table"
1889d7937e2eSIntel 				" on socket %d\n", socketid);
1890d7937e2eSIntel 
1891d7937e2eSIntel 	/* populate the LPM table */
1892d7937e2eSIntel 	for (i = 0; i < IPV4_L3FWD_NUM_ROUTES; i++) {
1893d7937e2eSIntel 		ret = rte_lpm_add(ipv4_l3fwd_lookup_struct[socketid],
1894d7937e2eSIntel 			ipv4_l3fwd_route_array[i].ip,
1895d7937e2eSIntel 			ipv4_l3fwd_route_array[i].depth,
1896d7937e2eSIntel 			ipv4_l3fwd_route_array[i].if_out);
1897d7937e2eSIntel 
1898d7937e2eSIntel 		if (ret < 0) {
1899d7937e2eSIntel 			rte_exit(EXIT_FAILURE, "Unable to add entry %u to the "
1900d7937e2eSIntel 				"l3fwd LPM table on socket %d\n",
1901d7937e2eSIntel 				i, socketid);
1902d7937e2eSIntel 		}
1903d7937e2eSIntel 
1904d7937e2eSIntel 		printf("LPM: Adding route 0x%08x / %d (%d)\n",
1905d7937e2eSIntel 			(unsigned)ipv4_l3fwd_route_array[i].ip,
1906d7937e2eSIntel 			ipv4_l3fwd_route_array[i].depth,
1907d7937e2eSIntel 			ipv4_l3fwd_route_array[i].if_out);
1908d7937e2eSIntel 	}
1909d7937e2eSIntel }
1910d7937e2eSIntel #endif
1911d7937e2eSIntel 
1912d7937e2eSIntel static int
1913d7937e2eSIntel init_mem(unsigned nb_mbuf)
1914d7937e2eSIntel {
1915d7937e2eSIntel 	struct lcore_conf *qconf;
1916d7937e2eSIntel 	int socketid;
1917d7937e2eSIntel 	unsigned lcore_id;
1918d7937e2eSIntel 	char s[64];
1919d7937e2eSIntel 
1920d7937e2eSIntel 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
1921d7937e2eSIntel 		if (rte_lcore_is_enabled(lcore_id) == 0)
1922d7937e2eSIntel 			continue;
1923d7937e2eSIntel 
1924d7937e2eSIntel 		if (numa_on)
1925d7937e2eSIntel 			socketid = rte_lcore_to_socket_id(lcore_id);
1926d7937e2eSIntel 		else
1927d7937e2eSIntel 			socketid = 0;
1928d7937e2eSIntel 
1929d7937e2eSIntel 		if (socketid >= NB_SOCKETS) {
1930d7937e2eSIntel 			rte_exit(EXIT_FAILURE, "Socket %d of lcore %u is "
1931d7937e2eSIntel 					"out of range %d\n", socketid,
1932d7937e2eSIntel 						lcore_id, NB_SOCKETS);
1933d7937e2eSIntel 		}
1934d7937e2eSIntel 		if (pktmbuf_pool[socketid] == NULL) {
19356f41fe75SStephen Hemminger 			snprintf(s, sizeof(s), "mbuf_pool_%d", socketid);
1936d7937e2eSIntel 			pktmbuf_pool[socketid] =
1937ea0c20eaSOlivier Matz 				rte_pktmbuf_pool_create(s, nb_mbuf,
1938824cb29cSKonstantin Ananyev 					MEMPOOL_CACHE_SIZE, 0,
1939824cb29cSKonstantin Ananyev 					RTE_MBUF_DEFAULT_BUF_SIZE,
1940ea0c20eaSOlivier Matz 					socketid);
1941d7937e2eSIntel 			if (pktmbuf_pool[socketid] == NULL)
1942d7937e2eSIntel 				rte_exit(EXIT_FAILURE,
1943d7937e2eSIntel 					"Cannot init mbuf pool on socket %d\n",
1944d7937e2eSIntel 								socketid);
1945d7937e2eSIntel 			else
1946d7937e2eSIntel 				printf("Allocated mbuf pool on socket %d\n",
1947d7937e2eSIntel 								socketid);
1948d7937e2eSIntel 
1949d7937e2eSIntel #if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
1950d7937e2eSIntel 			setup_lpm(socketid);
1951d7937e2eSIntel #else
1952d7937e2eSIntel 			setup_hash(socketid);
1953d7937e2eSIntel #endif
1954d7937e2eSIntel 		}
1955d7937e2eSIntel 		qconf = &lcore_conf[lcore_id];
1956d7937e2eSIntel 		qconf->ipv4_lookup_struct = ipv4_l3fwd_lookup_struct[socketid];
1957d7937e2eSIntel #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
1958d7937e2eSIntel 		qconf->ipv6_lookup_struct = ipv6_l3fwd_lookup_struct[socketid];
1959d7937e2eSIntel #endif
1960d7937e2eSIntel 	}
1961d7937e2eSIntel 	return 0;
1962d7937e2eSIntel }
1963d7937e2eSIntel 
1964d7937e2eSIntel /* Check the link status of all ports in up to 9s, and print them finally */
1965d7937e2eSIntel static void
19668728ccf3SThomas Monjalon check_all_ports_link_status(uint32_t port_mask)
1967d7937e2eSIntel {
1968d7937e2eSIntel #define CHECK_INTERVAL 100 /* 100ms */
1969d7937e2eSIntel #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
1970f8244c63SZhiyong Yang 	uint8_t count, all_ports_up, print_flag = 0;
1971f8244c63SZhiyong Yang 	uint16_t portid;
1972d7937e2eSIntel 	struct rte_eth_link link;
1973d7937e2eSIntel 
1974d7937e2eSIntel 	printf("\nChecking link status");
1975d7937e2eSIntel 	fflush(stdout);
1976d7937e2eSIntel 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
1977d7937e2eSIntel 		all_ports_up = 1;
19788728ccf3SThomas Monjalon 		RTE_ETH_FOREACH_DEV(portid) {
1979d7937e2eSIntel 			if ((port_mask & (1 << portid)) == 0)
1980d7937e2eSIntel 				continue;
1981d7937e2eSIntel 			memset(&link, 0, sizeof(link));
1982d7937e2eSIntel 			rte_eth_link_get_nowait(portid, &link);
1983d7937e2eSIntel 			/* print link status if flag set */
1984d7937e2eSIntel 			if (print_flag == 1) {
1985d7937e2eSIntel 				if (link.link_status)
1986d7937e2eSIntel 					printf("Port %d Link Up - speed %u "
1987d7937e2eSIntel 						"Mbps - %s\n", (uint8_t)portid,
1988d7937e2eSIntel 						(unsigned)link.link_speed,
1989d7937e2eSIntel 				(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
1990d7937e2eSIntel 					("full-duplex") : ("half-duplex\n"));
1991d7937e2eSIntel 				else
1992d7937e2eSIntel 					printf("Port %d Link Down\n",
1993d7937e2eSIntel 						(uint8_t)portid);
1994d7937e2eSIntel 				continue;
1995d7937e2eSIntel 			}
1996d7937e2eSIntel 			/* clear all_ports_up flag if any link down */
199709419f23SThomas Monjalon 			if (link.link_status == ETH_LINK_DOWN) {
1998d7937e2eSIntel 				all_ports_up = 0;
1999d7937e2eSIntel 				break;
2000d7937e2eSIntel 			}
2001d7937e2eSIntel 		}
2002d7937e2eSIntel 		/* after finally printing all link status, get out */
2003d7937e2eSIntel 		if (print_flag == 1)
2004d7937e2eSIntel 			break;
2005d7937e2eSIntel 
2006d7937e2eSIntel 		if (all_ports_up == 0) {
2007d7937e2eSIntel 			printf(".");
2008d7937e2eSIntel 			fflush(stdout);
2009d7937e2eSIntel 			rte_delay_ms(CHECK_INTERVAL);
2010d7937e2eSIntel 		}
2011d7937e2eSIntel 
2012d7937e2eSIntel 		/* set the print_flag if all ports up or timeout */
2013d7937e2eSIntel 		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
2014d7937e2eSIntel 			print_flag = 1;
2015d7937e2eSIntel 			printf("done\n");
2016d7937e2eSIntel 		}
2017d7937e2eSIntel 	}
2018d7937e2eSIntel }
2019d7937e2eSIntel 
202047523597SZhiyong Yang static int check_ptype(uint16_t portid)
202182bea466SJianfeng Tan {
202282bea466SJianfeng Tan 	int i, ret;
202382bea466SJianfeng Tan 	int ptype_l3_ipv4 = 0;
202482bea466SJianfeng Tan #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
202582bea466SJianfeng Tan 	int ptype_l3_ipv6 = 0;
202682bea466SJianfeng Tan #endif
202782bea466SJianfeng Tan 	uint32_t ptype_mask = RTE_PTYPE_L3_MASK;
202882bea466SJianfeng Tan 
202982bea466SJianfeng Tan 	ret = rte_eth_dev_get_supported_ptypes(portid, ptype_mask, NULL, 0);
203082bea466SJianfeng Tan 	if (ret <= 0)
203182bea466SJianfeng Tan 		return 0;
203282bea466SJianfeng Tan 
203382bea466SJianfeng Tan 	uint32_t ptypes[ret];
203482bea466SJianfeng Tan 
203582bea466SJianfeng Tan 	ret = rte_eth_dev_get_supported_ptypes(portid, ptype_mask, ptypes, ret);
203682bea466SJianfeng Tan 	for (i = 0; i < ret; ++i) {
203782bea466SJianfeng Tan 		if (ptypes[i] & RTE_PTYPE_L3_IPV4)
203882bea466SJianfeng Tan 			ptype_l3_ipv4 = 1;
203982bea466SJianfeng Tan #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
204082bea466SJianfeng Tan 		if (ptypes[i] & RTE_PTYPE_L3_IPV6)
204182bea466SJianfeng Tan 			ptype_l3_ipv6 = 1;
204282bea466SJianfeng Tan #endif
204382bea466SJianfeng Tan 	}
204482bea466SJianfeng Tan 
204582bea466SJianfeng Tan 	if (ptype_l3_ipv4 == 0)
204682bea466SJianfeng Tan 		printf("port %d cannot parse RTE_PTYPE_L3_IPV4\n", portid);
204782bea466SJianfeng Tan 
204882bea466SJianfeng Tan #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
204982bea466SJianfeng Tan 	if (ptype_l3_ipv6 == 0)
205082bea466SJianfeng Tan 		printf("port %d cannot parse RTE_PTYPE_L3_IPV6\n", portid);
205182bea466SJianfeng Tan #endif
205282bea466SJianfeng Tan 
205382bea466SJianfeng Tan #if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
205482bea466SJianfeng Tan 	if (ptype_l3_ipv4)
205582bea466SJianfeng Tan #else /* APP_LOOKUP_EXACT_MATCH */
205682bea466SJianfeng Tan 	if (ptype_l3_ipv4 && ptype_l3_ipv6)
205782bea466SJianfeng Tan #endif
205882bea466SJianfeng Tan 		return 1;
205982bea466SJianfeng Tan 
206082bea466SJianfeng Tan 	return 0;
206182bea466SJianfeng Tan 
206282bea466SJianfeng Tan }
206382bea466SJianfeng Tan 
2064f88e7c17SRadu Nicolau static int
2065f88e7c17SRadu Nicolau init_power_library(void)
2066f88e7c17SRadu Nicolau {
2067f88e7c17SRadu Nicolau 	int ret = 0, lcore_id;
2068f88e7c17SRadu Nicolau 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
2069f88e7c17SRadu Nicolau 		if (rte_lcore_is_enabled(lcore_id)) {
2070f88e7c17SRadu Nicolau 			/* init power management library */
2071f88e7c17SRadu Nicolau 			ret = rte_power_init(lcore_id);
2072f88e7c17SRadu Nicolau 			if (ret)
2073f88e7c17SRadu Nicolau 				RTE_LOG(ERR, POWER,
2074f88e7c17SRadu Nicolau 				"Library initialization failed on core %u\n",
2075f88e7c17SRadu Nicolau 				lcore_id);
2076f88e7c17SRadu Nicolau 		}
2077f88e7c17SRadu Nicolau 	}
2078f88e7c17SRadu Nicolau 	return ret;
2079f88e7c17SRadu Nicolau }
2080a137d012SLiang Ma static void
2081609e7984SReshma Pattan update_telemetry(__attribute__((unused)) struct rte_timer *tim,
2082609e7984SReshma Pattan 		__attribute__((unused)) void *arg)
2083609e7984SReshma Pattan {
2084609e7984SReshma Pattan 	unsigned int lcore_id = rte_lcore_id();
2085609e7984SReshma Pattan 	struct lcore_conf *qconf;
2086609e7984SReshma Pattan 	uint64_t app_eps = 0, app_fps = 0, app_br = 0;
2087609e7984SReshma Pattan 	uint64_t values[3] = {0};
2088609e7984SReshma Pattan 	int ret;
2089609e7984SReshma Pattan 	uint64_t count = 0;
2090609e7984SReshma Pattan 
2091609e7984SReshma Pattan 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
2092609e7984SReshma Pattan 		qconf = &lcore_conf[lcore_id];
2093609e7984SReshma Pattan 		if (qconf->n_rx_queue == 0)
2094609e7984SReshma Pattan 			continue;
2095609e7984SReshma Pattan 		count++;
2096609e7984SReshma Pattan 		rte_spinlock_lock(&stats[lcore_id].telemetry_lock);
2097609e7984SReshma Pattan 		app_eps += stats[lcore_id].ep_nep[1];
2098609e7984SReshma Pattan 		app_fps += stats[lcore_id].fp_nfp[1];
2099609e7984SReshma Pattan 		app_br += stats[lcore_id].br;
2100609e7984SReshma Pattan 		rte_spinlock_unlock(&stats[lcore_id].telemetry_lock);
2101609e7984SReshma Pattan 	}
2102609e7984SReshma Pattan 
2103018faf21SDavid Hunt 	if (count > 0) {
2104018faf21SDavid Hunt 		values[0] = app_eps/count;
2105018faf21SDavid Hunt 		values[1] = app_fps/count;
2106018faf21SDavid Hunt 		values[2] = app_br/count;
2107018faf21SDavid Hunt 	} else {
2108018faf21SDavid Hunt 		values[0] = 0;
2109018faf21SDavid Hunt 		values[1] = 0;
2110018faf21SDavid Hunt 		values[2] = 0;
2111018faf21SDavid Hunt 	}
2112018faf21SDavid Hunt 
2113609e7984SReshma Pattan 	ret = rte_metrics_update_values(RTE_METRICS_GLOBAL, telstats_index,
2114609e7984SReshma Pattan 					values, RTE_DIM(values));
2115609e7984SReshma Pattan 	if (ret < 0)
2116609e7984SReshma Pattan 		RTE_LOG(WARNING, POWER, "failed to update metrcis\n");
2117609e7984SReshma Pattan }
2118609e7984SReshma Pattan static void
2119609e7984SReshma Pattan telemetry_setup_timer(void)
2120609e7984SReshma Pattan {
2121609e7984SReshma Pattan 	int lcore_id = rte_lcore_id();
2122609e7984SReshma Pattan 	uint64_t hz = rte_get_timer_hz();
2123609e7984SReshma Pattan 	uint64_t ticks;
2124609e7984SReshma Pattan 
2125609e7984SReshma Pattan 	ticks = hz / TELEMETRY_INTERVALS_PER_SEC;
2126609e7984SReshma Pattan 	rte_timer_reset_sync(&telemetry_timer,
2127609e7984SReshma Pattan 			ticks,
2128609e7984SReshma Pattan 			PERIODICAL,
2129609e7984SReshma Pattan 			lcore_id,
2130609e7984SReshma Pattan 			update_telemetry,
2131609e7984SReshma Pattan 			NULL);
2132609e7984SReshma Pattan }
2133609e7984SReshma Pattan static void
2134a137d012SLiang Ma empty_poll_setup_timer(void)
2135a137d012SLiang Ma {
2136a137d012SLiang Ma 	int lcore_id = rte_lcore_id();
2137a137d012SLiang Ma 	uint64_t hz = rte_get_timer_hz();
2138a137d012SLiang Ma 
2139a137d012SLiang Ma 	struct  ep_params *ep_ptr = ep_params;
2140a137d012SLiang Ma 
2141a137d012SLiang Ma 	ep_ptr->interval_ticks = hz / INTERVALS_PER_SECOND;
2142a137d012SLiang Ma 
2143a137d012SLiang Ma 	rte_timer_reset_sync(&ep_ptr->timer0,
2144a137d012SLiang Ma 			ep_ptr->interval_ticks,
2145a137d012SLiang Ma 			PERIODICAL,
2146a137d012SLiang Ma 			lcore_id,
2147a137d012SLiang Ma 			rte_empty_poll_detection,
2148a137d012SLiang Ma 			(void *)ep_ptr);
2149a137d012SLiang Ma 
2150a137d012SLiang Ma }
2151a137d012SLiang Ma static int
2152a137d012SLiang Ma launch_timer(unsigned int lcore_id)
2153a137d012SLiang Ma {
2154a137d012SLiang Ma 	int64_t prev_tsc = 0, cur_tsc, diff_tsc, cycles_10ms;
2155a137d012SLiang Ma 
2156a137d012SLiang Ma 	RTE_SET_USED(lcore_id);
2157a137d012SLiang Ma 
2158a137d012SLiang Ma 
2159a137d012SLiang Ma 	if (rte_get_master_lcore() != lcore_id) {
2160a137d012SLiang Ma 		rte_panic("timer on lcore:%d which is not master core:%d\n",
2161a137d012SLiang Ma 				lcore_id,
2162a137d012SLiang Ma 				rte_get_master_lcore());
2163a137d012SLiang Ma 	}
2164a137d012SLiang Ma 
2165a137d012SLiang Ma 	RTE_LOG(INFO, POWER, "Bring up the Timer\n");
2166a137d012SLiang Ma 
2167609e7984SReshma Pattan 	if (app_mode == APP_MODE_EMPTY_POLL)
2168a137d012SLiang Ma 		empty_poll_setup_timer();
2169609e7984SReshma Pattan 	else
2170609e7984SReshma Pattan 		telemetry_setup_timer();
2171a137d012SLiang Ma 
2172a137d012SLiang Ma 	cycles_10ms = rte_get_timer_hz() / 100;
2173a137d012SLiang Ma 
2174a137d012SLiang Ma 	while (!is_done()) {
2175a137d012SLiang Ma 		cur_tsc = rte_rdtsc();
2176a137d012SLiang Ma 		diff_tsc = cur_tsc - prev_tsc;
2177a137d012SLiang Ma 		if (diff_tsc > cycles_10ms) {
2178a137d012SLiang Ma 			rte_timer_manage();
2179a137d012SLiang Ma 			prev_tsc = cur_tsc;
2180a137d012SLiang Ma 			cycles_10ms = rte_get_timer_hz() / 100;
2181a137d012SLiang Ma 		}
2182a137d012SLiang Ma 	}
2183a137d012SLiang Ma 
2184a137d012SLiang Ma 	RTE_LOG(INFO, POWER, "Timer_subsystem is done\n");
2185a137d012SLiang Ma 
2186a137d012SLiang Ma 	return 0;
2187a137d012SLiang Ma }
2188a137d012SLiang Ma 
2189f88e7c17SRadu Nicolau 
2190d7937e2eSIntel int
219198a16481SDavid Marchand main(int argc, char **argv)
2192d7937e2eSIntel {
2193d7937e2eSIntel 	struct lcore_conf *qconf;
219481f7ecd9SPablo de Lara 	struct rte_eth_dev_info dev_info;
219581f7ecd9SPablo de Lara 	struct rte_eth_txconf *txconf;
2196d7937e2eSIntel 	int ret;
219747523597SZhiyong Yang 	uint16_t nb_ports;
2198d7937e2eSIntel 	uint16_t queueid;
2199d7937e2eSIntel 	unsigned lcore_id;
2200d7937e2eSIntel 	uint64_t hz;
2201d7937e2eSIntel 	uint32_t n_tx_queue, nb_lcores;
2202aee3bc79SCunming Liang 	uint32_t dev_rxq_num, dev_txq_num;
2203f8244c63SZhiyong Yang 	uint8_t nb_rx_queue, queue, socketid;
2204f8244c63SZhiyong Yang 	uint16_t portid;
2205609e7984SReshma Pattan 	uint8_t num_telstats = RTE_DIM(telstats_strings);
2206609e7984SReshma Pattan 	const char *ptr_strings[num_telstats];
2207d7937e2eSIntel 
2208d7937e2eSIntel 	/* catch SIGINT and restore cpufreq governor to ondemand */
2209d7937e2eSIntel 	signal(SIGINT, signal_exit_now);
2210d7937e2eSIntel 
2211d7937e2eSIntel 	/* init EAL */
2212d7937e2eSIntel 	ret = rte_eal_init(argc, argv);
2213d7937e2eSIntel 	if (ret < 0)
2214d7937e2eSIntel 		rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n");
2215d7937e2eSIntel 	argc -= ret;
2216d7937e2eSIntel 	argv += ret;
2217d7937e2eSIntel 
2218d7937e2eSIntel 	/* init RTE timer library to be used late */
2219d7937e2eSIntel 	rte_timer_subsystem_init();
2220d7937e2eSIntel 
2221d7937e2eSIntel 	/* parse application arguments (after the EAL ones) */
2222d7937e2eSIntel 	ret = parse_args(argc, argv);
2223d7937e2eSIntel 	if (ret < 0)
2224d7937e2eSIntel 		rte_exit(EXIT_FAILURE, "Invalid L3FWD parameters\n");
2225d7937e2eSIntel 
2226f88e7c17SRadu Nicolau 	if (init_power_library())
22276265115fSMoti Haimovsky 		RTE_LOG(ERR, L3FWD_POWER, "init_power_library failed\n");
2228f88e7c17SRadu Nicolau 
2229f88e7c17SRadu Nicolau 	if (update_lcore_params() < 0)
2230f88e7c17SRadu Nicolau 		rte_exit(EXIT_FAILURE, "update_lcore_params failed\n");
2231f88e7c17SRadu Nicolau 
2232d7937e2eSIntel 	if (check_lcore_params() < 0)
2233d7937e2eSIntel 		rte_exit(EXIT_FAILURE, "check_lcore_params failed\n");
2234d7937e2eSIntel 
2235d7937e2eSIntel 	ret = init_lcore_rx_queues();
2236d7937e2eSIntel 	if (ret < 0)
2237d7937e2eSIntel 		rte_exit(EXIT_FAILURE, "init_lcore_rx_queues failed\n");
2238d7937e2eSIntel 
2239d9a42a69SThomas Monjalon 	nb_ports = rte_eth_dev_count_avail();
2240d7937e2eSIntel 
2241a9dbe180SThomas Monjalon 	if (check_port_config() < 0)
2242d7937e2eSIntel 		rte_exit(EXIT_FAILURE, "check_port_config failed\n");
2243d7937e2eSIntel 
2244d7937e2eSIntel 	nb_lcores = rte_lcore_count();
2245d7937e2eSIntel 
2246d7937e2eSIntel 	/* initialize all ports */
22478728ccf3SThomas Monjalon 	RTE_ETH_FOREACH_DEV(portid) {
224840df1d7aSShahaf Shuler 		struct rte_eth_conf local_port_conf = port_conf;
224940df1d7aSShahaf Shuler 
2250d7937e2eSIntel 		/* skip ports that are not enabled */
2251d7937e2eSIntel 		if ((enabled_port_mask & (1 << portid)) == 0) {
2252d7937e2eSIntel 			printf("\nSkipping disabled port %d\n", portid);
2253d7937e2eSIntel 			continue;
2254d7937e2eSIntel 		}
2255d7937e2eSIntel 
2256d7937e2eSIntel 		/* init port */
2257d7937e2eSIntel 		printf("Initializing port %d ... ", portid );
2258d7937e2eSIntel 		fflush(stdout);
2259d7937e2eSIntel 
2260*089e5ed7SIvan Ilchenko 		ret = rte_eth_dev_info_get(portid, &dev_info);
2261*089e5ed7SIvan Ilchenko 		if (ret != 0)
2262*089e5ed7SIvan Ilchenko 			rte_exit(EXIT_FAILURE,
2263*089e5ed7SIvan Ilchenko 				"Error during getting device (port %u) info: %s\n",
2264*089e5ed7SIvan Ilchenko 				portid, strerror(-ret));
2265*089e5ed7SIvan Ilchenko 
2266aee3bc79SCunming Liang 		dev_rxq_num = dev_info.max_rx_queues;
2267aee3bc79SCunming Liang 		dev_txq_num = dev_info.max_tx_queues;
2268aee3bc79SCunming Liang 
2269d7937e2eSIntel 		nb_rx_queue = get_port_n_rx_queues(portid);
2270aee3bc79SCunming Liang 		if (nb_rx_queue > dev_rxq_num)
2271aee3bc79SCunming Liang 			rte_exit(EXIT_FAILURE,
2272aee3bc79SCunming Liang 				"Cannot configure not existed rxq: "
2273aee3bc79SCunming Liang 				"port=%d\n", portid);
2274aee3bc79SCunming Liang 
2275d7937e2eSIntel 		n_tx_queue = nb_lcores;
2276aee3bc79SCunming Liang 		if (n_tx_queue > dev_txq_num)
2277aee3bc79SCunming Liang 			n_tx_queue = dev_txq_num;
2278d7937e2eSIntel 		printf("Creating queues: nb_rxq=%d nb_txq=%u... ",
2279d7937e2eSIntel 			nb_rx_queue, (unsigned)n_tx_queue );
2280ddc554adSJingjing Wu 		/* If number of Rx queue is 0, no need to enable Rx interrupt */
2281ddc554adSJingjing Wu 		if (nb_rx_queue == 0)
228240df1d7aSShahaf Shuler 			local_port_conf.intr_conf.rxq = 0;
2283*089e5ed7SIvan Ilchenko 
2284*089e5ed7SIvan Ilchenko 		ret = rte_eth_dev_info_get(portid, &dev_info);
2285*089e5ed7SIvan Ilchenko 		if (ret != 0)
2286*089e5ed7SIvan Ilchenko 			rte_exit(EXIT_FAILURE,
2287*089e5ed7SIvan Ilchenko 				"Error during getting device (port %u) info: %s\n",
2288*089e5ed7SIvan Ilchenko 				portid, strerror(-ret));
2289*089e5ed7SIvan Ilchenko 
229040df1d7aSShahaf Shuler 		if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
229140df1d7aSShahaf Shuler 			local_port_conf.txmode.offloads |=
229240df1d7aSShahaf Shuler 				DEV_TX_OFFLOAD_MBUF_FAST_FREE;
22934f5701f2SFerruh Yigit 
22944f5701f2SFerruh Yigit 		local_port_conf.rx_adv_conf.rss_conf.rss_hf &=
22954f5701f2SFerruh Yigit 			dev_info.flow_type_rss_offloads;
22964f5701f2SFerruh Yigit 		if (local_port_conf.rx_adv_conf.rss_conf.rss_hf !=
22974f5701f2SFerruh Yigit 				port_conf.rx_adv_conf.rss_conf.rss_hf) {
22984f5701f2SFerruh Yigit 			printf("Port %u modified RSS hash function based on hardware support,"
22994f5701f2SFerruh Yigit 				"requested:%#"PRIx64" configured:%#"PRIx64"\n",
23004f5701f2SFerruh Yigit 				portid,
23014f5701f2SFerruh Yigit 				port_conf.rx_adv_conf.rss_conf.rss_hf,
23024f5701f2SFerruh Yigit 				local_port_conf.rx_adv_conf.rss_conf.rss_hf);
23034f5701f2SFerruh Yigit 		}
23044f5701f2SFerruh Yigit 
2305d7937e2eSIntel 		ret = rte_eth_dev_configure(portid, nb_rx_queue,
230640df1d7aSShahaf Shuler 					(uint16_t)n_tx_queue, &local_port_conf);
2307d7937e2eSIntel 		if (ret < 0)
2308d7937e2eSIntel 			rte_exit(EXIT_FAILURE, "Cannot configure device: "
2309d7937e2eSIntel 					"err=%d, port=%d\n", ret, portid);
2310d7937e2eSIntel 
231160efb44fSRoman Zhukov 		ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
231260efb44fSRoman Zhukov 						       &nb_txd);
231360efb44fSRoman Zhukov 		if (ret < 0)
231460efb44fSRoman Zhukov 			rte_exit(EXIT_FAILURE,
231560efb44fSRoman Zhukov 				 "Cannot adjust number of descriptors: err=%d, port=%d\n",
231660efb44fSRoman Zhukov 				 ret, portid);
231760efb44fSRoman Zhukov 
2318d7937e2eSIntel 		rte_eth_macaddr_get(portid, &ports_eth_addr[portid]);
2319d7937e2eSIntel 		print_ethaddr(" Address:", &ports_eth_addr[portid]);
2320d7937e2eSIntel 		printf(", ");
2321d7937e2eSIntel 
2322d7937e2eSIntel 		/* init memory */
2323d7937e2eSIntel 		ret = init_mem(NB_MBUF);
2324d7937e2eSIntel 		if (ret < 0)
2325d7937e2eSIntel 			rte_exit(EXIT_FAILURE, "init_mem failed\n");
2326d7937e2eSIntel 
2327e2366e74STomasz Kulasek 		for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
2328e2366e74STomasz Kulasek 			if (rte_lcore_is_enabled(lcore_id) == 0)
2329e2366e74STomasz Kulasek 				continue;
2330e2366e74STomasz Kulasek 
2331e2366e74STomasz Kulasek 			/* Initialize TX buffers */
2332e2366e74STomasz Kulasek 			qconf = &lcore_conf[lcore_id];
2333e2366e74STomasz Kulasek 			qconf->tx_buffer[portid] = rte_zmalloc_socket("tx_buffer",
2334e2366e74STomasz Kulasek 				RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
2335e2366e74STomasz Kulasek 				rte_eth_dev_socket_id(portid));
2336e2366e74STomasz Kulasek 			if (qconf->tx_buffer[portid] == NULL)
2337e2366e74STomasz Kulasek 				rte_exit(EXIT_FAILURE, "Can't allocate tx buffer for port %u\n",
2338f8244c63SZhiyong Yang 						 portid);
2339e2366e74STomasz Kulasek 
2340e2366e74STomasz Kulasek 			rte_eth_tx_buffer_init(qconf->tx_buffer[portid], MAX_PKT_BURST);
2341e2366e74STomasz Kulasek 		}
2342e2366e74STomasz Kulasek 
2343d7937e2eSIntel 		/* init one TX queue per couple (lcore,port) */
2344d7937e2eSIntel 		queueid = 0;
2345d7937e2eSIntel 		for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
2346d7937e2eSIntel 			if (rte_lcore_is_enabled(lcore_id) == 0)
2347d7937e2eSIntel 				continue;
2348d7937e2eSIntel 
2349aee3bc79SCunming Liang 			if (queueid >= dev_txq_num)
2350aee3bc79SCunming Liang 				continue;
2351aee3bc79SCunming Liang 
2352d7937e2eSIntel 			if (numa_on)
2353d7937e2eSIntel 				socketid = \
2354d7937e2eSIntel 				(uint8_t)rte_lcore_to_socket_id(lcore_id);
2355d7937e2eSIntel 			else
2356d7937e2eSIntel 				socketid = 0;
2357d7937e2eSIntel 
2358d7937e2eSIntel 			printf("txq=%u,%d,%d ", lcore_id, queueid, socketid);
2359d7937e2eSIntel 			fflush(stdout);
236081f7ecd9SPablo de Lara 
236181f7ecd9SPablo de Lara 			txconf = &dev_info.default_txconf;
236240df1d7aSShahaf Shuler 			txconf->offloads = local_port_conf.txmode.offloads;
2363d7937e2eSIntel 			ret = rte_eth_tx_queue_setup(portid, queueid, nb_txd,
236481f7ecd9SPablo de Lara 						     socketid, txconf);
2365d7937e2eSIntel 			if (ret < 0)
2366d7937e2eSIntel 				rte_exit(EXIT_FAILURE,
2367d7937e2eSIntel 					"rte_eth_tx_queue_setup: err=%d, "
2368d7937e2eSIntel 						"port=%d\n", ret, portid);
2369d7937e2eSIntel 
2370d7937e2eSIntel 			qconf = &lcore_conf[lcore_id];
2371d7937e2eSIntel 			qconf->tx_queue_id[portid] = queueid;
2372d7937e2eSIntel 			queueid++;
2373e2366e74STomasz Kulasek 
2374e2366e74STomasz Kulasek 			qconf->tx_port_id[qconf->n_tx_port] = portid;
2375dd1c68faSTomasz Kulasek 			qconf->n_tx_port++;
2376d7937e2eSIntel 		}
2377d7937e2eSIntel 		printf("\n");
2378d7937e2eSIntel 	}
2379d7937e2eSIntel 
2380d7937e2eSIntel 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
2381d7937e2eSIntel 		if (rte_lcore_is_enabled(lcore_id) == 0)
2382d7937e2eSIntel 			continue;
2383d7937e2eSIntel 
2384609e7984SReshma Pattan 		if (app_mode == APP_MODE_LEGACY) {
2385d7937e2eSIntel 			/* init timer structures for each enabled lcore */
2386d7937e2eSIntel 			rte_timer_init(&power_timers[lcore_id]);
2387d7937e2eSIntel 			hz = rte_get_timer_hz();
2388d7937e2eSIntel 			rte_timer_reset(&power_timers[lcore_id],
2389a137d012SLiang Ma 					hz/TIMER_NUMBER_PER_SECOND,
2390a137d012SLiang Ma 					SINGLE, lcore_id,
2391d7937e2eSIntel 					power_timer_cb, NULL);
2392a137d012SLiang Ma 		}
2393d7937e2eSIntel 		qconf = &lcore_conf[lcore_id];
2394d7937e2eSIntel 		printf("\nInitializing rx queues on lcore %u ... ", lcore_id );
2395d7937e2eSIntel 		fflush(stdout);
2396d7937e2eSIntel 		/* init RX queues */
2397d7937e2eSIntel 		for(queue = 0; queue < qconf->n_rx_queue; ++queue) {
239840df1d7aSShahaf Shuler 			struct rte_eth_rxconf rxq_conf;
239940df1d7aSShahaf Shuler 
2400d7937e2eSIntel 			portid = qconf->rx_queue_list[queue].port_id;
2401d7937e2eSIntel 			queueid = qconf->rx_queue_list[queue].queue_id;
2402d7937e2eSIntel 
2403d7937e2eSIntel 			if (numa_on)
2404d7937e2eSIntel 				socketid = \
2405d7937e2eSIntel 				(uint8_t)rte_lcore_to_socket_id(lcore_id);
2406d7937e2eSIntel 			else
2407d7937e2eSIntel 				socketid = 0;
2408d7937e2eSIntel 
2409d7937e2eSIntel 			printf("rxq=%d,%d,%d ", portid, queueid, socketid);
2410d7937e2eSIntel 			fflush(stdout);
2411d7937e2eSIntel 
2412*089e5ed7SIvan Ilchenko 			ret = rte_eth_dev_info_get(portid, &dev_info);
2413*089e5ed7SIvan Ilchenko 			if (ret != 0)
2414*089e5ed7SIvan Ilchenko 				rte_exit(EXIT_FAILURE,
2415*089e5ed7SIvan Ilchenko 					"Error during getting device (port %u) info: %s\n",
2416*089e5ed7SIvan Ilchenko 					portid, strerror(-ret));
2417*089e5ed7SIvan Ilchenko 
241840df1d7aSShahaf Shuler 			rxq_conf = dev_info.default_rxconf;
24195c5c1f99SMarcin Zapolski 			rxq_conf.offloads = port_conf.rxmode.offloads;
2420d7937e2eSIntel 			ret = rte_eth_rx_queue_setup(portid, queueid, nb_rxd,
242140df1d7aSShahaf Shuler 				socketid, &rxq_conf,
242281f7ecd9SPablo de Lara 				pktmbuf_pool[socketid]);
2423d7937e2eSIntel 			if (ret < 0)
2424d7937e2eSIntel 				rte_exit(EXIT_FAILURE,
2425d7937e2eSIntel 					"rte_eth_rx_queue_setup: err=%d, "
2426d7937e2eSIntel 						"port=%d\n", ret, portid);
242782bea466SJianfeng Tan 
242882bea466SJianfeng Tan 			if (parse_ptype) {
242982bea466SJianfeng Tan 				if (add_cb_parse_ptype(portid, queueid) < 0)
243082bea466SJianfeng Tan 					rte_exit(EXIT_FAILURE,
243182bea466SJianfeng Tan 						 "Fail to add ptype cb\n");
243282bea466SJianfeng Tan 			} else if (!check_ptype(portid))
243382bea466SJianfeng Tan 				rte_exit(EXIT_FAILURE,
243482bea466SJianfeng Tan 					 "PMD can not provide needed ptypes\n");
2435d7937e2eSIntel 		}
2436d7937e2eSIntel 	}
2437d7937e2eSIntel 
2438d7937e2eSIntel 	printf("\n");
2439d7937e2eSIntel 
2440d7937e2eSIntel 	/* start ports */
24418728ccf3SThomas Monjalon 	RTE_ETH_FOREACH_DEV(portid) {
2442d7937e2eSIntel 		if ((enabled_port_mask & (1 << portid)) == 0) {
2443d7937e2eSIntel 			continue;
2444d7937e2eSIntel 		}
2445d7937e2eSIntel 		/* Start device */
2446d7937e2eSIntel 		ret = rte_eth_dev_start(portid);
2447d7937e2eSIntel 		if (ret < 0)
2448d7937e2eSIntel 			rte_exit(EXIT_FAILURE, "rte_eth_dev_start: err=%d, "
2449d7937e2eSIntel 						"port=%d\n", ret, portid);
2450d7937e2eSIntel 		/*
2451d7937e2eSIntel 		 * If enabled, put device in promiscuous mode.
2452d7937e2eSIntel 		 * This allows IO forwarding mode to forward packets
2453d7937e2eSIntel 		 * to itself through 2 cross-connected  ports of the
2454d7937e2eSIntel 		 * target machine.
2455d7937e2eSIntel 		 */
2456d7937e2eSIntel 		if (promiscuous_on)
2457d7937e2eSIntel 			rte_eth_promiscuous_enable(portid);
2458aee3bc79SCunming Liang 		/* initialize spinlock for each port */
2459aee3bc79SCunming Liang 		rte_spinlock_init(&(locks[portid]));
2460d7937e2eSIntel 	}
2461d7937e2eSIntel 
24628728ccf3SThomas Monjalon 	check_all_ports_link_status(enabled_port_mask);
2463d7937e2eSIntel 
2464609e7984SReshma Pattan 	if (app_mode == APP_MODE_EMPTY_POLL) {
2465a137d012SLiang Ma 
2466a137d012SLiang Ma 		if (empty_poll_train) {
2467a137d012SLiang Ma 			policy.state = TRAINING;
2468a137d012SLiang Ma 		} else {
2469a137d012SLiang Ma 			policy.state = MED_NORMAL;
2470a137d012SLiang Ma 			policy.med_base_edpi = ep_med_edpi;
2471a137d012SLiang Ma 			policy.hgh_base_edpi = ep_hgh_edpi;
2472a137d012SLiang Ma 		}
2473a137d012SLiang Ma 
2474a137d012SLiang Ma 		ret = rte_power_empty_poll_stat_init(&ep_params,
2475a137d012SLiang Ma 				freq_tlb,
2476a137d012SLiang Ma 				&policy);
2477a137d012SLiang Ma 		if (ret < 0)
2478a137d012SLiang Ma 			rte_exit(EXIT_FAILURE, "empty poll init failed");
2479a137d012SLiang Ma 	}
2480a137d012SLiang Ma 
2481a137d012SLiang Ma 
2482d7937e2eSIntel 	/* launch per-lcore init on every lcore */
2483609e7984SReshma Pattan 	if (app_mode == APP_MODE_LEGACY) {
2484d7937e2eSIntel 		rte_eal_mp_remote_launch(main_loop, NULL, CALL_MASTER);
2485609e7984SReshma Pattan 	} else if (app_mode == APP_MODE_EMPTY_POLL) {
2486a137d012SLiang Ma 		empty_poll_stop = false;
2487a137d012SLiang Ma 		rte_eal_mp_remote_launch(main_empty_poll_loop, NULL,
2488a137d012SLiang Ma 				SKIP_MASTER);
2489609e7984SReshma Pattan 	} else {
2490292472baSThomas Monjalon 		unsigned int i;
2491292472baSThomas Monjalon 
2492609e7984SReshma Pattan 		/* Init metrics library */
2493609e7984SReshma Pattan 		rte_metrics_init(rte_socket_id());
2494609e7984SReshma Pattan 		/** Register stats with metrics library */
2495292472baSThomas Monjalon 		for (i = 0; i < num_telstats; i++)
2496609e7984SReshma Pattan 			ptr_strings[i] = telstats_strings[i].name;
2497609e7984SReshma Pattan 
2498609e7984SReshma Pattan 		ret = rte_metrics_reg_names(ptr_strings, num_telstats);
2499609e7984SReshma Pattan 		if (ret >= 0)
2500609e7984SReshma Pattan 			telstats_index = ret;
2501609e7984SReshma Pattan 		else
2502609e7984SReshma Pattan 			rte_exit(EXIT_FAILURE, "failed to register metrics names");
2503609e7984SReshma Pattan 
2504609e7984SReshma Pattan 		RTE_LCORE_FOREACH_SLAVE(lcore_id) {
2505609e7984SReshma Pattan 			rte_spinlock_init(&stats[lcore_id].telemetry_lock);
2506609e7984SReshma Pattan 		}
2507609e7984SReshma Pattan 		rte_timer_init(&telemetry_timer);
2508609e7984SReshma Pattan 		rte_eal_mp_remote_launch(main_telemetry_loop, NULL,
2509609e7984SReshma Pattan 						SKIP_MASTER);
2510a137d012SLiang Ma 	}
2511a137d012SLiang Ma 
2512609e7984SReshma Pattan 	if (app_mode == APP_MODE_EMPTY_POLL || app_mode == APP_MODE_TELEMETRY)
2513a137d012SLiang Ma 		launch_timer(rte_lcore_id());
2514a137d012SLiang Ma 
2515d7937e2eSIntel 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
2516d7937e2eSIntel 		if (rte_eal_wait_lcore(lcore_id) < 0)
2517d7937e2eSIntel 			return -1;
2518d7937e2eSIntel 	}
2519d7937e2eSIntel 
2520609e7984SReshma Pattan 	if (app_mode == APP_MODE_EMPTY_POLL)
2521a137d012SLiang Ma 		rte_power_empty_poll_stat_free();
2522a137d012SLiang Ma 
2523d7937e2eSIntel 	return 0;
2524d7937e2eSIntel }
2525