app/testpmd: enable per queue configure
[dpdk.git] / app / test-pmd / testpmd.c
index 308c1b7..e757d81 100644 (file)
@@ -1,34 +1,5 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2017 Intel Corporation
  */
 
 #include <stdarg.h>
@@ -38,8 +9,10 @@
 #include <string.h>
 #include <time.h>
 #include <fcntl.h>
+#include <sys/mman.h>
 #include <sys/types.h>
 #include <errno.h>
+#include <stdbool.h>
 
 #include <sys/queue.h>
 #include <sys/stat.h>
@@ -56,7 +29,6 @@
 #include <rte_cycles.h>
 #include <rte_memory.h>
 #include <rte_memcpy.h>
-#include <rte_memzone.h>
 #include <rte_launch.h>
 #include <rte_eal.h>
 #include <rte_alarm.h>
@@ -67,6 +39,7 @@
 #include <rte_mempool.h>
 #include <rte_malloc.h>
 #include <rte_mbuf.h>
+#include <rte_mbuf_pool_ops.h>
 #include <rte_interrupts.h>
 #include <rte_pci.h>
 #include <rte_ether.h>
@@ -76,9 +49,6 @@
 #ifdef RTE_LIBRTE_IXGBE_PMD
 #include <rte_pmd_ixgbe.h>
 #endif
-#ifdef RTE_LIBRTE_PMD_XENVIRT
-#include <rte_eth_xenvirt.h>
-#endif
 #ifdef RTE_LIBRTE_PDUMP
 #include <rte_pdump.h>
 #endif
@@ -94,6 +64,7 @@
 #include "testpmd.h"
 
 uint16_t verbose_level = 0; /**< Silent by default. */
+int testpmd_logtype; /**< Log type for testpmd logs */
 
 /* use master core for command line ? */
 uint8_t interactive = 0;
@@ -121,6 +92,24 @@ uint8_t socket_num = UMA_NO_CONFIG;
  */
 uint8_t mp_anon = 0;
 
+/*
+ * Store specified sockets on which memory pool to be used by ports
+ * is allocated.
+ */
+uint8_t port_numa[RTE_MAX_ETHPORTS];
+
+/*
+ * Store specified sockets on which RX ring to be used by ports
+ * is allocated.
+ */
+uint8_t rxring_numa[RTE_MAX_ETHPORTS];
+
+/*
+ * Store specified sockets on which TX ring to be used by ports
+ * is allocated.
+ */
+uint8_t txring_numa[RTE_MAX_ETHPORTS];
+
 /*
  * Record the Ethernet address of peer target ports to which packets are
  * forwarded.
@@ -166,6 +155,10 @@ struct fwd_engine * fwd_engines[] = {
        &tx_only_engine,
        &csum_fwd_engine,
        &icmp_echo_engine,
+#if defined RTE_LIBRTE_PMD_SOFTNIC && defined RTE_LIBRTE_SCHED
+       &softnic_tm_engine,
+       &softnic_tm_bypass_engine,
+#endif
 #ifdef RTE_LIBRTE_IEEE1588
        &ieee1588_fwd_engine,
 #endif
@@ -182,6 +175,13 @@ uint16_t mbuf_data_size = DEFAULT_MBUF_DATA_SIZE; /**< Mbuf data space size. */
 uint32_t param_total_num_mbufs = 0;  /**< number of mbufs in all pools - if
                                       * specified on command-line. */
 uint16_t stats_period; /**< Period to show statistics (disabled by default) */
+
+/*
+ * In container, it cannot terminate the process which running with 'stats-period'
+ * option. Set flag to exit stats period loop after received SIGINT/SIGTERM.
+ */
+uint8_t f_quit;
+
 /*
  * Configuration of packet segments used by the "txonly" processing engine.
  */
@@ -211,9 +211,10 @@ queueid_t nb_txq = 1; /**< Number of TX queues per port. */
 
 /*
  * Configurable number of RX/TX ring descriptors.
+ * Defaults are supplied by drivers via ethdev.
  */
-#define RTE_TEST_RX_DESC_DEFAULT 128
-#define RTE_TEST_TX_DESC_DEFAULT 512
+#define RTE_TEST_RX_DESC_DEFAULT 0
+#define RTE_TEST_TX_DESC_DEFAULT 0
 uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; /**< Number of RX descriptors. */
 uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; /**< Number of TX descriptors. */
 
@@ -250,11 +251,6 @@ int16_t tx_free_thresh = RTE_PMD_PARAM_UNSET;
  */
 int16_t tx_rs_thresh = RTE_PMD_PARAM_UNSET;
 
-/*
- * Configurable value of TX queue flags.
- */
-int32_t txq_flags = RTE_PMD_PARAM_UNSET;
-
 /*
  * Receive Side Scaling (RSS) configuration.
  */
@@ -270,6 +266,11 @@ uint16_t port_topology = PORT_TOPOLOGY_PAIRED; /* Ports are paired by default */
  */
 uint8_t no_flush_rx = 0; /* flush by default */
 
+/*
+ * Flow API isolated mode.
+ */
+uint8_t flow_isolate_all;
+
 /*
  * Avoids to check link status when starting/stopping a port.
  */
@@ -285,6 +286,8 @@ uint8_t lsc_interrupt = 1; /* enabled by default */
  */
 uint8_t rmv_interrupt = 1; /* enabled by default */
 
