xref: /dpdk/examples/ip_reassembly/main.c (revision e9d48c0072d36eb6423b45fba4ec49d0def6c36f)
1cc8f4d02SIntel /*-
2cc8f4d02SIntel  *   BSD LICENSE
3cc8f4d02SIntel  *
4*e9d48c00SBruce Richardson  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5cc8f4d02SIntel  *   All rights reserved.
6cc8f4d02SIntel  *
7cc8f4d02SIntel  *   Redistribution and use in source and binary forms, with or without
8cc8f4d02SIntel  *   modification, are permitted provided that the following conditions
9cc8f4d02SIntel  *   are met:
10cc8f4d02SIntel  *
11cc8f4d02SIntel  *     * Redistributions of source code must retain the above copyright
12cc8f4d02SIntel  *       notice, this list of conditions and the following disclaimer.
13cc8f4d02SIntel  *     * Redistributions in binary form must reproduce the above copyright
14cc8f4d02SIntel  *       notice, this list of conditions and the following disclaimer in
15cc8f4d02SIntel  *       the documentation and/or other materials provided with the
16cc8f4d02SIntel  *       distribution.
17cc8f4d02SIntel  *     * Neither the name of Intel Corporation nor the names of its
18cc8f4d02SIntel  *       contributors may be used to endorse or promote products derived
19cc8f4d02SIntel  *       from this software without specific prior written permission.
20cc8f4d02SIntel  *
21cc8f4d02SIntel  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22cc8f4d02SIntel  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23cc8f4d02SIntel  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24cc8f4d02SIntel  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25cc8f4d02SIntel  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26cc8f4d02SIntel  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27cc8f4d02SIntel  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28cc8f4d02SIntel  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29cc8f4d02SIntel  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30cc8f4d02SIntel  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31cc8f4d02SIntel  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32cc8f4d02SIntel  */
33cc8f4d02SIntel 
34cc8f4d02SIntel #include <stdio.h>
35cc8f4d02SIntel #include <stdlib.h>
36cc8f4d02SIntel #include <stdint.h>
37cc8f4d02SIntel #include <inttypes.h>
38cc8f4d02SIntel #include <sys/types.h>
39cc8f4d02SIntel #include <string.h>
40cc8f4d02SIntel #include <sys/queue.h>
41cc8f4d02SIntel #include <stdarg.h>
42cc8f4d02SIntel #include <errno.h>
43cc8f4d02SIntel #include <getopt.h>
44cc8f4d02SIntel #include <signal.h>
45cc8f4d02SIntel 
46cc8f4d02SIntel #include <rte_common.h>
47cc8f4d02SIntel #include <rte_byteorder.h>
48cc8f4d02SIntel #include <rte_log.h>
49cc8f4d02SIntel #include <rte_memory.h>
50cc8f4d02SIntel #include <rte_memcpy.h>
51cc8f4d02SIntel #include <rte_memzone.h>
52cc8f4d02SIntel #include <rte_tailq.h>
53cc8f4d02SIntel #include <rte_eal.h>
54cc8f4d02SIntel #include <rte_per_lcore.h>
55cc8f4d02SIntel #include <rte_launch.h>
56cc8f4d02SIntel #include <rte_atomic.h>
57cc8f4d02SIntel #include <rte_cycles.h>
58cc8f4d02SIntel #include <rte_prefetch.h>
59cc8f4d02SIntel #include <rte_lcore.h>
60cc8f4d02SIntel #include <rte_per_lcore.h>
61cc8f4d02SIntel #include <rte_branch_prediction.h>
62cc8f4d02SIntel #include <rte_interrupts.h>
63cc8f4d02SIntel #include <rte_pci.h>
64cc8f4d02SIntel #include <rte_random.h>
65cc8f4d02SIntel #include <rte_debug.h>
66cc8f4d02SIntel #include <rte_ether.h>
67cc8f4d02SIntel #include <rte_ethdev.h>
68cc8f4d02SIntel #include <rte_ring.h>
69cc8f4d02SIntel #include <rte_mempool.h>
70cc8f4d02SIntel #include <rte_mbuf.h>
71cc8f4d02SIntel #include <rte_malloc.h>
72cc8f4d02SIntel #include <rte_ip.h>
73cc8f4d02SIntel #include <rte_tcp.h>
74cc8f4d02SIntel #include <rte_udp.h>
75cc8f4d02SIntel #include <rte_string_fns.h>
76cc8f4d02SIntel #include "main.h"
77cc8f4d02SIntel 
78cc8f4d02SIntel #define APP_LOOKUP_EXACT_MATCH          0
79cc8f4d02SIntel #define APP_LOOKUP_LPM                  1
80cc8f4d02SIntel #define DO_RFC_1812_CHECKS
81cc8f4d02SIntel 
82cc8f4d02SIntel #ifndef APP_LOOKUP_METHOD
83cc8f4d02SIntel #define APP_LOOKUP_METHOD             APP_LOOKUP_LPM
84cc8f4d02SIntel #endif
85cc8f4d02SIntel 
86cc8f4d02SIntel #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
87cc8f4d02SIntel #include <rte_hash.h>
88cc8f4d02SIntel #elif (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
89cc8f4d02SIntel #include <rte_lpm.h>
90cc8f4d02SIntel #include <rte_lpm6.h>
91cc8f4d02SIntel #else
92cc8f4d02SIntel #error "APP_LOOKUP_METHOD set to incorrect value"
93cc8f4d02SIntel #endif
94cc8f4d02SIntel 
95595ea7dcSIntel #define MAX_PKT_BURST 32
96595ea7dcSIntel 
97595ea7dcSIntel #include "ipv4_rsmbl.h"
98595ea7dcSIntel 
99cc8f4d02SIntel #ifndef IPv6_BYTES
100cc8f4d02SIntel #define IPv6_BYTES_FMT "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"\
101cc8f4d02SIntel                        "%02x%02x:%02x%02x:%02x%02x:%02x%02x"
102cc8f4d02SIntel #define IPv6_BYTES(addr) \
103cc8f4d02SIntel 	addr[0],  addr[1], addr[2],  addr[3], \
104cc8f4d02SIntel 	addr[4],  addr[5], addr[6],  addr[7], \
105cc8f4d02SIntel 	addr[8],  addr[9], addr[10], addr[11],\
106cc8f4d02SIntel 	addr[12], addr[13],addr[14], addr[15]
107cc8f4d02SIntel #endif
108cc8f4d02SIntel 
109cc8f4d02SIntel 
110cc8f4d02SIntel #define RTE_LOGTYPE_L3FWD RTE_LOGTYPE_USER1
111cc8f4d02SIntel 
112cc8f4d02SIntel #define MAX_PORTS	RTE_MAX_ETHPORTS
113cc8f4d02SIntel 
114cc8f4d02SIntel #define MAX_JUMBO_PKT_LEN  9600
115cc8f4d02SIntel 
116cc8f4d02SIntel #define IPV6_ADDR_LEN 16
117cc8f4d02SIntel 
118cc8f4d02SIntel #define MEMPOOL_CACHE_SIZE 256
119cc8f4d02SIntel 
120cc8f4d02SIntel #define	BUF_SIZE	2048
121cc8f4d02SIntel #define MBUF_SIZE	\
122cc8f4d02SIntel 	(BUF_SIZE + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
123cc8f4d02SIntel 
124cc8f4d02SIntel #define	MAX_FLOW_NUM	UINT16_MAX
125cc8f4d02SIntel #define	MIN_FLOW_NUM	1
126cc8f4d02SIntel #define	DEF_FLOW_NUM	0x1000
127cc8f4d02SIntel 
128cc8f4d02SIntel /* TTL numbers are in ms. */
129cc8f4d02SIntel #define	MAX_FLOW_TTL	(3600 * MS_PER_S)
130cc8f4d02SIntel #define	MIN_FLOW_TTL	1
131cc8f4d02SIntel #define	DEF_FLOW_TTL	MS_PER_S
132cc8f4d02SIntel 
133cc8f4d02SIntel #define	DEF_MBUF_NUM	0x400
134cc8f4d02SIntel 
135cc8f4d02SIntel /* Should be power of two. */
136cc8f4d02SIntel #define	IPV4_FRAG_TBL_BUCKET_ENTRIES	2
137cc8f4d02SIntel 
138cc8f4d02SIntel static uint32_t max_flow_num = DEF_FLOW_NUM;
139cc8f4d02SIntel static uint32_t max_flow_ttl = DEF_FLOW_TTL;
140cc8f4d02SIntel 
141cc8f4d02SIntel /*
142cc8f4d02SIntel  * RX and TX Prefetch, Host, and Write-back threshold values should be
143cc8f4d02SIntel  * carefully set for optimal performance. Consult the network
144cc8f4d02SIntel  * controller's datasheet and supporting DPDK documentation for guidance
145cc8f4d02SIntel  * on how these parameters should be set.
146cc8f4d02SIntel  */
147cc8f4d02SIntel #define RX_PTHRESH 8 /**< Default values of RX prefetch threshold reg. */
148cc8f4d02SIntel #define RX_HTHRESH 8 /**< Default values of RX host threshold reg. */
149cc8f4d02SIntel #define RX_WTHRESH 4 /**< Default values of RX write-back threshold reg. */
150cc8f4d02SIntel 
151cc8f4d02SIntel /*
152cc8f4d02SIntel  * These default values are optimized for use with the Intel(R) 82599 10 GbE
153cc8f4d02SIntel  * Controller and the DPDK ixgbe PMD. Consider using other values for other
154cc8f4d02SIntel  * network controllers and/or network drivers.
155cc8f4d02SIntel  */
156cc8f4d02SIntel #define TX_PTHRESH 36 /**< Default values of TX prefetch threshold reg. */
157cc8f4d02SIntel #define TX_HTHRESH 0  /**< Default values of TX host threshold reg. */
158cc8f4d02SIntel #define TX_WTHRESH 0  /**< Default values of TX write-back threshold reg. */
159cc8f4d02SIntel 
160cc8f4d02SIntel #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
161cc8f4d02SIntel 
162cc8f4d02SIntel #define NB_SOCKETS 8
163cc8f4d02SIntel 
164cc8f4d02SIntel /* Configure how many packets ahead to prefetch, when reading packets */
165cc8f4d02SIntel #define PREFETCH_OFFSET	3
166cc8f4d02SIntel 
167cc8f4d02SIntel /*
168cc8f4d02SIntel  * Configurable number of RX/TX ring descriptors
169cc8f4d02SIntel  */
170cc8f4d02SIntel #define RTE_TEST_RX_DESC_DEFAULT 128
171cc8f4d02SIntel #define RTE_TEST_TX_DESC_DEFAULT 512
172595ea7dcSIntel 
173cc8f4d02SIntel static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
174cc8f4d02SIntel static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
175cc8f4d02SIntel 
176cc8f4d02SIntel /* ethernet addresses of ports */
177cc8f4d02SIntel static struct ether_addr ports_eth_addr[MAX_PORTS];
178cc8f4d02SIntel 
179cc8f4d02SIntel /* mask of enabled ports */
180cc8f4d02SIntel static uint32_t enabled_port_mask = 0;
181cc8f4d02SIntel static int promiscuous_on = 0; /**< Ports set in promiscuous mode off by default. */
182cc8f4d02SIntel static int numa_on = 1; /**< NUMA is enabled by default. */
183cc8f4d02SIntel 
184cc8f4d02SIntel struct mbuf_table {
185595ea7dcSIntel 	uint32_t len;
186595ea7dcSIntel 	uint32_t head;
187595ea7dcSIntel 	uint32_t tail;
188595ea7dcSIntel 	struct rte_mbuf *m_table[0];
189cc8f4d02SIntel };
190cc8f4d02SIntel 
191cc8f4d02SIntel struct lcore_rx_queue {
192cc8f4d02SIntel 	uint8_t port_id;
193cc8f4d02SIntel 	uint8_t queue_id;
194cc8f4d02SIntel } __rte_cache_aligned;
195cc8f4d02SIntel 
196cc8f4d02SIntel #define MAX_RX_QUEUE_PER_LCORE 16
197cc8f4d02SIntel #define MAX_TX_QUEUE_PER_PORT MAX_PORTS
198cc8f4d02SIntel #define MAX_RX_QUEUE_PER_PORT 128
199cc8f4d02SIntel 
200cc8f4d02SIntel #define MAX_LCORE_PARAMS 1024
201cc8f4d02SIntel struct lcore_params {
202cc8f4d02SIntel 	uint8_t port_id;
203cc8f4d02SIntel 	uint8_t queue_id;
204cc8f4d02SIntel 	uint8_t lcore_id;
205cc8f4d02SIntel } __rte_cache_aligned;
206cc8f4d02SIntel 
207cc8f4d02SIntel static struct lcore_params lcore_params_array[MAX_LCORE_PARAMS];
208cc8f4d02SIntel static struct lcore_params lcore_params_array_default[] = {
209cc8f4d02SIntel 	{0, 0, 2},
210cc8f4d02SIntel 	{0, 1, 2},
211cc8f4d02SIntel 	{0, 2, 2},
212cc8f4d02SIntel 	{1, 0, 2},
213cc8f4d02SIntel 	{1, 1, 2},
214cc8f4d02SIntel 	{1, 2, 2},
215cc8f4d02SIntel 	{2, 0, 2},
216cc8f4d02SIntel 	{3, 0, 3},
217cc8f4d02SIntel 	{3, 1, 3},
218cc8f4d02SIntel };
219cc8f4d02SIntel 
220cc8f4d02SIntel static struct lcore_params * lcore_params = lcore_params_array_default;
221cc8f4d02SIntel static uint16_t nb_lcore_params = sizeof(lcore_params_array_default) /
222cc8f4d02SIntel 				sizeof(lcore_params_array_default[0]);
223cc8f4d02SIntel 
224cc8f4d02SIntel static struct rte_eth_conf port_conf = {
225cc8f4d02SIntel 	.rxmode = {
226cc8f4d02SIntel 		.max_rx_pkt_len = ETHER_MAX_LEN,
227cc8f4d02SIntel 		.split_hdr_size = 0,
228cc8f4d02SIntel 		.header_split   = 0, /**< Header Split disabled */
229cc8f4d02SIntel 		.hw_ip_checksum = 1, /**< IP checksum offload enabled */
230cc8f4d02SIntel 		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
231cc8f4d02SIntel 		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
232cc8f4d02SIntel 		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
233cc8f4d02SIntel 	},
234cc8f4d02SIntel 	.rx_adv_conf = {
235cc8f4d02SIntel 		.rss_conf = {
236cc8f4d02SIntel 			.rss_key = NULL,
237cc8f4d02SIntel 			.rss_hf = ETH_RSS_IPV4 | ETH_RSS_IPV6,
238cc8f4d02SIntel 		},
239cc8f4d02SIntel 	},
240cc8f4d02SIntel 	.txmode = {
241cc8f4d02SIntel 		.mq_mode = ETH_MQ_TX_NONE,
242cc8f4d02SIntel 	},
243cc8f4d02SIntel };
244cc8f4d02SIntel 
245cc8f4d02SIntel static const struct rte_eth_rxconf rx_conf = {
246cc8f4d02SIntel 	.rx_thresh = {
247cc8f4d02SIntel 		.pthresh = RX_PTHRESH,
248cc8f4d02SIntel 		.hthresh = RX_HTHRESH,
249cc8f4d02SIntel 		.wthresh = RX_WTHRESH,
250cc8f4d02SIntel 	},
251cc8f4d02SIntel 	.rx_free_thresh = 32,
252cc8f4d02SIntel };
253cc8f4d02SIntel 
254cc8f4d02SIntel static const struct rte_eth_txconf tx_conf = {
255cc8f4d02SIntel 	.tx_thresh = {
256cc8f4d02SIntel 		.pthresh = TX_PTHRESH,
257cc8f4d02SIntel 		.hthresh = TX_HTHRESH,
258cc8f4d02SIntel 		.wthresh = TX_WTHRESH,
259cc8f4d02SIntel 	},
260cc8f4d02SIntel 	.tx_free_thresh = 0, /* Use PMD default values */
261cc8f4d02SIntel 	.tx_rs_thresh = 0, /* Use PMD default values */
262cc8f4d02SIntel 	.txq_flags = 0x0,
263cc8f4d02SIntel };
264cc8f4d02SIntel 
265cc8f4d02SIntel #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
266cc8f4d02SIntel 
267cc8f4d02SIntel #ifdef RTE_MACHINE_CPUFLAG_SSE4_2
268cc8f4d02SIntel #include <rte_hash_crc.h>
269cc8f4d02SIntel #define DEFAULT_HASH_FUNC       rte_hash_crc
270cc8f4d02SIntel #else
271cc8f4d02SIntel #include <rte_jhash.h>
272cc8f4d02SIntel #define DEFAULT_HASH_FUNC       rte_jhash
273cc8f4d02SIntel #endif
274cc8f4d02SIntel 
275cc8f4d02SIntel struct ipv4_5tuple {
276cc8f4d02SIntel 	uint32_t ip_dst;
277cc8f4d02SIntel 	uint32_t ip_src;
278cc8f4d02SIntel 	uint16_t port_dst;
279cc8f4d02SIntel 	uint16_t port_src;
280cc8f4d02SIntel 	uint8_t  proto;
281cc8f4d02SIntel } __attribute__((__packed__));
282cc8f4d02SIntel 
283cc8f4d02SIntel struct ipv6_5tuple {
284cc8f4d02SIntel 	uint8_t  ip_dst[IPV6_ADDR_LEN];
285cc8f4d02SIntel 	uint8_t  ip_src[IPV6_ADDR_LEN];
286cc8f4d02SIntel 	uint16_t port_dst;
287cc8f4d02SIntel 	uint16_t port_src;
288cc8f4d02SIntel 	uint8_t  proto;
289cc8f4d02SIntel } __attribute__((__packed__));
290cc8f4d02SIntel 
291cc8f4d02SIntel struct ipv4_l3fwd_route {
292cc8f4d02SIntel 	struct ipv4_5tuple key;
293cc8f4d02SIntel 	uint8_t if_out;
294cc8f4d02SIntel };
295cc8f4d02SIntel 
296cc8f4d02SIntel struct ipv6_l3fwd_route {
297cc8f4d02SIntel 	struct ipv6_5tuple key;
298cc8f4d02SIntel 	uint8_t if_out;
299cc8f4d02SIntel };
300cc8f4d02SIntel 
301cc8f4d02SIntel static struct ipv4_l3fwd_route ipv4_l3fwd_route_array[] = {
302cc8f4d02SIntel 	{{IPv4(100,10,0,1), IPv4(200,10,0,1), 101, 11, IPPROTO_TCP}, 0},
303cc8f4d02SIntel 	{{IPv4(100,20,0,2), IPv4(200,20,0,2), 102, 12, IPPROTO_TCP}, 1},
304cc8f4d02SIntel 	{{IPv4(100,30,0,3), IPv4(200,30,0,3), 103, 13, IPPROTO_TCP}, 2},
305cc8f4d02SIntel 	{{IPv4(100,40,0,4), IPv4(200,40,0,4), 104, 14, IPPROTO_TCP}, 3},
306cc8f4d02SIntel };
307cc8f4d02SIntel 
308cc8f4d02SIntel static struct ipv6_l3fwd_route ipv6_l3fwd_route_array[] = {
309cc8f4d02SIntel 	{
310cc8f4d02SIntel 		{
311cc8f4d02SIntel 			{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312cc8f4d02SIntel 			 0x02, 0x1b, 0x21, 0xff, 0xfe, 0x91, 0x38, 0x05},
313cc8f4d02SIntel 			{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
314cc8f4d02SIntel 			 0x02, 0x1e, 0x67, 0xff, 0xfe, 0x0d, 0xb6, 0x0a},
315cc8f4d02SIntel 			 1, 10, IPPROTO_UDP
316cc8f4d02SIntel 		}, 4
317cc8f4d02SIntel 	},
318cc8f4d02SIntel };
319cc8f4d02SIntel 
320cc8f4d02SIntel typedef struct rte_hash lookup_struct_t;
321cc8f4d02SIntel static lookup_struct_t *ipv4_l3fwd_lookup_struct[NB_SOCKETS];
322cc8f4d02SIntel static lookup_struct_t *ipv6_l3fwd_lookup_struct[NB_SOCKETS];
323cc8f4d02SIntel 
324cc8f4d02SIntel #define L3FWD_HASH_ENTRIES	1024
325cc8f4d02SIntel 
326cc8f4d02SIntel #define IPV4_L3FWD_NUM_ROUTES \
327cc8f4d02SIntel 	(sizeof(ipv4_l3fwd_route_array) / sizeof(ipv4_l3fwd_route_array[0]))
328cc8f4d02SIntel 
329cc8f4d02SIntel #define IPV6_L3FWD_NUM_ROUTES \
330cc8f4d02SIntel 	(sizeof(ipv6_l3fwd_route_array) / sizeof(ipv6_l3fwd_route_array[0]))
331cc8f4d02SIntel 
332cc8f4d02SIntel static uint8_t ipv4_l3fwd_out_if[L3FWD_HASH_ENTRIES] __rte_cache_aligned;
333cc8f4d02SIntel static uint8_t ipv6_l3fwd_out_if[L3FWD_HASH_ENTRIES] __rte_cache_aligned;
334cc8f4d02SIntel #endif
335cc8f4d02SIntel 
336cc8f4d02SIntel #if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
337cc8f4d02SIntel struct ipv4_l3fwd_route {
338cc8f4d02SIntel 	uint32_t ip;
339cc8f4d02SIntel 	uint8_t  depth;
340cc8f4d02SIntel 	uint8_t  if_out;
341cc8f4d02SIntel };
342cc8f4d02SIntel 
343cc8f4d02SIntel struct ipv6_l3fwd_route {
344cc8f4d02SIntel 	uint8_t ip[16];
345cc8f4d02SIntel 	uint8_t  depth;
346cc8f4d02SIntel 	uint8_t  if_out;
347cc8f4d02SIntel };
348cc8f4d02SIntel 
349cc8f4d02SIntel static struct ipv4_l3fwd_route ipv4_l3fwd_route_array[] = {
350cc8f4d02SIntel 	{IPv4(1,1,1,0), 24, 0},
351cc8f4d02SIntel 	{IPv4(2,1,1,0), 24, 1},
352cc8f4d02SIntel 	{IPv4(3,1,1,0), 24, 2},
353cc8f4d02SIntel 	{IPv4(4,1,1,0), 24, 3},
354cc8f4d02SIntel 	{IPv4(5,1,1,0), 24, 4},
355cc8f4d02SIntel 	{IPv4(6,1,1,0), 24, 5},
356cc8f4d02SIntel 	{IPv4(7,1,1,0), 24, 6},
357cc8f4d02SIntel 	{IPv4(8,1,1,0), 24, 7},
358cc8f4d02SIntel };
359cc8f4d02SIntel 
360cc8f4d02SIntel static struct ipv6_l3fwd_route ipv6_l3fwd_route_array[] = {
361cc8f4d02SIntel 	{{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, 0},
362cc8f4d02SIntel 	{{2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, 1},
363cc8f4d02SIntel 	{{3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, 2},
364cc8f4d02SIntel 	{{4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, 3},
365cc8f4d02SIntel 	{{5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, 4},
366cc8f4d02SIntel 	{{6,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, 5},
367cc8f4d02SIntel 	{{7,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, 6},
368cc8f4d02SIntel 	{{8,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, 7},
369cc8f4d02SIntel };
370cc8f4d02SIntel 
371cc8f4d02SIntel #define IPV4_L3FWD_NUM_ROUTES \
372cc8f4d02SIntel 	(sizeof(ipv4_l3fwd_route_array) / sizeof(ipv4_l3fwd_route_array[0]))
373cc8f4d02SIntel #define IPV6_L3FWD_NUM_ROUTES \
374cc8f4d02SIntel 	(sizeof(ipv6_l3fwd_route_array) / sizeof(ipv6_l3fwd_route_array[0]))
375cc8f4d02SIntel 
376cc8f4d02SIntel #define IPV4_L3FWD_LPM_MAX_RULES         1024
377cc8f4d02SIntel #define IPV6_L3FWD_LPM_MAX_RULES         1024
378cc8f4d02SIntel #define IPV6_L3FWD_LPM_NUMBER_TBL8S (1 << 16)
379cc8f4d02SIntel 
380cc8f4d02SIntel typedef struct rte_lpm lookup_struct_t;
381cc8f4d02SIntel typedef struct rte_lpm6 lookup6_struct_t;
382cc8f4d02SIntel static lookup_struct_t *ipv4_l3fwd_lookup_struct[NB_SOCKETS];
383cc8f4d02SIntel static lookup6_struct_t *ipv6_l3fwd_lookup_struct[NB_SOCKETS];
384cc8f4d02SIntel #endif
385cc8f4d02SIntel 
386595ea7dcSIntel struct tx_lcore_stat {
387595ea7dcSIntel 	uint64_t call;
388595ea7dcSIntel 	uint64_t drop;
389595ea7dcSIntel 	uint64_t queue;
390595ea7dcSIntel 	uint64_t send;
391595ea7dcSIntel };
392595ea7dcSIntel 
393595ea7dcSIntel #ifdef IPV4_FRAG_TBL_STAT
394595ea7dcSIntel #define	TX_LCORE_STAT_UPDATE(s, f, v)	((s)->f += (v))
395595ea7dcSIntel #else
396595ea7dcSIntel #define	TX_LCORE_STAT_UPDATE(s, f, v)	do {} while (0)
397595ea7dcSIntel #endif /* IPV4_FRAG_TBL_STAT */
398595ea7dcSIntel 
399cc8f4d02SIntel struct lcore_conf {
400cc8f4d02SIntel 	uint16_t n_rx_queue;
401cc8f4d02SIntel 	struct lcore_rx_queue rx_queue_list[MAX_RX_QUEUE_PER_LCORE];
402cc8f4d02SIntel 	uint16_t tx_queue_id[MAX_PORTS];
403cc8f4d02SIntel 	lookup_struct_t * ipv4_lookup_struct;
404cc8f4d02SIntel #if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
405cc8f4d02SIntel 	lookup6_struct_t * ipv6_lookup_struct;
406cc8f4d02SIntel #else
407cc8f4d02SIntel 	lookup_struct_t * ipv6_lookup_struct;
408cc8f4d02SIntel #endif
409cc8f4d02SIntel 	struct ipv4_frag_tbl *frag_tbl[MAX_RX_QUEUE_PER_LCORE];
410cc8f4d02SIntel 	struct rte_mempool *pool[MAX_RX_QUEUE_PER_LCORE];
411595ea7dcSIntel 	struct ipv4_frag_death_row death_row;
412595ea7dcSIntel 	struct mbuf_table *tx_mbufs[MAX_PORTS];
413595ea7dcSIntel 	struct tx_lcore_stat tx_stat;
414cc8f4d02SIntel } __rte_cache_aligned;
415cc8f4d02SIntel 
416cc8f4d02SIntel static struct lcore_conf lcore_conf[RTE_MAX_LCORE];
417cc8f4d02SIntel 
418595ea7dcSIntel /*
419595ea7dcSIntel  * If number of queued packets reached given threahold, then
420595ea7dcSIntel  * send burst of packets on an output interface.
421595ea7dcSIntel  */
422595ea7dcSIntel static inline uint32_t
423595ea7dcSIntel send_burst(struct lcore_conf *qconf, uint32_t thresh, uint8_t port)
424cc8f4d02SIntel {
425595ea7dcSIntel 	uint32_t fill, len, k, n;
426595ea7dcSIntel 	struct mbuf_table *txmb;
427cc8f4d02SIntel 
428595ea7dcSIntel 	txmb = qconf->tx_mbufs[port];
429595ea7dcSIntel 	len = txmb->len;
430cc8f4d02SIntel 
431595ea7dcSIntel 	if ((int32_t)(fill = txmb->head - txmb->tail) < 0)
432595ea7dcSIntel 		fill += len;
433595ea7dcSIntel 
434595ea7dcSIntel 	if (fill >= thresh) {
435595ea7dcSIntel 		n = RTE_MIN(len - txmb->tail, fill);
436595ea7dcSIntel 
437595ea7dcSIntel 		k = rte_eth_tx_burst(port, qconf->tx_queue_id[port],
438595ea7dcSIntel 			txmb->m_table + txmb->tail, (uint16_t)n);
439595ea7dcSIntel 
440595ea7dcSIntel 		TX_LCORE_STAT_UPDATE(&qconf->tx_stat, call, 1);
441595ea7dcSIntel 		TX_LCORE_STAT_UPDATE(&qconf->tx_stat, send, k);
442595ea7dcSIntel 
443595ea7dcSIntel 		fill -= k;
444595ea7dcSIntel 		if ((txmb->tail += k) == len)
445595ea7dcSIntel 			txmb->tail = 0;
446cc8f4d02SIntel 	}
447cc8f4d02SIntel 
448595ea7dcSIntel 	return (fill);
449cc8f4d02SIntel }
450cc8f4d02SIntel 
451cc8f4d02SIntel /* Enqueue a single packet, and send burst if queue is filled */
452cc8f4d02SIntel static inline int
453cc8f4d02SIntel send_single_packet(struct rte_mbuf *m, uint8_t port)
454cc8f4d02SIntel {
455595ea7dcSIntel 	uint32_t fill, lcore_id, len;
456cc8f4d02SIntel 	struct lcore_conf *qconf;
457595ea7dcSIntel 	struct mbuf_table *txmb;
458cc8f4d02SIntel 
459cc8f4d02SIntel 	lcore_id = rte_lcore_id();
460cc8f4d02SIntel 	qconf = &lcore_conf[lcore_id];
461cc8f4d02SIntel 
462595ea7dcSIntel 	txmb = qconf->tx_mbufs[port];
463595ea7dcSIntel 	len = txmb->len;
464595ea7dcSIntel 
465595ea7dcSIntel 	fill = send_burst(qconf, MAX_PKT_BURST, port);
466595ea7dcSIntel 
467595ea7dcSIntel 	if (fill == len - 1) {
468595ea7dcSIntel 		TX_LCORE_STAT_UPDATE(&qconf->tx_stat, drop, 1);
469595ea7dcSIntel 		rte_pktmbuf_free(txmb->m_table[txmb->tail]);
470595ea7dcSIntel 		if (++txmb->tail == len)
471595ea7dcSIntel 			txmb->tail = 0;
472cc8f4d02SIntel 	}
473cc8f4d02SIntel 
474595ea7dcSIntel 	TX_LCORE_STAT_UPDATE(&qconf->tx_stat, queue, 1);
475595ea7dcSIntel 	txmb->m_table[txmb->head] = m;
476595ea7dcSIntel 	if(++txmb->head == len)
477595ea7dcSIntel 		txmb->head = 0;
478595ea7dcSIntel 
479595ea7dcSIntel 	return (0);
480cc8f4d02SIntel }
481cc8f4d02SIntel 
482cc8f4d02SIntel #ifdef DO_RFC_1812_CHECKS
483cc8f4d02SIntel static inline int
484cc8f4d02SIntel is_valid_ipv4_pkt(struct ipv4_hdr *pkt, uint32_t link_len)
485cc8f4d02SIntel {
486cc8f4d02SIntel 	/* From http://www.rfc-editor.org/rfc/rfc1812.txt section 5.2.2 */
487cc8f4d02SIntel 	/*
488cc8f4d02SIntel 	 * 1. The packet length reported by the Link Layer must be large
489cc8f4d02SIntel 	 * enough to hold the minimum length legal IP datagram (20 bytes).
490cc8f4d02SIntel 	 */
491cc8f4d02SIntel 	if (link_len < sizeof(struct ipv4_hdr))
492cc8f4d02SIntel 		return -1;
493cc8f4d02SIntel 
494cc8f4d02SIntel 	/* 2. The IP checksum must be correct. */
495cc8f4d02SIntel 	/* this is checked in H/W */
496cc8f4d02SIntel 
497cc8f4d02SIntel 	/*
498cc8f4d02SIntel 	 * 3. The IP version number must be 4. If the version number is not 4
499cc8f4d02SIntel 	 * then the packet may be another version of IP, such as IPng or
500cc8f4d02SIntel 	 * ST-II.
501cc8f4d02SIntel 	 */
502cc8f4d02SIntel 	if (((pkt->version_ihl) >> 4) != 4)
503cc8f4d02SIntel 		return -3;
504cc8f4d02SIntel 	/*
505cc8f4d02SIntel 	 * 4. The IP header length field must be large enough to hold the
506cc8f4d02SIntel 	 * minimum length legal IP datagram (20 bytes = 5 words).
507cc8f4d02SIntel 	 */
508cc8f4d02SIntel 	if ((pkt->version_ihl & 0xf) < 5)
509cc8f4d02SIntel 		return -4;
510cc8f4d02SIntel 
511cc8f4d02SIntel 	/*
512cc8f4d02SIntel 	 * 5. The IP total length field must be large enough to hold the IP
513cc8f4d02SIntel 	 * datagram header, whose length is specified in the IP header length
514cc8f4d02SIntel 	 * field.
515cc8f4d02SIntel 	 */
516cc8f4d02SIntel 	if (rte_cpu_to_be_16(pkt->total_length) < sizeof(struct ipv4_hdr))
517cc8f4d02SIntel 		return -5;
518cc8f4d02SIntel 
519cc8f4d02SIntel 	return 0;
520cc8f4d02SIntel }
521cc8f4d02SIntel #endif
522cc8f4d02SIntel 
523cc8f4d02SIntel #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
524cc8f4d02SIntel static void
525cc8f4d02SIntel print_ipv4_key(struct ipv4_5tuple key)
526cc8f4d02SIntel {
527cc8f4d02SIntel 	printf("IP dst = %08x, IP src = %08x, port dst = %d, port src = %d, proto = %d\n",
528cc8f4d02SIntel 			(unsigned)key.ip_dst, (unsigned)key.ip_src, key.port_dst, key.port_src, key.proto);
529cc8f4d02SIntel }
530cc8f4d02SIntel static void
531cc8f4d02SIntel print_ipv6_key(struct ipv6_5tuple key)
532cc8f4d02SIntel {
533cc8f4d02SIntel 	printf( "IP dst = " IPv6_BYTES_FMT ", IP src = " IPv6_BYTES_FMT ", "
534cc8f4d02SIntel 	        "port dst = %d, port src = %d, proto = %d\n",
535cc8f4d02SIntel 	        IPv6_BYTES(key.ip_dst), IPv6_BYTES(key.ip_src),
536cc8f4d02SIntel 	        key.port_dst, key.port_src, key.proto);
537cc8f4d02SIntel }
538cc8f4d02SIntel 
539cc8f4d02SIntel static inline uint8_t
540cc8f4d02SIntel get_ipv4_dst_port(struct ipv4_hdr *ipv4_hdr,  uint8_t portid, lookup_struct_t * ipv4_l3fwd_lookup_struct)
541cc8f4d02SIntel {
542cc8f4d02SIntel 	struct ipv4_5tuple key;
543cc8f4d02SIntel 	struct tcp_hdr *tcp;
544cc8f4d02SIntel 	struct udp_hdr *udp;
545cc8f4d02SIntel 	int ret = 0;
546cc8f4d02SIntel 
547cc8f4d02SIntel 	key.ip_dst = rte_be_to_cpu_32(ipv4_hdr->dst_addr);
548cc8f4d02SIntel 	key.ip_src = rte_be_to_cpu_32(ipv4_hdr->src_addr);
549cc8f4d02SIntel 	key.proto = ipv4_hdr->next_proto_id;
550cc8f4d02SIntel 
551cc8f4d02SIntel 	switch (ipv4_hdr->next_proto_id) {
552cc8f4d02SIntel 	case IPPROTO_TCP:
553cc8f4d02SIntel 		tcp = (struct tcp_hdr *)((unsigned char *) ipv4_hdr +
554cc8f4d02SIntel 					sizeof(struct ipv4_hdr));
555cc8f4d02SIntel 		key.port_dst = rte_be_to_cpu_16(tcp->dst_port);
556cc8f4d02SIntel 		key.port_src = rte_be_to_cpu_16(tcp->src_port);
557cc8f4d02SIntel 		break;
558cc8f4d02SIntel 
559cc8f4d02SIntel 	case IPPROTO_UDP:
560cc8f4d02SIntel 		udp = (struct udp_hdr *)((unsigned char *) ipv4_hdr +
561cc8f4d02SIntel 					sizeof(struct ipv4_hdr));
562cc8f4d02SIntel 		key.port_dst = rte_be_to_cpu_16(udp->dst_port);
563cc8f4d02SIntel 		key.port_src = rte_be_to_cpu_16(udp->src_port);
564cc8f4d02SIntel 		break;
565cc8f4d02SIntel 
566cc8f4d02SIntel 	default:
567cc8f4d02SIntel 		key.port_dst = 0;
568cc8f4d02SIntel 		key.port_src = 0;
569cc8f4d02SIntel 		break;
570cc8f4d02SIntel 	}
571cc8f4d02SIntel 
572cc8f4d02SIntel 	/* Find destination port */
573cc8f4d02SIntel 	ret = rte_hash_lookup(ipv4_l3fwd_lookup_struct, (const void *)&key);
574cc8f4d02SIntel 	return (uint8_t)((ret < 0)? portid : ipv4_l3fwd_out_if[ret]);
575cc8f4d02SIntel }
576cc8f4d02SIntel 
577cc8f4d02SIntel static inline uint8_t
578cc8f4d02SIntel get_ipv6_dst_port(struct ipv6_hdr *ipv6_hdr,  uint8_t portid, lookup_struct_t * ipv6_l3fwd_lookup_struct)
579cc8f4d02SIntel {
580cc8f4d02SIntel 	struct ipv6_5tuple key;
581cc8f4d02SIntel 	struct tcp_hdr *tcp;
582cc8f4d02SIntel 	struct udp_hdr *udp;
583cc8f4d02SIntel 	int ret = 0;
584cc8f4d02SIntel 
585cc8f4d02SIntel 	memcpy(key.ip_dst, ipv6_hdr->dst_addr, IPV6_ADDR_LEN);
586cc8f4d02SIntel 	memcpy(key.ip_src, ipv6_hdr->src_addr, IPV6_ADDR_LEN);
587cc8f4d02SIntel 
588cc8f4d02SIntel 	key.proto = ipv6_hdr->proto;
589cc8f4d02SIntel 
590cc8f4d02SIntel 	switch (ipv6_hdr->proto) {
591cc8f4d02SIntel 	case IPPROTO_TCP:
592cc8f4d02SIntel 		tcp = (struct tcp_hdr *)((unsigned char *) ipv6_hdr +
593cc8f4d02SIntel 					sizeof(struct ipv6_hdr));
594cc8f4d02SIntel 		key.port_dst = rte_be_to_cpu_16(tcp->dst_port);
595cc8f4d02SIntel 		key.port_src = rte_be_to_cpu_16(tcp->src_port);
596cc8f4d02SIntel 		break;
597cc8f4d02SIntel 
598cc8f4d02SIntel 	case IPPROTO_UDP:
599cc8f4d02SIntel 		udp = (struct udp_hdr *)((unsigned char *) ipv6_hdr +
600cc8f4d02SIntel 					sizeof(struct ipv6_hdr));
601cc8f4d02SIntel 		key.port_dst = rte_be_to_cpu_16(udp->dst_port);
602cc8f4d02SIntel 		key.port_src = rte_be_to_cpu_16(udp->src_port);
603cc8f4d02SIntel 		break;
604cc8f4d02SIntel 
605cc8f4d02SIntel 	default:
606cc8f4d02SIntel 		key.port_dst = 0;
607cc8f4d02SIntel 		key.port_src = 0;
608cc8f4d02SIntel 		break;
609cc8f4d02SIntel 	}
610cc8f4d02SIntel 
611cc8f4d02SIntel 	/* Find destination port */
612cc8f4d02SIntel 	ret = rte_hash_lookup(ipv6_l3fwd_lookup_struct, (const void *)&key);
613cc8f4d02SIntel 	return (uint8_t)((ret < 0)? portid : ipv6_l3fwd_out_if[ret]);
614cc8f4d02SIntel }
615cc8f4d02SIntel #endif
616cc8f4d02SIntel 
617cc8f4d02SIntel #if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
618cc8f4d02SIntel static inline uint8_t
619cc8f4d02SIntel get_ipv4_dst_port(struct ipv4_hdr *ipv4_hdr,  uint8_t portid, lookup_struct_t * ipv4_l3fwd_lookup_struct)
620cc8f4d02SIntel {
621cc8f4d02SIntel 	uint8_t next_hop;
622cc8f4d02SIntel 
623cc8f4d02SIntel 	return (uint8_t) ((rte_lpm_lookup(ipv4_l3fwd_lookup_struct,
624cc8f4d02SIntel 			rte_be_to_cpu_32(ipv4_hdr->dst_addr), &next_hop) == 0)?
625cc8f4d02SIntel 			next_hop : portid);
626cc8f4d02SIntel }
627cc8f4d02SIntel 
628cc8f4d02SIntel static inline uint8_t
629cc8f4d02SIntel get_ipv6_dst_port(struct ipv6_hdr *ipv6_hdr,  uint8_t portid, lookup6_struct_t * ipv6_l3fwd_lookup_struct)
630cc8f4d02SIntel {
631cc8f4d02SIntel 	uint8_t next_hop;
632cc8f4d02SIntel 
633cc8f4d02SIntel 	return (uint8_t) ((rte_lpm6_lookup(ipv6_l3fwd_lookup_struct,
634cc8f4d02SIntel 			ipv6_hdr->dst_addr, &next_hop) == 0)?
635cc8f4d02SIntel 			next_hop : portid);
636cc8f4d02SIntel }
637cc8f4d02SIntel #endif
638cc8f4d02SIntel 
639cc8f4d02SIntel static inline void
640cc8f4d02SIntel l3fwd_simple_forward(struct rte_mbuf *m, uint8_t portid, uint32_t queue,
641cc8f4d02SIntel 	struct lcore_conf *qconf, uint64_t tms)
642cc8f4d02SIntel {
643cc8f4d02SIntel 	struct ether_hdr *eth_hdr;
644cc8f4d02SIntel 	struct ipv4_hdr *ipv4_hdr;
645cc8f4d02SIntel 	void *d_addr_bytes;
646cc8f4d02SIntel 	uint8_t dst_port;
647cc8f4d02SIntel 	uint16_t flag_offset, ip_flag, ip_ofs;
648cc8f4d02SIntel 
649cc8f4d02SIntel 	eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
650cc8f4d02SIntel 
651cc8f4d02SIntel 	if (m->ol_flags & PKT_RX_IPV4_HDR) {
652cc8f4d02SIntel 		/* Handle IPv4 headers.*/
653cc8f4d02SIntel 		ipv4_hdr = (struct ipv4_hdr *)(eth_hdr + 1);
654cc8f4d02SIntel 
655cc8f4d02SIntel #ifdef DO_RFC_1812_CHECKS
656cc8f4d02SIntel 		/* Check to make sure the packet is valid (RFC1812) */
657cc8f4d02SIntel 		if (is_valid_ipv4_pkt(ipv4_hdr, m->pkt.pkt_len) < 0) {
658cc8f4d02SIntel 			rte_pktmbuf_free(m);
659cc8f4d02SIntel 			return;
660cc8f4d02SIntel 		}
661cc8f4d02SIntel 
662cc8f4d02SIntel 		/* Update time to live and header checksum */
663cc8f4d02SIntel 		--(ipv4_hdr->time_to_live);
664cc8f4d02SIntel 		++(ipv4_hdr->hdr_checksum);
665cc8f4d02SIntel #endif
666cc8f4d02SIntel 
667cc8f4d02SIntel 		flag_offset = rte_be_to_cpu_16(ipv4_hdr->fragment_offset);
668cc8f4d02SIntel 		ip_ofs = (uint16_t)(flag_offset & IPV4_HDR_OFFSET_MASK);
669cc8f4d02SIntel 		ip_flag = (uint16_t)(flag_offset & IPV4_HDR_MF_FLAG);
670cc8f4d02SIntel 
671cc8f4d02SIntel 		 /* if it is a fragmented packet, then try to reassemble. */
672cc8f4d02SIntel 		if (ip_flag != 0 || ip_ofs  != 0) {
673cc8f4d02SIntel 
674cc8f4d02SIntel 			struct rte_mbuf *mo;
675cc8f4d02SIntel 			struct ipv4_frag_tbl *tbl;
676595ea7dcSIntel 			struct ipv4_frag_death_row *dr;
677cc8f4d02SIntel 
678cc8f4d02SIntel 			tbl = qconf->frag_tbl[queue];
679595ea7dcSIntel 			dr = &qconf->death_row;
680cc8f4d02SIntel 
681cc8f4d02SIntel 			/* prepare mbuf: setup l2_len/l3_len. */
682cc8f4d02SIntel 			m->pkt.vlan_macip.f.l2_len = sizeof(*eth_hdr);
683cc8f4d02SIntel 			m->pkt.vlan_macip.f.l3_len = sizeof(*ipv4_hdr);
684cc8f4d02SIntel 
685cc8f4d02SIntel 			/* process this fragment. */
686595ea7dcSIntel 			if ((mo = ipv4_frag_mbuf(tbl, dr, m, tms, ipv4_hdr,
687cc8f4d02SIntel 					ip_ofs, ip_flag)) == NULL)
688cc8f4d02SIntel 				/* no packet to send out. */
689cc8f4d02SIntel 				return;
690cc8f4d02SIntel 
691cc8f4d02SIntel 			/* we have our packet reassembled. */
692cc8f4d02SIntel 			if (mo != m) {
693cc8f4d02SIntel 				m = mo;
694cc8f4d02SIntel 				eth_hdr = rte_pktmbuf_mtod(m,
695cc8f4d02SIntel 					struct ether_hdr *);
696cc8f4d02SIntel 				ipv4_hdr = (struct ipv4_hdr *)(eth_hdr + 1);
697cc8f4d02SIntel 			}
698cc8f4d02SIntel 		}
699cc8f4d02SIntel 
700595ea7dcSIntel 		dst_port = get_ipv4_dst_port(ipv4_hdr, portid,
701595ea7dcSIntel 			qconf->ipv4_lookup_struct);
702595ea7dcSIntel 		if (dst_port >= MAX_PORTS ||
703595ea7dcSIntel 				(enabled_port_mask & 1 << dst_port) == 0)
704cc8f4d02SIntel 			dst_port = portid;
705cc8f4d02SIntel 
706cc8f4d02SIntel 		/* 02:00:00:00:00:xx */
707cc8f4d02SIntel 		d_addr_bytes = &eth_hdr->d_addr.addr_bytes[0];
708cc8f4d02SIntel 		*((uint64_t *)d_addr_bytes) = 0x000000000002 + ((uint64_t)dst_port << 40);
709cc8f4d02SIntel 
710cc8f4d02SIntel 		/* src addr */
711cc8f4d02SIntel 		ether_addr_copy(&ports_eth_addr[dst_port], &eth_hdr->s_addr);
712cc8f4d02SIntel 
713cc8f4d02SIntel 		send_single_packet(m, dst_port);
714cc8f4d02SIntel 	}
715cc8f4d02SIntel 	else {
716cc8f4d02SIntel 		/* Handle IPv6 headers.*/
717cc8f4d02SIntel 		struct ipv6_hdr *ipv6_hdr;
718cc8f4d02SIntel 
719cc8f4d02SIntel 		ipv6_hdr = (struct ipv6_hdr *)(rte_pktmbuf_mtod(m, unsigned char *) +
720cc8f4d02SIntel 				sizeof(struct ether_hdr));
721cc8f4d02SIntel 
722cc8f4d02SIntel 		dst_port = get_ipv6_dst_port(ipv6_hdr, portid, qconf->ipv6_lookup_struct);
723cc8f4d02SIntel 
724cc8f4d02SIntel 		if (dst_port >= MAX_PORTS || (enabled_port_mask & 1 << dst_port) == 0)
725cc8f4d02SIntel 			dst_port = portid;
726cc8f4d02SIntel 
727cc8f4d02SIntel 		/* 02:00:00:00:00:xx */
728cc8f4d02SIntel 		d_addr_bytes = &eth_hdr->d_addr.addr_bytes[0];
729cc8f4d02SIntel 		*((uint64_t *)d_addr_bytes) = 0x000000000002 + ((uint64_t)dst_port << 40);
730cc8f4d02SIntel 
731cc8f4d02SIntel 		/* src addr */
732cc8f4d02SIntel 		ether_addr_copy(&ports_eth_addr[dst_port], &eth_hdr->s_addr);
733cc8f4d02SIntel 
734cc8f4d02SIntel 		send_single_packet(m, dst_port);
735cc8f4d02SIntel 	}
736cc8f4d02SIntel 
737cc8f4d02SIntel }
738cc8f4d02SIntel 
739cc8f4d02SIntel /* main processing loop */
740cc8f4d02SIntel static int
741cc8f4d02SIntel main_loop(__attribute__((unused)) void *dummy)
742cc8f4d02SIntel {
743cc8f4d02SIntel 	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
744cc8f4d02SIntel 	unsigned lcore_id;
745cc8f4d02SIntel 	uint64_t diff_tsc, cur_tsc, prev_tsc;
746cc8f4d02SIntel 	int i, j, nb_rx;
747cc8f4d02SIntel 	uint8_t portid, queueid;
748cc8f4d02SIntel 	struct lcore_conf *qconf;
749cc8f4d02SIntel 	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;
750cc8f4d02SIntel 
751cc8f4d02SIntel 	prev_tsc = 0;
752cc8f4d02SIntel 
753cc8f4d02SIntel 	lcore_id = rte_lcore_id();
754cc8f4d02SIntel 	qconf = &lcore_conf[lcore_id];
755cc8f4d02SIntel 
756cc8f4d02SIntel 	if (qconf->n_rx_queue == 0) {
757cc8f4d02SIntel 		RTE_LOG(INFO, L3FWD, "lcore %u has nothing to do\n", lcore_id);
758cc8f4d02SIntel 		return 0;
759cc8f4d02SIntel 	}
760cc8f4d02SIntel 
761cc8f4d02SIntel 	RTE_LOG(INFO, L3FWD, "entering main loop on lcore %u\n", lcore_id);
762cc8f4d02SIntel 
763cc8f4d02SIntel 	for (i = 0; i < qconf->n_rx_queue; i++) {
764cc8f4d02SIntel 
765cc8f4d02SIntel 		portid = qconf->rx_queue_list[i].port_id;
766cc8f4d02SIntel 		queueid = qconf->rx_queue_list[i].queue_id;
767cc8f4d02SIntel 		RTE_LOG(INFO, L3FWD, " -- lcoreid=%u portid=%hhu rxqueueid=%hhu\n", lcore_id,
768cc8f4d02SIntel 			portid, queueid);
769cc8f4d02SIntel 	}
770cc8f4d02SIntel 
771cc8f4d02SIntel 	while (1) {
772cc8f4d02SIntel 
773cc8f4d02SIntel 		cur_tsc = rte_rdtsc();
774cc8f4d02SIntel 
775cc8f4d02SIntel 		/*
776cc8f4d02SIntel 		 * TX burst queue drain
777cc8f4d02SIntel 		 */
778cc8f4d02SIntel 		diff_tsc = cur_tsc - prev_tsc;
779cc8f4d02SIntel 		if (unlikely(diff_tsc > drain_tsc)) {
780cc8f4d02SIntel 
781cc8f4d02SIntel 			/*
782cc8f4d02SIntel 			 * This could be optimized (use queueid instead of
783cc8f4d02SIntel 			 * portid), but it is not called so often
784cc8f4d02SIntel 			 */
785cc8f4d02SIntel 			for (portid = 0; portid < MAX_PORTS; portid++) {
786595ea7dcSIntel 				if ((enabled_port_mask & (1 << portid)) != 0)
787595ea7dcSIntel 					send_burst(qconf, 1, portid);
788cc8f4d02SIntel 			}
789cc8f4d02SIntel 
790cc8f4d02SIntel 			prev_tsc = cur_tsc;
791cc8f4d02SIntel 		}
792cc8f4d02SIntel 
793cc8f4d02SIntel 		/*
794cc8f4d02SIntel 		 * Read packet from RX queues
795cc8f4d02SIntel 		 */
796cc8f4d02SIntel 		for (i = 0; i < qconf->n_rx_queue; ++i) {
797cc8f4d02SIntel 
798cc8f4d02SIntel 			portid = qconf->rx_queue_list[i].port_id;
799cc8f4d02SIntel 			queueid = qconf->rx_queue_list[i].queue_id;
800cc8f4d02SIntel 
801cc8f4d02SIntel 			nb_rx = rte_eth_rx_burst(portid, queueid, pkts_burst,
802cc8f4d02SIntel 				MAX_PKT_BURST);
803cc8f4d02SIntel 
804cc8f4d02SIntel 			/* Prefetch first packets */
805cc8f4d02SIntel 			for (j = 0; j < PREFETCH_OFFSET && j < nb_rx; j++) {
806cc8f4d02SIntel 				rte_prefetch0(rte_pktmbuf_mtod(
807cc8f4d02SIntel 						pkts_burst[j], void *));
808cc8f4d02SIntel 			}
809cc8f4d02SIntel 
810cc8f4d02SIntel 			/* Prefetch and forward already prefetched packets */
811cc8f4d02SIntel 			for (j = 0; j < (nb_rx - PREFETCH_OFFSET); j++) {
812cc8f4d02SIntel 				rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[
813cc8f4d02SIntel 					j + PREFETCH_OFFSET], void *));
814cc8f4d02SIntel 				l3fwd_simple_forward(pkts_burst[j], portid,
815cc8f4d02SIntel 					i, qconf, cur_tsc);
816cc8f4d02SIntel 			}
817cc8f4d02SIntel 
818cc8f4d02SIntel 			/* Forward remaining prefetched packets */
819cc8f4d02SIntel 			for (; j < nb_rx; j++) {
820cc8f4d02SIntel 				l3fwd_simple_forward(pkts_burst[j], portid,
821cc8f4d02SIntel 					i, qconf, cur_tsc);
822cc8f4d02SIntel 			}
823595ea7dcSIntel 
824595ea7dcSIntel 			ipv4_frag_free_death_row(&qconf->death_row,
825595ea7dcSIntel 				PREFETCH_OFFSET);
826cc8f4d02SIntel 		}
827cc8f4d02SIntel 	}
828cc8f4d02SIntel }
829cc8f4d02SIntel 
830cc8f4d02SIntel static int
831cc8f4d02SIntel check_lcore_params(void)
832cc8f4d02SIntel {
833cc8f4d02SIntel 	uint8_t queue, lcore;
834cc8f4d02SIntel 	uint16_t i;
835cc8f4d02SIntel 	int socketid;
836cc8f4d02SIntel 
837cc8f4d02SIntel 	for (i = 0; i < nb_lcore_params; ++i) {
838cc8f4d02SIntel 		queue = lcore_params[i].queue_id;
839cc8f4d02SIntel 		if (queue >= MAX_RX_QUEUE_PER_PORT) {
840cc8f4d02SIntel 			printf("invalid queue number: %hhu\n", queue);
841cc8f4d02SIntel 			return -1;
842cc8f4d02SIntel 		}
843cc8f4d02SIntel 		lcore = lcore_params[i].lcore_id;
844cc8f4d02SIntel 		if (!rte_lcore_is_enabled(lcore)) {
845cc8f4d02SIntel 			printf("error: lcore %hhu is not enabled in lcore mask\n", lcore);
846cc8f4d02SIntel 			return -1;
847cc8f4d02SIntel 		}
848cc8f4d02SIntel 		if ((socketid = rte_lcore_to_socket_id(lcore) != 0) &&
849cc8f4d02SIntel 			(numa_on == 0)) {
850cc8f4d02SIntel 			printf("warning: lcore %hhu is on socket %d with numa off \n",
851cc8f4d02SIntel 				lcore, socketid);
852cc8f4d02SIntel 		}
853cc8f4d02SIntel 	}
854cc8f4d02SIntel 	return 0;
855cc8f4d02SIntel }
856cc8f4d02SIntel 
857cc8f4d02SIntel static int
858cc8f4d02SIntel check_port_config(const unsigned nb_ports)
859cc8f4d02SIntel {
860cc8f4d02SIntel 	unsigned portid;
861cc8f4d02SIntel 	uint16_t i;
862cc8f4d02SIntel 
863cc8f4d02SIntel 	for (i = 0; i < nb_lcore_params; ++i) {
864cc8f4d02SIntel 		portid = lcore_params[i].port_id;
865cc8f4d02SIntel 		if ((enabled_port_mask & (1 << portid)) == 0) {
866cc8f4d02SIntel 			printf("port %u is not enabled in port mask\n", portid);
867cc8f4d02SIntel 			return -1;
868cc8f4d02SIntel 		}
869cc8f4d02SIntel 		if (portid >= nb_ports) {
870cc8f4d02SIntel 			printf("port %u is not present on the board\n", portid);
871cc8f4d02SIntel 			return -1;
872cc8f4d02SIntel 		}
873cc8f4d02SIntel 	}
874cc8f4d02SIntel 	return 0;
875cc8f4d02SIntel }
876cc8f4d02SIntel 
877cc8f4d02SIntel static uint8_t
878cc8f4d02SIntel get_port_n_rx_queues(const uint8_t port)
879cc8f4d02SIntel {
880cc8f4d02SIntel 	int queue = -1;
881cc8f4d02SIntel 	uint16_t i;
882cc8f4d02SIntel 
883cc8f4d02SIntel 	for (i = 0; i < nb_lcore_params; ++i) {
884cc8f4d02SIntel 		if (lcore_params[i].port_id == port && lcore_params[i].queue_id > queue)
885cc8f4d02SIntel 			queue = lcore_params[i].queue_id;
886cc8f4d02SIntel 	}
887cc8f4d02SIntel 	return (uint8_t)(++queue);
888cc8f4d02SIntel }
889cc8f4d02SIntel 
890cc8f4d02SIntel static int
891cc8f4d02SIntel init_lcore_rx_queues(void)
892cc8f4d02SIntel {
893cc8f4d02SIntel 	uint16_t i, nb_rx_queue;
894cc8f4d02SIntel 	uint8_t lcore;
895cc8f4d02SIntel 
896cc8f4d02SIntel 	for (i = 0; i < nb_lcore_params; ++i) {
897cc8f4d02SIntel 		lcore = lcore_params[i].lcore_id;
898cc8f4d02SIntel 		nb_rx_queue = lcore_conf[lcore].n_rx_queue;
899cc8f4d02SIntel 		if (nb_rx_queue >= MAX_RX_QUEUE_PER_LCORE) {
900cc8f4d02SIntel 			printf("error: too many queues (%u) for lcore: %u\n",
901cc8f4d02SIntel 				(unsigned)nb_rx_queue + 1, (unsigned)lcore);
902cc8f4d02SIntel 			return -1;
903cc8f4d02SIntel 		} else {
904cc8f4d02SIntel 			lcore_conf[lcore].rx_queue_list[nb_rx_queue].port_id =
905cc8f4d02SIntel 				lcore_params[i].port_id;
906cc8f4d02SIntel 			lcore_conf[lcore].rx_queue_list[nb_rx_queue].queue_id =
907cc8f4d02SIntel 				lcore_params[i].queue_id;
908cc8f4d02SIntel 			lcore_conf[lcore].n_rx_queue++;
909cc8f4d02SIntel 		}
910cc8f4d02SIntel 	}
911cc8f4d02SIntel 	return 0;
912cc8f4d02SIntel }
913cc8f4d02SIntel 
914cc8f4d02SIntel /* display usage */
915cc8f4d02SIntel static void
916cc8f4d02SIntel print_usage(const char *prgname)
917cc8f4d02SIntel {
918cc8f4d02SIntel 	printf ("%s [EAL options] -- -p PORTMASK -P"
919cc8f4d02SIntel 		"  [--config (port,queue,lcore)[,(port,queue,lcore]]"
920cc8f4d02SIntel 		"  [--enable-jumbo [--max-pkt-len PKTLEN]]"
921cc8f4d02SIntel 		"  [--maxflows=<flows>]  [--flowttl=<ttl>[(s|ms)]]\n"
922cc8f4d02SIntel 		"  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
923cc8f4d02SIntel 		"  -P : enable promiscuous mode\n"
924cc8f4d02SIntel 		"  --config (port,queue,lcore): rx queues configuration\n"
925cc8f4d02SIntel 		"  --no-numa: optional, disable numa awareness\n"
926cc8f4d02SIntel 		"  --enable-jumbo: enable jumbo frame"
927cc8f4d02SIntel 		" which max packet len is PKTLEN in decimal (64-9600)\n"
928cc8f4d02SIntel 		"  --maxflows=<flows>: optional, maximum number of flows "
929cc8f4d02SIntel 		"supported\n"
930cc8f4d02SIntel 		"  --flowttl=<ttl>[(s|ms)]: optional, maximum TTL for each "
931cc8f4d02SIntel 		"flow\n",
932cc8f4d02SIntel 		prgname);
933cc8f4d02SIntel }
934cc8f4d02SIntel 
935cc8f4d02SIntel static uint32_t
936cc8f4d02SIntel parse_flow_num(const char *str, uint32_t min, uint32_t max, uint32_t *val)
937cc8f4d02SIntel {
938cc8f4d02SIntel 	char *end;
939cc8f4d02SIntel 	uint64_t v;
940cc8f4d02SIntel 
941cc8f4d02SIntel 	/* parse decimal string */
942cc8f4d02SIntel 	errno = 0;
943cc8f4d02SIntel 	v = strtoul(str, &end, 10);
944cc8f4d02SIntel 	if (errno != 0 || *end != '\0')
945cc8f4d02SIntel 		return (-EINVAL);
946cc8f4d02SIntel 
947cc8f4d02SIntel 	if (v < min || v > max)
948cc8f4d02SIntel 		return (-EINVAL);
949cc8f4d02SIntel 
950cc8f4d02SIntel 	*val = (uint32_t)v;
951cc8f4d02SIntel 	return (0);
952cc8f4d02SIntel }
953cc8f4d02SIntel 
954cc8f4d02SIntel static int
955cc8f4d02SIntel parse_flow_ttl(const char *str, uint32_t min, uint32_t max, uint32_t *val)
956cc8f4d02SIntel {
957cc8f4d02SIntel 	char *end;
958cc8f4d02SIntel 	uint64_t v;
959cc8f4d02SIntel 
960cc8f4d02SIntel 	static const char frmt_sec[] = "s";
961cc8f4d02SIntel 	static const char frmt_msec[] = "ms";
962cc8f4d02SIntel 
963cc8f4d02SIntel 	/* parse decimal string */
964cc8f4d02SIntel 	errno = 0;
965cc8f4d02SIntel 	v = strtoul(str, &end, 10);
966cc8f4d02SIntel 	if (errno != 0)
967cc8f4d02SIntel 		return (-EINVAL);
968cc8f4d02SIntel 
969cc8f4d02SIntel 	if (*end != '\0') {
970cc8f4d02SIntel 		if (strncmp(frmt_sec, end, sizeof(frmt_sec)) == 0)
971cc8f4d02SIntel 			v *= MS_PER_S;
972cc8f4d02SIntel 		else if (strncmp(frmt_msec, end, sizeof (frmt_msec)) != 0)
973cc8f4d02SIntel 			return (-EINVAL);
974cc8f4d02SIntel 	}
975cc8f4d02SIntel 
976cc8f4d02SIntel 	if (v < min || v > max)
977cc8f4d02SIntel 		return (-EINVAL);
978cc8f4d02SIntel 
979cc8f4d02SIntel 	*val = (uint32_t)v;
980cc8f4d02SIntel 	return (0);
981cc8f4d02SIntel }
982cc8f4d02SIntel 
983cc8f4d02SIntel 
984cc8f4d02SIntel static int parse_max_pkt_len(const char *pktlen)
985cc8f4d02SIntel {
986cc8f4d02SIntel 	char *end = NULL;
987cc8f4d02SIntel 	unsigned long len;
988cc8f4d02SIntel 
989cc8f4d02SIntel 	/* parse decimal string */
990cc8f4d02SIntel 	len = strtoul(pktlen, &end, 10);
991cc8f4d02SIntel 	if ((pktlen[0] == '\0') || (end == NULL) || (*end != '\0'))
992cc8f4d02SIntel 		return -1;
993cc8f4d02SIntel 
994cc8f4d02SIntel 	if (len == 0)
995cc8f4d02SIntel 		return -1;
996cc8f4d02SIntel 
997cc8f4d02SIntel 	return len;
998cc8f4d02SIntel }
999cc8f4d02SIntel 
1000cc8f4d02SIntel static int
1001cc8f4d02SIntel parse_portmask(const char *portmask)
1002cc8f4d02SIntel {
1003cc8f4d02SIntel 	char *end = NULL;
1004cc8f4d02SIntel 	unsigned long pm;
1005cc8f4d02SIntel 
1006cc8f4d02SIntel 	/* parse hexadecimal string */
1007cc8f4d02SIntel 	pm = strtoul(portmask, &end, 16);
1008cc8f4d02SIntel 	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
1009cc8f4d02SIntel 		return -1;
1010cc8f4d02SIntel 
1011cc8f4d02SIntel 	if (pm == 0)
1012cc8f4d02SIntel 		return -1;
1013cc8f4d02SIntel 
1014cc8f4d02SIntel 	return pm;
1015cc8f4d02SIntel }
1016cc8f4d02SIntel 
1017cc8f4d02SIntel static int
1018cc8f4d02SIntel parse_config(const char *q_arg)
1019cc8f4d02SIntel {
1020cc8f4d02SIntel 	char s[256];
1021cc8f4d02SIntel 	const char *p, *p0 = q_arg;
1022cc8f4d02SIntel 	char *end;
1023cc8f4d02SIntel 	enum fieldnames {
1024cc8f4d02SIntel 		FLD_PORT = 0,
1025cc8f4d02SIntel 		FLD_QUEUE,
1026cc8f4d02SIntel 		FLD_LCORE,
1027cc8f4d02SIntel 		_NUM_FLD
1028cc8f4d02SIntel 	};
1029cc8f4d02SIntel 	unsigned long int_fld[_NUM_FLD];
1030cc8f4d02SIntel 	char *str_fld[_NUM_FLD];
1031cc8f4d02SIntel 	int i;
1032cc8f4d02SIntel 	unsigned size;
1033cc8f4d02SIntel 
1034cc8f4d02SIntel 	nb_lcore_params = 0;
1035cc8f4d02SIntel 
1036cc8f4d02SIntel 	while ((p = strchr(p0,'(')) != NULL) {
1037cc8f4d02SIntel 		++p;
1038cc8f4d02SIntel 		if((p0 = strchr(p,')')) == NULL)
1039cc8f4d02SIntel 			return -1;
1040cc8f4d02SIntel 
1041cc8f4d02SIntel 		size = p0 - p;
1042cc8f4d02SIntel 		if(size >= sizeof(s))
1043cc8f4d02SIntel 			return -1;
1044cc8f4d02SIntel 
1045cc8f4d02SIntel 		rte_snprintf(s, sizeof(s), "%.*s", size, p);
1046cc8f4d02SIntel 		if (rte_strsplit(s, sizeof(s), str_fld, _NUM_FLD, ',') != _NUM_FLD)
1047cc8f4d02SIntel 			return -1;
1048cc8f4d02SIntel 		for (i = 0; i < _NUM_FLD; i++){
1049cc8f4d02SIntel 			errno = 0;
1050cc8f4d02SIntel 			int_fld[i] = strtoul(str_fld[i], &end, 0);
1051cc8f4d02SIntel 			if (errno != 0 || end == str_fld[i] || int_fld[i] > 255)
1052cc8f4d02SIntel 				return -1;
1053cc8f4d02SIntel 		}
1054cc8f4d02SIntel 		if (nb_lcore_params >= MAX_LCORE_PARAMS) {
1055cc8f4d02SIntel 			printf("exceeded max number of lcore params: %hu\n",
1056cc8f4d02SIntel 				nb_lcore_params);
1057cc8f4d02SIntel 			return -1;
1058cc8f4d02SIntel 		}
1059cc8f4d02SIntel 		lcore_params_array[nb_lcore_params].port_id = (uint8_t)int_fld[FLD_PORT];
1060cc8f4d02SIntel 		lcore_params_array[nb_lcore_params].queue_id = (uint8_t)int_fld[FLD_QUEUE];
1061cc8f4d02SIntel 		lcore_params_array[nb_lcore_params].lcore_id = (uint8_t)int_fld[FLD_LCORE];
1062cc8f4d02SIntel 		++nb_lcore_params;
1063cc8f4d02SIntel 	}
1064cc8f4d02SIntel 	lcore_params = lcore_params_array;
1065cc8f4d02SIntel 	return 0;
1066cc8f4d02SIntel }
1067cc8f4d02SIntel 
1068cc8f4d02SIntel /* Parse the argument given in the command line of the application */
1069cc8f4d02SIntel static int
1070cc8f4d02SIntel parse_args(int argc, char **argv)
1071cc8f4d02SIntel {
1072cc8f4d02SIntel 	int opt, ret;
1073cc8f4d02SIntel 	char **argvopt;
1074cc8f4d02SIntel 	int option_index;
1075cc8f4d02SIntel 	char *prgname = argv[0];
1076cc8f4d02SIntel 	static struct option lgopts[] = {
1077cc8f4d02SIntel 		{"config", 1, 0, 0},
1078cc8f4d02SIntel 		{"no-numa", 0, 0, 0},
1079cc8f4d02SIntel 		{"enable-jumbo", 0, 0, 0},
1080cc8f4d02SIntel 		{"maxflows", 1, 0, 0},
1081cc8f4d02SIntel 		{"flowttl", 1, 0, 0},
1082cc8f4d02SIntel 		{NULL, 0, 0, 0}
1083cc8f4d02SIntel 	};
1084cc8f4d02SIntel 
1085cc8f4d02SIntel 	argvopt = argv;
1086cc8f4d02SIntel 
1087cc8f4d02SIntel 	while ((opt = getopt_long(argc, argvopt, "p:P",
1088cc8f4d02SIntel 				lgopts, &option_index)) != EOF) {
1089cc8f4d02SIntel 
1090cc8f4d02SIntel 		switch (opt) {
1091cc8f4d02SIntel 		/* portmask */
1092cc8f4d02SIntel 		case 'p':
1093cc8f4d02SIntel 			enabled_port_mask = parse_portmask(optarg);
1094cc8f4d02SIntel 			if (enabled_port_mask == 0) {
1095cc8f4d02SIntel 				printf("invalid portmask\n");
1096cc8f4d02SIntel 				print_usage(prgname);
1097cc8f4d02SIntel 				return -1;
1098cc8f4d02SIntel 			}
1099cc8f4d02SIntel 			break;
1100cc8f4d02SIntel 		case 'P':
1101cc8f4d02SIntel 			printf("Promiscuous mode selected\n");
1102cc8f4d02SIntel 			promiscuous_on = 1;
1103cc8f4d02SIntel 			break;
1104cc8f4d02SIntel 
1105cc8f4d02SIntel 		/* long options */
1106cc8f4d02SIntel 		case 0:
1107cc8f4d02SIntel 			if (!strncmp(lgopts[option_index].name, "config", 6)) {
1108cc8f4d02SIntel 				ret = parse_config(optarg);
1109cc8f4d02SIntel 				if (ret) {
1110cc8f4d02SIntel 					printf("invalid config\n");
1111cc8f4d02SIntel 					print_usage(prgname);
1112cc8f4d02SIntel 					return -1;
1113cc8f4d02SIntel 				}
1114cc8f4d02SIntel 			}
1115cc8f4d02SIntel 
1116cc8f4d02SIntel 			if (!strncmp(lgopts[option_index].name, "no-numa", 7)) {
1117cc8f4d02SIntel 				printf("numa is disabled \n");
1118cc8f4d02SIntel 				numa_on = 0;
1119cc8f4d02SIntel 			}
1120cc8f4d02SIntel 
1121cc8f4d02SIntel 			if (!strncmp(lgopts[option_index].name,
1122cc8f4d02SIntel 					"maxflows", 8)) {
1123cc8f4d02SIntel 				if ((ret = parse_flow_num(optarg, MIN_FLOW_NUM,
1124cc8f4d02SIntel 						MAX_FLOW_NUM,
1125cc8f4d02SIntel 						&max_flow_num)) != 0) {
1126cc8f4d02SIntel 					printf("invalid value: \"%s\" for "
1127cc8f4d02SIntel 						"parameter %s\n",
1128cc8f4d02SIntel 						optarg,
1129cc8f4d02SIntel 						lgopts[option_index].name);
1130cc8f4d02SIntel 					print_usage(prgname);
1131cc8f4d02SIntel 					return (ret);
1132cc8f4d02SIntel 				}
1133cc8f4d02SIntel 			}
1134cc8f4d02SIntel 
1135cc8f4d02SIntel 			if (!strncmp(lgopts[option_index].name, "flowttl", 7)) {
1136cc8f4d02SIntel 				if ((ret = parse_flow_ttl(optarg, MIN_FLOW_TTL,
1137cc8f4d02SIntel 						MAX_FLOW_TTL,
1138cc8f4d02SIntel 						&max_flow_ttl)) != 0) {
1139cc8f4d02SIntel 					printf("invalid value: \"%s\" for "
1140cc8f4d02SIntel 						"parameter %s\n",
1141cc8f4d02SIntel 						optarg,
1142cc8f4d02SIntel 						lgopts[option_index].name);
1143cc8f4d02SIntel 					print_usage(prgname);
1144cc8f4d02SIntel 					return (ret);
1145cc8f4d02SIntel 				}
1146cc8f4d02SIntel 			}
1147cc8f4d02SIntel 
1148cc8f4d02SIntel 			if (!strncmp(lgopts[option_index].name, "enable-jumbo", 12)) {
1149cc8f4d02SIntel 				struct option lenopts = {"max-pkt-len", required_argument, 0, 0};
1150cc8f4d02SIntel 
1151cc8f4d02SIntel 				printf("jumbo frame is enabled \n");
1152cc8f4d02SIntel 				port_conf.rxmode.jumbo_frame = 1;
1153cc8f4d02SIntel 
1154cc8f4d02SIntel 				/* if no max-pkt-len set, use the default value ETHER_MAX_LEN */
1155cc8f4d02SIntel 				if (0 == getopt_long(argc, argvopt, "", &lenopts, &option_index)) {
1156cc8f4d02SIntel 					ret = parse_max_pkt_len(optarg);
1157cc8f4d02SIntel 					if ((ret < 64) || (ret > MAX_JUMBO_PKT_LEN)){
1158cc8f4d02SIntel 						printf("invalid packet length\n");
1159cc8f4d02SIntel 						print_usage(prgname);
1160cc8f4d02SIntel 						return -1;
1161cc8f4d02SIntel 					}
1162cc8f4d02SIntel 					port_conf.rxmode.max_rx_pkt_len = ret;
1163cc8f4d02SIntel 				}
1164cc8f4d02SIntel 				printf("set jumbo frame max packet length to %u\n",
1165cc8f4d02SIntel 						(unsigned int)port_conf.rxmode.max_rx_pkt_len);
1166cc8f4d02SIntel 			}
1167cc8f4d02SIntel 
1168cc8f4d02SIntel 			break;
1169cc8f4d02SIntel 
1170cc8f4d02SIntel 		default:
1171cc8f4d02SIntel 			print_usage(prgname);
1172cc8f4d02SIntel 			return -1;
1173cc8f4d02SIntel 		}
1174cc8f4d02SIntel 	}
1175cc8f4d02SIntel 
1176cc8f4d02SIntel 	if (optind >= 0)
1177cc8f4d02SIntel 		argv[optind-1] = prgname;
1178cc8f4d02SIntel 
1179cc8f4d02SIntel 	ret = optind-1;
1180cc8f4d02SIntel 	optind = 0; /* reset getopt lib */
1181cc8f4d02SIntel 	return ret;
1182cc8f4d02SIntel }
1183cc8f4d02SIntel 
1184cc8f4d02SIntel static void
1185cc8f4d02SIntel print_ethaddr(const char *name, const struct ether_addr *eth_addr)
1186cc8f4d02SIntel {
1187cc8f4d02SIntel 	printf ("%s%02X:%02X:%02X:%02X:%02X:%02X", name,
1188cc8f4d02SIntel 		eth_addr->addr_bytes[0],
1189cc8f4d02SIntel 		eth_addr->addr_bytes[1],
1190cc8f4d02SIntel 		eth_addr->addr_bytes[2],
1191cc8f4d02SIntel 		eth_addr->addr_bytes[3],
1192cc8f4d02SIntel 		eth_addr->addr_bytes[4],
1193cc8f4d02SIntel 		eth_addr->addr_bytes[5]);
1194cc8f4d02SIntel }
1195cc8f4d02SIntel 
1196cc8f4d02SIntel #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
1197cc8f4d02SIntel static void
1198cc8f4d02SIntel setup_hash(int socketid)
1199cc8f4d02SIntel {
1200cc8f4d02SIntel 	struct rte_hash_parameters ipv4_l3fwd_hash_params = {
1201cc8f4d02SIntel 		.name = NULL,
1202cc8f4d02SIntel 		.entries = L3FWD_HASH_ENTRIES,
1203cc8f4d02SIntel 		.bucket_entries = 4,
1204cc8f4d02SIntel 		.key_len = sizeof(struct ipv4_5tuple),
1205cc8f4d02SIntel 		.hash_func = DEFAULT_HASH_FUNC,
1206cc8f4d02SIntel 		.hash_func_init_val = 0,
1207cc8f4d02SIntel 	};
1208cc8f4d02SIntel 
1209cc8f4d02SIntel 	struct rte_hash_parameters ipv6_l3fwd_hash_params = {
1210cc8f4d02SIntel 		.name = NULL,
1211cc8f4d02SIntel 		.entries = L3FWD_HASH_ENTRIES,
1212cc8f4d02SIntel 		.bucket_entries = 4,
1213cc8f4d02SIntel 		.key_len = sizeof(struct ipv6_5tuple),
1214cc8f4d02SIntel 		.hash_func = DEFAULT_HASH_FUNC,
1215cc8f4d02SIntel 		.hash_func_init_val = 0,
1216cc8f4d02SIntel 	};
1217cc8f4d02SIntel 
1218cc8f4d02SIntel 	unsigned i;
1219cc8f4d02SIntel 	int ret;
1220cc8f4d02SIntel 	char s[64];
1221cc8f4d02SIntel 
1222cc8f4d02SIntel 	/* create ipv4 hash */
1223cc8f4d02SIntel 	rte_snprintf(s, sizeof(s), "ipv4_l3fwd_hash_%d", socketid);
1224cc8f4d02SIntel 	ipv4_l3fwd_hash_params.name = s;
1225cc8f4d02SIntel 	ipv4_l3fwd_hash_params.socket_id = socketid;
1226cc8f4d02SIntel 	ipv4_l3fwd_lookup_struct[socketid] = rte_hash_create(&ipv4_l3fwd_hash_params);
1227cc8f4d02SIntel 	if (ipv4_l3fwd_lookup_struct[socketid] == NULL)
1228cc8f4d02SIntel 		rte_exit(EXIT_FAILURE, "Unable to create the l3fwd hash on "
1229cc8f4d02SIntel 				"socket %d\n", socketid);
1230cc8f4d02SIntel 
1231cc8f4d02SIntel 	/* create ipv6 hash */
1232cc8f4d02SIntel 	rte_snprintf(s, sizeof(s), "ipv6_l3fwd_hash_%d", socketid);
1233cc8f4d02SIntel 	ipv6_l3fwd_hash_params.name = s;
1234cc8f4d02SIntel 	ipv6_l3fwd_hash_params.socket_id = socketid;
1235cc8f4d02SIntel 	ipv6_l3fwd_lookup_struct[socketid] = rte_hash_create(&ipv6_l3fwd_hash_params);
1236cc8f4d02SIntel 	if (ipv6_l3fwd_lookup_struct[socketid] == NULL)
1237cc8f4d02SIntel 		rte_exit(EXIT_FAILURE, "Unable to create the l3fwd hash on "
1238cc8f4d02SIntel 				"socket %d\n", socketid);
1239cc8f4d02SIntel 
1240cc8f4d02SIntel 
1241cc8f4d02SIntel 	/* populate the ipv4 hash */
1242cc8f4d02SIntel 	for (i = 0; i < IPV4_L3FWD_NUM_ROUTES; i++) {
1243cc8f4d02SIntel 		ret = rte_hash_add_key (ipv4_l3fwd_lookup_struct[socketid],
1244cc8f4d02SIntel 				(void *) &ipv4_l3fwd_route_array[i].key);
1245cc8f4d02SIntel 		if (ret < 0) {
1246cc8f4d02SIntel 			rte_exit(EXIT_FAILURE, "Unable to add entry %u to the"
1247cc8f4d02SIntel 				"l3fwd hash on socket %d\n", i, socketid);
1248cc8f4d02SIntel 		}
1249cc8f4d02SIntel 		ipv4_l3fwd_out_if[ret] = ipv4_l3fwd_route_array[i].if_out;
1250cc8f4d02SIntel 		printf("Hash: Adding key\n");
1251cc8f4d02SIntel 		print_ipv4_key(ipv4_l3fwd_route_array[i].key);
1252cc8f4d02SIntel 	}
1253cc8f4d02SIntel 
1254cc8f4d02SIntel 	/* populate the ipv6 hash */
1255cc8f4d02SIntel 	for (i = 0; i < IPV6_L3FWD_NUM_ROUTES; i++) {
1256cc8f4d02SIntel 		ret = rte_hash_add_key (ipv6_l3fwd_lookup_struct[socketid],
1257cc8f4d02SIntel 				(void *) &ipv6_l3fwd_route_array[i].key);
1258cc8f4d02SIntel 		if (ret < 0) {
1259cc8f4d02SIntel 			rte_exit(EXIT_FAILURE, "Unable to add entry %u to the"
1260cc8f4d02SIntel 				"l3fwd hash on socket %d\n", i, socketid);
1261cc8f4d02SIntel 		}
1262cc8f4d02SIntel 		ipv6_l3fwd_out_if[ret] = ipv6_l3fwd_route_array[i].if_out;
1263cc8f4d02SIntel 		printf("Hash: Adding key\n");
1264cc8f4d02SIntel 		print_ipv6_key(ipv6_l3fwd_route_array[i].key);
1265cc8f4d02SIntel 	}
1266cc8f4d02SIntel }
1267cc8f4d02SIntel #endif
1268cc8f4d02SIntel 
1269cc8f4d02SIntel #if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
1270cc8f4d02SIntel static void
1271cc8f4d02SIntel setup_lpm(int socketid)
1272cc8f4d02SIntel {
1273cc8f4d02SIntel 	struct rte_lpm6_config config;
1274cc8f4d02SIntel 	unsigned i;
1275cc8f4d02SIntel 	int ret;
1276cc8f4d02SIntel 	char s[64];
1277cc8f4d02SIntel 
1278cc8f4d02SIntel 	/* create the LPM table */
1279cc8f4d02SIntel 	rte_snprintf(s, sizeof(s), "IPV4_L3FWD_LPM_%d", socketid);
1280cc8f4d02SIntel 	ipv4_l3fwd_lookup_struct[socketid] = rte_lpm_create(s, socketid,
1281cc8f4d02SIntel 				IPV4_L3FWD_LPM_MAX_RULES, 0);
1282cc8f4d02SIntel 	if (ipv4_l3fwd_lookup_struct[socketid] == NULL)
1283cc8f4d02SIntel 		rte_exit(EXIT_FAILURE, "Unable to create the l3fwd LPM table"
1284cc8f4d02SIntel 				" on socket %d\n", socketid);
1285cc8f4d02SIntel 
1286cc8f4d02SIntel 	/* populate the LPM table */
1287cc8f4d02SIntel 	for (i = 0; i < IPV4_L3FWD_NUM_ROUTES; i++) {
1288cc8f4d02SIntel 		ret = rte_lpm_add(ipv4_l3fwd_lookup_struct[socketid],
1289cc8f4d02SIntel 			ipv4_l3fwd_route_array[i].ip,
1290cc8f4d02SIntel 			ipv4_l3fwd_route_array[i].depth,
1291cc8f4d02SIntel 			ipv4_l3fwd_route_array[i].if_out);
1292cc8f4d02SIntel 
1293cc8f4d02SIntel 		if (ret < 0) {
1294cc8f4d02SIntel 			rte_exit(EXIT_FAILURE, "Unable to add entry %u to the "
1295cc8f4d02SIntel 				"l3fwd LPM table on socket %d\n",
1296cc8f4d02SIntel 				i, socketid);
1297cc8f4d02SIntel 		}
1298cc8f4d02SIntel 
1299cc8f4d02SIntel 		printf("LPM: Adding route 0x%08x / %d (%d)\n",
1300cc8f4d02SIntel 			(unsigned)ipv4_l3fwd_route_array[i].ip,
1301cc8f4d02SIntel 			ipv4_l3fwd_route_array[i].depth,
1302cc8f4d02SIntel 			ipv4_l3fwd_route_array[i].if_out);
1303cc8f4d02SIntel 	}
1304cc8f4d02SIntel 
1305cc8f4d02SIntel 	/* create the LPM6 table */
1306cc8f4d02SIntel 	rte_snprintf(s, sizeof(s), "IPV6_L3FWD_LPM_%d", socketid);
1307cc8f4d02SIntel 
1308cc8f4d02SIntel 	config.max_rules = IPV6_L3FWD_LPM_MAX_RULES;
1309cc8f4d02SIntel 	config.number_tbl8s = IPV6_L3FWD_LPM_NUMBER_TBL8S;
1310cc8f4d02SIntel 	config.flags = 0;
1311cc8f4d02SIntel 	ipv6_l3fwd_lookup_struct[socketid] = rte_lpm6_create(s, socketid,
1312cc8f4d02SIntel 				&config);
1313cc8f4d02SIntel 	if (ipv6_l3fwd_lookup_struct[socketid] == NULL)
1314cc8f4d02SIntel 		rte_exit(EXIT_FAILURE, "Unable to create the l3fwd LPM table"
1315cc8f4d02SIntel 				" on socket %d\n", socketid);
1316cc8f4d02SIntel 
1317cc8f4d02SIntel 	/* populate the LPM table */
1318cc8f4d02SIntel 	for (i = 0; i < IPV6_L3FWD_NUM_ROUTES; i++) {
1319cc8f4d02SIntel 		ret = rte_lpm6_add(ipv6_l3fwd_lookup_struct[socketid],
1320cc8f4d02SIntel 			ipv6_l3fwd_route_array[i].ip,
1321cc8f4d02SIntel 			ipv6_l3fwd_route_array[i].depth,
1322cc8f4d02SIntel 			ipv6_l3fwd_route_array[i].if_out);
1323cc8f4d02SIntel 
1324cc8f4d02SIntel 		if (ret < 0) {
1325cc8f4d02SIntel 			rte_exit(EXIT_FAILURE, "Unable to add entry %u to the "
1326cc8f4d02SIntel 				"l3fwd LPM table on socket %d\n",
1327cc8f4d02SIntel 				i, socketid);
1328cc8f4d02SIntel 		}
1329cc8f4d02SIntel 
1330cc8f4d02SIntel 		printf("LPM: Adding route %s / %d (%d)\n",
1331cc8f4d02SIntel 			"IPV6",
1332cc8f4d02SIntel 			ipv6_l3fwd_route_array[i].depth,
1333cc8f4d02SIntel 			ipv6_l3fwd_route_array[i].if_out);
1334cc8f4d02SIntel 	}
1335cc8f4d02SIntel }
1336cc8f4d02SIntel #endif
1337cc8f4d02SIntel 
1338cc8f4d02SIntel static int
1339cc8f4d02SIntel init_mem(void)
1340cc8f4d02SIntel {
1341cc8f4d02SIntel 	struct lcore_conf *qconf;
1342cc8f4d02SIntel 	int socketid;
1343cc8f4d02SIntel 	unsigned lcore_id;
1344cc8f4d02SIntel 
1345cc8f4d02SIntel 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
1346cc8f4d02SIntel 		if (rte_lcore_is_enabled(lcore_id) == 0)
1347cc8f4d02SIntel 			continue;
1348cc8f4d02SIntel 
1349cc8f4d02SIntel 		if (numa_on)
1350cc8f4d02SIntel 			socketid = rte_lcore_to_socket_id(lcore_id);
1351cc8f4d02SIntel 		else
1352cc8f4d02SIntel 			socketid = 0;
1353cc8f4d02SIntel 
1354cc8f4d02SIntel 		if (socketid >= NB_SOCKETS) {
1355cc8f4d02SIntel 			rte_exit(EXIT_FAILURE,
1356cc8f4d02SIntel 				"Socket %d of lcore %u is out of range %d\n",
1357cc8f4d02SIntel 				socketid, lcore_id, NB_SOCKETS);
1358cc8f4d02SIntel 		}
1359cc8f4d02SIntel 
1360cc8f4d02SIntel #if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
1361cc8f4d02SIntel 			setup_lpm(socketid);
1362cc8f4d02SIntel #else
1363cc8f4d02SIntel 			setup_hash(socketid);
1364cc8f4d02SIntel #endif
1365cc8f4d02SIntel 		qconf = &lcore_conf[lcore_id];
1366cc8f4d02SIntel 		qconf->ipv4_lookup_struct = ipv4_l3fwd_lookup_struct[socketid];
1367cc8f4d02SIntel 		qconf->ipv6_lookup_struct = ipv6_l3fwd_lookup_struct[socketid];
1368cc8f4d02SIntel 	}
1369cc8f4d02SIntel 	return 0;
1370cc8f4d02SIntel }
1371cc8f4d02SIntel 
1372cc8f4d02SIntel /* Check the link status of all ports in up to 9s, and print them finally */
1373cc8f4d02SIntel static void
1374cc8f4d02SIntel check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
1375cc8f4d02SIntel {
1376cc8f4d02SIntel #define CHECK_INTERVAL 100 /* 100ms */
1377cc8f4d02SIntel #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
1378cc8f4d02SIntel 	uint8_t portid, count, all_ports_up, print_flag = 0;
1379cc8f4d02SIntel 	struct rte_eth_link link;
1380cc8f4d02SIntel 
1381cc8f4d02SIntel 	printf("\nChecking link status");
1382cc8f4d02SIntel 	fflush(stdout);
1383cc8f4d02SIntel 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
1384cc8f4d02SIntel 		all_ports_up = 1;
1385cc8f4d02SIntel 		for (portid = 0; portid < port_num; portid++) {
1386cc8f4d02SIntel 			if ((port_mask & (1 << portid)) == 0)
1387cc8f4d02SIntel 				continue;
1388cc8f4d02SIntel 			memset(&link, 0, sizeof(link));
1389cc8f4d02SIntel 			rte_eth_link_get_nowait(portid, &link);
1390cc8f4d02SIntel 			/* print link status if flag set */
1391cc8f4d02SIntel 			if (print_flag == 1) {
1392cc8f4d02SIntel 				if (link.link_status)
1393cc8f4d02SIntel 					printf("Port %d Link Up - speed %u "
1394cc8f4d02SIntel 						"Mbps - %s\n", (uint8_t)portid,
1395cc8f4d02SIntel 						(unsigned)link.link_speed,
1396cc8f4d02SIntel 				(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
1397cc8f4d02SIntel 					("full-duplex") : ("half-duplex\n"));
1398cc8f4d02SIntel 				else
1399cc8f4d02SIntel 					printf("Port %d Link Down\n",
1400cc8f4d02SIntel 						(uint8_t)portid);
1401cc8f4d02SIntel 				continue;
1402cc8f4d02SIntel 			}
1403cc8f4d02SIntel 			/* clear all_ports_up flag if any link down */
1404cc8f4d02SIntel 			if (link.link_status == 0) {
1405cc8f4d02SIntel 				all_ports_up = 0;
1406cc8f4d02SIntel 				break;
1407cc8f4d02SIntel 			}
1408cc8f4d02SIntel 		}
1409cc8f4d02SIntel 		/* after finally printing all link status, get out */
1410cc8f4d02SIntel 		if (print_flag == 1)
1411cc8f4d02SIntel 			break;
1412cc8f4d02SIntel 
1413cc8f4d02SIntel 		if (all_ports_up == 0) {
1414cc8f4d02SIntel 			printf(".");
1415cc8f4d02SIntel 			fflush(stdout);
1416cc8f4d02SIntel 			rte_delay_ms(CHECK_INTERVAL);
1417cc8f4d02SIntel 		}
1418cc8f4d02SIntel 
1419cc8f4d02SIntel 		/* set the print_flag if all ports up or timeout */
1420cc8f4d02SIntel 		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
1421cc8f4d02SIntel 			print_flag = 1;
1422cc8f4d02SIntel 			printf("done\n");
1423cc8f4d02SIntel 		}
1424cc8f4d02SIntel 	}
1425cc8f4d02SIntel }
1426595ea7dcSIntel static void
1427595ea7dcSIntel setup_port_tbl(struct lcore_conf *qconf, uint32_t lcore, int socket,
1428595ea7dcSIntel 	uint32_t port)
1429595ea7dcSIntel {
1430595ea7dcSIntel 	struct mbuf_table *mtb;
1431595ea7dcSIntel 	uint32_t n;
1432595ea7dcSIntel 	size_t sz;
1433595ea7dcSIntel 
1434595ea7dcSIntel 	n = RTE_MAX(max_flow_num, 2UL * MAX_PKT_BURST);
1435595ea7dcSIntel 	sz = sizeof (*mtb) + sizeof (mtb->m_table[0]) *  n;
1436595ea7dcSIntel 
1437595ea7dcSIntel 	if ((mtb = rte_zmalloc_socket(__func__, sz, CACHE_LINE_SIZE,
1438595ea7dcSIntel 			socket)) == NULL)
1439595ea7dcSIntel 		rte_exit(EXIT_FAILURE, "%s() for lcore: %u, port: %u "
1440595ea7dcSIntel 			"failed to allocate %zu bytes\n",
1441595ea7dcSIntel 			__func__, lcore, port, sz);
1442595ea7dcSIntel 
1443595ea7dcSIntel 	mtb->len = n;
1444595ea7dcSIntel 	qconf->tx_mbufs[port] = mtb;
1445595ea7dcSIntel }
1446cc8f4d02SIntel 
1447cc8f4d02SIntel static void
1448595ea7dcSIntel setup_queue_tbl(struct lcore_conf *qconf, uint32_t lcore, int socket,
1449cc8f4d02SIntel 	uint32_t queue)
1450cc8f4d02SIntel {
1451cc8f4d02SIntel 	uint32_t nb_mbuf;
1452cc8f4d02SIntel 	uint64_t frag_cycles;
1453cc8f4d02SIntel 	char buf[RTE_MEMPOOL_NAMESIZE];
1454cc8f4d02SIntel 
1455cc8f4d02SIntel 	frag_cycles = (rte_get_tsc_hz() + MS_PER_S - 1) / MS_PER_S *
1456cc8f4d02SIntel 		max_flow_ttl;
1457cc8f4d02SIntel 
1458cc8f4d02SIntel 	if ((qconf->frag_tbl[queue] = ipv4_frag_tbl_create(max_flow_num,
1459cc8f4d02SIntel 			IPV4_FRAG_TBL_BUCKET_ENTRIES, max_flow_num, frag_cycles,
1460cc8f4d02SIntel 			socket)) == NULL)
1461cc8f4d02SIntel 		rte_exit(EXIT_FAILURE, "ipv4_frag_tbl_create(%u) on "
1462cc8f4d02SIntel 			"lcore: %u for queue: %u failed\n",
1463cc8f4d02SIntel 			max_flow_num, lcore, queue);
1464cc8f4d02SIntel 
1465595ea7dcSIntel 	/*
1466595ea7dcSIntel 	 * At any given moment up to <max_flow_num * (MAX_FRAG_NUM - 1)>
1467595ea7dcSIntel 	 * mbufs could be stored int the fragment table.
1468595ea7dcSIntel 	 * Plus, each TX queue can hold up to <max_flow_num> packets.
1469595ea7dcSIntel 	 */
1470595ea7dcSIntel 
1471595ea7dcSIntel 	nb_mbuf = 2 * RTE_MAX(max_flow_num, 2UL * MAX_PKT_BURST) * MAX_FRAG_NUM;
1472cc8f4d02SIntel 	nb_mbuf *= (port_conf.rxmode.max_rx_pkt_len + BUF_SIZE - 1) / BUF_SIZE;
1473595ea7dcSIntel 	nb_mbuf += RTE_TEST_RX_DESC_DEFAULT + RTE_TEST_TX_DESC_DEFAULT;
1474595ea7dcSIntel 
1475cc8f4d02SIntel 	nb_mbuf = RTE_MAX(nb_mbuf, (uint32_t)DEF_MBUF_NUM);
1476cc8f4d02SIntel 
1477cc8f4d02SIntel 	rte_snprintf(buf, sizeof(buf), "mbuf_pool_%u_%u", lcore, queue);
1478cc8f4d02SIntel 
1479cc8f4d02SIntel 	if ((qconf->pool[queue] = rte_mempool_create(buf, nb_mbuf, MBUF_SIZE, 0,
1480cc8f4d02SIntel 			sizeof(struct rte_pktmbuf_pool_private),
1481cc8f4d02SIntel 			rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, NULL,
1482cc8f4d02SIntel 			socket, MEMPOOL_F_SP_PUT | MEMPOOL_F_SC_GET)) == NULL)
1483cc8f4d02SIntel 		rte_exit(EXIT_FAILURE, "mempool_create(%s) failed", buf);
1484cc8f4d02SIntel }
1485cc8f4d02SIntel 
1486cc8f4d02SIntel static void
1487595ea7dcSIntel queue_dump_stat(void)
1488cc8f4d02SIntel {
1489cc8f4d02SIntel 	uint32_t i, lcore;
1490cc8f4d02SIntel 	const struct lcore_conf *qconf;
1491cc8f4d02SIntel 
1492cc8f4d02SIntel 	for (lcore = 0; lcore < RTE_MAX_LCORE; lcore++) {
1493cc8f4d02SIntel 		if (rte_lcore_is_enabled(lcore) == 0)
1494cc8f4d02SIntel 			continue;
1495cc8f4d02SIntel 
1496cc8f4d02SIntel 		qconf = lcore_conf + lcore;
1497cc8f4d02SIntel 		for (i = 0; i < qconf->n_rx_queue; i++) {
1498cc8f4d02SIntel 
1499cc8f4d02SIntel 			fprintf(stdout, " -- lcoreid=%u portid=%hhu "
1500cc8f4d02SIntel 				"rxqueueid=%hhu frag tbl stat:\n",
1501cc8f4d02SIntel 				lcore,  qconf->rx_queue_list[i].port_id,
1502cc8f4d02SIntel 				qconf->rx_queue_list[i].queue_id);
1503cc8f4d02SIntel 			ipv4_frag_tbl_dump_stat(stdout, qconf->frag_tbl[i]);
1504595ea7dcSIntel 			fprintf(stdout, "TX bursts:\t%" PRIu64 "\n"
1505595ea7dcSIntel 				"TX packets _queued:\t%" PRIu64 "\n"
1506595ea7dcSIntel 				"TX packets dropped:\t%" PRIu64 "\n"
1507595ea7dcSIntel 				"TX packets send:\t%" PRIu64 "\n",
1508595ea7dcSIntel 				qconf->tx_stat.call,
1509595ea7dcSIntel 				qconf->tx_stat.queue,
1510595ea7dcSIntel 				qconf->tx_stat.drop,
1511595ea7dcSIntel 				qconf->tx_stat.send);
1512cc8f4d02SIntel 		}
1513cc8f4d02SIntel 	}
1514cc8f4d02SIntel }
1515cc8f4d02SIntel 
1516cc8f4d02SIntel static void
1517cc8f4d02SIntel signal_handler(int signum)
1518cc8f4d02SIntel {
1519595ea7dcSIntel 	queue_dump_stat();
1520cc8f4d02SIntel 	if (signum != SIGUSR1)
1521cc8f4d02SIntel 		rte_exit(0, "received signal: %d, exiting\n", signum);
1522cc8f4d02SIntel }
1523cc8f4d02SIntel 
1524cc8f4d02SIntel int
1525cc8f4d02SIntel MAIN(int argc, char **argv)
1526cc8f4d02SIntel {
1527cc8f4d02SIntel 	struct lcore_conf *qconf;
1528cc8f4d02SIntel 	int ret;
1529cc8f4d02SIntel 	unsigned nb_ports;
1530cc8f4d02SIntel 	uint16_t queueid;
1531cc8f4d02SIntel 	unsigned lcore_id;
1532cc8f4d02SIntel 	uint32_t n_tx_queue, nb_lcores;
1533cc8f4d02SIntel 	uint8_t portid, nb_rx_queue, queue, socketid;
1534cc8f4d02SIntel 
1535cc8f4d02SIntel 	/* init EAL */
1536cc8f4d02SIntel 	ret = rte_eal_init(argc, argv);
1537cc8f4d02SIntel 	if (ret < 0)
1538cc8f4d02SIntel 		rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n");
1539cc8f4d02SIntel 	argc -= ret;
1540cc8f4d02SIntel 	argv += ret;
1541cc8f4d02SIntel 
1542cc8f4d02SIntel 	/* parse application arguments (after the EAL ones) */
1543cc8f4d02SIntel 	ret = parse_args(argc, argv);
1544cc8f4d02SIntel 	if (ret < 0)
1545cc8f4d02SIntel 		rte_exit(EXIT_FAILURE, "Invalid L3FWD parameters\n");
1546cc8f4d02SIntel 
1547cc8f4d02SIntel 	if (check_lcore_params() < 0)
1548cc8f4d02SIntel 		rte_exit(EXIT_FAILURE, "check_lcore_params failed\n");
1549cc8f4d02SIntel 
1550cc8f4d02SIntel 	ret = init_lcore_rx_queues();
1551cc8f4d02SIntel 	if (ret < 0)
1552cc8f4d02SIntel 		rte_exit(EXIT_FAILURE, "init_lcore_rx_queues failed\n");
1553cc8f4d02SIntel 
1554cc8f4d02SIntel 
1555cc8f4d02SIntel 	/* init driver(s) */
1556cc8f4d02SIntel 	if (rte_pmd_init_all() < 0)
1557cc8f4d02SIntel 		rte_exit(EXIT_FAILURE, "Cannot init pmd\n");
1558cc8f4d02SIntel 
1559cc8f4d02SIntel 	if (rte_eal_pci_probe() < 0)
1560cc8f4d02SIntel 		rte_exit(EXIT_FAILURE, "Cannot probe PCI\n");
1561cc8f4d02SIntel 
1562cc8f4d02SIntel 	nb_ports = rte_eth_dev_count();
1563cc8f4d02SIntel 	if (nb_ports > MAX_PORTS)
1564cc8f4d02SIntel 		nb_ports = MAX_PORTS;
1565cc8f4d02SIntel 
1566cc8f4d02SIntel 	if (check_port_config(nb_ports) < 0)
1567cc8f4d02SIntel 		rte_exit(EXIT_FAILURE, "check_port_config failed\n");
1568cc8f4d02SIntel 
1569cc8f4d02SIntel 	nb_lcores = rte_lcore_count();
1570cc8f4d02SIntel 
1571cc8f4d02SIntel 	/* initialize all ports */
1572cc8f4d02SIntel 	for (portid = 0; portid < nb_ports; portid++) {
1573cc8f4d02SIntel 		/* skip ports that are not enabled */
1574cc8f4d02SIntel 		if ((enabled_port_mask & (1 << portid)) == 0) {
1575cc8f4d02SIntel 			printf("\nSkipping disabled port %d\n", portid);
1576cc8f4d02SIntel 			continue;
1577cc8f4d02SIntel 		}
1578cc8f4d02SIntel 
1579cc8f4d02SIntel 		/* init port */
1580cc8f4d02SIntel 		printf("Initializing port %d ... ", portid );
1581cc8f4d02SIntel 		fflush(stdout);
1582cc8f4d02SIntel 
1583cc8f4d02SIntel 		nb_rx_queue = get_port_n_rx_queues(portid);
1584cc8f4d02SIntel 		n_tx_queue = nb_lcores;
1585cc8f4d02SIntel 		if (n_tx_queue > MAX_TX_QUEUE_PER_PORT)
1586cc8f4d02SIntel 			n_tx_queue = MAX_TX_QUEUE_PER_PORT;
1587cc8f4d02SIntel 		printf("Creating queues: nb_rxq=%d nb_txq=%u... ",
1588cc8f4d02SIntel 			nb_rx_queue, (unsigned)n_tx_queue );
1589cc8f4d02SIntel 		ret = rte_eth_dev_configure(portid, nb_rx_queue,
1590cc8f4d02SIntel 					(uint16_t)n_tx_queue, &port_conf);
1591cc8f4d02SIntel 		if (ret < 0)
1592cc8f4d02SIntel 			rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%d\n",
1593cc8f4d02SIntel 				ret, portid);
1594cc8f4d02SIntel 
1595cc8f4d02SIntel 		rte_eth_macaddr_get(portid, &ports_eth_addr[portid]);
1596cc8f4d02SIntel 		print_ethaddr(" Address:", &ports_eth_addr[portid]);
1597cc8f4d02SIntel 		printf(", ");
1598cc8f4d02SIntel 
1599cc8f4d02SIntel 		/* init memory */
1600cc8f4d02SIntel 		ret = init_mem();
1601cc8f4d02SIntel 		if (ret < 0)
1602cc8f4d02SIntel 			rte_exit(EXIT_FAILURE, "init_mem failed\n");
1603cc8f4d02SIntel 
1604cc8f4d02SIntel 		/* init one TX queue per couple (lcore,port) */
1605cc8f4d02SIntel 		queueid = 0;
1606cc8f4d02SIntel 		for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
1607cc8f4d02SIntel 			if (rte_lcore_is_enabled(lcore_id) == 0)
1608cc8f4d02SIntel 				continue;
1609cc8f4d02SIntel 
1610cc8f4d02SIntel 			if (numa_on)
1611cc8f4d02SIntel 				socketid = (uint8_t)rte_lcore_to_socket_id(lcore_id);
1612cc8f4d02SIntel 			else
1613cc8f4d02SIntel 				socketid = 0;
1614cc8f4d02SIntel 
1615cc8f4d02SIntel 			printf("txq=%u,%d,%d ", lcore_id, queueid, socketid);
1616cc8f4d02SIntel 			fflush(stdout);
1617cc8f4d02SIntel 			ret = rte_eth_tx_queue_setup(portid, queueid, nb_txd,
1618cc8f4d02SIntel 						     socketid, &tx_conf);
1619cc8f4d02SIntel 			if (ret < 0)
1620cc8f4d02SIntel 				rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup: err=%d, "
1621cc8f4d02SIntel 					"port=%d\n", ret, portid);
1622cc8f4d02SIntel 
1623cc8f4d02SIntel 			qconf = &lcore_conf[lcore_id];
1624cc8f4d02SIntel 			qconf->tx_queue_id[portid] = queueid;
1625595ea7dcSIntel 			setup_port_tbl(qconf, lcore_id, socketid, portid);
1626cc8f4d02SIntel 			queueid++;
1627cc8f4d02SIntel 		}
1628cc8f4d02SIntel 		printf("\n");
1629cc8f4d02SIntel 	}
1630cc8f4d02SIntel 
1631cc8f4d02SIntel 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
1632cc8f4d02SIntel 		if (rte_lcore_is_enabled(lcore_id) == 0)
1633cc8f4d02SIntel 			continue;
1634cc8f4d02SIntel 		qconf = &lcore_conf[lcore_id];
1635cc8f4d02SIntel 		printf("\nInitializing rx queues on lcore %u ... ", lcore_id );
1636cc8f4d02SIntel 		fflush(stdout);
1637cc8f4d02SIntel 		/* init RX queues */
1638cc8f4d02SIntel 		for(queue = 0; queue < qconf->n_rx_queue; ++queue) {
1639cc8f4d02SIntel 			portid = qconf->rx_queue_list[queue].port_id;
1640cc8f4d02SIntel 			queueid = qconf->rx_queue_list[queue].queue_id;
1641cc8f4d02SIntel 
1642cc8f4d02SIntel 			if (numa_on)
1643cc8f4d02SIntel 				socketid = (uint8_t)rte_lcore_to_socket_id(lcore_id);
1644cc8f4d02SIntel 			else
1645cc8f4d02SIntel 				socketid = 0;
1646cc8f4d02SIntel 
1647cc8f4d02SIntel 			printf("rxq=%d,%d,%d ", portid, queueid, socketid);
1648cc8f4d02SIntel 			fflush(stdout);
1649cc8f4d02SIntel 
1650595ea7dcSIntel 			setup_queue_tbl(qconf, lcore_id, socketid, queue);
1651cc8f4d02SIntel 
1652cc8f4d02SIntel 			ret = rte_eth_rx_queue_setup(portid, queueid, nb_rxd,
1653cc8f4d02SIntel 				        socketid, &rx_conf, qconf->pool[queue]);
1654cc8f4d02SIntel 			if (ret < 0)
1655cc8f4d02SIntel 				rte_exit(EXIT_FAILURE,
1656cc8f4d02SIntel 					"rte_eth_rx_queue_setup: err=%d,"
1657cc8f4d02SIntel 					"port=%d\n", ret, portid);
1658cc8f4d02SIntel 		}
1659cc8f4d02SIntel 	}
1660cc8f4d02SIntel 
1661cc8f4d02SIntel 	printf("\n");
1662cc8f4d02SIntel 
1663cc8f4d02SIntel 	/* start ports */
1664cc8f4d02SIntel 	for (portid = 0; portid < nb_ports; portid++) {
1665cc8f4d02SIntel 		if ((enabled_port_mask & (1 << portid)) == 0) {
1666cc8f4d02SIntel 			continue;
1667cc8f4d02SIntel 		}
1668cc8f4d02SIntel 		/* Start device */
1669cc8f4d02SIntel 		ret = rte_eth_dev_start(portid);
1670cc8f4d02SIntel 		if (ret < 0)
1671cc8f4d02SIntel 			rte_exit(EXIT_FAILURE, "rte_eth_dev_start: err=%d, port=%d\n",
1672cc8f4d02SIntel 				ret, portid);
1673cc8f4d02SIntel 
1674cc8f4d02SIntel 		/*
1675cc8f4d02SIntel 		 * If enabled, put device in promiscuous mode.
1676cc8f4d02SIntel 		 * This allows IO forwarding mode to forward packets
1677cc8f4d02SIntel 		 * to itself through 2 cross-connected  ports of the
1678cc8f4d02SIntel 		 * target machine.
1679cc8f4d02SIntel 		 */
1680cc8f4d02SIntel 		if (promiscuous_on)
1681cc8f4d02SIntel 			rte_eth_promiscuous_enable(portid);
1682cc8f4d02SIntel 	}
1683cc8f4d02SIntel 
1684cc8f4d02SIntel 	check_all_ports_link_status((uint8_t)nb_ports, enabled_port_mask);
1685cc8f4d02SIntel 
1686cc8f4d02SIntel 	signal(SIGUSR1, signal_handler);
1687cc8f4d02SIntel 	signal(SIGTERM, signal_handler);
1688cc8f4d02SIntel 	signal(SIGINT, signal_handler);
1689cc8f4d02SIntel 
1690cc8f4d02SIntel 	/* launch per-lcore init on every lcore */
1691cc8f4d02SIntel 	rte_eal_mp_remote_launch(main_loop, NULL, CALL_MASTER);
1692cc8f4d02SIntel 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
1693cc8f4d02SIntel 		if (rte_eal_wait_lcore(lcore_id) < 0)
1694cc8f4d02SIntel 			return -1;
1695cc8f4d02SIntel 	}
1696cc8f4d02SIntel 
1697cc8f4d02SIntel 	return 0;
1698cc8f4d02SIntel }
1699