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