main.c revision aab0c291
1/*-
2 *   BSD LICENSE
3 *
4 *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
5 *   All rights reserved.
6 *
7 *   Redistribution and use in source and binary forms, with or without
8 *   modification, are permitted provided that the following conditions
9 *   are met:
10 *
11 *     * Redistributions of source code must retain the above copyright
12 *       notice, this list of conditions and the following disclaimer.
13 *     * Redistributions in binary form must reproduce the above copyright
14 *       notice, this list of conditions and the following disclaimer in
15 *       the documentation and/or other materials provided with the
16 *       distribution.
17 *     * Neither the name of Intel Corporation nor the names of its
18 *       contributors may be used to endorse or promote products derived
19 *       from this software without specific prior written permission.
20 *
21 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <stdint.h>
38#include <inttypes.h>
39#include <sys/types.h>
40#include <sys/queue.h>
41#include <netinet/in.h>
42#include <setjmp.h>
43#include <stdarg.h>
44#include <ctype.h>
45#include <errno.h>
46#include <getopt.h>
47
48#include <rte_common.h>
49#include <rte_log.h>
50#include <rte_malloc.h>
51#include <rte_memory.h>
52#include <rte_memcpy.h>
53#include <rte_memzone.h>
54#include <rte_eal.h>
55#include <rte_per_lcore.h>
56#include <rte_launch.h>
57#include <rte_atomic.h>
58#include <rte_cycles.h>
59#include <rte_prefetch.h>
60#include <rte_lcore.h>
61#include <rte_per_lcore.h>
62#include <rte_branch_prediction.h>
63#include <rte_interrupts.h>
64#include <rte_pci.h>
65#include <rte_random.h>
66#include <rte_debug.h>
67#include <rte_ether.h>
68#include <rte_ethdev.h>
69#include <rte_mempool.h>
70#include <rte_mbuf.h>
71#include <rte_timer.h>
72#include <rte_keepalive.h>
73
74#include "shm.h"
75
76#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
77
78#define NB_MBUF   8192
79
80#define MAX_PKT_BURST 32
81#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
82
83/*
84 * Configurable number of RX/TX ring descriptors
85 */
86#define RTE_TEST_RX_DESC_DEFAULT 128
87#define RTE_TEST_TX_DESC_DEFAULT 512
88static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
89static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
90
91/* ethernet addresses of ports */
92static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
93
94/* mask of enabled ports */
95static uint32_t l2fwd_enabled_port_mask;
96
97/* list of enabled ports */
98static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
99
100static unsigned int l2fwd_rx_queue_per_lcore = 1;
101
102#define MAX_RX_QUEUE_PER_LCORE 16
103#define MAX_TX_QUEUE_PER_PORT 16
104struct lcore_queue_conf {
105	unsigned n_rx_port;
106	unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
107} __rte_cache_aligned;
108struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
109
110struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
111
112static const struct rte_eth_conf port_conf = {
113	.rxmode = {
114		.split_hdr_size = 0,
115		.header_split   = 0, /**< Header Split disabled */
116		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
117		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
118		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
119		.hw_strip_crc   = 1, /**< CRC stripped by hardware */
120	},
121	.txmode = {
122		.mq_mode = ETH_MQ_TX_NONE,
123	},
124};
125
126struct rte_mempool *l2fwd_pktmbuf_pool = NULL;
127
128/* Per-port statistics struct */
129struct l2fwd_port_statistics {
130	uint64_t tx;
131	uint64_t rx;
132	uint64_t dropped;
133} __rte_cache_aligned;
134struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
135
136/* A tsc-based timer responsible for triggering statistics printout */
137#define TIMER_MILLISECOND 1
138#define MAX_TIMER_PERIOD 86400 /* 1 day max */
139static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000; /* 10 seconds */
140static int64_t check_period = 5; /* default check cycle is 5ms */
141
142/* Keepalive structure */
143struct rte_keepalive *rte_global_keepalive_info;
144
145/* Print out statistics on packets dropped */
146static void
147print_stats(__attribute__((unused)) struct rte_timer *ptr_timer,
148	__attribute__((unused)) void *ptr_data)
149{
150	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
151	unsigned portid;
152
153	total_packets_dropped = 0;
154	total_packets_tx = 0;
155	total_packets_rx = 0;
156
157	const char clr[] = { 27, '[', '2', 'J', '\0' };
158	const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
159
160		/* Clear screen and move to top left */
161	printf("%s%s", clr, topLeft);
162
163	printf("\nPort statistics ====================================");
164
165	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
166		/* skip disabled ports */
167		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
168			continue;
169		printf("\nStatistics for port %u ------------------------------"
170			   "\nPackets sent: %24"PRIu64
171			   "\nPackets received: %20"PRIu64
172			   "\nPackets dropped: %21"PRIu64,
173			   portid,
174			   port_statistics[portid].tx,
175			   port_statistics[portid].rx,
176			   port_statistics[portid].dropped);
177
178		total_packets_dropped += port_statistics[portid].dropped;
179		total_packets_tx += port_statistics[portid].tx;
180		total_packets_rx += port_statistics[portid].rx;
181	}
182	printf("\nAggregate statistics ==============================="
183		   "\nTotal packets sent: %18"PRIu64
184		   "\nTotal packets received: %14"PRIu64
185		   "\nTotal packets dropped: %15"PRIu64,
186		   total_packets_tx,
187		   total_packets_rx,
188		   total_packets_dropped);
189	printf("\n====================================================\n");
190}
191
192static void
193l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
194{
195	struct ether_hdr *eth;
196	void *tmp;
197	int sent;
198	unsigned dst_port;
199	struct rte_eth_dev_tx_buffer *buffer;
200
201	dst_port = l2fwd_dst_ports[portid];
202	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
203
204	/* 02:00:00:00:00:xx */
205	tmp = &eth->d_addr.addr_bytes[0];
206	*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
207
208	/* src addr */
209	ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);
210
211	buffer = tx_buffer[dst_port];
212	sent = rte_eth_tx_buffer(dst_port, 0, buffer, m);
213	if (sent)
214		port_statistics[dst_port].tx += sent;
215}
216
217/* main processing loop */
218static void
219l2fwd_main_loop(void)
220{
221	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
222	struct rte_mbuf *m;
223	int sent;
224	unsigned lcore_id;
225	uint64_t prev_tsc, diff_tsc, cur_tsc;
226	unsigned i, j, portid, nb_rx;
227	struct lcore_queue_conf *qconf;
228	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1)
229		/ US_PER_S * BURST_TX_DRAIN_US;
230	struct rte_eth_dev_tx_buffer *buffer;
231
232	prev_tsc = 0;
233
234	lcore_id = rte_lcore_id();
235	qconf = &lcore_queue_conf[lcore_id];
236
237	if (qconf->n_rx_port == 0) {
238		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
239		return;
240	}
241
242	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
243
244	for (i = 0; i < qconf->n_rx_port; i++) {
245
246		portid = qconf->rx_port_list[i];
247		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
248			portid);
249	}
250
251	uint64_t tsc_initial = rte_rdtsc();
252	uint64_t tsc_lifetime = (rand()&0x07) * rte_get_tsc_hz();
253
254	while (1) {
255		/* Keepalive heartbeat */
256		rte_keepalive_mark_alive(rte_global_keepalive_info);
257
258		cur_tsc = rte_rdtsc();
259
260		/*
261		 * Die randomly within 7 secs for demo purposes if
262		 * keepalive enabled
263		 */
264		if (check_period > 0 && cur_tsc - tsc_initial > tsc_lifetime)
265			break;
266
267		/*
268		 * TX burst queue drain
269		 */
270		diff_tsc = cur_tsc - prev_tsc;
271		if (unlikely(diff_tsc > drain_tsc)) {
272
273			for (i = 0; i < qconf->n_rx_port; i++) {
274
275				portid = l2fwd_dst_ports[qconf->rx_port_list[i]];
276				buffer = tx_buffer[portid];
277
278				sent = rte_eth_tx_buffer_flush(portid, 0, buffer);
279				if (sent)
280					port_statistics[portid].tx += sent;
281
282			}
283
284			prev_tsc = cur_tsc;
285		}
286
287		/*
288		 * Read packet from RX queues
289		 */
290		for (i = 0; i < qconf->n_rx_port; i++) {
291
292			portid = qconf->rx_port_list[i];
293			nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
294						 pkts_burst, MAX_PKT_BURST);
295
296			port_statistics[portid].rx += nb_rx;
297
298			for (j = 0; j < nb_rx; j++) {
299				m = pkts_burst[j];
300				rte_prefetch0(rte_pktmbuf_mtod(m, void *));
301				l2fwd_simple_forward(m, portid);
302			}
303		}
304	}
305}
306
307static int
308l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy)
309{
310	l2fwd_main_loop();
311	return 0;
312}
313
314/* display usage */
315static void
316l2fwd_usage(const char *prgname)
317{
318	printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
319	       "  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
320	       "  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
321	       "  -K PERIOD: Keepalive check period (5 default; 86400 max)\n"
322		   "  -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n",
323	       prgname);
324}
325
326static int
327l2fwd_parse_portmask(const char *portmask)
328{
329	char *end = NULL;
330	unsigned long pm;
331
332	/* parse hexadecimal string */
333	pm = strtoul(portmask, &end, 16);
334	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
335		return -1;
336
337	if (pm == 0)
338		return -1;
339
340	return pm;
341}
342
343static unsigned int
344l2fwd_parse_nqueue(const char *q_arg)
345{
346	char *end = NULL;
347	unsigned long n;
348
349	/* parse hexadecimal string */
350	n = strtoul(q_arg, &end, 10);
351	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
352		return 0;
353	if (n == 0)
354		return 0;
355	if (n >= MAX_RX_QUEUE_PER_LCORE)
356		return 0;
357
358	return n;
359}
360
361static int
362l2fwd_parse_timer_period(const char *q_arg)
363{
364	char *end = NULL;
365	int n;
366
367	/* parse number string */
368	n = strtol(q_arg, &end, 10);
369	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
370		return -1;
371	if (n >= MAX_TIMER_PERIOD)
372		return -1;
373
374	return n;
375}
376
377static int
378l2fwd_parse_check_period(const char *q_arg)
379{
380	char *end = NULL;
381	int n;
382
383	/* parse number string */
384	n = strtol(q_arg, &end, 10);
385	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
386		return -1;
387	if (n >= MAX_TIMER_PERIOD)
388		return -1;
389
390	return n;
391}
392
393/* Parse the argument given in the command line of the application */
394static int
395l2fwd_parse_args(int argc, char **argv)
396{
397	int opt, ret;
398	char **argvopt;
399	int option_index;
400	char *prgname = argv[0];
401	static struct option lgopts[] = {
402		{NULL, 0, 0, 0}
403	};
404
405	argvopt = argv;
406
407	while ((opt = getopt_long(argc, argvopt, "p:q:T:K:",
408				  lgopts, &option_index)) != EOF) {
409
410		switch (opt) {
411		/* portmask */
412		case 'p':
413			l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
414			if (l2fwd_enabled_port_mask == 0) {
415				printf("invalid portmask\n");
416				l2fwd_usage(prgname);
417				return -1;
418			}
419			break;
420
421		/* nqueue */
422		case 'q':
423			l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
424			if (l2fwd_rx_queue_per_lcore == 0) {
425				printf("invalid queue number\n");
426				l2fwd_usage(prgname);
427				return -1;
428			}
429			break;
430
431		/* timer period */
432		case 'T':
433			timer_period = l2fwd_parse_timer_period(optarg)
434				* (int64_t)(1000 * TIMER_MILLISECOND);
435			if (timer_period < 0) {
436				printf("invalid timer period\n");
437				l2fwd_usage(prgname);
438				return -1;
439			}
440			break;
441
442		/* Check period */
443		case 'K':
444			check_period = l2fwd_parse_check_period(optarg);
445			if (check_period < 0) {
446				printf("invalid check period\n");
447				l2fwd_usage(prgname);
448				return -1;
449			}
450			break;
451
452		/* long options */
453		case 0:
454			l2fwd_usage(prgname);
455			return -1;
456
457		default:
458			l2fwd_usage(prgname);
459			return -1;
460		}
461	}
462
463	if (optind >= 0)
464		argv[optind-1] = prgname;
465
466	ret = optind-1;
467	optind = 0; /* reset getopt lib */
468	return ret;
469}
470
471/* Check the link status of all ports in up to 9s, and print them finally */
472static void
473check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
474{
475#define CHECK_INTERVAL 100 /* 100ms */
476#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
477	uint8_t portid, count, all_ports_up, print_flag = 0;
478	struct rte_eth_link link;
479
480	printf("\nChecking link status");
481	fflush(stdout);
482	for (count = 0; count <= MAX_CHECK_TIME; count++) {
483		all_ports_up = 1;
484		for (portid = 0; portid < port_num; portid++) {
485			if ((port_mask & (1 << portid)) == 0)
486				continue;
487			memset(&link, 0, sizeof(link));
488			rte_eth_link_get_nowait(portid, &link);
489			/* print link status if flag set */
490			if (print_flag == 1) {
491				if (link.link_status)
492					printf("Port %d Link Up - speed %u "
493						"Mbps - %s\n", (uint8_t)portid,
494						(unsigned)link.link_speed,
495				(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
496					("full-duplex") : ("half-duplex\n"));
497				else
498					printf("Port %d Link Down\n",
499						(uint8_t)portid);
500				continue;
501			}
502			/* clear all_ports_up flag if any link down */
503			if (link.link_status == ETH_LINK_DOWN) {
504				all_ports_up = 0;
505				break;
506			}
507		}
508		/* after finally printing all link status, get out */
509		if (print_flag == 1)
510			break;
511
512		if (all_ports_up == 0) {
513			printf(".");
514			fflush(stdout);
515			rte_delay_ms(CHECK_INTERVAL);
516		}
517
518		/* set the print_flag if all ports up or timeout */
519		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
520			print_flag = 1;
521			printf("done\n");
522		}
523	}
524}
525
526static void
527dead_core(__rte_unused void *ptr_data, const int id_core)
528{
529	printf("Dead core %i - restarting..\n", id_core);
530	if (rte_eal_get_lcore_state(id_core) == FINISHED) {
531		rte_eal_wait_lcore(id_core);
532		rte_eal_remote_launch(l2fwd_launch_one_lcore, NULL, id_core);
533	} else {
534		printf("..false positive!\n");
535	}
536}
537
538static void
539relay_core_state(void *ptr_data, const int id_core,
540	const enum rte_keepalive_state core_state, uint64_t last_alive)
541{
542	rte_keepalive_relayed_state((struct rte_keepalive_shm *)ptr_data,
543		id_core, core_state, last_alive);
544}
545
546int
547main(int argc, char **argv)
548{
549	struct lcore_queue_conf *qconf;
550	struct rte_eth_dev_info dev_info;
551	int ret;
552	uint8_t nb_ports;
553	uint8_t nb_ports_available;
554	uint8_t portid, last_port;
555	unsigned lcore_id, rx_lcore_id;
556	unsigned nb_ports_in_mask = 0;
557
558	/* init EAL */
559	ret = rte_eal_init(argc, argv);
560	if (ret < 0)
561		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
562	argc -= ret;
563	argv += ret;
564
565	l2fwd_enabled_port_mask = 0;
566
567	/* parse application arguments (after the EAL ones) */
568	ret = l2fwd_parse_args(argc, argv);
569	if (ret < 0)
570		rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
571
572	/* create the mbuf pool */
573	l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF, 32,
574		0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
575	if (l2fwd_pktmbuf_pool == NULL)
576		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
577
578	nb_ports = rte_eth_dev_count();
579	if (nb_ports == 0)
580		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
581
582	/* reset l2fwd_dst_ports */
583	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
584		l2fwd_dst_ports[portid] = 0;
585	last_port = 0;
586
587	/*
588	 * Each logical core is assigned a dedicated TX queue on each port.
589	 */
590	for (portid = 0; portid < nb_ports; portid++) {
591		/* skip ports that are not enabled */
592		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
593			continue;
594
595		if (nb_ports_in_mask % 2) {
596			l2fwd_dst_ports[portid] = last_port;
597			l2fwd_dst_ports[last_port] = portid;
598		} else
599			last_port = portid;
600
601		nb_ports_in_mask++;
602
603		rte_eth_dev_info_get(portid, &dev_info);
604	}
605	if (nb_ports_in_mask % 2) {
606		printf("Notice: odd number of ports in portmask.\n");
607		l2fwd_dst_ports[last_port] = last_port;
608	}
609
610	rx_lcore_id = 1;
611	qconf = NULL;
612
613	/* Initialize the port/queue configuration of each logical core */
614	for (portid = 0; portid < nb_ports; portid++) {
615		/* skip ports that are not enabled */
616		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
617			continue;
618
619		/* get the lcore_id for this port */
620		while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
621		       lcore_queue_conf[rx_lcore_id].n_rx_port ==
622		       l2fwd_rx_queue_per_lcore) {
623			rx_lcore_id++;
624			if (rx_lcore_id >= RTE_MAX_LCORE)
625				rte_exit(EXIT_FAILURE, "Not enough cores\n");
626		}
627
628		if (qconf != &lcore_queue_conf[rx_lcore_id])
629			/* Assigned a new logical core in the loop above. */
630			qconf = &lcore_queue_conf[rx_lcore_id];
631
632		qconf->rx_port_list[qconf->n_rx_port] = portid;
633		qconf->n_rx_port++;
634		printf("Lcore %u: RX port %u\n",
635			rx_lcore_id, (unsigned) portid);
636	}
637
638	nb_ports_available = nb_ports;
639
640	/* Initialise each port */
641	for (portid = 0; portid < nb_ports; portid++) {
642		/* skip ports that are not enabled */
643		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
644			printf("Skipping disabled port %u\n",
645				(unsigned) portid);
646			nb_ports_available--;
647			continue;
648		}
649		/* init port */
650		printf("Initializing port %u... ", (unsigned) portid);
651		fflush(stdout);
652		ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
653		if (ret < 0)
654			rte_exit(EXIT_FAILURE,
655				"Cannot configure device: err=%d, port=%u\n",
656				ret, (unsigned) portid);
657
658		rte_eth_macaddr_get(portid, &l2fwd_ports_eth_addr[portid]);
659
660		/* init one RX queue */
661		fflush(stdout);
662		ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
663					     rte_eth_dev_socket_id(portid),
664					     NULL,
665					     l2fwd_pktmbuf_pool);
666		if (ret < 0)
667			rte_exit(EXIT_FAILURE,
668				"rte_eth_rx_queue_setup:err=%d, port=%u\n",
669				ret, (unsigned) portid);
670
671		/* init one TX queue on each port */
672		fflush(stdout);
673		ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
674				rte_eth_dev_socket_id(portid),
675				NULL);
676		if (ret < 0)
677			rte_exit(EXIT_FAILURE,
678				"rte_eth_tx_queue_setup:err=%d, port=%u\n",
679				ret, (unsigned) portid);
680
681		/* Initialize TX buffers */
682		tx_buffer[portid] = rte_zmalloc_socket("tx_buffer",
683				RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
684				rte_eth_dev_socket_id(portid));
685		if (tx_buffer[portid] == NULL)
686			rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n",
687					(unsigned) portid);
688
689		rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);
690
691		ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],
692				rte_eth_tx_buffer_count_callback,
693				&port_statistics[portid].dropped);
694		if (ret < 0)
695				rte_exit(EXIT_FAILURE, "Cannot set error callback for "
696						"tx buffer on port %u\n", (unsigned) portid);
697
698		/* Start device */
699		ret = rte_eth_dev_start(portid);
700		if (ret < 0)
701			rte_exit(EXIT_FAILURE,
702				"rte_eth_dev_start:err=%d, port=%u\n",
703				  ret, (unsigned) portid);
704
705		rte_eth_promiscuous_enable(portid);
706
707		printf("Port %u, MAC address: "
708			"%02X:%02X:%02X:%02X:%02X:%02X\n\n",
709			(unsigned) portid,
710			l2fwd_ports_eth_addr[portid].addr_bytes[0],
711			l2fwd_ports_eth_addr[portid].addr_bytes[1],
712			l2fwd_ports_eth_addr[portid].addr_bytes[2],
713			l2fwd_ports_eth_addr[portid].addr_bytes[3],
714			l2fwd_ports_eth_addr[portid].addr_bytes[4],
715			l2fwd_ports_eth_addr[portid].addr_bytes[5]);
716
717		/* initialize port stats */
718		memset(&port_statistics, 0, sizeof(port_statistics));
719	}
720
721	if (!nb_ports_available) {
722		rte_exit(EXIT_FAILURE,
723			"All available ports are disabled. Please set portmask.\n");
724	}
725
726	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
727
728	struct rte_timer hb_timer, stats_timer;
729
730	rte_timer_subsystem_init();
731	rte_timer_init(&stats_timer);
732
733	if (check_period > 0) {
734		struct rte_keepalive_shm *ka_shm;
735
736		ka_shm = rte_keepalive_shm_create();
737		if (ka_shm == NULL)
738			rte_exit(EXIT_FAILURE,
739				"rte_keepalive_shm_create() failed");
740		rte_global_keepalive_info =
741			rte_keepalive_create(&dead_core, ka_shm);
742		if (rte_global_keepalive_info == NULL)
743			rte_exit(EXIT_FAILURE, "init_keep_alive() failed");
744		rte_keepalive_register_relay_callback(rte_global_keepalive_info,
745			relay_core_state, ka_shm);
746		rte_timer_init(&hb_timer);
747		if (rte_timer_reset(&hb_timer,
748				(check_period * rte_get_timer_hz()) / 1000,
749				PERIODICAL,
750				rte_lcore_id(),
751				(void(*)(struct rte_timer*, void*))
752				&rte_keepalive_dispatch_pings,
753				rte_global_keepalive_info
754				) != 0 )
755			rte_exit(EXIT_FAILURE, "Keepalive setup failure.\n");
756	}
757	if (timer_period > 0) {
758		if (rte_timer_reset(&stats_timer,
759				(timer_period * rte_get_timer_hz()) / 1000,
760				PERIODICAL,
761				rte_lcore_id(),
762				&print_stats, NULL
763				) != 0 )
764			rte_exit(EXIT_FAILURE, "Stats setup failure.\n");
765	}
766	/* launch per-lcore init on every slave lcore */
767	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
768		struct lcore_queue_conf *qconf = &lcore_queue_conf[lcore_id];
769
770		if (qconf->n_rx_port == 0)
771			RTE_LOG(INFO, L2FWD,
772				"lcore %u has nothing to do\n",
773				lcore_id
774				);
775		else {
776			rte_eal_remote_launch(
777				l2fwd_launch_one_lcore,
778				NULL,
779				lcore_id
780				);
781			rte_keepalive_register_core(rte_global_keepalive_info,
782				lcore_id);
783		}
784	}
785	for (;;) {
786		rte_timer_manage();
787		rte_delay_ms(5);
788		}
789
790	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
791		if (rte_eal_wait_lcore(lcore_id) < 0)
792			return -1;
793	}
794
795	return 0;
796}
797