+uint8_t hot_plug = 0; /**< hotplug disabled by default. */
+
 /*
  * Display or mask ether events
  * Default to all events except VF_MBOX
@@ -293,6 +296,7 @@ uint32_t event_print_mask = (UINT32_C(1) << RTE_ETH_EVENT_UNKNOWN) |
                            (UINT32_C(1) << RTE_ETH_EVENT_INTR_LSC) |
                            (UINT32_C(1) << RTE_ETH_EVENT_QUEUE_STATE) |
                            (UINT32_C(1) << RTE_ETH_EVENT_INTR_RESET) |
+                           (UINT32_C(1) << RTE_ETH_EVENT_IPSEC) |
                            (UINT32_C(1) << RTE_ETH_EVENT_MACSEC) |
                            (UINT32_C(1) << RTE_ETH_EVENT_INTR_RMV);
 
@@ -325,14 +329,12 @@ lcoreid_t latencystats_lcore_id = -1;
  */
 struct rte_eth_rxmode rx_mode = {
        .max_rx_pkt_len = ETHER_MAX_LEN, /**< Default maximum frame length. */
-       .split_hdr_size = 0,
-       .header_split   = 0, /**< Header Split disabled. */
-       .hw_ip_checksum = 0, /**< IP checksum offload disabled. */
-       .hw_vlan_filter = 1, /**< VLAN filtering enabled. */
-       .hw_vlan_strip  = 1, /**< VLAN strip enabled. */
-       .hw_vlan_extend = 0, /**< Extended VLAN disabled. */
-       .jumbo_frame    = 0, /**< Jumbo Frame Support disabled. */
-       .hw_strip_crc   = 1, /**< CRC stripping by hardware enabled. */
+       .offloads = DEV_RX_OFFLOAD_CRC_STRIP,
+       .ignore_offload_bitfield = 1,
+};
+
+struct rte_eth_txmode tx_mode = {
+       .offloads = DEV_TX_OFFLOAD_MBUF_FAST_FREE,
 };
 
 struct rte_fdir_conf fdir_conf = {
@@ -369,6 +371,11 @@ struct queue_stats_mappings *rx_queue_stats_mappings = rx_queue_stats_mappings_a
 uint16_t nb_tx_queue_stats_mappings = 0;
 uint16_t nb_rx_queue_stats_mappings = 0;
 
+/*
+ * Display zero values by default for xstats
+ */
+uint8_t xstats_hide_zero;
+
 unsigned int num_sockets = 0;
 unsigned int socket_ids[RTE_MAX_NUMA_NODES];
 
@@ -379,12 +386,22 @@ lcoreid_t bitrate_lcore_id;
 uint8_t bitrate_enabled;
 #endif
 
+struct gro_status gro_ports[RTE_MAX_ETHPORTS];
+uint8_t gro_flush_cycles = GRO_DEFAULT_FLUSH_CYCLES;
+
 /* Forward function declarations */
-static void map_port_queue_stats_mapping_registers(uint8_t pi, struct rte_port *port);
+static void map_port_queue_stats_mapping_registers(portid_t pi,
+                                                  struct rte_port *port);
 static void check_all_ports_link_status(uint32_t port_mask);
-static int eth_event_callback(uint8_t port_id,
+static int eth_event_callback(portid_t port_id,
                              enum rte_eth_event_type type,
                              void *param, void *ret_param);
+static void eth_dev_event_callback(char *device_name,
+                               enum rte_dev_event_type type,
+                               void *param);
+static int eth_dev_event_callback_register(void);
+static int eth_dev_event_callback_unregister(void);
+
 
 /*
  * Check if all the ports are started.
@@ -392,6 +409,9 @@ static int eth_event_callback(uint8_t port_id,
  */
 static int all_ports_started(void);
 
+struct gso_status gso_ports[RTE_MAX_ETHPORTS];
+uint16_t gso_max_segment_size = ETHER_MAX_LEN - ETHER_CRC_LEN;
+
 /*
  * Helper function to check if socket is already discovered.
  * If yes, return positive value. If not, return zero.
@@ -455,9 +475,10 @@ static void
 set_default_fwd_ports_config(void)
 {
        portid_t pt_id;
+       int i = 0;
 
-       for (pt_id = 0; pt_id < nb_ports; pt_id++)
-               fwd_ports_ids[pt_id] = pt_id;
+       RTE_ETH_FOREACH_DEV(pt_id)
+               fwd_ports_ids[i++] = pt_id;
 
        nb_cfg_ports = nb_ports;
        nb_fwd_ports = nb_ports;
@@ -485,41 +506,31 @@ mbuf_pool_create(uint16_t mbuf_seg_size, unsigned nb_mbuf,
        mb_size = sizeof(struct rte_mbuf) + mbuf_seg_size;
        mbuf_poolname_build(socket_id, pool_name, sizeof(pool_name));
 
-       RTE_LOG(INFO, USER1,
+       TESTPMD_LOG(INFO,
                "create a new mbuf pool <%s>: n=%u, size=%u, socket=%u\n",
                pool_name, nb_mbuf, mbuf_seg_size, socket_id);
 
-#ifdef RTE_LIBRTE_PMD_XENVIRT
-       rte_mp = rte_mempool_gntalloc_create(pool_name, nb_mbuf, mb_size,
-               (unsigned) mb_mempool_cache,
-               sizeof(struct rte_pktmbuf_pool_private),
-               rte_pktmbuf_pool_init, NULL,
-               rte_pktmbuf_init, NULL,
-               socket_id, 0);
-#endif
-
-       /* if the former XEN allocation failed fall back to normal allocation */
-       if (rte_mp == NULL) {
-               if (mp_anon != 0) {
-                       rte_mp = rte_mempool_create_empty(pool_name, nb_mbuf,
-                               mb_size, (unsigned) mb_mempool_cache,
-                               sizeof(struct rte_pktmbuf_pool_private),
-                               socket_id, 0);
-                       if (rte_mp == NULL)
-                               goto err;
-
-                       if (rte_mempool_populate_anon(rte_mp) == 0) {
-                               rte_mempool_free(rte_mp);
-                               rte_mp = NULL;
-                               goto err;
-                       }
-                       rte_pktmbuf_pool_init(rte_mp, NULL);
-                       rte_mempool_obj_iter(rte_mp, rte_pktmbuf_init, NULL);
-               } else {
-                       /* wrapper to rte_mempool_create() */
-                       rte_mp = rte_pktmbuf_pool_create(pool_name, nb_mbuf,
-                               mb_mempool_cache, 0, mbuf_seg_size, socket_id);
+       if (mp_anon != 0) {
+               rte_mp = rte_mempool_create_empty(pool_name, nb_mbuf,
+                       mb_size, (unsigned) mb_mempool_cache,
+                       sizeof(struct rte_pktmbuf_pool_private),
+                       socket_id, 0);
+               if (rte_mp == NULL)
+                       goto err;
+
+               if (rte_mempool_populate_anon(rte_mp) == 0) {
+                       rte_mempool_free(rte_mp);
+                       rte_mp = NULL;
+                       goto err;
                }
+               rte_pktmbuf_pool_init(rte_mp, NULL);
+               rte_mempool_obj_iter(rte_mp, rte_pktmbuf_init, NULL);
+       } else {
+               /* wrapper to rte_mempool_create() */
+               TESTPMD_LOG(INFO, "preferred mempool ops selected: %s\n",
+                               rte_mbuf_best_mempool_ops());
+               rte_mp = rte_pktmbuf_pool_create(pool_name, nb_mbuf,
+                       mb_mempool_cache, 0, mbuf_seg_size, socket_id);
        }
 
 err:
@@ -553,6 +564,98 @@ check_socket_id(const unsigned int socket_id)
        return 0;
 }
 
+/*
+ * Get the allowed maximum number of RX queues.
+ * *pid return the port id which has minimal value of
+ * max_rx_queues in all ports.
+ */
+queueid_t
+get_allowed_max_nb_rxq(portid_t *pid)
+{
+       queueid_t allowed_max_rxq = MAX_QUEUE_ID;
+       portid_t pi;
+       struct rte_eth_dev_info dev_info;
+
+       RTE_ETH_FOREACH_DEV(pi) {
+               rte_eth_dev_info_get(pi, &dev_info);
+               if (dev_info.max_rx_queues < allowed_max_rxq) {
+                       allowed_max_rxq = dev_info.max_rx_queues;
+                       *pid = pi;
+               }
+       }
+       return allowed_max_rxq;
+}
+
+/*
+ * Check input rxq is valid or not.
+ * If input rxq is not greater than any of maximum number
+ * of RX queues of all ports, it is valid.
+ * if valid, return 0, else return -1
+ */
+int
+check_nb_rxq(queueid_t rxq)
+{
+       queueid_t allowed_max_rxq;
+       portid_t pid = 0;
+
+       allowed_max_rxq = get_allowed_max_nb_rxq(&pid);
+       if (rxq > allowed_max_rxq) {
+               printf("Fail: input rxq (%u) can't be greater "
+                      "than max_rx_queues (%u) of port %u\n",
+                      rxq,
+                      allowed_max_rxq,
+                      pid);
+               return -1;
+       }
+       return 0;
+}
+
+/*
+ * Get the allowed maximum number of TX queues.
+ * *pid return the port id which has minimal value of
+ * max_tx_queues in all ports.
+ */
+queueid_t
+get_allowed_max_nb_txq(portid_t *pid)
+{
+       queueid_t allowed_max_txq = MAX_QUEUE_ID;
+       portid_t pi;
+       struct rte_eth_dev_info dev_info;
+
+       RTE_ETH_FOREACH_DEV(pi) {
+               rte_eth_dev_info_get(pi, &dev_info);
+               if (dev_info.max_tx_queues < allowed_max_txq) {
+                       allowed_max_txq = dev_info.max_tx_queues;
+                       *pid = pi;
+               }
+       }
+       return allowed_max_txq;
+}
+
+/*
+ * Check input txq is valid or not.
+ * If input txq is not greater than any of maximum number
+ * of TX queues of all ports, it is valid.
+ * if valid, return 0, else return -1
+ */
+int
+check_nb_txq(queueid_t txq)
+{
+       queueid_t allowed_max_txq;
+       portid_t pid = 0;
+
+       allowed_max_txq = get_allowed_max_nb_txq(&pid);
+       if (txq > allowed_max_txq) {
+               printf("Fail: input txq (%u) can't be greater "
+                      "than max_tx_queues (%u) of port %u\n",
+                      txq,
+                      allowed_max_txq,
+                      pid);
+               return -1;
+       }
+       return 0;
+}
+
 static void
 init_config(void)
 {
@@ -562,6 +665,8 @@ init_config(void)
        unsigned int nb_mbuf_per_pool;
        lcoreid_t  lc_id;
        uint8_t port_per_socket[RTE_MAX_NUMA_NODES];
+       struct rte_gro_param gro_param;
+       uint32_t gso_types;
 
        memset(port_per_socket,0,RTE_MAX_NUMA_NODES);
 
@@ -592,8 +697,14 @@ init_config(void)
 
        RTE_ETH_FOREACH_DEV(pid) {
                port = &ports[pid];
+               /* Apply default TxRx configuration for all ports */
+               port->dev_conf.txmode = tx_mode;
+               port->dev_conf.rxmode = rx_mode;
                rte_eth_dev_info_get(pid, &port->dev_info);
-
+               if (!(port->dev_info.tx_offload_capa &
+                     DEV_TX_OFFLOAD_MBUF_FAST_FREE))
+                       port->dev_conf.txmode.offloads &=
+                               ~DEV_TX_OFFLOAD_MBUF_FAST_FREE;
                if (numa_support) {
                        if (port_numa[pid] != NUMA_NO_CONFIG)
                                port_per_socket[port_numa[pid]]++;
@@ -646,6 +757,8 @@ init_config(void)
 
        init_port_config();
 
+       gso_types = DEV_TX_OFFLOAD_TCP_TSO | DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
+               DEV_TX_OFFLOAD_GRE_TNL_TSO;
        /*
         * Records which Mbuf pool to use by each logical core, if needed.
         */
@@ -656,6 +769,13 @@ init_config(void)
                if (mbp == NULL)
                        mbp = mbuf_pool_find(0);
                fwd_lcores[lc_id]->mbp = mbp;
+               /* initialize GSO context */
+               fwd_lcores[lc_id]->gso_ctx.direct_pool = mbp;
+               fwd_lcores[lc_id]->gso_ctx.indirect_pool = mbp;
+               fwd_lcores[lc_id]->gso_ctx.gso_types = gso_types;
+               fwd_lcores[lc_id]->gso_ctx.gso_size = ETHER_MAX_LEN -
+                       ETHER_CRC_LEN;
+               fwd_lcores[lc_id]->gso_ctx.flag = 0;
        }
 
        /* Configuration of packet forwarding streams. */
@@ -663,6 +783,20 @@ init_config(void)
                rte_exit(EXIT_FAILURE, "FAIL from init_fwd_streams()\n");
 
        fwd_config_setup();
+
+       /* create a gro context for each lcore */
+       gro_param.gro_types = RTE_GRO_TCP_IPV4;
+       gro_param.max_flow_num = GRO_MAX_FLUSH_CYCLES;
+       gro_param.max_item_per_flow = MAX_PKT_BURST;
+       for (lc_id = 0; lc_id < nb_lcores; lc_id++) {
+               gro_param.socket_id = rte_lcore_to_socket_id(
+                               fwd_lcores_cpuids[lc_id]);
+               fwd_lcores[lc_id]->gro_ctx = rte_gro_ctx_create(&gro_param);
+               if (fwd_lcores[lc_id]->gro_ctx == NULL) {
+                       rte_exit(EXIT_FAILURE,
+                                       "rte_gro_ctx_create() failed\n");
+               }
+       }
 }
 
 
@@ -987,9 +1121,8 @@ run_pkt_fwd_on_lcore(struct fwd_lcore *fc, packet_fwd_t pkt_fwd)
        uint64_t tics_per_1sec;
        uint64_t tics_datum;
        uint64_t tics_current;
-       uint8_t idx_port, cnt_ports;
+       uint16_t idx_port;
 
-       cnt_ports = rte_eth_dev_count();
        tics_datum = rte_rdtsc();
        tics_per_1sec = rte_get_timer_hz();
 #endif
@@ -1004,9 +1137,7 @@ run_pkt_fwd_on_lcore(struct fwd_lcore *fc, packet_fwd_t pkt_fwd)
                        tics_current = rte_rdtsc();
                        if (tics_current - tics_datum >= tics_per_1sec) {
                                /* Periodic bitrate calculation */
-                               for (idx_port = 0;
-                                               idx_port < cnt_ports;
-                                               idx_port++)
+                               RTE_ETH_FOREACH_DEV(idx_port)
                                        rte_stats_bitrate_calc(bitrate_data,
                                                idx_port);
                                tics_datum = tics_current;
@@ -1209,6 +1340,7 @@ stop_packet_forwarding(void)
 #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
        uint64_t fwd_cycles;
 #endif
+
        static const char *acc_stats_border = "+++++++++++++++";
 
        if (test_done) {
@@ -1299,6 +1431,7 @@ stop_packet_forwarding(void)
 
                fwd_port_stats_display(pt_id, &stats);
        }
+
        printf("\n  %s Accumulated forward statistics for all ports"
               "%s\n",
               acc_stats_border, acc_stats_border);
@@ -1327,14 +1460,14 @@ stop_packet_forwarding(void)
 void
 dev_set_link_up(portid_t pid)
 {
-       if (rte_eth_dev_set_link_up((uint8_t)pid) < 0)
+       if (rte_eth_dev_set_link_up(pid) < 0)
                printf("\nSet link up fail.\n");
 }
 
 void
 dev_set_link_down(portid_t pid)
 {
-       if (rte_eth_dev_set_link_down((uint8_t)pid) < 0)
+       if (rte_eth_dev_set_link_down(pid) < 0)
                printf("\nSet link down fail.\n");
 }
 
@@ -1356,16 +1489,24 @@ all_ports_started(void)
        return 1;
 }
 
+int
+port_is_stopped(portid_t port_id)
+{
+       struct rte_port *port = &ports[port_id];
+
+       if ((port->port_status != RTE_PORT_STOPPED) &&
+           (port->slave_flag == 0))
+               return 0;
+       return 1;
+}
+
 int
 all_ports_stopped(void)
 {
        portid_t pi;
-       struct rte_port *port;
 
        RTE_ETH_FOREACH_DEV(pi) {
-               port = &ports[pi];
-               if ((port->port_status != RTE_PORT_STOPPED) &&
-                       (port->slave_flag == 0))
+               if (!port_is_stopped(pi))
                        return 0;
        }
 
@@ -1426,6 +1567,15 @@ start_port(portid_t pid)
                if (port->need_reconfig > 0) {
                        port->need_reconfig = 0;
 
+                       if (flow_isolate_all) {
+                               int ret = port_flow_isolate(pi, 1);
+                               if (ret) {
+                                       printf("Failed to apply isolated"
+                                              " mode on port %d\n", pi);
+                                       return -1;
+                               }
+                       }
+
                        printf("Configuring Port %d (socket %u)\n", pi,
                                        port->socket_id);
                        /* configure port */
@@ -1446,15 +1596,22 @@ start_port(portid_t pid)
                        port->need_reconfig_queues = 0;
                        /* setup tx queues */
                        for (qi = 0; qi < nb_txq; qi++) {
+                               port->tx_conf[qi].txq_flags =
+                                       ETH_TXQ_FLAGS_IGNORE;
+                               /* Apply Tx offloads configuration */
+                               port->tx_conf[qi].offloads =
+                                       port->dev_conf.txmode.offloads;
                                if ((numa_support) &&
                                        (txring_numa[pi] != NUMA_NO_CONFIG))
                                        diag = rte_eth_tx_queue_setup(pi, qi,
-                                               nb_txd,txring_numa[pi],
-                                               &(port->tx_conf));
+                                               port->nb_tx_desc[qi],
+                                               txring_numa[pi],
+                                               &(port->tx_conf[qi]));
                                else
                                        diag = rte_eth_tx_queue_setup(pi, qi,
-                                               nb_txd,port->socket_id,
-                                               &(port->tx_conf));
+                                               port->nb_tx_desc[qi],
+                                               port->socket_id,
+                                               &(port->tx_conf[qi]));
 
                                if (diag == 0)
                                        continue;
@@ -1465,13 +1622,17 @@ start_port(portid_t pid)
                                                        RTE_PORT_STOPPED) == 0)
                                        printf("Port %d can not be set back "
                                                        "to stopped\n", pi);
-                               printf("Fail to configure port %d tx queues\n", pi);
+                               printf("Fail to configure port %d tx queues\n",
+                                      pi);
                                /* try to reconfigure queues next time */
                                port->need_reconfig_queues = 1;
                                return -1;
                        }
-                       /* setup rx queues */
                        for (qi = 0; qi < nb_rxq; qi++) {
+                               /* Apply Rx offloads configuration */
+                               port->rx_conf[qi].offloads =
+                                       port->dev_conf.rxmode.offloads;
+                               /* setup rx queues */
                                if ((numa_support) &&
                                        (rxring_numa[pi] != NUMA_NO_CONFIG)) {
                                        struct rte_mempool * mp =
@@ -1485,8 +1646,10 @@ start_port(portid_t pid)
                                        }
 
                                        diag = rte_eth_rx_queue_setup(pi, qi,
-                                            nb_rxd,rxring_numa[pi],
-                                            &(port->rx_conf),mp);
+                                            port->nb_rx_desc[pi],
+                                            rxring_numa[pi],
+                                            &(port->rx_conf[qi]),
+                                            mp);
                                } else {
                                        struct rte_mempool *mp =
                                                mbuf_pool_find(port->socket_id);
@@ -1498,8 +1661,10 @@ start_port(portid_t pid)
                                                return -1;
                                        }
                                        diag = rte_eth_rx_queue_setup(pi, qi,
-                                            nb_rxd,port->socket_id,
-                                            &(port->rx_conf), mp);
+                                            port->nb_rx_desc[pi],
+                                            port->socket_id,
+                                            &(port->rx_conf[qi]),
+                                            mp);
                                }
                                if (diag == 0)
                                        continue;
