1*2bfe3f2eSlogwang /*-
2*2bfe3f2eSlogwang  *   BSD LICENSE
3*2bfe3f2eSlogwang  *
4*2bfe3f2eSlogwang  *   Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
5*2bfe3f2eSlogwang  *   All rights reserved.
6*2bfe3f2eSlogwang  *
7*2bfe3f2eSlogwang  *   Redistribution and use in source and binary forms, with or without
8*2bfe3f2eSlogwang  *   modification, are permitted provided that the following conditions
9*2bfe3f2eSlogwang  *   are met:
10*2bfe3f2eSlogwang  *
11*2bfe3f2eSlogwang  *     * Redistributions of source code must retain the above copyright
12*2bfe3f2eSlogwang  *       notice, this list of conditions and the following disclaimer.
13*2bfe3f2eSlogwang  *     * Redistributions in binary form must reproduce the above copyright
14*2bfe3f2eSlogwang  *       notice, this list of conditions and the following disclaimer in
15*2bfe3f2eSlogwang  *       the documentation and/or other materials provided with the
16*2bfe3f2eSlogwang  *       distribution.
17*2bfe3f2eSlogwang  *     * Neither the name of Intel Corporation nor the names of its
18*2bfe3f2eSlogwang  *       contributors may be used to endorse or promote products derived
19*2bfe3f2eSlogwang  *       from this software without specific prior written permission.
20*2bfe3f2eSlogwang  *
21*2bfe3f2eSlogwang  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22*2bfe3f2eSlogwang  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23*2bfe3f2eSlogwang  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24*2bfe3f2eSlogwang  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25*2bfe3f2eSlogwang  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26*2bfe3f2eSlogwang  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27*2bfe3f2eSlogwang  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28*2bfe3f2eSlogwang  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29*2bfe3f2eSlogwang  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30*2bfe3f2eSlogwang  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31*2bfe3f2eSlogwang  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32*2bfe3f2eSlogwang  */
33*2bfe3f2eSlogwang 
34*2bfe3f2eSlogwang #include <stdint.h>
35*2bfe3f2eSlogwang #include <stdio.h>
36*2bfe3f2eSlogwang #include <inttypes.h>
37*2bfe3f2eSlogwang #include <stdarg.h>
38*2bfe3f2eSlogwang #include <errno.h>
39*2bfe3f2eSlogwang #include <sys/queue.h>
40*2bfe3f2eSlogwang #include <stdlib.h>
41*2bfe3f2eSlogwang #include <getopt.h>
42*2bfe3f2eSlogwang #include <string.h>
43*2bfe3f2eSlogwang 
44*2bfe3f2eSlogwang #include <rte_common.h>
45*2bfe3f2eSlogwang #include <rte_malloc.h>
46*2bfe3f2eSlogwang #include <rte_memory.h>
47*2bfe3f2eSlogwang #include <rte_memzone.h>
48*2bfe3f2eSlogwang #include <rte_eal.h>
49*2bfe3f2eSlogwang #include <rte_atomic.h>
50*2bfe3f2eSlogwang #include <rte_branch_prediction.h>
51*2bfe3f2eSlogwang #include <rte_log.h>
52*2bfe3f2eSlogwang #include <rte_per_lcore.h>
53*2bfe3f2eSlogwang #include <rte_launch.h>
54*2bfe3f2eSlogwang #include <rte_lcore.h>
55*2bfe3f2eSlogwang #include <rte_ring.h>
56*2bfe3f2eSlogwang #include <rte_debug.h>
57*2bfe3f2eSlogwang #include <rte_mempool.h>
58*2bfe3f2eSlogwang #include <rte_mbuf.h>
59*2bfe3f2eSlogwang #include <rte_interrupts.h>
60*2bfe3f2eSlogwang #include <rte_ether.h>
61*2bfe3f2eSlogwang #include <rte_ethdev.h>
62*2bfe3f2eSlogwang #include <rte_string_fns.h>
63*2bfe3f2eSlogwang #include <rte_ip.h>
64*2bfe3f2eSlogwang 
65*2bfe3f2eSlogwang #include "common.h"
66*2bfe3f2eSlogwang 
67*2bfe3f2eSlogwang /* Number of packets to attempt to read from queue */
68*2bfe3f2eSlogwang #define PKT_READ_SIZE  ((uint16_t)32)
69*2bfe3f2eSlogwang 
70*2bfe3f2eSlogwang /*
71*2bfe3f2eSlogwang  * Our node id number - tells us which rx queue to read, and NIC TX
72*2bfe3f2eSlogwang  * queue to write to.
73*2bfe3f2eSlogwang  */
74*2bfe3f2eSlogwang static uint8_t node_id;
75*2bfe3f2eSlogwang 
76*2bfe3f2eSlogwang #define MBQ_CAPACITY 32
77*2bfe3f2eSlogwang 
78*2bfe3f2eSlogwang /* maps input ports to output ports for packets */
79*2bfe3f2eSlogwang static uint16_t output_ports[RTE_MAX_ETHPORTS];
80*2bfe3f2eSlogwang 
81*2bfe3f2eSlogwang /* buffers up a set of packet that are ready to send */
82*2bfe3f2eSlogwang struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
83*2bfe3f2eSlogwang 
84*2bfe3f2eSlogwang /* shared data from server. We update statistics here */
85*2bfe3f2eSlogwang static struct tx_stats *tx_stats;
86*2bfe3f2eSlogwang 
87*2bfe3f2eSlogwang static struct filter_stats *filter_stats;
88*2bfe3f2eSlogwang 
89*2bfe3f2eSlogwang /*
90*2bfe3f2eSlogwang  * print a usage message
91*2bfe3f2eSlogwang  */
92*2bfe3f2eSlogwang static void
93*2bfe3f2eSlogwang usage(const char *progname)
94*2bfe3f2eSlogwang {
95*2bfe3f2eSlogwang 	printf("Usage: %s [EAL args] -- -n <node_id>\n\n", progname);
96*2bfe3f2eSlogwang }
97*2bfe3f2eSlogwang 
98*2bfe3f2eSlogwang /*
99*2bfe3f2eSlogwang  * Convert the node id number from a string to an int.
100*2bfe3f2eSlogwang  */
101*2bfe3f2eSlogwang static int
102*2bfe3f2eSlogwang parse_node_num(const char *node)
103*2bfe3f2eSlogwang {
104*2bfe3f2eSlogwang 	char *end = NULL;
105*2bfe3f2eSlogwang 	unsigned long temp;
106*2bfe3f2eSlogwang 
107*2bfe3f2eSlogwang 	if (node == NULL || *node == '\0')
108*2bfe3f2eSlogwang 		return -1;
109*2bfe3f2eSlogwang 
110*2bfe3f2eSlogwang 	temp = strtoul(node, &end, 10);
111*2bfe3f2eSlogwang 	if (end == NULL || *end != '\0')
112*2bfe3f2eSlogwang 		return -1;
113*2bfe3f2eSlogwang 
114*2bfe3f2eSlogwang 	node_id = (uint8_t)temp;
115*2bfe3f2eSlogwang 	return 0;
116*2bfe3f2eSlogwang }
117*2bfe3f2eSlogwang 
118*2bfe3f2eSlogwang /*
119*2bfe3f2eSlogwang  * Parse the application arguments to the node app.
120*2bfe3f2eSlogwang  */
121*2bfe3f2eSlogwang static int
122*2bfe3f2eSlogwang parse_app_args(int argc, char *argv[])
123*2bfe3f2eSlogwang {
124*2bfe3f2eSlogwang 	int option_index, opt;
125*2bfe3f2eSlogwang 	char **argvopt = argv;
126*2bfe3f2eSlogwang 	const char *progname = NULL;
127*2bfe3f2eSlogwang 	static struct option lgopts[] = { /* no long options */
128*2bfe3f2eSlogwang 		{NULL, 0, 0, 0 }
129*2bfe3f2eSlogwang 	};
130*2bfe3f2eSlogwang 	progname = argv[0];
131*2bfe3f2eSlogwang 
132*2bfe3f2eSlogwang 	while ((opt = getopt_long(argc, argvopt, "n:", lgopts,
133*2bfe3f2eSlogwang 		&option_index)) != EOF) {
134*2bfe3f2eSlogwang 		switch (opt) {
135*2bfe3f2eSlogwang 		case 'n':
136*2bfe3f2eSlogwang 			if (parse_node_num(optarg) != 0) {
137*2bfe3f2eSlogwang 				usage(progname);
138*2bfe3f2eSlogwang 				return -1;
139*2bfe3f2eSlogwang 			}
140*2bfe3f2eSlogwang 			break;
141*2bfe3f2eSlogwang 		default:
142*2bfe3f2eSlogwang 			usage(progname);
143*2bfe3f2eSlogwang 			return -1;
144*2bfe3f2eSlogwang 		}
145*2bfe3f2eSlogwang 	}
146*2bfe3f2eSlogwang 	return 0;
147*2bfe3f2eSlogwang }
148*2bfe3f2eSlogwang 
149*2bfe3f2eSlogwang /*
150*2bfe3f2eSlogwang  * Tx buffer error callback
151*2bfe3f2eSlogwang  */
152*2bfe3f2eSlogwang static void
153*2bfe3f2eSlogwang flush_tx_error_callback(struct rte_mbuf **unsent, uint16_t count,
154*2bfe3f2eSlogwang 		void *userdata) {
155*2bfe3f2eSlogwang 	int i;
156*2bfe3f2eSlogwang 	uint16_t port_id = (uintptr_t)userdata;
157*2bfe3f2eSlogwang 
158*2bfe3f2eSlogwang 	tx_stats->tx_drop[port_id] += count;
159*2bfe3f2eSlogwang 
160*2bfe3f2eSlogwang 	/* free the mbufs which failed from transmit */
161*2bfe3f2eSlogwang 	for (i = 0; i < count; i++)
162*2bfe3f2eSlogwang 		rte_pktmbuf_free(unsent[i]);
163*2bfe3f2eSlogwang 
164*2bfe3f2eSlogwang }
165*2bfe3f2eSlogwang 
166*2bfe3f2eSlogwang static void
167*2bfe3f2eSlogwang configure_tx_buffer(uint16_t port_id, uint16_t size)
168*2bfe3f2eSlogwang {
169*2bfe3f2eSlogwang 	int ret;
170*2bfe3f2eSlogwang 
171*2bfe3f2eSlogwang 	/* Initialize TX buffers */
172*2bfe3f2eSlogwang 	tx_buffer[port_id] = rte_zmalloc_socket("tx_buffer",
173*2bfe3f2eSlogwang 			RTE_ETH_TX_BUFFER_SIZE(size), 0,
174*2bfe3f2eSlogwang 			rte_eth_dev_socket_id(port_id));
175*2bfe3f2eSlogwang 	if (tx_buffer[port_id] == NULL)
176*2bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE,
177*2bfe3f2eSlogwang 			"Cannot allocate buffer for tx on port %u\n", port_id);
178*2bfe3f2eSlogwang 
179*2bfe3f2eSlogwang 	rte_eth_tx_buffer_init(tx_buffer[port_id], size);
180*2bfe3f2eSlogwang 
181*2bfe3f2eSlogwang 	ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[port_id],
182*2bfe3f2eSlogwang 			flush_tx_error_callback, (void *)(intptr_t)port_id);
183*2bfe3f2eSlogwang 	if (ret < 0)
184*2bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE,
185*2bfe3f2eSlogwang 			"Cannot set error callback for tx buffer on port %u\n",
186*2bfe3f2eSlogwang 			port_id);
187*2bfe3f2eSlogwang }
188*2bfe3f2eSlogwang 
189*2bfe3f2eSlogwang /*
190*2bfe3f2eSlogwang  * set up output ports so that all traffic on port gets sent out
191*2bfe3f2eSlogwang  * its paired port. Index using actual port numbers since that is
192*2bfe3f2eSlogwang  * what comes in the mbuf structure.
193*2bfe3f2eSlogwang  */
194*2bfe3f2eSlogwang static void
195*2bfe3f2eSlogwang configure_output_ports(const struct shared_info *info)
196*2bfe3f2eSlogwang {
197*2bfe3f2eSlogwang 	int i;
198*2bfe3f2eSlogwang 
199*2bfe3f2eSlogwang 	if (info->num_ports > RTE_MAX_ETHPORTS)
200*2bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Too many ethernet ports. "
201*2bfe3f2eSlogwang 				"RTE_MAX_ETHPORTS = %u\n",
202*2bfe3f2eSlogwang 				(unsigned int)RTE_MAX_ETHPORTS);
203*2bfe3f2eSlogwang 	for (i = 0; i < info->num_ports - 1; i += 2) {
204*2bfe3f2eSlogwang 		uint8_t p1 = info->id[i];
205*2bfe3f2eSlogwang 		uint8_t p2 = info->id[i+1];
206*2bfe3f2eSlogwang 
207*2bfe3f2eSlogwang 		output_ports[p1] = p2;
208*2bfe3f2eSlogwang 		output_ports[p2] = p1;
209*2bfe3f2eSlogwang 
210*2bfe3f2eSlogwang 		configure_tx_buffer(p1, MBQ_CAPACITY);
211*2bfe3f2eSlogwang 		configure_tx_buffer(p2, MBQ_CAPACITY);
212*2bfe3f2eSlogwang 
213*2bfe3f2eSlogwang 	}
214*2bfe3f2eSlogwang }
215*2bfe3f2eSlogwang 
216*2bfe3f2eSlogwang /*
217*2bfe3f2eSlogwang  * Create the hash table that will contain the flows that
218*2bfe3f2eSlogwang  * the node will handle, which will be used to decide if packet
219*2bfe3f2eSlogwang  * is transmitted or dropped.
220*2bfe3f2eSlogwang  */
221*2bfe3f2eSlogwang static struct rte_hash *
222*2bfe3f2eSlogwang create_hash_table(const struct shared_info *info)
223*2bfe3f2eSlogwang {
224*2bfe3f2eSlogwang 	uint32_t num_flows_node = info->num_flows / info->num_nodes;
225*2bfe3f2eSlogwang 	char name[RTE_HASH_NAMESIZE];
226*2bfe3f2eSlogwang 	struct rte_hash *h;
227*2bfe3f2eSlogwang 
228*2bfe3f2eSlogwang 	/* create table */
229*2bfe3f2eSlogwang 	struct rte_hash_parameters hash_params = {
230*2bfe3f2eSlogwang 		.entries = num_flows_node * 2, /* table load = 50% */
231*2bfe3f2eSlogwang 		.key_len = sizeof(uint32_t), /* Store IPv4 dest IP address */
232*2bfe3f2eSlogwang 		.socket_id = rte_socket_id(),
233*2bfe3f2eSlogwang 		.hash_func_init_val = 0,
234*2bfe3f2eSlogwang 	};
235*2bfe3f2eSlogwang 
236*2bfe3f2eSlogwang 	snprintf(name, sizeof(name), "hash_table_%d", node_id);
237*2bfe3f2eSlogwang 	hash_params.name = name;
238*2bfe3f2eSlogwang 	h = rte_hash_create(&hash_params);
239*2bfe3f2eSlogwang 
240*2bfe3f2eSlogwang 	if (h == NULL)
241*2bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE,
242*2bfe3f2eSlogwang 				"Problem creating the hash table for node %d\n",
243*2bfe3f2eSlogwang 				node_id);
244*2bfe3f2eSlogwang 	return h;
245*2bfe3f2eSlogwang }
246*2bfe3f2eSlogwang 
247*2bfe3f2eSlogwang static void
248*2bfe3f2eSlogwang populate_hash_table(const struct rte_hash *h, const struct shared_info *info)
249*2bfe3f2eSlogwang {
250*2bfe3f2eSlogwang 	unsigned int i;
251*2bfe3f2eSlogwang 	int32_t ret;
252*2bfe3f2eSlogwang 	uint32_t ip_dst;
253*2bfe3f2eSlogwang 	uint32_t num_flows_node = 0;
254*2bfe3f2eSlogwang 	uint64_t target_node;
255*2bfe3f2eSlogwang 
256*2bfe3f2eSlogwang 	/* Add flows in table */
257*2bfe3f2eSlogwang 	for (i = 0; i < info->num_flows; i++) {
258*2bfe3f2eSlogwang 		target_node = i % info->num_nodes;
259*2bfe3f2eSlogwang 		if (target_node != node_id)
260*2bfe3f2eSlogwang 			continue;
261*2bfe3f2eSlogwang 
262*2bfe3f2eSlogwang 		ip_dst = rte_cpu_to_be_32(i);
263*2bfe3f2eSlogwang 
264*2bfe3f2eSlogwang 		ret = rte_hash_add_key(h, (void *) &ip_dst);
265*2bfe3f2eSlogwang 		if (ret < 0)
266*2bfe3f2eSlogwang 			rte_exit(EXIT_FAILURE, "Unable to add entry %u "
267*2bfe3f2eSlogwang 					"in hash table\n", i);
268*2bfe3f2eSlogwang 		else
269*2bfe3f2eSlogwang 			num_flows_node++;
270*2bfe3f2eSlogwang 
271*2bfe3f2eSlogwang 	}
272*2bfe3f2eSlogwang 
273*2bfe3f2eSlogwang 	printf("Hash table: Adding 0x%x keys\n", num_flows_node);
274*2bfe3f2eSlogwang }
275*2bfe3f2eSlogwang 
276*2bfe3f2eSlogwang /*
277*2bfe3f2eSlogwang  * This function performs routing of packets
278*2bfe3f2eSlogwang  * Just sends each input packet out an output port based solely on the input
279*2bfe3f2eSlogwang  * port it arrived on.
280*2bfe3f2eSlogwang  */
281*2bfe3f2eSlogwang static inline void
282*2bfe3f2eSlogwang transmit_packet(struct rte_mbuf *buf)
283*2bfe3f2eSlogwang {
284*2bfe3f2eSlogwang 	int sent;
285*2bfe3f2eSlogwang 	const uint16_t in_port = buf->port;
286*2bfe3f2eSlogwang 	const uint16_t out_port = output_ports[in_port];
287*2bfe3f2eSlogwang 	struct rte_eth_dev_tx_buffer *buffer = tx_buffer[out_port];
288*2bfe3f2eSlogwang 
289*2bfe3f2eSlogwang 	sent = rte_eth_tx_buffer(out_port, node_id, buffer, buf);
290*2bfe3f2eSlogwang 	if (sent)
291*2bfe3f2eSlogwang 		tx_stats->tx[out_port] += sent;
292*2bfe3f2eSlogwang 
293*2bfe3f2eSlogwang }
294*2bfe3f2eSlogwang 
295*2bfe3f2eSlogwang static inline void
296*2bfe3f2eSlogwang handle_packets(struct rte_hash *h, struct rte_mbuf **bufs, uint16_t num_packets)
297*2bfe3f2eSlogwang {
298*2bfe3f2eSlogwang 	struct ipv4_hdr *ipv4_hdr;
299*2bfe3f2eSlogwang 	uint32_t ipv4_dst_ip[PKT_READ_SIZE];
300*2bfe3f2eSlogwang 	const void *key_ptrs[PKT_READ_SIZE];
301*2bfe3f2eSlogwang 	unsigned int i;
302*2bfe3f2eSlogwang 	int32_t positions[PKT_READ_SIZE] = {0};
303*2bfe3f2eSlogwang 
304*2bfe3f2eSlogwang 	for (i = 0; i < num_packets; i++) {
305*2bfe3f2eSlogwang 		/* Handle IPv4 header.*/
306*2bfe3f2eSlogwang 		ipv4_hdr = rte_pktmbuf_mtod_offset(bufs[i], struct ipv4_hdr *,
307*2bfe3f2eSlogwang 				sizeof(struct ether_hdr));
308*2bfe3f2eSlogwang 		ipv4_dst_ip[i] = ipv4_hdr->dst_addr;
309*2bfe3f2eSlogwang 		key_ptrs[i] = &ipv4_dst_ip[i];
310*2bfe3f2eSlogwang 	}
311*2bfe3f2eSlogwang 	/* Check if packets belongs to any flows handled by this node */
312*2bfe3f2eSlogwang 	rte_hash_lookup_bulk(h, key_ptrs, num_packets, positions);
313*2bfe3f2eSlogwang 
314*2bfe3f2eSlogwang 	for (i = 0; i < num_packets; i++) {
315*2bfe3f2eSlogwang 		if (likely(positions[i] >= 0)) {
316*2bfe3f2eSlogwang 			filter_stats->passed++;
317*2bfe3f2eSlogwang 			transmit_packet(bufs[i]);
318*2bfe3f2eSlogwang 		} else {
319*2bfe3f2eSlogwang 			filter_stats->drop++;
320*2bfe3f2eSlogwang 			/* Drop packet, as flow is not handled by this node */
321*2bfe3f2eSlogwang 			rte_pktmbuf_free(bufs[i]);
322*2bfe3f2eSlogwang 		}
323*2bfe3f2eSlogwang 	}
324*2bfe3f2eSlogwang }
325*2bfe3f2eSlogwang 
326*2bfe3f2eSlogwang /*
327*2bfe3f2eSlogwang  * Application main function - loops through
328*2bfe3f2eSlogwang  * receiving and processing packets. Never returns
329*2bfe3f2eSlogwang  */
330*2bfe3f2eSlogwang int
331*2bfe3f2eSlogwang main(int argc, char *argv[])
332*2bfe3f2eSlogwang {
333*2bfe3f2eSlogwang 	const struct rte_memzone *mz;
334*2bfe3f2eSlogwang 	struct rte_ring *rx_ring;
335*2bfe3f2eSlogwang 	struct rte_hash *h;
336*2bfe3f2eSlogwang 	struct rte_mempool *mp;
337*2bfe3f2eSlogwang 	struct shared_info *info;
338*2bfe3f2eSlogwang 	int need_flush = 0; /* indicates whether we have unsent packets */
339*2bfe3f2eSlogwang 	int retval;
340*2bfe3f2eSlogwang 	void *pkts[PKT_READ_SIZE];
341*2bfe3f2eSlogwang 	uint16_t sent;
342*2bfe3f2eSlogwang 
343*2bfe3f2eSlogwang 	retval = rte_eal_init(argc, argv);
344*2bfe3f2eSlogwang 	if (retval  < 0)
345*2bfe3f2eSlogwang 		return -1;
346*2bfe3f2eSlogwang 	argc -= retval;
347*2bfe3f2eSlogwang 	argv += retval;
348*2bfe3f2eSlogwang 
349*2bfe3f2eSlogwang 	if (parse_app_args(argc, argv) < 0)
350*2bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Invalid command-line arguments\n");
351*2bfe3f2eSlogwang 
352*2bfe3f2eSlogwang 	if (rte_eth_dev_count() == 0)
353*2bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
354*2bfe3f2eSlogwang 
355*2bfe3f2eSlogwang 	rx_ring = rte_ring_lookup(get_rx_queue_name(node_id));
356*2bfe3f2eSlogwang 	if (rx_ring == NULL)
357*2bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Cannot get RX ring - "
358*2bfe3f2eSlogwang 				"is server process running?\n");
359*2bfe3f2eSlogwang 
360*2bfe3f2eSlogwang 	mp = rte_mempool_lookup(PKTMBUF_POOL_NAME);
361*2bfe3f2eSlogwang 	if (mp == NULL)
362*2bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Cannot get mempool for mbufs\n");
363*2bfe3f2eSlogwang 
364*2bfe3f2eSlogwang 	mz = rte_memzone_lookup(MZ_SHARED_INFO);
365*2bfe3f2eSlogwang 	if (mz == NULL)
366*2bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Cannot get port info structure\n");
367*2bfe3f2eSlogwang 	info = mz->addr;
368*2bfe3f2eSlogwang 	tx_stats = &(info->tx_stats[node_id]);
369*2bfe3f2eSlogwang 	filter_stats = &(info->filter_stats[node_id]);
370*2bfe3f2eSlogwang 
371*2bfe3f2eSlogwang 	configure_output_ports(info);
372*2bfe3f2eSlogwang 
373*2bfe3f2eSlogwang 	h = create_hash_table(info);
374*2bfe3f2eSlogwang 
375*2bfe3f2eSlogwang 	populate_hash_table(h, info);
376*2bfe3f2eSlogwang 
377*2bfe3f2eSlogwang 	RTE_LOG(INFO, APP, "Finished Process Init.\n");
378*2bfe3f2eSlogwang 
379*2bfe3f2eSlogwang 	printf("\nNode process %d handling packets\n", node_id);
380*2bfe3f2eSlogwang 	printf("[Press Ctrl-C to quit ...]\n");
381*2bfe3f2eSlogwang 
382*2bfe3f2eSlogwang 	for (;;) {
383*2bfe3f2eSlogwang 		uint16_t  rx_pkts = PKT_READ_SIZE;
384*2bfe3f2eSlogwang 		uint16_t port;
385*2bfe3f2eSlogwang 
386*2bfe3f2eSlogwang 		/*
387*2bfe3f2eSlogwang 		 * Try dequeuing max possible packets first, if that fails,
388*2bfe3f2eSlogwang 		 * get the most we can. Loop body should only execute once,
389*2bfe3f2eSlogwang 		 * maximum
390*2bfe3f2eSlogwang 		 */
391*2bfe3f2eSlogwang 		while (rx_pkts > 0 &&
392*2bfe3f2eSlogwang 				unlikely(rte_ring_dequeue_bulk(rx_ring, pkts,
393*2bfe3f2eSlogwang 					rx_pkts, NULL) == 0))
394*2bfe3f2eSlogwang 			rx_pkts = (uint16_t)RTE_MIN(rte_ring_count(rx_ring),
395*2bfe3f2eSlogwang 					PKT_READ_SIZE);
396*2bfe3f2eSlogwang 
397*2bfe3f2eSlogwang 		if (unlikely(rx_pkts == 0)) {
398*2bfe3f2eSlogwang 			if (need_flush)
399*2bfe3f2eSlogwang 				for (port = 0; port < info->num_ports; port++) {
400*2bfe3f2eSlogwang 					sent = rte_eth_tx_buffer_flush(
401*2bfe3f2eSlogwang 							info->id[port],
402*2bfe3f2eSlogwang 							node_id,
403*2bfe3f2eSlogwang 							tx_buffer[port]);
404*2bfe3f2eSlogwang 					if (unlikely(sent))
405*2bfe3f2eSlogwang 						tx_stats->tx[port] += sent;
406*2bfe3f2eSlogwang 				}
407*2bfe3f2eSlogwang 			need_flush = 0;
408*2bfe3f2eSlogwang 			continue;
409*2bfe3f2eSlogwang 		}
410*2bfe3f2eSlogwang 
411*2bfe3f2eSlogwang 		handle_packets(h, (struct rte_mbuf **)pkts, rx_pkts);
412*2bfe3f2eSlogwang 
413*2bfe3f2eSlogwang 		need_flush = 1;
414*2bfe3f2eSlogwang 	}
415*2bfe3f2eSlogwang }
416