13998e2a0SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 23998e2a0SBruce Richardson * Copyright(c) 2010-2016 Intel Corporation 3e64833f2SRemy Horton */ 4e64833f2SRemy Horton 5e64833f2SRemy Horton #include <stdio.h> 6e64833f2SRemy Horton #include <stdlib.h> 7e64833f2SRemy Horton #include <string.h> 8e64833f2SRemy Horton #include <stdint.h> 9e64833f2SRemy Horton #include <inttypes.h> 10e64833f2SRemy Horton #include <sys/types.h> 11e64833f2SRemy Horton #include <sys/queue.h> 12e64833f2SRemy Horton #include <netinet/in.h> 13e64833f2SRemy Horton #include <setjmp.h> 14e64833f2SRemy Horton #include <stdarg.h> 15e64833f2SRemy Horton #include <ctype.h> 16e64833f2SRemy Horton #include <errno.h> 17e64833f2SRemy Horton #include <getopt.h> 1891e89e47SRemy Horton #include <signal.h> 19e64833f2SRemy Horton 20e64833f2SRemy Horton #include <rte_common.h> 21e64833f2SRemy Horton #include <rte_log.h> 22e2366e74STomasz Kulasek #include <rte_malloc.h> 23e64833f2SRemy Horton #include <rte_memory.h> 24e64833f2SRemy Horton #include <rte_memcpy.h> 25e64833f2SRemy Horton #include <rte_eal.h> 26e64833f2SRemy Horton #include <rte_launch.h> 27e64833f2SRemy Horton #include <rte_atomic.h> 28e64833f2SRemy Horton #include <rte_cycles.h> 29e64833f2SRemy Horton #include <rte_prefetch.h> 30e64833f2SRemy Horton #include <rte_lcore.h> 31e64833f2SRemy Horton #include <rte_per_lcore.h> 32e64833f2SRemy Horton #include <rte_branch_prediction.h> 33e64833f2SRemy Horton #include <rte_interrupts.h> 34e64833f2SRemy Horton #include <rte_random.h> 35e64833f2SRemy Horton #include <rte_debug.h> 36e64833f2SRemy Horton #include <rte_ether.h> 37e64833f2SRemy Horton #include <rte_ethdev.h> 38e64833f2SRemy Horton #include <rte_mempool.h> 39e64833f2SRemy Horton #include <rte_mbuf.h> 40e64833f2SRemy Horton #include <rte_timer.h> 41e64833f2SRemy Horton #include <rte_keepalive.h> 42e64833f2SRemy Horton 437b2a704cSRemy Horton #include "shm.h" 447b2a704cSRemy Horton 45e64833f2SRemy Horton #define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1 46e64833f2SRemy Horton 470c2b79e8SLouise Kilheeney #define NB_MBUF_PER_PORT 3000 48e64833f2SRemy Horton 49e64833f2SRemy Horton #define MAX_PKT_BURST 32 50e64833f2SRemy Horton #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */ 51e64833f2SRemy Horton 52e64833f2SRemy Horton /* 53e64833f2SRemy Horton * Configurable number of RX/TX ring descriptors 54e64833f2SRemy Horton */ 55867a6c66SKevin Laatz #define RTE_TEST_RX_DESC_DEFAULT 1024 56867a6c66SKevin Laatz #define RTE_TEST_TX_DESC_DEFAULT 1024 57e64833f2SRemy Horton static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; 58e64833f2SRemy Horton static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; 59e64833f2SRemy Horton 60e64833f2SRemy Horton /* ethernet addresses of ports */ 616d13ea8eSOlivier Matz static struct rte_ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS]; 62e64833f2SRemy Horton 63e64833f2SRemy Horton /* mask of enabled ports */ 64e64833f2SRemy Horton static uint32_t l2fwd_enabled_port_mask; 65e64833f2SRemy Horton 66e64833f2SRemy Horton /* list of enabled ports */ 67e64833f2SRemy Horton static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS]; 68e64833f2SRemy Horton 69e64833f2SRemy Horton static unsigned int l2fwd_rx_queue_per_lcore = 1; 70e64833f2SRemy Horton 71e64833f2SRemy Horton #define MAX_RX_QUEUE_PER_LCORE 16 72e64833f2SRemy Horton #define MAX_TX_QUEUE_PER_PORT 16 73e64833f2SRemy Horton struct lcore_queue_conf { 74e64833f2SRemy Horton unsigned n_rx_port; 75e64833f2SRemy Horton unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE]; 76e64833f2SRemy Horton } __rte_cache_aligned; 77e64833f2SRemy Horton struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE]; 78e64833f2SRemy Horton 79e2366e74STomasz Kulasek struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS]; 80e2366e74STomasz Kulasek 81563e239bSShahaf Shuler static struct rte_eth_conf port_conf = { 82e64833f2SRemy Horton .rxmode = { 83e64833f2SRemy Horton .split_hdr_size = 0, 84e64833f2SRemy Horton }, 85e64833f2SRemy Horton .txmode = { 86e64833f2SRemy Horton .mq_mode = ETH_MQ_TX_NONE, 87e64833f2SRemy Horton }, 88e64833f2SRemy Horton }; 89e64833f2SRemy Horton 90e64833f2SRemy Horton struct rte_mempool *l2fwd_pktmbuf_pool = NULL; 91e64833f2SRemy Horton 92e64833f2SRemy Horton /* Per-port statistics struct */ 93e64833f2SRemy Horton struct l2fwd_port_statistics { 94e64833f2SRemy Horton uint64_t tx; 95e64833f2SRemy Horton uint64_t rx; 96e64833f2SRemy Horton uint64_t dropped; 97e64833f2SRemy Horton } __rte_cache_aligned; 98e64833f2SRemy Horton struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS]; 99e64833f2SRemy Horton 100e64833f2SRemy Horton /* A tsc-based timer responsible for triggering statistics printout */ 101e64833f2SRemy Horton #define TIMER_MILLISECOND 1 102e64833f2SRemy Horton #define MAX_TIMER_PERIOD 86400 /* 1 day max */ 103e64833f2SRemy Horton static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000; /* 10 seconds */ 104e64833f2SRemy Horton static int64_t check_period = 5; /* default check cycle is 5ms */ 105e64833f2SRemy Horton 106e64833f2SRemy Horton /* Keepalive structure */ 107e64833f2SRemy Horton struct rte_keepalive *rte_global_keepalive_info; 108e64833f2SRemy Horton 10991e89e47SRemy Horton /* Termination signalling */ 11091e89e47SRemy Horton static int terminate_signal_received; 11191e89e47SRemy Horton 11291e89e47SRemy Horton /* Termination signal handler */ 11391e89e47SRemy Horton static void handle_sigterm(__rte_unused int value) 11491e89e47SRemy Horton { 11591e89e47SRemy Horton terminate_signal_received = 1; 11691e89e47SRemy Horton } 11791e89e47SRemy Horton 118e64833f2SRemy Horton /* Print out statistics on packets dropped */ 119e64833f2SRemy Horton static void 120f2fc83b4SThomas Monjalon print_stats(__rte_unused struct rte_timer *ptr_timer, 121f2fc83b4SThomas Monjalon __rte_unused void *ptr_data) 122e64833f2SRemy Horton { 123e64833f2SRemy Horton uint64_t total_packets_dropped, total_packets_tx, total_packets_rx; 124f8244c63SZhiyong Yang uint16_t portid; 125e64833f2SRemy Horton 126e64833f2SRemy Horton total_packets_dropped = 0; 127e64833f2SRemy Horton total_packets_tx = 0; 128e64833f2SRemy Horton total_packets_rx = 0; 129e64833f2SRemy Horton 130e64833f2SRemy Horton const char clr[] = { 27, '[', '2', 'J', '\0' }; 131e64833f2SRemy Horton const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' }; 132e64833f2SRemy Horton 133e64833f2SRemy Horton /* Clear screen and move to top left */ 134e64833f2SRemy Horton printf("%s%s", clr, topLeft); 135e64833f2SRemy Horton 136e64833f2SRemy Horton printf("\nPort statistics ===================================="); 137e64833f2SRemy Horton 138e64833f2SRemy Horton for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { 139e64833f2SRemy Horton /* skip disabled ports */ 140e64833f2SRemy Horton if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 141e64833f2SRemy Horton continue; 142e64833f2SRemy Horton printf("\nStatistics for port %u ------------------------------" 143e64833f2SRemy Horton "\nPackets sent: %24"PRIu64 144e64833f2SRemy Horton "\nPackets received: %20"PRIu64 145e64833f2SRemy Horton "\nPackets dropped: %21"PRIu64, 146e64833f2SRemy Horton portid, 147e64833f2SRemy Horton port_statistics[portid].tx, 148e64833f2SRemy Horton port_statistics[portid].rx, 149e64833f2SRemy Horton port_statistics[portid].dropped); 150e64833f2SRemy Horton 151e64833f2SRemy Horton total_packets_dropped += port_statistics[portid].dropped; 152e64833f2SRemy Horton total_packets_tx += port_statistics[portid].tx; 153e64833f2SRemy Horton total_packets_rx += port_statistics[portid].rx; 154e64833f2SRemy Horton } 155e64833f2SRemy Horton printf("\nAggregate statistics ===============================" 156e64833f2SRemy Horton "\nTotal packets sent: %18"PRIu64 157e64833f2SRemy Horton "\nTotal packets received: %14"PRIu64 158e64833f2SRemy Horton "\nTotal packets dropped: %15"PRIu64, 159e64833f2SRemy Horton total_packets_tx, 160e64833f2SRemy Horton total_packets_rx, 161e64833f2SRemy Horton total_packets_dropped); 162e64833f2SRemy Horton printf("\n====================================================\n"); 1633ee6f706SGeorgiy Levashov 1643ee6f706SGeorgiy Levashov fflush(stdout); 165e64833f2SRemy Horton } 166e64833f2SRemy Horton 167e64833f2SRemy Horton static void 168e64833f2SRemy Horton l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid) 169e64833f2SRemy Horton { 1706d13ea8eSOlivier Matz struct rte_ether_hdr *eth; 171e64833f2SRemy Horton void *tmp; 172e2366e74STomasz Kulasek int sent; 173e64833f2SRemy Horton unsigned dst_port; 174e2366e74STomasz Kulasek struct rte_eth_dev_tx_buffer *buffer; 175e64833f2SRemy Horton 176e64833f2SRemy Horton dst_port = l2fwd_dst_ports[portid]; 1776d13ea8eSOlivier Matz eth = rte_pktmbuf_mtod(m, struct rte_ether_hdr *); 178e64833f2SRemy Horton 179e64833f2SRemy Horton /* 02:00:00:00:00:xx */ 180e64833f2SRemy Horton tmp = ð->d_addr.addr_bytes[0]; 181e64833f2SRemy Horton *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40); 182e64833f2SRemy Horton 183e64833f2SRemy Horton /* src addr */ 184538da7a1SOlivier Matz rte_ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], ð->s_addr); 185e64833f2SRemy Horton 186e2366e74STomasz Kulasek buffer = tx_buffer[dst_port]; 187e2366e74STomasz Kulasek sent = rte_eth_tx_buffer(dst_port, 0, buffer, m); 188e2366e74STomasz Kulasek if (sent) 189e2366e74STomasz Kulasek port_statistics[dst_port].tx += sent; 190e64833f2SRemy Horton } 191e64833f2SRemy Horton 192e64833f2SRemy Horton /* main processing loop */ 193e64833f2SRemy Horton static void 194e64833f2SRemy Horton l2fwd_main_loop(void) 195e64833f2SRemy Horton { 196e64833f2SRemy Horton struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; 197e64833f2SRemy Horton struct rte_mbuf *m; 198e2366e74STomasz Kulasek int sent; 199e64833f2SRemy Horton unsigned lcore_id; 200e64833f2SRemy Horton uint64_t prev_tsc, diff_tsc, cur_tsc; 201e64833f2SRemy Horton unsigned i, j, portid, nb_rx; 202e64833f2SRemy Horton struct lcore_queue_conf *qconf; 203e64833f2SRemy Horton const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) 204e64833f2SRemy Horton / US_PER_S * BURST_TX_DRAIN_US; 205e2366e74STomasz Kulasek struct rte_eth_dev_tx_buffer *buffer; 206e64833f2SRemy Horton 207e64833f2SRemy Horton prev_tsc = 0; 208e64833f2SRemy Horton 209e64833f2SRemy Horton lcore_id = rte_lcore_id(); 210e64833f2SRemy Horton qconf = &lcore_queue_conf[lcore_id]; 211e64833f2SRemy Horton 212e64833f2SRemy Horton if (qconf->n_rx_port == 0) { 213e64833f2SRemy Horton RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id); 214e64833f2SRemy Horton return; 215e64833f2SRemy Horton } 216e64833f2SRemy Horton 217e64833f2SRemy Horton RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id); 218e64833f2SRemy Horton 219e64833f2SRemy Horton for (i = 0; i < qconf->n_rx_port; i++) { 220e64833f2SRemy Horton 221e64833f2SRemy Horton portid = qconf->rx_port_list[i]; 222e64833f2SRemy Horton RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id, 223e64833f2SRemy Horton portid); 224e64833f2SRemy Horton } 225e64833f2SRemy Horton 226e64833f2SRemy Horton uint64_t tsc_initial = rte_rdtsc(); 227e64833f2SRemy Horton uint64_t tsc_lifetime = (rand()&0x07) * rte_get_tsc_hz(); 228e64833f2SRemy Horton 22991e89e47SRemy Horton while (!terminate_signal_received) { 230e64833f2SRemy Horton /* Keepalive heartbeat */ 231e64833f2SRemy Horton rte_keepalive_mark_alive(rte_global_keepalive_info); 232e64833f2SRemy Horton 233e64833f2SRemy Horton cur_tsc = rte_rdtsc(); 234e64833f2SRemy Horton 235e64833f2SRemy Horton /* 236e64833f2SRemy Horton * Die randomly within 7 secs for demo purposes if 237e64833f2SRemy Horton * keepalive enabled 238e64833f2SRemy Horton */ 239e64833f2SRemy Horton if (check_period > 0 && cur_tsc - tsc_initial > tsc_lifetime) 240e64833f2SRemy Horton break; 241e64833f2SRemy Horton 242e64833f2SRemy Horton /* 243e64833f2SRemy Horton * TX burst queue drain 244e64833f2SRemy Horton */ 245e64833f2SRemy Horton diff_tsc = cur_tsc - prev_tsc; 246e64833f2SRemy Horton if (unlikely(diff_tsc > drain_tsc)) { 247e64833f2SRemy Horton 248e2366e74STomasz Kulasek for (i = 0; i < qconf->n_rx_port; i++) { 249e2366e74STomasz Kulasek 250e2366e74STomasz Kulasek portid = l2fwd_dst_ports[qconf->rx_port_list[i]]; 251e2366e74STomasz Kulasek buffer = tx_buffer[portid]; 252e2366e74STomasz Kulasek 253e2366e74STomasz Kulasek sent = rte_eth_tx_buffer_flush(portid, 0, buffer); 254e2366e74STomasz Kulasek if (sent) 255e2366e74STomasz Kulasek port_statistics[portid].tx += sent; 256e2366e74STomasz Kulasek 257e64833f2SRemy Horton } 258e64833f2SRemy Horton 259e64833f2SRemy Horton prev_tsc = cur_tsc; 260e64833f2SRemy Horton } 261e64833f2SRemy Horton 262e64833f2SRemy Horton /* 263e64833f2SRemy Horton * Read packet from RX queues 264e64833f2SRemy Horton */ 265e64833f2SRemy Horton for (i = 0; i < qconf->n_rx_port; i++) { 266e64833f2SRemy Horton 267e64833f2SRemy Horton portid = qconf->rx_port_list[i]; 268f8244c63SZhiyong Yang nb_rx = rte_eth_rx_burst(portid, 0, 269e64833f2SRemy Horton pkts_burst, MAX_PKT_BURST); 270e64833f2SRemy Horton 271e64833f2SRemy Horton port_statistics[portid].rx += nb_rx; 272e64833f2SRemy Horton 273e64833f2SRemy Horton for (j = 0; j < nb_rx; j++) { 274e64833f2SRemy Horton m = pkts_burst[j]; 275e64833f2SRemy Horton rte_prefetch0(rte_pktmbuf_mtod(m, void *)); 276e64833f2SRemy Horton l2fwd_simple_forward(m, portid); 277e64833f2SRemy Horton } 278e64833f2SRemy Horton } 279e64833f2SRemy Horton } 280e64833f2SRemy Horton } 281e64833f2SRemy Horton 282e64833f2SRemy Horton static int 283f2fc83b4SThomas Monjalon l2fwd_launch_one_lcore(__rte_unused void *dummy) 284e64833f2SRemy Horton { 285e64833f2SRemy Horton l2fwd_main_loop(); 286e64833f2SRemy Horton return 0; 287e64833f2SRemy Horton } 288e64833f2SRemy Horton 289e64833f2SRemy Horton /* display usage */ 290e64833f2SRemy Horton static void 291e64833f2SRemy Horton l2fwd_usage(const char *prgname) 292e64833f2SRemy Horton { 293e64833f2SRemy Horton printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n" 294e64833f2SRemy Horton " -p PORTMASK: hexadecimal bitmask of ports to configure\n" 295e64833f2SRemy Horton " -q NQ: number of queue (=ports) per lcore (default is 1)\n" 296e64833f2SRemy Horton " -K PERIOD: Keepalive check period (5 default; 86400 max)\n" 297e64833f2SRemy Horton " -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n", 298e64833f2SRemy Horton prgname); 299e64833f2SRemy Horton } 300e64833f2SRemy Horton 301e64833f2SRemy Horton static int 302e64833f2SRemy Horton l2fwd_parse_portmask(const char *portmask) 303e64833f2SRemy Horton { 304e64833f2SRemy Horton char *end = NULL; 305e64833f2SRemy Horton unsigned long pm; 306e64833f2SRemy Horton 307e64833f2SRemy Horton /* parse hexadecimal string */ 308e64833f2SRemy Horton pm = strtoul(portmask, &end, 16); 309e64833f2SRemy Horton if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) 310*ce6b8c31SSarosh Arif return 0; 311e64833f2SRemy Horton 312e64833f2SRemy Horton return pm; 313e64833f2SRemy Horton } 314e64833f2SRemy Horton 315e64833f2SRemy Horton static unsigned int 316e64833f2SRemy Horton l2fwd_parse_nqueue(const char *q_arg) 317e64833f2SRemy Horton { 318e64833f2SRemy Horton char *end = NULL; 319e64833f2SRemy Horton unsigned long n; 320e64833f2SRemy Horton 321e64833f2SRemy Horton /* parse hexadecimal string */ 322e64833f2SRemy Horton n = strtoul(q_arg, &end, 10); 323e64833f2SRemy Horton if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 324e64833f2SRemy Horton return 0; 325e64833f2SRemy Horton if (n == 0) 326e64833f2SRemy Horton return 0; 327e64833f2SRemy Horton if (n >= MAX_RX_QUEUE_PER_LCORE) 328e64833f2SRemy Horton return 0; 329e64833f2SRemy Horton 330e64833f2SRemy Horton return n; 331e64833f2SRemy Horton } 332e64833f2SRemy Horton 333e64833f2SRemy Horton static int 334e64833f2SRemy Horton l2fwd_parse_timer_period(const char *q_arg) 335e64833f2SRemy Horton { 336e64833f2SRemy Horton char *end = NULL; 337e64833f2SRemy Horton int n; 338e64833f2SRemy Horton 339e64833f2SRemy Horton /* parse number string */ 340e64833f2SRemy Horton n = strtol(q_arg, &end, 10); 341e64833f2SRemy Horton if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 342e64833f2SRemy Horton return -1; 343e64833f2SRemy Horton if (n >= MAX_TIMER_PERIOD) 344e64833f2SRemy Horton return -1; 345e64833f2SRemy Horton 346e64833f2SRemy Horton return n; 347e64833f2SRemy Horton } 348e64833f2SRemy Horton 349e64833f2SRemy Horton static int 350e64833f2SRemy Horton l2fwd_parse_check_period(const char *q_arg) 351e64833f2SRemy Horton { 352e64833f2SRemy Horton char *end = NULL; 353e64833f2SRemy Horton int n; 354e64833f2SRemy Horton 355e64833f2SRemy Horton /* parse number string */ 356e64833f2SRemy Horton n = strtol(q_arg, &end, 10); 357e64833f2SRemy Horton if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 358e64833f2SRemy Horton return -1; 359e64833f2SRemy Horton if (n >= MAX_TIMER_PERIOD) 360e64833f2SRemy Horton return -1; 361e64833f2SRemy Horton 362e64833f2SRemy Horton return n; 363e64833f2SRemy Horton } 364e64833f2SRemy Horton 365e64833f2SRemy Horton /* Parse the argument given in the command line of the application */ 366e64833f2SRemy Horton static int 367e64833f2SRemy Horton l2fwd_parse_args(int argc, char **argv) 368e64833f2SRemy Horton { 369e64833f2SRemy Horton int opt, ret; 370e64833f2SRemy Horton char **argvopt; 371e64833f2SRemy Horton int option_index; 372e64833f2SRemy Horton char *prgname = argv[0]; 373e64833f2SRemy Horton static struct option lgopts[] = { 374e64833f2SRemy Horton {NULL, 0, 0, 0} 375e64833f2SRemy Horton }; 376e64833f2SRemy Horton 377e64833f2SRemy Horton argvopt = argv; 378e64833f2SRemy Horton 379e64833f2SRemy Horton while ((opt = getopt_long(argc, argvopt, "p:q:T:K:", 380e64833f2SRemy Horton lgopts, &option_index)) != EOF) { 381e64833f2SRemy Horton 382e64833f2SRemy Horton switch (opt) { 383e64833f2SRemy Horton /* portmask */ 384e64833f2SRemy Horton case 'p': 385e64833f2SRemy Horton l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg); 386e64833f2SRemy Horton if (l2fwd_enabled_port_mask == 0) { 387e64833f2SRemy Horton printf("invalid portmask\n"); 388e64833f2SRemy Horton l2fwd_usage(prgname); 389e64833f2SRemy Horton return -1; 390e64833f2SRemy Horton } 391e64833f2SRemy Horton break; 392e64833f2SRemy Horton 393e64833f2SRemy Horton /* nqueue */ 394e64833f2SRemy Horton case 'q': 395e64833f2SRemy Horton l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg); 396e64833f2SRemy Horton if (l2fwd_rx_queue_per_lcore == 0) { 397e64833f2SRemy Horton printf("invalid queue number\n"); 398e64833f2SRemy Horton l2fwd_usage(prgname); 399e64833f2SRemy Horton return -1; 400e64833f2SRemy Horton } 401e64833f2SRemy Horton break; 402e64833f2SRemy Horton 403e64833f2SRemy Horton /* timer period */ 404e64833f2SRemy Horton case 'T': 405e64833f2SRemy Horton timer_period = l2fwd_parse_timer_period(optarg) 40683c27f59SRemy Horton * (int64_t)(1000 * TIMER_MILLISECOND); 407e64833f2SRemy Horton if (timer_period < 0) { 408e64833f2SRemy Horton printf("invalid timer period\n"); 409e64833f2SRemy Horton l2fwd_usage(prgname); 410e64833f2SRemy Horton return -1; 411e64833f2SRemy Horton } 412e64833f2SRemy Horton break; 413e64833f2SRemy Horton 414e64833f2SRemy Horton /* Check period */ 415e64833f2SRemy Horton case 'K': 416e64833f2SRemy Horton check_period = l2fwd_parse_check_period(optarg); 417e64833f2SRemy Horton if (check_period < 0) { 418e64833f2SRemy Horton printf("invalid check period\n"); 419e64833f2SRemy Horton l2fwd_usage(prgname); 420e64833f2SRemy Horton return -1; 421e64833f2SRemy Horton } 422e64833f2SRemy Horton break; 423e64833f2SRemy Horton 424e64833f2SRemy Horton /* long options */ 425e64833f2SRemy Horton case 0: 426e64833f2SRemy Horton l2fwd_usage(prgname); 427e64833f2SRemy Horton return -1; 428e64833f2SRemy Horton 429e64833f2SRemy Horton default: 430e64833f2SRemy Horton l2fwd_usage(prgname); 431e64833f2SRemy Horton return -1; 432e64833f2SRemy Horton } 433e64833f2SRemy Horton } 434e64833f2SRemy Horton 435e64833f2SRemy Horton if (optind >= 0) 436e64833f2SRemy Horton argv[optind-1] = prgname; 437e64833f2SRemy Horton 438e64833f2SRemy Horton ret = optind-1; 4399d5ca532SKeith Wiles optind = 1; /* reset getopt lib */ 440e64833f2SRemy Horton return ret; 441e64833f2SRemy Horton } 442e64833f2SRemy Horton 443e64833f2SRemy Horton /* Check the link status of all ports in up to 9s, and print them finally */ 444e64833f2SRemy Horton static void 4458728ccf3SThomas Monjalon check_all_ports_link_status(uint32_t port_mask) 446e64833f2SRemy Horton { 447e64833f2SRemy Horton #define CHECK_INTERVAL 100 /* 100ms */ 448e64833f2SRemy Horton #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ 449f8244c63SZhiyong Yang uint16_t portid; 450f8244c63SZhiyong Yang uint8_t count, all_ports_up, print_flag = 0; 451e64833f2SRemy Horton struct rte_eth_link link; 45222e5c73bSIgor Romanov int ret; 453e64833f2SRemy Horton 454e64833f2SRemy Horton printf("\nChecking link status"); 455e64833f2SRemy Horton fflush(stdout); 456e64833f2SRemy Horton for (count = 0; count <= MAX_CHECK_TIME; count++) { 457e64833f2SRemy Horton all_ports_up = 1; 4588728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) { 459e64833f2SRemy Horton if ((port_mask & (1 << portid)) == 0) 460e64833f2SRemy Horton continue; 461e64833f2SRemy Horton memset(&link, 0, sizeof(link)); 46222e5c73bSIgor Romanov ret = rte_eth_link_get_nowait(portid, &link); 46322e5c73bSIgor Romanov if (ret < 0) { 46422e5c73bSIgor Romanov all_ports_up = 0; 46522e5c73bSIgor Romanov if (print_flag == 1) 46622e5c73bSIgor Romanov printf("Port %u link get failed: %s\n", 46722e5c73bSIgor Romanov portid, rte_strerror(-ret)); 46822e5c73bSIgor Romanov continue; 46922e5c73bSIgor Romanov } 470e64833f2SRemy Horton /* print link status if flag set */ 471e64833f2SRemy Horton if (print_flag == 1) { 472e64833f2SRemy Horton if (link.link_status) 473f8244c63SZhiyong Yang printf( 474f8244c63SZhiyong Yang "Port%d Link Up. Speed %u Mbps - %s\n", 475f8244c63SZhiyong Yang portid, link.link_speed, 476e64833f2SRemy Horton (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? 477c81e3f21SIvan Dyukov ("full-duplex") : ("half-duplex")); 478e64833f2SRemy Horton else 479f8244c63SZhiyong Yang printf("Port %d Link Down\n", portid); 480e64833f2SRemy Horton continue; 481e64833f2SRemy Horton } 482e64833f2SRemy Horton /* clear all_ports_up flag if any link down */ 48309419f23SThomas Monjalon if (link.link_status == ETH_LINK_DOWN) { 484e64833f2SRemy Horton all_ports_up = 0; 485e64833f2SRemy Horton break; 486e64833f2SRemy Horton } 487e64833f2SRemy Horton } 488e64833f2SRemy Horton /* after finally printing all link status, get out */ 489e64833f2SRemy Horton if (print_flag == 1) 490e64833f2SRemy Horton break; 491e64833f2SRemy Horton 492e64833f2SRemy Horton if (all_ports_up == 0) { 493e64833f2SRemy Horton printf("."); 494e64833f2SRemy Horton fflush(stdout); 495e64833f2SRemy Horton rte_delay_ms(CHECK_INTERVAL); 496e64833f2SRemy Horton } 497e64833f2SRemy Horton 498e64833f2SRemy Horton /* set the print_flag if all ports up or timeout */ 499e64833f2SRemy Horton if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { 500e64833f2SRemy Horton print_flag = 1; 501e64833f2SRemy Horton printf("done\n"); 502e64833f2SRemy Horton } 503e64833f2SRemy Horton } 504e64833f2SRemy Horton } 505e64833f2SRemy Horton 506e64833f2SRemy Horton static void 5077b2a704cSRemy Horton dead_core(__rte_unused void *ptr_data, const int id_core) 508e64833f2SRemy Horton { 50991e89e47SRemy Horton if (terminate_signal_received) 51091e89e47SRemy Horton return; 511e64833f2SRemy Horton printf("Dead core %i - restarting..\n", id_core); 512e64833f2SRemy Horton if (rte_eal_get_lcore_state(id_core) == FINISHED) { 513e64833f2SRemy Horton rte_eal_wait_lcore(id_core); 514e64833f2SRemy Horton rte_eal_remote_launch(l2fwd_launch_one_lcore, NULL, id_core); 515e64833f2SRemy Horton } else { 516e64833f2SRemy Horton printf("..false positive!\n"); 517e64833f2SRemy Horton } 518e64833f2SRemy Horton } 519e64833f2SRemy Horton 5207b2a704cSRemy Horton static void 5217b2a704cSRemy Horton relay_core_state(void *ptr_data, const int id_core, 5227b2a704cSRemy Horton const enum rte_keepalive_state core_state, uint64_t last_alive) 5237b2a704cSRemy Horton { 5247b2a704cSRemy Horton rte_keepalive_relayed_state((struct rte_keepalive_shm *)ptr_data, 5257b2a704cSRemy Horton id_core, core_state, last_alive); 5267b2a704cSRemy Horton } 5277b2a704cSRemy Horton 528e64833f2SRemy Horton int 529e64833f2SRemy Horton main(int argc, char **argv) 530e64833f2SRemy Horton { 531e64833f2SRemy Horton struct lcore_queue_conf *qconf; 532e64833f2SRemy Horton int ret; 533f8244c63SZhiyong Yang uint16_t nb_ports; 5348728ccf3SThomas Monjalon uint16_t nb_ports_available = 0; 535f8244c63SZhiyong Yang uint16_t portid, last_port; 536e64833f2SRemy Horton unsigned lcore_id, rx_lcore_id; 537e64833f2SRemy Horton unsigned nb_ports_in_mask = 0; 5380c2b79e8SLouise Kilheeney unsigned int total_nb_mbufs; 53991e89e47SRemy Horton struct sigaction signal_handler; 54093543923SRemy Horton struct rte_keepalive_shm *ka_shm; 54191e89e47SRemy Horton 54291e89e47SRemy Horton memset(&signal_handler, 0, sizeof(signal_handler)); 54391e89e47SRemy Horton terminate_signal_received = 0; 54491e89e47SRemy Horton signal_handler.sa_handler = &handle_sigterm; 54591e89e47SRemy Horton if (sigaction(SIGINT, &signal_handler, NULL) == -1 || 54691e89e47SRemy Horton sigaction(SIGTERM, &signal_handler, NULL) == -1) 54791e89e47SRemy Horton rte_exit(EXIT_FAILURE, "SIGNAL\n"); 54891e89e47SRemy Horton 549e64833f2SRemy Horton 550e64833f2SRemy Horton /* init EAL */ 551e64833f2SRemy Horton ret = rte_eal_init(argc, argv); 552e64833f2SRemy Horton if (ret < 0) 553e64833f2SRemy Horton rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n"); 554e64833f2SRemy Horton argc -= ret; 555e64833f2SRemy Horton argv += ret; 556e64833f2SRemy Horton 557e64833f2SRemy Horton l2fwd_enabled_port_mask = 0; 558e64833f2SRemy Horton 559e64833f2SRemy Horton /* parse application arguments (after the EAL ones) */ 560e64833f2SRemy Horton ret = l2fwd_parse_args(argc, argv); 561e64833f2SRemy Horton if (ret < 0) 562e64833f2SRemy Horton rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n"); 563e64833f2SRemy Horton 564d9a42a69SThomas Monjalon nb_ports = rte_eth_dev_count_avail(); 565e64833f2SRemy Horton if (nb_ports == 0) 566e64833f2SRemy Horton rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n"); 567e64833f2SRemy Horton 5680c2b79e8SLouise Kilheeney /* create the mbuf pool */ 5690c2b79e8SLouise Kilheeney total_nb_mbufs = NB_MBUF_PER_PORT * nb_ports; 5700c2b79e8SLouise Kilheeney 5710c2b79e8SLouise Kilheeney l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", 5720c2b79e8SLouise Kilheeney total_nb_mbufs, 32, 0, RTE_MBUF_DEFAULT_BUF_SIZE, 5730c2b79e8SLouise Kilheeney rte_socket_id()); 5740c2b79e8SLouise Kilheeney if (l2fwd_pktmbuf_pool == NULL) 5750c2b79e8SLouise Kilheeney rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n"); 5760c2b79e8SLouise Kilheeney 577e64833f2SRemy Horton /* reset l2fwd_dst_ports */ 578e64833f2SRemy Horton for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) 579e64833f2SRemy Horton l2fwd_dst_ports[portid] = 0; 580e64833f2SRemy Horton last_port = 0; 581e64833f2SRemy Horton 582e64833f2SRemy Horton /* 583e64833f2SRemy Horton * Each logical core is assigned a dedicated TX queue on each port. 584e64833f2SRemy Horton */ 5858728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) { 586e64833f2SRemy Horton /* skip ports that are not enabled */ 587e64833f2SRemy Horton if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 588e64833f2SRemy Horton continue; 589e64833f2SRemy Horton 590e64833f2SRemy Horton if (nb_ports_in_mask % 2) { 591e64833f2SRemy Horton l2fwd_dst_ports[portid] = last_port; 592e64833f2SRemy Horton l2fwd_dst_ports[last_port] = portid; 593e64833f2SRemy Horton } else 594e64833f2SRemy Horton last_port = portid; 595e64833f2SRemy Horton 596e64833f2SRemy Horton nb_ports_in_mask++; 597e64833f2SRemy Horton } 598e64833f2SRemy Horton if (nb_ports_in_mask % 2) { 599e64833f2SRemy Horton printf("Notice: odd number of ports in portmask.\n"); 600e64833f2SRemy Horton l2fwd_dst_ports[last_port] = last_port; 601e64833f2SRemy Horton } 602e64833f2SRemy Horton 603e64833f2SRemy Horton rx_lcore_id = 1; 604e64833f2SRemy Horton qconf = NULL; 605e64833f2SRemy Horton 606e64833f2SRemy Horton /* Initialize the port/queue configuration of each logical core */ 6078728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) { 608e64833f2SRemy Horton /* skip ports that are not enabled */ 609e64833f2SRemy Horton if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 610e64833f2SRemy Horton continue; 611e64833f2SRemy Horton 612e64833f2SRemy Horton /* get the lcore_id for this port */ 613e64833f2SRemy Horton while (rte_lcore_is_enabled(rx_lcore_id) == 0 || 614e64833f2SRemy Horton lcore_queue_conf[rx_lcore_id].n_rx_port == 615e64833f2SRemy Horton l2fwd_rx_queue_per_lcore) { 616e64833f2SRemy Horton rx_lcore_id++; 617e64833f2SRemy Horton if (rx_lcore_id >= RTE_MAX_LCORE) 618e64833f2SRemy Horton rte_exit(EXIT_FAILURE, "Not enough cores\n"); 619e64833f2SRemy Horton } 620e64833f2SRemy Horton 621e64833f2SRemy Horton if (qconf != &lcore_queue_conf[rx_lcore_id]) 622e64833f2SRemy Horton /* Assigned a new logical core in the loop above. */ 623e64833f2SRemy Horton qconf = &lcore_queue_conf[rx_lcore_id]; 624e64833f2SRemy Horton 625e64833f2SRemy Horton qconf->rx_port_list[qconf->n_rx_port] = portid; 626e64833f2SRemy Horton qconf->n_rx_port++; 627e64833f2SRemy Horton printf("Lcore %u: RX port %u\n", 628f8244c63SZhiyong Yang rx_lcore_id, portid); 629e64833f2SRemy Horton } 630e64833f2SRemy Horton 631e64833f2SRemy Horton /* Initialise each port */ 6328728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) { 633563e239bSShahaf Shuler struct rte_eth_dev_info dev_info; 634563e239bSShahaf Shuler struct rte_eth_rxconf rxq_conf; 635563e239bSShahaf Shuler struct rte_eth_txconf txq_conf; 636563e239bSShahaf Shuler struct rte_eth_conf local_port_conf = port_conf; 637563e239bSShahaf Shuler 638e64833f2SRemy Horton /* skip ports that are not enabled */ 639e64833f2SRemy Horton if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) { 640f8244c63SZhiyong Yang printf("Skipping disabled port %u\n", portid); 641e64833f2SRemy Horton continue; 642e64833f2SRemy Horton } 6438728ccf3SThomas Monjalon nb_ports_available++; 6448728ccf3SThomas Monjalon 645e64833f2SRemy Horton /* init port */ 646f8244c63SZhiyong Yang printf("Initializing port %u... ", portid); 647e64833f2SRemy Horton fflush(stdout); 648089e5ed7SIvan Ilchenko 649089e5ed7SIvan Ilchenko ret = rte_eth_dev_info_get(portid, &dev_info); 650089e5ed7SIvan Ilchenko if (ret != 0) 651089e5ed7SIvan Ilchenko rte_exit(EXIT_FAILURE, 652089e5ed7SIvan Ilchenko "Error during getting device (port %u) info: %s\n", 653089e5ed7SIvan Ilchenko portid, strerror(-ret)); 654089e5ed7SIvan Ilchenko 655563e239bSShahaf Shuler if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) 656563e239bSShahaf Shuler local_port_conf.txmode.offloads |= 657563e239bSShahaf Shuler DEV_TX_OFFLOAD_MBUF_FAST_FREE; 658563e239bSShahaf Shuler ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf); 659e64833f2SRemy Horton if (ret < 0) 660e64833f2SRemy Horton rte_exit(EXIT_FAILURE, 661e64833f2SRemy Horton "Cannot configure device: err=%d, port=%u\n", 662f8244c63SZhiyong Yang ret, portid); 663e64833f2SRemy Horton 66460efb44fSRoman Zhukov ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, 66560efb44fSRoman Zhukov &nb_txd); 66660efb44fSRoman Zhukov if (ret < 0) 66760efb44fSRoman Zhukov rte_exit(EXIT_FAILURE, 66860efb44fSRoman Zhukov "Cannot adjust number of descriptors: err=%d, port=%u\n", 669f8244c63SZhiyong Yang ret, portid); 67060efb44fSRoman Zhukov 67170febdcfSIgor Romanov ret = rte_eth_macaddr_get(portid, 67270febdcfSIgor Romanov &l2fwd_ports_eth_addr[portid]); 67370febdcfSIgor Romanov if (ret < 0) 67470febdcfSIgor Romanov rte_exit(EXIT_FAILURE, 67570febdcfSIgor Romanov "Cannot mac address: err=%d, port=%u\n", 67670febdcfSIgor Romanov ret, portid); 677e64833f2SRemy Horton 678e64833f2SRemy Horton /* init one RX queue */ 679e64833f2SRemy Horton fflush(stdout); 680563e239bSShahaf Shuler rxq_conf = dev_info.default_rxconf; 681563e239bSShahaf Shuler rxq_conf.offloads = local_port_conf.rxmode.offloads; 682e64833f2SRemy Horton ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd, 683e64833f2SRemy Horton rte_eth_dev_socket_id(portid), 684563e239bSShahaf Shuler &rxq_conf, 685e64833f2SRemy Horton l2fwd_pktmbuf_pool); 686e64833f2SRemy Horton if (ret < 0) 687e64833f2SRemy Horton rte_exit(EXIT_FAILURE, 688e64833f2SRemy Horton "rte_eth_rx_queue_setup:err=%d, port=%u\n", 689f8244c63SZhiyong Yang ret, portid); 690e64833f2SRemy Horton 691e64833f2SRemy Horton /* init one TX queue on each port */ 692e64833f2SRemy Horton fflush(stdout); 693563e239bSShahaf Shuler txq_conf = dev_info.default_txconf; 694563e239bSShahaf Shuler txq_conf.offloads = local_port_conf.txmode.offloads; 695e64833f2SRemy Horton ret = rte_eth_tx_queue_setup(portid, 0, nb_txd, 696e64833f2SRemy Horton rte_eth_dev_socket_id(portid), 697563e239bSShahaf Shuler &txq_conf); 698e64833f2SRemy Horton if (ret < 0) 699e64833f2SRemy Horton rte_exit(EXIT_FAILURE, 700e64833f2SRemy Horton "rte_eth_tx_queue_setup:err=%d, port=%u\n", 701f8244c63SZhiyong Yang ret, portid); 702e64833f2SRemy Horton 703e2366e74STomasz Kulasek /* Initialize TX buffers */ 704e2366e74STomasz Kulasek tx_buffer[portid] = rte_zmalloc_socket("tx_buffer", 705e2366e74STomasz Kulasek RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0, 706e2366e74STomasz Kulasek rte_eth_dev_socket_id(portid)); 707e2366e74STomasz Kulasek if (tx_buffer[portid] == NULL) 708e2366e74STomasz Kulasek rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n", 709f8244c63SZhiyong Yang portid); 710e2366e74STomasz Kulasek 711e2366e74STomasz Kulasek rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST); 712e2366e74STomasz Kulasek 713e2366e74STomasz Kulasek ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid], 714e2366e74STomasz Kulasek rte_eth_tx_buffer_count_callback, 715e2366e74STomasz Kulasek &port_statistics[portid].dropped); 716e2366e74STomasz Kulasek if (ret < 0) 717f8244c63SZhiyong Yang rte_exit(EXIT_FAILURE, 718f8244c63SZhiyong Yang "Cannot set error callback for tx buffer on port %u\n", 719f8244c63SZhiyong Yang portid); 720e2366e74STomasz Kulasek 721e64833f2SRemy Horton /* Start device */ 722e64833f2SRemy Horton ret = rte_eth_dev_start(portid); 723e64833f2SRemy Horton if (ret < 0) 724e64833f2SRemy Horton rte_exit(EXIT_FAILURE, 725e64833f2SRemy Horton "rte_eth_dev_start:err=%d, port=%u\n", 726f8244c63SZhiyong Yang ret, portid); 727e64833f2SRemy Horton 728f430bbceSIvan Ilchenko ret = rte_eth_promiscuous_enable(portid); 729f430bbceSIvan Ilchenko if (ret != 0) 730f430bbceSIvan Ilchenko rte_exit(EXIT_FAILURE, 731f430bbceSIvan Ilchenko "rte_eth_promiscuous_enable:err=%s, port=%u\n", 732f430bbceSIvan Ilchenko rte_strerror(-ret), portid); 733e64833f2SRemy Horton 734e64833f2SRemy Horton printf("Port %u, MAC address: " 735e64833f2SRemy Horton "%02X:%02X:%02X:%02X:%02X:%02X\n\n", 736f8244c63SZhiyong Yang portid, 737e64833f2SRemy Horton l2fwd_ports_eth_addr[portid].addr_bytes[0], 738e64833f2SRemy Horton l2fwd_ports_eth_addr[portid].addr_bytes[1], 739e64833f2SRemy Horton l2fwd_ports_eth_addr[portid].addr_bytes[2], 740e64833f2SRemy Horton l2fwd_ports_eth_addr[portid].addr_bytes[3], 741e64833f2SRemy Horton l2fwd_ports_eth_addr[portid].addr_bytes[4], 742e64833f2SRemy Horton l2fwd_ports_eth_addr[portid].addr_bytes[5]); 743e64833f2SRemy Horton 744e64833f2SRemy Horton /* initialize port stats */ 745e64833f2SRemy Horton memset(&port_statistics, 0, sizeof(port_statistics)); 746e64833f2SRemy Horton } 747e64833f2SRemy Horton 748e64833f2SRemy Horton if (!nb_ports_available) { 749e64833f2SRemy Horton rte_exit(EXIT_FAILURE, 750e64833f2SRemy Horton "All available ports are disabled. Please set portmask.\n"); 751e64833f2SRemy Horton } 752e64833f2SRemy Horton 7538728ccf3SThomas Monjalon check_all_ports_link_status(l2fwd_enabled_port_mask); 754e64833f2SRemy Horton 755e64833f2SRemy Horton struct rte_timer hb_timer, stats_timer; 756e64833f2SRemy Horton 757e64833f2SRemy Horton rte_timer_subsystem_init(); 758e64833f2SRemy Horton rte_timer_init(&stats_timer); 759e64833f2SRemy Horton 76093543923SRemy Horton ka_shm = NULL; 761e64833f2SRemy Horton if (check_period > 0) { 7627b2a704cSRemy Horton ka_shm = rte_keepalive_shm_create(); 7637b2a704cSRemy Horton if (ka_shm == NULL) 7647b2a704cSRemy Horton rte_exit(EXIT_FAILURE, 7657b2a704cSRemy Horton "rte_keepalive_shm_create() failed"); 766e64833f2SRemy Horton rte_global_keepalive_info = 7677b2a704cSRemy Horton rte_keepalive_create(&dead_core, ka_shm); 768e64833f2SRemy Horton if (rte_global_keepalive_info == NULL) 769e64833f2SRemy Horton rte_exit(EXIT_FAILURE, "init_keep_alive() failed"); 7707b2a704cSRemy Horton rte_keepalive_register_relay_callback(rte_global_keepalive_info, 7717b2a704cSRemy Horton relay_core_state, ka_shm); 772e64833f2SRemy Horton rte_timer_init(&hb_timer); 773e64833f2SRemy Horton if (rte_timer_reset(&hb_timer, 774e64833f2SRemy Horton (check_period * rte_get_timer_hz()) / 1000, 775e64833f2SRemy Horton PERIODICAL, 776e64833f2SRemy Horton rte_lcore_id(), 777e64833f2SRemy Horton (void(*)(struct rte_timer*, void*)) 778e64833f2SRemy Horton &rte_keepalive_dispatch_pings, 779e64833f2SRemy Horton rte_global_keepalive_info 780e64833f2SRemy Horton ) != 0 ) 781e64833f2SRemy Horton rte_exit(EXIT_FAILURE, "Keepalive setup failure.\n"); 782e64833f2SRemy Horton } 783e64833f2SRemy Horton if (timer_period > 0) { 784e64833f2SRemy Horton if (rte_timer_reset(&stats_timer, 785e64833f2SRemy Horton (timer_period * rte_get_timer_hz()) / 1000, 786e64833f2SRemy Horton PERIODICAL, 787e64833f2SRemy Horton rte_lcore_id(), 788e64833f2SRemy Horton &print_stats, NULL 789e64833f2SRemy Horton ) != 0 ) 790e64833f2SRemy Horton rte_exit(EXIT_FAILURE, "Stats setup failure.\n"); 791e64833f2SRemy Horton } 792e64833f2SRemy Horton /* launch per-lcore init on every slave lcore */ 793e64833f2SRemy Horton RTE_LCORE_FOREACH_SLAVE(lcore_id) { 794e64833f2SRemy Horton struct lcore_queue_conf *qconf = &lcore_queue_conf[lcore_id]; 795e64833f2SRemy Horton 796e64833f2SRemy Horton if (qconf->n_rx_port == 0) 797e64833f2SRemy Horton RTE_LOG(INFO, L2FWD, 798e64833f2SRemy Horton "lcore %u has nothing to do\n", 799e64833f2SRemy Horton lcore_id 800e64833f2SRemy Horton ); 801e64833f2SRemy Horton else { 802e64833f2SRemy Horton rte_eal_remote_launch( 803e64833f2SRemy Horton l2fwd_launch_one_lcore, 804e64833f2SRemy Horton NULL, 805e64833f2SRemy Horton lcore_id 806e64833f2SRemy Horton ); 807e64833f2SRemy Horton rte_keepalive_register_core(rte_global_keepalive_info, 808e64833f2SRemy Horton lcore_id); 809e64833f2SRemy Horton } 810e64833f2SRemy Horton } 81191e89e47SRemy Horton while (!terminate_signal_received) { 812e64833f2SRemy Horton rte_timer_manage(); 813e64833f2SRemy Horton rte_delay_ms(5); 814e64833f2SRemy Horton } 815e64833f2SRemy Horton 816e64833f2SRemy Horton RTE_LCORE_FOREACH_SLAVE(lcore_id) { 817e64833f2SRemy Horton if (rte_eal_wait_lcore(lcore_id) < 0) 818e64833f2SRemy Horton return -1; 819e64833f2SRemy Horton } 820e64833f2SRemy Horton 82193543923SRemy Horton if (ka_shm != NULL) 82293543923SRemy Horton rte_keepalive_shm_cleanup(ka_shm); 823e64833f2SRemy Horton return 0; 824e64833f2SRemy Horton } 825