@@ -1510,27 +1675,14 @@ start_port(portid_t pid)
                                                        RTE_PORT_STOPPED) == 0)
                                        printf("Port %d can not be set back "
                                                        "to stopped\n", pi);
-                               printf("Fail to configure port %d rx queues\n", pi);
+                               printf("Fail to configure port %d rx queues\n",
+                                      pi);
                                /* try to reconfigure queues next time */
                                port->need_reconfig_queues = 1;
                                return -1;
                        }
                }
 
-               for (event_type = RTE_ETH_EVENT_UNKNOWN;
-                    event_type < RTE_ETH_EVENT_MAX;
-                    event_type++) {
-                       diag = rte_eth_dev_callback_register(pi,
-                                                       event_type,
-                                                       eth_event_callback,
-                                                       NULL);
-                       if (diag) {
-                               printf("Failed to setup even callback for event %d\n",
-                                       event_type);
-                               return -1;
-                       }
-               }
-
                /* start port */
                if (rte_eth_dev_start(pi) < 0) {
                        printf("Fail to start port %d\n", pi);
@@ -1557,6 +1709,20 @@ start_port(portid_t pid)
                need_check_link_status = 1;
        }
 
+       for (event_type = RTE_ETH_EVENT_UNKNOWN;
+            event_type < RTE_ETH_EVENT_MAX;
+            event_type++) {
+               diag = rte_eth_dev_callback_register(RTE_ETH_ALL,
+                                               event_type,
+                                               eth_event_callback,
+                                               NULL);
+               if (diag) {
+                       printf("Failed to setup even callback for event %d\n",
+                               event_type);
+                       return -1;
+               }
+       }
+
        if (need_check_link_status == 1 && !no_link_check)
                check_all_ports_link_status(RTE_PORT_ALL);
        else if (need_check_link_status == 0)
@@ -1665,6 +1831,80 @@ close_port(portid_t pid)
        printf("Done\n");
 }
 
+void
+reset_port(portid_t pid)
+{
+       int diag;
+       portid_t pi;
+       struct rte_port *port;
+
+       if (port_id_is_invalid(pid, ENABLED_WARN))
+               return;
+
+       printf("Resetting ports...\n");
+
+       RTE_ETH_FOREACH_DEV(pi) {
+               if (pid != pi && pid != (portid_t)RTE_PORT_ALL)
+                       continue;
+
+               if (port_is_forwarding(pi) != 0 && test_done == 0) {
+                       printf("Please remove port %d from forwarding "
+                              "configuration.\n", pi);
+                       continue;
+               }
+
+               if (port_is_bonding_slave(pi)) {
+                       printf("Please remove port %d from bonded device.\n",
+                              pi);
+                       continue;
+               }
+
+               diag = rte_eth_dev_reset(pi);
+               if (diag == 0) {
+                       port = &ports[pi];
+                       port->need_reconfig = 1;
+                       port->need_reconfig_queues = 1;
+               } else {
+                       printf("Failed to reset port %d. diag=%d\n", pi, diag);
+               }
+       }
+
+       printf("Done\n");
+}
+
+static int
+eth_dev_event_callback_register(void)
+{
+       int ret;
+
+       /* register the device event callback */
+       ret = rte_dev_event_callback_register(NULL,
+               eth_dev_event_callback, NULL);
+       if (ret) {
+               printf("Failed to register device event callback\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+
+static int
+eth_dev_event_callback_unregister(void)
+{
+       int ret;
+
+       /* unregister the device event callback */
+       ret = rte_dev_event_callback_unregister(NULL,
+               eth_dev_event_callback, NULL);
+       if (ret < 0) {
+               printf("Failed to unregister device event callback\n");
+               return -1;
+       }
+
+       return 0;
+}
+
 void
 attach_port(char *identifier)
 {
@@ -1688,7 +1928,7 @@ attach_port(char *identifier)
        reconfig(pi, socket_id);
        rte_eth_promiscuous_enable(pi);
 
-       nb_ports = rte_eth_dev_count();
+       nb_ports = rte_eth_dev_count_avail();
 
        ports[pi].port_status = RTE_PORT_STOPPED;
 
@@ -1697,7 +1937,7 @@ attach_port(char *identifier)
 }
 
 void
-detach_port(uint8_t port_id)
+detach_port(portid_t port_id)
 {
        char name[RTE_ETH_NAME_MAX_LEN];
 
@@ -1711,10 +1951,12 @@ detach_port(uint8_t port_id)
        if (ports[port_id].flow_list)
                port_flow_flush(port_id);
 
-       if (rte_eth_dev_detach(port_id, name))
+       if (rte_eth_dev_detach(port_id, name)) {
+               TESTPMD_LOG(ERR, "Failed to detach port '%s'\n", name);
                return;
+       }
 
-       nb_ports = rte_eth_dev_count();
+       nb_ports = rte_eth_dev_count_avail();
 
        printf("Port '%s' is detached. Now total ports is %d\n",
                        name, nb_ports);
@@ -1726,6 +1968,7 @@ void
 pmd_test_exit(void)
 {
        portid_t pt_id;
+       int ret;
 
        if (test_done == 0)
                stop_packet_forwarding();
@@ -1739,6 +1982,19 @@ pmd_test_exit(void)
                        close_port(pt_id);
                }
        }
+
+       if (hot_plug) {
+               ret = rte_dev_event_monitor_stop();
+               if (ret)
+                       RTE_LOG(ERR, EAL,
+                               "fail to stop device event monitor.");
+
+               ret = eth_dev_event_callback_unregister();
+               if (ret)
+                       RTE_LOG(ERR, EAL,
+                               "fail to unregister all event callbacks.");
+       }
+
        printf("\nBye...\n");
 }
 
@@ -1756,7 +2012,8 @@ check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
-       uint8_t portid, count, all_ports_up, print_flag = 0;
+       portid_t portid;
+       uint8_t count, all_ports_up, print_flag = 0;
        struct rte_eth_link link;
 
        printf("Checking link statuses...\n");
@@ -1771,14 +2028,13 @@ check_all_ports_link_status(uint32_t port_mask)
                        /* print link status if flag set */
                        if (print_flag == 1) {
                                if (link.link_status)
-                                       printf("Port %d Link Up - speed %u "
-                                               "Mbps - %s\n", (uint8_t)portid,
-                                               (unsigned)link.link_speed,
+                                       printf(
+                                       "Port%d Link Up. speed %u Mbps- %s\n",
+                                       portid, link.link_speed,
                                (link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
                                        ("full-duplex") : ("half-duplex\n"));
                                else
-                                       printf("Port %d Link Down\n",
-                                               (uint8_t)portid);
+                                       printf("Port %d Link Down\n", portid);
                                continue;
                        }
                        /* clear all_ports_up flag if any link down */
@@ -1810,7 +2066,7 @@ static void
 rmv_event_callback(void *arg)
 {
        struct rte_eth_dev *dev;
-       uint8_t port_id = (intptr_t)arg;
+       portid_t port_id = (intptr_t)arg;
 
        RTE_ETH_VALID_PORTID_OR_RET(port_id);
        dev = &rte_eth_devices[port_id];
@@ -1818,13 +2074,14 @@ rmv_event_callback(void *arg)
        stop_port(port_id);
        close_port(port_id);
        printf("removing device %s\n", dev->device->name);
-       rte_eal_dev_detach(dev->device);
-       dev->state = RTE_ETH_DEV_UNUSED;
+       if (rte_eal_dev_detach(dev->device))
+               TESTPMD_LOG(ERR, "Failed to detach device %s\n",
+                       dev->device->name);
 }
 
 /* This function is used by the interrupt thread */
 static int
-eth_event_callback(uint8_t port_id, enum rte_eth_event_type type, void *param,
+eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param,
                  void *ret_param)
 {
        static const char * const event_desc[] = {
@@ -1833,8 +2090,11 @@ eth_event_callback(uint8_t port_id, enum rte_eth_event_type type, void *param,
                [RTE_ETH_EVENT_QUEUE_STATE] = "Queue state",
                [RTE_ETH_EVENT_INTR_RESET] = "Interrupt reset",
                [RTE_ETH_EVENT_VF_MBOX] = "VF Mbox",
+               [RTE_ETH_EVENT_IPSEC] = "IPsec",
                [RTE_ETH_EVENT_MACSEC] = "MACsec",
                [RTE_ETH_EVENT_INTR_RMV] = "device removal",
+               [RTE_ETH_EVENT_NEW] = "device probed",
+               [RTE_ETH_EVENT_DESTROY] = "device released",
                [RTE_ETH_EVENT_MAX] = NULL,
        };
 
@@ -1851,6 +2111,9 @@ eth_event_callback(uint8_t port_id, enum rte_eth_event_type type, void *param,
                fflush(stdout);
        }
 
+       if (port_id_is_invalid(port_id, DISABLED_WARN))
+               return 0;
+
        switch (type) {
        case RTE_ETH_EVENT_INTR_RMV:
                if (rte_eal_alarm_set(100000,
@@ -1863,8 +2126,39 @@ eth_event_callback(uint8_t port_id, enum rte_eth_event_type type, void *param,
        return 0;
 }
 
+/* This function is used by the interrupt thread */
+static void
+eth_dev_event_callback(char *device_name, enum rte_dev_event_type type,
+                            __rte_unused void *arg)
+{
+       if (type >= RTE_DEV_EVENT_MAX) {
+               fprintf(stderr, "%s called upon invalid event %d\n",
+                       __func__, type);
+               fflush(stderr);
+       }
+
+       switch (type) {
+       case RTE_DEV_EVENT_REMOVE:
+               RTE_LOG(ERR, EAL, "The device: %s has been removed!\n",
+                       device_name);
+               /* TODO: After finish failure handle, begin to stop
+                * packet forward, stop port, close port, detach port.
+                */
+               break;
+       case RTE_DEV_EVENT_ADD:
+               RTE_LOG(ERR, EAL, "The device: %s has been added!\n",
+                       device_name);
+               /* TODO: After finish kernel driver binding,
+                * begin to attach port.
+                */
+               break;
+       default:
+               break;
+       }
+}
+
 static int
-set_tx_queue_stats_mapping_registers(uint8_t port_id, struct rte_port *port)
+set_tx_queue_stats_mapping_registers(portid_t port_id, struct rte_port *port)
 {
        uint16_t i;
        int diag;
@@ -1887,7 +2181,7 @@ set_tx_queue_stats_mapping_registers(uint8_t port_id, struct rte_port *port)
 }
 
 static int
-set_rx_queue_stats_mapping_registers(uint8_t port_id, struct rte_port *port)
+set_rx_queue_stats_mapping_registers(portid_t port_id, struct rte_port *port)
 {
        uint16_t i;
        int diag;
@@ -1910,7 +2204,7 @@ set_rx_queue_stats_mapping_registers(uint8_t port_id, struct rte_port *port)
 }
 
 static void
-map_port_queue_stats_mapping_registers(uint8_t pi, struct rte_port *port)
+map_port_queue_stats_mapping_registers(portid_t pi, struct rte_port *port)
 {
        int diag = 0;
 
@@ -1944,42 +2238,51 @@ map_port_queue_stats_mapping_registers(uint8_t pi, struct rte_port *port)
 static void
 rxtx_port_config(struct rte_port *port)
 {
-       port->rx_conf = port->dev_info.default_rxconf;
-       port->tx_conf = port->dev_info.default_txconf;
+       uint16_t qid;
+
+       for (qid = 0; qid < nb_rxq; qid++) {
+               port->rx_conf[qid] = port->dev_info.default_rxconf;
 
-       /* Check if any RX/TX parameters have been passed */
-       if (rx_pthresh != RTE_PMD_PARAM_UNSET)
-               port->rx_conf.rx_thresh.pthresh = rx_pthresh;
+               /* Check if any Rx parameters have been passed */
+               if (rx_pthresh != RTE_PMD_PARAM_UNSET)
+                       port->rx_conf[qid].rx_thresh.pthresh = rx_pthresh;
 
-       if (rx_hthresh != RTE_PMD_PARAM_UNSET)
-               port->rx_conf.rx_thresh.hthresh = rx_hthresh;
+               if (rx_hthresh != RTE_PMD_PARAM_UNSET)
+                       port->rx_conf[qid].rx_thresh.hthresh = rx_hthresh;
 
-       if (rx_wthresh != RTE_PMD_PARAM_UNSET)
-               port->rx_conf.rx_thresh.wthresh = rx_wthresh;
+               if (rx_wthresh != RTE_PMD_PARAM_UNSET)
+                       port->rx_conf[qid].rx_thresh.wthresh = rx_wthresh;
 
-       if (rx_free_thresh != RTE_PMD_PARAM_UNSET)
-               port->rx_conf.rx_free_thresh = rx_free_thresh;
+               if (rx_free_thresh != RTE_PMD_PARAM_UNSET)
+                       port->rx_conf[qid].rx_free_thresh = rx_free_thresh;
 
-       if (rx_drop_en != RTE_PMD_PARAM_UNSET)
-               port->rx_conf.rx_drop_en = rx_drop_en;
+               if (rx_drop_en != RTE_PMD_PARAM_UNSET)
+                       port->rx_conf[qid].rx_drop_en = rx_drop_en;
 
-       if (tx_pthresh != RTE_PMD_PARAM_UNSET)
-               port->tx_conf.tx_thresh.pthresh = tx_pthresh;
+               port->nb_rx_desc[qid] = nb_rxd;
+       }
+
+       for (qid = 0; qid < nb_txq; qid++) {
+               port->tx_conf[qid] = port->dev_info.default_txconf;
 
-       if (tx_hthresh != RTE_PMD_PARAM_UNSET)
-               port->tx_conf.tx_thresh.hthresh = tx_hthresh;
+               /* Check if any Tx parameters have been passed */
+               if (tx_pthresh != RTE_PMD_PARAM_UNSET)
+                       port->tx_conf[qid].tx_thresh.pthresh = tx_pthresh;
 
-       if (tx_wthresh != RTE_PMD_PARAM_UNSET)
-               port->tx_conf.tx_thresh.wthresh = tx_wthresh;
+               if (tx_hthresh != RTE_PMD_PARAM_UNSET)
+                       port->tx_conf[qid].tx_thresh.hthresh = tx_hthresh;
 
-       if (tx_rs_thresh != RTE_PMD_PARAM_UNSET)
-               port->tx_conf.tx_rs_thresh = tx_rs_thresh;
+               if (tx_wthresh != RTE_PMD_PARAM_UNSET)
+                       port->tx_conf[qid].tx_thresh.wthresh = tx_wthresh;
 
-       if (tx_free_thresh != RTE_PMD_PARAM_UNSET)
-               port->tx_conf.tx_free_thresh = tx_free_thresh;
+               if (tx_rs_thresh != RTE_PMD_PARAM_UNSET)
+                       port->tx_conf[qid].tx_rs_thresh = tx_rs_thresh;
 
-       if (txq_flags != RTE_PMD_PARAM_UNSET)
-               port->tx_conf.txq_flags = txq_flags;
+               if (tx_free_thresh != RTE_PMD_PARAM_UNSET)
+                       port->tx_conf[qid].tx_free_thresh = tx_free_thresh;
+
+               port->nb_tx_desc[qid] = nb_txd;
+       }
 }
 
 void
@@ -1990,7 +2293,6 @@ init_port_config(void)
 
        RTE_ETH_FOREACH_DEV(pid) {
                port = &ports[pid];
-               port->dev_conf.rxmode = rx_mode;
                port->dev_conf.fdir_conf = fdir_conf;
                if (nb_rxq > 1) {
                        port->dev_conf.rx_adv_conf.rss_conf.rss_key = NULL;
@@ -2024,6 +2326,17 @@ init_port_config(void)
                    (rte_eth_devices[pid].data->dev_flags &
                     RTE_ETH_DEV_INTR_RMV))
                        port->dev_conf.intr_conf.rmv = 1;
+
+#if defined RTE_LIBRTE_PMD_SOFTNIC && defined RTE_LIBRTE_SCHED
+               /* Detect softnic port */
+               if (!strcmp(port->dev_info.driver_name, "net_softnic")) {
+                       port->softnic_enable = 1;
+                       memset(&port->softport, 0, sizeof(struct softnic_port));
+
+                       if (!strcmp(cur_fwd_eng->fwd_mode_name, "tm"))
+                               port->softport.tm_flag = 1;
+               }
+#endif
        }
 }
 
@@ -2091,8 +2404,8 @@ get_eth_dcb_conf(struct rte_eth_conf *eth_conf,
                                1 << (i % vmdq_rx_conf->nb_queue_pools);
                }
                for (i = 0; i < ETH_DCB_NUM_USER_PRIORITIES; i++) {
-                       vmdq_rx_conf->dcb_tc[i] = i;
-                       vmdq_tx_conf->dcb_tc[i] = i;
+                       vmdq_rx_conf->dcb_tc[i] = i % num_tcs;
+                       vmdq_tx_conf->dcb_tc[i] = i % num_tcs;
                }
 
                /* set DCB mode of RX and TX of multiple queues */
@@ -2142,18 +2455,21 @@ init_port_dcb_config(portid_t pid,
        /* Enter DCB configuration status */
        dcb_config = 1;
 
+       port_conf.rxmode = rte_port->dev_conf.rxmode;
+       port_conf.txmode = rte_port->dev_conf.txmode;
+
        /*set configuration of DCB in vt mode and DCB in non-vt mode*/
        retval = get_eth_dcb_conf(&port_conf, dcb_mode, num_tcs, pfc_en);
        if (retval < 0)
                return retval;
-       port_conf.rxmode.hw_vlan_filter = 1;
+       port_conf.rxmode.offloads |= DEV_RX_OFFLOAD_VLAN_FILTER;
 
        /**
         * Write the configuration into the device.
         * Set the numbers of RX & TX queues to 0, so
         * the RX & TX queues will not be setup.
         */
-       (void)rte_eth_dev_configure(pid, 0, 0, &port_conf);
+       rte_eth_dev_configure(pid, 0, 0, &port_conf);
 
        rte_eth_dev_info_get(pid, &rte_port->dev_info);
 
@@ -2195,7 +2511,7 @@ init_port_dcb_config(portid_t pid,
 
        rxtx_port_config(rte_port);
        /* VLAN filter */
-       rte_port->dev_conf.rxmode.hw_vlan_filter = 1;
+       rte_port->dev_conf.rxmode.offloads |= DEV_RX_OFFLOAD_VLAN_FILTER;
        for (i = 0; i < RTE_DIM(vlan_tags); i++)
                rx_vft_set(pid, vlan_tags[i], 1);
 
@@ -2257,6 +2573,8 @@ signal_handler(int signum)
                rte_latencystats_uninit();
 #endif
                force_quit();
+               /* Set flag to indicate the force termination. */
+               f_quit = 1;
                /* exit with the expected status */
                signal(signum, SIG_DFL);
                kill(getpid(), signum);
@@ -2266,8 +2584,9 @@ signal_handler(int signum)
 int
 main(int argc, char** argv)
 {
-       int  diag;
-       uint8_t port_id;
+       int diag;
+       portid_t port_id;
+       int ret;
 
        signal(SIGINT, signal_handler);
        signal(SIGTERM, signal_handler);
@@ -2276,14 +2595,24 @@ main(int argc, char** argv)
        if (diag < 0)
                rte_panic("Cannot init EAL\n");
 
+       testpmd_logtype = rte_log_register("testpmd");
+       if (testpmd_logtype < 0)
+               rte_panic("Cannot register log type");
+       rte_log_set_level(testpmd_logtype, RTE_LOG_DEBUG);
+
+       if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
+               TESTPMD_LOG(NOTICE, "mlockall() failed with error \"%s\"\n",
+                       strerror(errno));
+       }
+
 #ifdef RTE_LIBRTE_PDUMP
        /* initialize packet capture framework */
        rte_pdump_init(NULL);
 #endif
 
-       nb_ports = (portid_t) rte_eth_dev_count();
+       nb_ports = (portid_t) rte_eth_dev_count_avail();
        if (nb_ports == 0)
-               RTE_LOG(WARNING, EAL, "No probed ethernet devices\n");
+               TESTPMD_LOG(WARNING, "No probed ethernet devices\n");
 
        /* allocate port structures, and init them */
        init_port();
@@ -2309,6 +2638,13 @@ main(int argc, char** argv)
        if (tx_first && interactive)
                rte_exit(EXIT_FAILURE, "--tx-first cannot be used on "
                                "interactive mode.\n");
+
+       if (tx_first && lsc_interrupt) {
+               printf("Warning: lsc_interrupt needs to be off when "
+                               " using tx_first. Disabling.\n");
+               lsc_interrupt = 0;
+       }
+
        if (!nb_rxq && !nb_txq)
                printf("Warning: Either rx or tx queues should be non-zero\n");
 
@@ -2318,6 +2654,18 @@ main(int argc, char** argv)
                       nb_rxq, nb_txq);
 
        init_config();
+
+       if (hot_plug) {
+               /* enable hot plug monitoring */
+               ret = rte_dev_event_monitor_start();
+               if (ret) {
+                       rte_errno = EINVAL;
+                       return -1;
+               }
+               eth_dev_event_callback_register();
+
+       }
+
        if (start_port(RTE_PORT_ALL) != 0)
                rte_exit(EXIT_FAILURE, "Start ports failed\n");
 
@@ -2367,6 +2715,8 @@ main(int argc, char** argv)
                char c;
                int rc;
 
+               f_quit = 0;
+
                printf("No commandline core given, start packet forwarding\n");
                start_packet_forwarding(tx_first);
                if (stats_period != 0) {
@@ -2376,7 +2726,7 @@ main(int argc, char** argv)
                        /* Convert to number of cycles */
                        timer_period = stats_period * rte_get_timer_hz();
 
-                       while (1) {
+                       while (f_quit == 0) {
                                cur_time = rte_get_timer_cycles();
                                diff_time += cur_time - prev_time;