examples/ip_reassembly: overhaul
authorAnatoly Burakov <anatoly.burakov@intel.com>
Wed, 28 May 2014 17:32:47 +0000 (18:32 +0100)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Mon, 16 Jun 2014 16:55:05 +0000 (18:55 +0200)
New stuff:
* Support for regular traffic as well as IPv4 and IPv6
* Simplified config
* Routing table printed out on start
* Uses LPM/LPM6 for lookup
* Unmatched traffic is sent to the originating port

Signed-off-by: Anatoly Burakov <anatoly.burakov@intel.com>
Tested-by: Waterman Cao <waterman.cao@intel.com>
Acked-by: Thomas Monjalon <thomas.monjalon@6wind.com>
examples/ip_reassembly/Makefile
examples/ip_reassembly/main.c

index 9324e86..d9539a3 100644 (file)
@@ -52,7 +52,6 @@ CFLAGS += $(WERROR_FLAGS)
 # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603
 ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y)
 CFLAGS_main.o += -Wno-return-type
-CFLAGS_main.o += -DIPV4_FRAG_TBL_STAT
 endif
 
 include $(RTE_SDK)/mk/rte.extapp.mk
index a1dcb14..9f4c669 100644 (file)
@@ -42,6 +42,7 @@
 #include <errno.h>
 #include <getopt.h>
 #include <signal.h>
+#include <sys/param.h>
 
 #include <rte_common.h>
 #include <rte_byteorder.h>
 #include <rte_tcp.h>
 #include <rte_udp.h>
 #include <rte_string_fns.h>
-#include "main.h"
-
-#define APP_LOOKUP_EXACT_MATCH          0
-#define APP_LOOKUP_LPM                  1
-#define DO_RFC_1812_CHECKS
-
-#ifndef APP_LOOKUP_METHOD
-#define APP_LOOKUP_METHOD             APP_LOOKUP_LPM
-#endif
-
-#if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
-#include <rte_hash.h>
-#elif (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
 #include <rte_lpm.h>
 #include <rte_lpm6.h>
-#else
-#error "APP_LOOKUP_METHOD set to incorrect value"
-#endif
 
-#define MAX_PKT_BURST 32
-
-#include "rte_ip_frag.h"
+#include <rte_ip_frag.h>
 
-#ifndef IPv6_BYTES
-#define IPv6_BYTES_FMT "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"\
-                       "%02x%02x:%02x%02x:%02x%02x:%02x%02x"
-#define IPv6_BYTES(addr) \
-       addr[0],  addr[1], addr[2],  addr[3], \
-       addr[4],  addr[5], addr[6],  addr[7], \
-       addr[8],  addr[9], addr[10], addr[11],\
-       addr[12], addr[13],addr[14], addr[15]
-#endif
+#include "main.h"
 
+#define MAX_PKT_BURST 32
 
-#define RTE_LOGTYPE_L3FWD RTE_LOGTYPE_USER1
 
-#define MAX_PORTS      RTE_MAX_ETHPORTS
+#define RTE_LOGTYPE_IP_RSMBL RTE_LOGTYPE_USER1
 
 #define MAX_JUMBO_PKT_LEN  9600
 
-#define IPV6_ADDR_LEN 16
-
-#define MEMPOOL_CACHE_SIZE 256
-
 #define        BUF_SIZE        2048
 #define MBUF_SIZE      \
        (BUF_SIZE + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
 
+#define NB_MBUF 8192
+
+/* allow max jumbo frame 9.5 KB */
+#define JUMBO_FRAME_MAX_SIZE   0x2600
+
 #define        MAX_FLOW_NUM    UINT16_MAX
 #define        MIN_FLOW_NUM    1
 #define        DEF_FLOW_NUM    0x1000
 #define        MIN_FLOW_TTL    1
 #define        DEF_FLOW_TTL    MS_PER_S
 
-#define        DEF_MBUF_NUM    0x400
+#define MAX_FRAG_NUM RTE_LIBRTE_IP_FRAG_MAX_FRAG
 
 /* Should be power of two. */
-#define        IPV4_FRAG_TBL_BUCKET_ENTRIES    2
+#define        IP_FRAG_TBL_BUCKET_ENTRIES      16
 
 static uint32_t max_flow_num = DEF_FLOW_NUM;
 static uint32_t max_flow_ttl = DEF_FLOW_TTL;
@@ -174,12 +150,33 @@ static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
 static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
 
 /* ethernet addresses of ports */
-static struct ether_addr ports_eth_addr[MAX_PORTS];
+static struct ether_addr ports_eth_addr[RTE_MAX_ETHPORTS];
+
+#ifndef IPv4_BYTES
+#define IPv4_BYTES_FMT "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8
+#define IPv4_BYTES(addr) \
+               (uint8_t) (((addr) >> 24) & 0xFF),\
+               (uint8_t) (((addr) >> 16) & 0xFF),\
+               (uint8_t) (((addr) >> 8) & 0xFF),\
+               (uint8_t) ((addr) & 0xFF)
+#endif
+
+#ifndef IPv6_BYTES
+#define IPv6_BYTES_FMT "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"\
+                       "%02x%02x:%02x%02x:%02x%02x:%02x%02x"
+#define IPv6_BYTES(addr) \
+       addr[0],  addr[1], addr[2],  addr[3], \
+       addr[4],  addr[5], addr[6],  addr[7], \
+       addr[8],  addr[9], addr[10], addr[11],\
+       addr[12], addr[13],addr[14], addr[15]
+#endif
+
+#define IPV6_ADDR_LEN 16
 
 /* mask of enabled ports */
 static uint32_t enabled_port_mask = 0;
-static int promiscuous_on = 0; /**< Ports set in promiscuous mode off by default. */
-static int numa_on = 1; /**< NUMA is enabled by default. */
+
+static int rx_queue_per_lcore = 1;
 
 struct mbuf_table {
        uint32_t len;
@@ -188,54 +185,50 @@ struct mbuf_table {
        struct rte_mbuf *m_table[0];
 };
 
-struct lcore_rx_queue {
-       uint8_t port_id;
-       uint8_t queue_id;
-} __rte_cache_aligned;
+struct rx_queue {
+       struct rte_ip_frag_tbl *frag_tbl;
+       struct rte_mempool *pool;
+       struct rte_lpm *lpm;
+       struct rte_lpm6 *lpm6;
+       uint8_t portid;
+};
+
+struct tx_lcore_stat {
+       uint64_t call;
+       uint64_t drop;
+       uint64_t queue;
+       uint64_t send;
+};
 
 #define MAX_RX_QUEUE_PER_LCORE 16
-#define MAX_TX_QUEUE_PER_PORT MAX_PORTS
+#define MAX_TX_QUEUE_PER_PORT 16
 #define MAX_RX_QUEUE_PER_PORT 128
 
-#define MAX_LCORE_PARAMS 1024
-struct lcore_params {
-       uint8_t port_id;
-       uint8_t queue_id;
-       uint8_t lcore_id;
+struct lcore_queue_conf {
+       uint16_t n_rx_queue;
+       struct rx_queue rx_queue_list[MAX_RX_QUEUE_PER_LCORE];
+       uint16_t tx_queue_id[RTE_MAX_ETHPORTS];
+       struct rte_ip_frag_death_row death_row;
+       struct mbuf_table *tx_mbufs[RTE_MAX_ETHPORTS];
+       struct tx_lcore_stat tx_stat;
 } __rte_cache_aligned;
-
-static struct lcore_params lcore_params_array[MAX_LCORE_PARAMS];
-static struct lcore_params lcore_params_array_default[] = {
-       {0, 0, 2},
-       {0, 1, 2},
-       {0, 2, 2},
-       {1, 0, 2},
-       {1, 1, 2},
-       {1, 2, 2},
-       {2, 0, 2},
-       {3, 0, 3},
-       {3, 1, 3},
-};
-
-static struct lcore_params * lcore_params = lcore_params_array_default;
-static uint16_t nb_lcore_params = sizeof(lcore_params_array_default) /
-                               sizeof(lcore_params_array_default[0]);
+static struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
 
 static struct rte_eth_conf port_conf = {
        .rxmode = {
-               .mq_mode        = ETH_MQ_RX_RSS,
-               .max_rx_pkt_len = ETHER_MAX_LEN,
+               .mq_mode        = ETH_MQ_RX_RSS,
+               .max_rx_pkt_len = JUMBO_FRAME_MAX_SIZE,
                .split_hdr_size = 0,
                .header_split   = 0, /**< Header Split disabled */
                .hw_ip_checksum = 1, /**< IP checksum offload enabled */
                .hw_vlan_filter = 0, /**< VLAN filtering disabled */
-               .jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+               .jumbo_frame    = 1, /**< Jumbo Frame Support disabled */
                .hw_strip_crc   = 0, /**< CRC stripped by hardware */
        },
        .rx_adv_conf = {
-               .rss_conf = {
-                       .rss_key = NULL,
-                       .rss_hf = ETH_RSS_IPV4 | ETH_RSS_IPV6,
+                       .rss_conf = {
+                               .rss_key = NULL,
+                               .rss_hf = ETH_RSS_IPV4 | ETH_RSS_IPV6,
                },
        },
        .txmode = {
@@ -263,102 +256,37 @@ static const struct rte_eth_txconf tx_conf = {
        .txq_flags = 0x0,
 };
 
-#if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
-
-#ifdef RTE_MACHINE_CPUFLAG_SSE4_2
-#include <rte_hash_crc.h>
-#define DEFAULT_HASH_FUNC       rte_hash_crc
-#else
-#include <rte_jhash.h>
-#define DEFAULT_HASH_FUNC       rte_jhash
-#endif
-
-struct ipv4_5tuple {
-       uint32_t ip_dst;
-       uint32_t ip_src;
-       uint16_t port_dst;
-       uint16_t port_src;
-       uint8_t  proto;
-} __attribute__((__packed__));
-
-struct ipv6_5tuple {
-       uint8_t  ip_dst[IPV6_ADDR_LEN];
-       uint8_t  ip_src[IPV6_ADDR_LEN];
-       uint16_t port_dst;
-       uint16_t port_src;
-       uint8_t  proto;
-} __attribute__((__packed__));
-
-struct ipv4_l3fwd_route {
-       struct ipv4_5tuple key;
-       uint8_t if_out;
-};
-
-struct ipv6_l3fwd_route {
-       struct ipv6_5tuple key;
-       uint8_t if_out;
-};
-
-static struct ipv4_l3fwd_route ipv4_l3fwd_route_array[] = {
-       {{IPv4(100,10,0,1), IPv4(200,10,0,1), 101, 11, IPPROTO_TCP}, 0},
-       {{IPv4(100,20,0,2), IPv4(200,20,0,2), 102, 12, IPPROTO_TCP}, 1},
-       {{IPv4(100,30,0,3), IPv4(200,30,0,3), 103, 13, IPPROTO_TCP}, 2},
-       {{IPv4(100,40,0,4), IPv4(200,40,0,4), 104, 14, IPPROTO_TCP}, 3},
-};
-
-static struct ipv6_l3fwd_route ipv6_l3fwd_route_array[] = {
-       {
-               {
-                       {0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                        0x02, 0x1b, 0x21, 0xff, 0xfe, 0x91, 0x38, 0x05},
-                       {0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                        0x02, 0x1e, 0x67, 0xff, 0xfe, 0x0d, 0xb6, 0x0a},
-                        1, 10, IPPROTO_UDP
-               }, 4
-       },
-};
-
-typedef struct rte_hash lookup_struct_t;
-static lookup_struct_t *ipv4_l3fwd_lookup_struct[NB_SOCKETS];
-static lookup_struct_t *ipv6_l3fwd_lookup_struct[NB_SOCKETS];
-
-#define L3FWD_HASH_ENTRIES     1024
-
-#define IPV4_L3FWD_NUM_ROUTES \
-       (sizeof(ipv4_l3fwd_route_array) / sizeof(ipv4_l3fwd_route_array[0]))
-
-#define IPV6_L3FWD_NUM_ROUTES \
-       (sizeof(ipv6_l3fwd_route_array) / sizeof(ipv6_l3fwd_route_array[0]))
-
-static uint8_t ipv4_l3fwd_out_if[L3FWD_HASH_ENTRIES] __rte_cache_aligned;
-static uint8_t ipv6_l3fwd_out_if[L3FWD_HASH_ENTRIES] __rte_cache_aligned;
-#endif
-
-#if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
-struct ipv4_l3fwd_route {
+/*
+ * IPv4 forwarding table
+ */
+struct l3fwd_ipv4_route {
        uint32_t ip;
        uint8_t  depth;
        uint8_t  if_out;
 };
 
-struct ipv6_l3fwd_route {
-       uint8_t ip[16];
-       uint8_t  depth;
-       uint8_t  if_out;
+struct l3fwd_ipv4_route l3fwd_ipv4_route_array[] = {
+               {IPv4(100,10,0,0), 16, 0},
+               {IPv4(100,20,0,0), 16, 1},
+               {IPv4(100,30,0,0), 16, 2},
+               {IPv4(100,40,0,0), 16, 3},
+               {IPv4(100,50,0,0), 16, 4},
+               {IPv4(100,60,0,0), 16, 5},
+               {IPv4(100,70,0,0), 16, 6},
+               {IPv4(100,80,0,0), 16, 7},
 };
 
-static struct ipv4_l3fwd_route ipv4_l3fwd_route_array[] = {
-       {IPv4(1,1,1,0), 24, 0},
-       {IPv4(2,1,1,0), 24, 1},
-       {IPv4(3,1,1,0), 24, 2},
-       {IPv4(4,1,1,0), 24, 3},
-       {IPv4(5,1,1,0), 24, 4},
-       {IPv4(6,1,1,0), 24, 5},
-       {IPv4(7,1,1,0), 24, 6},
-       {IPv4(8,1,1,0), 24, 7},
+/*
+ * IPv6 forwarding table
+ */
+
+struct l3fwd_ipv6_route {
+       uint8_t ip[IPV6_ADDR_LEN];
+       uint8_t depth;
+       uint8_t if_out;
 };
 
-static struct ipv6_l3fwd_route ipv6_l3fwd_route_array[] = {
+static struct l3fwd_ipv6_route l3fwd_ipv6_route_array[] = {
        {{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, 0},
        {{2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, 1},
        {{3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, 2},
@@ -369,59 +297,31 @@ static struct ipv6_l3fwd_route ipv6_l3fwd_route_array[] = {
        {{8,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, 7},
 };
 
-#define IPV4_L3FWD_NUM_ROUTES \
-       (sizeof(ipv4_l3fwd_route_array) / sizeof(ipv4_l3fwd_route_array[0]))
-#define IPV6_L3FWD_NUM_ROUTES \
-       (sizeof(ipv6_l3fwd_route_array) / sizeof(ipv6_l3fwd_route_array[0]))
-
-#define IPV4_L3FWD_LPM_MAX_RULES         1024
-#define IPV6_L3FWD_LPM_MAX_RULES         1024
-#define IPV6_L3FWD_LPM_NUMBER_TBL8S (1 << 16)
+#define LPM_MAX_RULES         1024
+#define LPM6_MAX_RULES         1024
+#define LPM6_NUMBER_TBL8S (1 << 16)
 
-typedef struct rte_lpm lookup_struct_t;
-typedef struct rte_lpm6 lookup6_struct_t;
-static lookup_struct_t *ipv4_l3fwd_lookup_struct[NB_SOCKETS];
-static lookup6_struct_t *ipv6_l3fwd_lookup_struct[NB_SOCKETS];
-#endif
-
-struct tx_lcore_stat {
-       uint64_t call;
-       uint64_t drop;
-       uint64_t queue;
-       uint64_t send;
+struct rte_lpm6_config lpm6_config = {
+               .max_rules = LPM6_MAX_RULES,
+               .number_tbl8s = LPM6_NUMBER_TBL8S,
+               .flags = 0
 };
 
-#ifdef IPV4_FRAG_TBL_STAT
-#define        TX_LCORE_STAT_UPDATE(s, f, v)   ((s)->f += (v))
-#else
-#define        TX_LCORE_STAT_UPDATE(s, f, v)   do {} while (0)
-#endif /* IPV4_FRAG_TBL_STAT */
+static struct rte_lpm *socket_lpm[RTE_MAX_NUMA_NODES];
+static struct rte_lpm6 *socket_lpm6[RTE_MAX_NUMA_NODES];
 
-struct lcore_conf {
-       uint16_t n_rx_queue;
-       struct lcore_rx_queue rx_queue_list[MAX_RX_QUEUE_PER_LCORE];
-       uint16_t tx_queue_id[MAX_PORTS];
-       lookup_struct_t * ipv4_lookup_struct;
-#if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
-       lookup6_struct_t * ipv6_lookup_struct;
+#ifdef IPV6_FRAG_TBL_STAT
+#define TX_LCORE_STAT_UPDATE(s, f, v)   ((s)->f += (v))
 #else
-       lookup_struct_t * ipv6_lookup_struct;
-#endif
-       struct rte_ip_frag_tbl *frag_tbl[MAX_RX_QUEUE_PER_LCORE];
-       struct rte_mempool *pool[MAX_RX_QUEUE_PER_LCORE];
-       struct rte_ip_frag_death_row death_row;
-       struct mbuf_table *tx_mbufs[MAX_PORTS];
-       struct tx_lcore_stat tx_stat;
-} __rte_cache_aligned;
-
-static struct lcore_conf lcore_conf[RTE_MAX_LCORE];
+#define TX_LCORE_STAT_UPDATE(s, f, v)   do {} while (0)
+#endif /* IPV6_FRAG_TBL_STAT */
 
 /*
  * If number of queued packets reached given threahold, then
  * send burst of packets on an output interface.
  */
 static inline uint32_t
-send_burst(struct lcore_conf *qconf, uint32_t thresh, uint8_t port)
+send_burst(struct lcore_queue_conf *qconf, uint32_t thresh, uint8_t port)
 {
        uint32_t fill, len, k, n;
        struct mbuf_table *txmb;
@@ -454,11 +354,11 @@ static inline int
 send_single_packet(struct rte_mbuf *m, uint8_t port)
 {
        uint32_t fill, lcore_id, len;
-       struct lcore_conf *qconf;
+       struct lcore_queue_conf *qconf;
        struct mbuf_table *txmb;
 
        lcore_id = rte_lcore_id();
-       qconf = &lcore_conf[lcore_id];
+       qconf = &lcore_queue_conf[lcore_id];
 
        txmb = qconf->tx_mbufs[port];
        len = txmb->len;
@@ -480,207 +380,44 @@ send_single_packet(struct rte_mbuf *m, uint8_t port)
        return (0);
 }
 
-#ifdef DO_RFC_1812_CHECKS
-static inline int
-is_valid_ipv4_pkt(struct ipv4_hdr *pkt, uint32_t link_len)
-{
-       /* From http://www.rfc-editor.org/rfc/rfc1812.txt section 5.2.2 */
-       /*
-        * 1. The packet length reported by the Link Layer must be large
-        * enough to hold the minimum length legal IP datagram (20 bytes).
-        */
-       if (link_len < sizeof(struct ipv4_hdr))
-               return -1;
-
-       /* 2. The IP checksum must be correct. */
-       /* this is checked in H/W */
-
-       /*
-        * 3. The IP version number must be 4. If the version number is not 4
-        * then the packet may be another version of IP, such as IPng or
-        * ST-II.
-        */
-       if (((pkt->version_ihl) >> 4) != 4)
-               return -3;
-       /*
-        * 4. The IP header length field must be large enough to hold the
-        * minimum length legal IP datagram (20 bytes = 5 words).
-        */
-       if ((pkt->version_ihl & 0xf) < 5)
-               return -4;
-
-       /*
-        * 5. The IP total length field must be large enough to hold the IP
-        * datagram header, whose length is specified in the IP header length
-        * field.
-        */
-       if (rte_cpu_to_be_16(pkt->total_length) < sizeof(struct ipv4_hdr))
-               return -5;
-
-       return 0;
-}
-#endif
-
-#if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
-static void
-print_ipv4_key(struct ipv4_5tuple key)
-{
-       printf("IP dst = %08x, IP src = %08x, port dst = %d, port src = %d, proto = %d\n",
-                       (unsigned)key.ip_dst, (unsigned)key.ip_src, key.port_dst, key.port_src, key.proto);
-}
-static void
-print_ipv6_key(struct ipv6_5tuple key)
-{
-       printf( "IP dst = " IPv6_BYTES_FMT ", IP src = " IPv6_BYTES_FMT ", "
-               "port dst = %d, port src = %d, proto = %d\n",
-               IPv6_BYTES(key.ip_dst), IPv6_BYTES(key.ip_src),
-               key.port_dst, key.port_src, key.proto);
-}
-
-static inline uint8_t
-get_ipv4_dst_port(struct ipv4_hdr *ipv4_hdr,  uint8_t portid, lookup_struct_t * ipv4_l3fwd_lookup_struct)
-{
-       struct ipv4_5tuple key;
-       struct tcp_hdr *tcp;
-       struct udp_hdr *udp;
-       int ret = 0;
-
-       key.ip_dst = rte_be_to_cpu_32(ipv4_hdr->dst_addr);
-       key.ip_src = rte_be_to_cpu_32(ipv4_hdr->src_addr);
-       key.proto = ipv4_hdr->next_proto_id;
-
-       switch (ipv4_hdr->next_proto_id) {
-       case IPPROTO_TCP:
-               tcp = (struct tcp_hdr *)((unsigned char *) ipv4_hdr +
-                                       sizeof(struct ipv4_hdr));
-               key.port_dst = rte_be_to_cpu_16(tcp->dst_port);
-               key.port_src = rte_be_to_cpu_16(tcp->src_port);
-               break;
-
-       case IPPROTO_UDP:
-               udp = (struct udp_hdr *)((unsigned char *) ipv4_hdr +
-                                       sizeof(struct ipv4_hdr));
-               key.port_dst = rte_be_to_cpu_16(udp->dst_port);
-               key.port_src = rte_be_to_cpu_16(udp->src_port);
-               break;
-
-       default:
-               key.port_dst = 0;
-               key.port_src = 0;
-               break;
-       }
-
-       /* Find destination port */
-       ret = rte_hash_lookup(ipv4_l3fwd_lookup_struct, (const void *)&key);
-       return (uint8_t)((ret < 0)? portid : ipv4_l3fwd_out_if[ret]);
-}
-
-static inline uint8_t
-get_ipv6_dst_port(struct ipv6_hdr *ipv6_hdr,  uint8_t portid, lookup_struct_t * ipv6_l3fwd_lookup_struct)
-{
-       struct ipv6_5tuple key;
-       struct tcp_hdr *tcp;
-       struct udp_hdr *udp;
-       int ret = 0;
-
-       memcpy(key.ip_dst, ipv6_hdr->dst_addr, IPV6_ADDR_LEN);
-       memcpy(key.ip_src, ipv6_hdr->src_addr, IPV6_ADDR_LEN);
-
-       key.proto = ipv6_hdr->proto;
-
-       switch (ipv6_hdr->proto) {
-       case IPPROTO_TCP:
-               tcp = (struct tcp_hdr *)((unsigned char *) ipv6_hdr +
-                                       sizeof(struct ipv6_hdr));
-               key.port_dst = rte_be_to_cpu_16(tcp->dst_port);
-               key.port_src = rte_be_to_cpu_16(tcp->src_port);
-               break;
-
-       case IPPROTO_UDP:
-               udp = (struct udp_hdr *)((unsigned char *) ipv6_hdr +
-                                       sizeof(struct ipv6_hdr));
-               key.port_dst = rte_be_to_cpu_16(udp->dst_port);
-               key.port_src = rte_be_to_cpu_16(udp->src_port);
-               break;
-
-       default:
-               key.port_dst = 0;
-               key.port_src = 0;
-               break;
-       }
-
-       /* Find destination port */
-       ret = rte_hash_lookup(ipv6_l3fwd_lookup_struct, (const void *)&key);
-       return (uint8_t)((ret < 0)? portid : ipv6_l3fwd_out_if[ret]);
-}
-#endif
-
-#if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
-static inline uint8_t
-get_ipv4_dst_port(struct ipv4_hdr *ipv4_hdr,  uint8_t portid, lookup_struct_t * ipv4_l3fwd_lookup_struct)
-{
-       uint8_t next_hop;
-
-       return (uint8_t) ((rte_lpm_lookup(ipv4_l3fwd_lookup_struct,
-                       rte_be_to_cpu_32(ipv4_hdr->dst_addr), &next_hop) == 0)?
-                       next_hop : portid);
-}
-
-static inline uint8_t
-get_ipv6_dst_port(struct ipv6_hdr *ipv6_hdr,  uint8_t portid, lookup6_struct_t * ipv6_l3fwd_lookup_struct)
-{
-       uint8_t next_hop;
-
-       return (uint8_t) ((rte_lpm6_lookup(ipv6_l3fwd_lookup_struct,
-                       ipv6_hdr->dst_addr, &next_hop) == 0)?
-                       next_hop : portid);
-}
-#endif
-
 static inline void
-l3fwd_simple_forward(struct rte_mbuf *m, uint8_t portid, uint32_t queue,
-       struct lcore_conf *qconf, uint64_t tms)
+reassemble(struct rte_mbuf *m, uint8_t portid, uint32_t queue,
+       struct lcore_queue_conf *qconf, uint64_t tms)
 {
        struct ether_hdr *eth_hdr;
-       struct ipv4_hdr *ipv4_hdr;
+       struct rte_ip_frag_tbl *tbl;
+       struct rte_ip_frag_death_row *dr;
+       struct rx_queue *rxq;
        void *d_addr_bytes;
-       uint8_t dst_port;
+       uint8_t next_hop, dst_port;
+
+       rxq = &qconf->rx_queue_list[queue];
 
        eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
 
-       if (m->ol_flags & PKT_RX_IPV4_HDR) {
-               /* Handle IPv4 headers.*/
-               ipv4_hdr = (struct ipv4_hdr *)(eth_hdr + 1);
+       dst_port = portid;
 
-#ifdef DO_RFC_1812_CHECKS
-               /* Check to make sure the packet is valid (RFC1812) */
-               if (is_valid_ipv4_pkt(ipv4_hdr, m->pkt.pkt_len) < 0) {
-                       rte_pktmbuf_free(m);
-                       return;
-               }
+       /* if packet is IPv4 */
+       if (m->ol_flags & (PKT_RX_IPV4_HDR)) {
+               struct ipv4_hdr *ip_hdr;
+               uint32_t ip_dst;
 
-               /* Update time to live and header checksum */
-               --(ipv4_hdr->time_to_live);
-               ++(ipv4_hdr->hdr_checksum);
-#endif
+               ip_hdr = (struct ipv4_hdr *)(eth_hdr + 1);
 
                 /* if it is a fragmented packet, then try to reassemble. */
-               if (rte_ipv4_frag_pkt_is_fragmented(ipv4_hdr)) {
-
+               if (rte_ipv4_frag_pkt_is_fragmented(ip_hdr)) {
                        struct rte_mbuf *mo;
-                       struct rte_ip_frag_tbl *tbl;
-                       struct rte_ip_frag_death_row *dr;
 
-                       tbl = qconf->frag_tbl[queue];
+                       tbl = rxq->frag_tbl;
                        dr = &qconf->death_row;
 
                        /* prepare mbuf: setup l2_len/l3_len. */
                        m->pkt.vlan_macip.f.l2_len = sizeof(*eth_hdr);
-                       m->pkt.vlan_macip.f.l3_len = sizeof(*ipv4_hdr);
+                       m->pkt.vlan_macip.f.l3_len = sizeof(*ip_hdr);
 
                        /* process this fragment. */
-                       if ((mo = rte_ipv4_frag_reassemble_packet(tbl, dr, m, tms,
-                                       ipv4_hdr)) == NULL)
+                       mo = rte_ipv4_frag_reassemble_packet(tbl, dr, m, tms, ip_hdr);
+                       if (mo == NULL)
                                /* no packet to send out. */
                                return;
 
@@ -689,47 +426,67 @@ l3fwd_simple_forward(struct rte_mbuf *m, uint8_t portid, uint32_t queue,
                                m = mo;
                                eth_hdr = rte_pktmbuf_mtod(m,
                                        struct ether_hdr *);
-                               ipv4_hdr = (struct ipv4_hdr *)(eth_hdr + 1);
+                               ip_hdr = (struct ipv4_hdr *)(eth_hdr + 1);
                        }
                }
+               ip_dst = rte_be_to_cpu_32(ip_hdr->dst_addr);
 
-               dst_port = get_ipv4_dst_port(ipv4_hdr, portid,
-                       qconf->ipv4_lookup_struct);
-               if (dst_port >= MAX_PORTS ||
-                               (enabled_port_mask & 1 << dst_port) == 0)
-                       dst_port = portid;
+               /* Find destination port */
+               if (rte_lpm_lookup(rxq->lpm, ip_dst, &next_hop) == 0 &&
+                               (enabled_port_mask & 1 << next_hop) != 0) {
+                       dst_port = next_hop;
+               }
 
-               /* 02:00:00:00:00:xx */
-               d_addr_bytes = &eth_hdr->d_addr.addr_bytes[0];
-               *((uint64_t *)d_addr_bytes) = 0x000000000002 + ((uint64_t)dst_port << 40);
+               eth_hdr->ether_type = rte_be_to_cpu_16(ETHER_TYPE_IPv4);
+       }
+       /* if packet is IPv6 */
+       else if (m->ol_flags & (PKT_RX_IPV6_HDR | PKT_RX_IPV6_HDR_EXT)) {
+               struct ipv6_extension_fragment *frag_hdr;
+               struct ipv6_hdr *ip_hdr;
 
-               /* src addr */
-               ether_addr_copy(&ports_eth_addr[dst_port], &eth_hdr->s_addr);
+               ip_hdr = (struct ipv6_hdr *)(eth_hdr + 1);
 
-               send_single_packet(m, dst_port);
-       }
-       else {
-               /* Handle IPv6 headers.*/
-               struct ipv6_hdr *ipv6_hdr;
+               frag_hdr = rte_ipv6_frag_get_ipv6_fragment_header(ip_hdr);
 
-               ipv6_hdr = (struct ipv6_hdr *)(rte_pktmbuf_mtod(m, unsigned char *) +
-                               sizeof(struct ether_hdr));
+               if (frag_hdr != NULL) {
+                       struct rte_mbuf *mo;
 
-               dst_port = get_ipv6_dst_port(ipv6_hdr, portid, qconf->ipv6_lookup_struct);
+                       tbl = rxq->frag_tbl;
+                       dr  = &qconf->death_row;
 
-               if (dst_port >= MAX_PORTS || (enabled_port_mask & 1 << dst_port) == 0)
-                       dst_port = portid;
+                       /* prepare mbuf: setup l2_len/l3_len. */
+                       m->pkt.vlan_macip.f.l2_len = sizeof(*eth_hdr);
+                       m->pkt.vlan_macip.f.l3_len = sizeof(*ip_hdr) + sizeof(*frag_hdr);
 
-               /* 02:00:00:00:00:xx */
-               d_addr_bytes = &eth_hdr->d_addr.addr_bytes[0];
-               *((uint64_t *)d_addr_bytes) = 0x000000000002 + ((uint64_t)dst_port << 40);
+                       mo = rte_ipv6_frag_reassemble_packet(tbl, dr, m, tms, ip_hdr, frag_hdr);
+                       if (mo == NULL)
+                               return;
 
-               /* src addr */
-               ether_addr_copy(&ports_eth_addr[dst_port], &eth_hdr->s_addr);
+                       if (mo != m) {
+                               m = mo;
+                               eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
+                               ip_hdr = (struct ipv6_hdr *)(eth_hdr + 1);
+                       }
+               }
 
-               send_single_packet(m, dst_port);
+               /* Find destination port */
+               if (rte_lpm6_lookup(rxq->lpm6, ip_hdr->dst_addr, &next_hop) == 0 &&
+                               (enabled_port_mask & 1 << next_hop) != 0) {
+                       dst_port = next_hop;
+               }
+
+               eth_hdr->ether_type = rte_be_to_cpu_16(ETHER_TYPE_IPv6);
        }
+       /* if packet wasn't IPv4 or IPv6, it's forwarded to the port it came from */
+
+       /* 02:00:00:00:00:xx */
+       d_addr_bytes = &eth_hdr->d_addr.addr_bytes[0];
+       *((uint64_t *)d_addr_bytes) = 0x000000000002 + ((uint64_t)dst_port << 40);
 
+       /* src addr */
+       ether_addr_copy(&ports_eth_addr[dst_port], &eth_hdr->s_addr);
+
+       send_single_packet(m, dst_port);
 }
 
 /* main processing loop */
@@ -740,28 +497,27 @@ main_loop(__attribute__((unused)) void *dummy)
        unsigned lcore_id;
        uint64_t diff_tsc, cur_tsc, prev_tsc;
        int i, j, nb_rx;
-       uint8_t portid, queueid;
-       struct lcore_conf *qconf;
+       uint8_t portid;
+       struct lcore_queue_conf *qconf;
        const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;
 
        prev_tsc = 0;
 
        lcore_id = rte_lcore_id();
-       qconf = &lcore_conf[lcore_id];
+       qconf = &lcore_queue_conf[lcore_id];
 
        if (qconf->n_rx_queue == 0) {
-               RTE_LOG(INFO, L3FWD, "lcore %u has nothing to do\n", lcore_id);
+               RTE_LOG(INFO, IP_RSMBL, "lcore %u has nothing to do\n", lcore_id);
                return 0;
        }
 
-       RTE_LOG(INFO, L3FWD, "entering main loop on lcore %u\n", lcore_id);
+       RTE_LOG(INFO, IP_RSMBL, "entering main loop on lcore %u\n", lcore_id);
 
        for (i = 0; i < qconf->n_rx_queue; i++) {
 
-               portid = qconf->rx_queue_list[i].port_id;
-               queueid = qconf->rx_queue_list[i].queue_id;
-               RTE_LOG(INFO, L3FWD, " -- lcoreid=%u portid=%hhu rxqueueid=%hhu\n", lcore_id,
-                       portid, queueid);
+               portid = qconf->rx_queue_list[i].portid;
+               RTE_LOG(INFO, IP_RSMBL, " -- lcoreid=%u portid=%hhu\n", lcore_id,
+                       portid);
        }
 
        while (1) {
@@ -778,7 +534,7 @@ main_loop(__attribute__((unused)) void *dummy)
                         * This could be optimized (use queueid instead of
                         * portid), but it is not called so often
                         */
-                       for (portid = 0; portid < MAX_PORTS; portid++) {
+                       for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
                                if ((enabled_port_mask & (1 << portid)) != 0)
                                        send_burst(qconf, 1, portid);
                        }
@@ -791,10 +547,9 @@ main_loop(__attribute__((unused)) void *dummy)
                 */
                for (i = 0; i < qconf->n_rx_queue; ++i) {
 
-                       portid = qconf->rx_queue_list[i].port_id;
-                       queueid = qconf->rx_queue_list[i].queue_id;
+                       portid = qconf->rx_queue_list[i].portid;
 
-                       nb_rx = rte_eth_rx_burst(portid, queueid, pkts_burst,
+                       nb_rx = rte_eth_rx_burst(portid, 0, pkts_burst,
                                MAX_PKT_BURST);
 
                        /* Prefetch first packets */
@@ -807,13 +562,13 @@ main_loop(__attribute__((unused)) void *dummy)
                        for (j = 0; j < (nb_rx - PREFETCH_OFFSET); j++) {
                                rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[
                                        j + PREFETCH_OFFSET], void *));
-                               l3fwd_simple_forward(pkts_burst[j], portid,
+                               reassemble(pkts_burst[j], portid,
                                        i, qconf, cur_tsc);
                        }
 
                        /* Forward remaining prefetched packets */
                        for (; j < nb_rx; j++) {
-                               l3fwd_simple_forward(pkts_burst[j], portid,
+                               reassemble(pkts_burst[j], portid,
                                        i, qconf, cur_tsc);
                        }
 
@@ -823,104 +578,15 @@ main_loop(__attribute__((unused)) void *dummy)
        }
 }
 
-static int
-check_lcore_params(void)
-{
-       uint8_t queue, lcore;
-       uint16_t i;
-       int socketid;
-
-       for (i = 0; i < nb_lcore_params; ++i) {
-               queue = lcore_params[i].queue_id;
-               if (queue >= MAX_RX_QUEUE_PER_PORT) {
-                       printf("invalid queue number: %hhu\n", queue);
-                       return -1;
-               }
-               lcore = lcore_params[i].lcore_id;
-               if (!rte_lcore_is_enabled(lcore)) {
-                       printf("error: lcore %hhu is not enabled in lcore mask\n", lcore);
-                       return -1;
-               }
-               if ((socketid = rte_lcore_to_socket_id(lcore) != 0) &&
-                       (numa_on == 0)) {
-                       printf("warning: lcore %hhu is on socket %d with numa off \n",
-                               lcore, socketid);
-               }
-       }
-       return 0;
-}
-
-static int
-check_port_config(const unsigned nb_ports)
-{
-       unsigned portid;
-       uint16_t i;
-
-       for (i = 0; i < nb_lcore_params; ++i) {
-               portid = lcore_params[i].port_id;
-               if ((enabled_port_mask & (1 << portid)) == 0) {
-                       printf("port %u is not enabled in port mask\n", portid);
-                       return -1;
-               }
-               if (portid >= nb_ports) {
-                       printf("port %u is not present on the board\n", portid);
-                       return -1;
-               }
-       }
-       return 0;
-}
-
-static uint8_t
-get_port_n_rx_queues(const uint8_t port)
-{
-       int queue = -1;
-       uint16_t i;
-
-       for (i = 0; i < nb_lcore_params; ++i) {
-               if (lcore_params[i].port_id == port && lcore_params[i].queue_id > queue)
-                       queue = lcore_params[i].queue_id;
-       }
-       return (uint8_t)(++queue);
-}
-
-static int
-init_lcore_rx_queues(void)
-{
-       uint16_t i, nb_rx_queue;
-       uint8_t lcore;
-
-       for (i = 0; i < nb_lcore_params; ++i) {
-               lcore = lcore_params[i].lcore_id;
-               nb_rx_queue = lcore_conf[lcore].n_rx_queue;
-               if (nb_rx_queue >= MAX_RX_QUEUE_PER_LCORE) {
-                       printf("error: too many queues (%u) for lcore: %u\n",
-                               (unsigned)nb_rx_queue + 1, (unsigned)lcore);
-                       return -1;
-               } else {
-                       lcore_conf[lcore].rx_queue_list[nb_rx_queue].port_id =
-                               lcore_params[i].port_id;
-                       lcore_conf[lcore].rx_queue_list[nb_rx_queue].queue_id =
-                               lcore_params[i].queue_id;
-                       lcore_conf[lcore].n_rx_queue++;
-               }
-       }
-       return 0;
-}
-
 /* display usage */
 static void
 print_usage(const char *prgname)
 {
-       printf ("%s [EAL options] -- -p PORTMASK -P"
-               "  [--config (port,queue,lcore)[,(port,queue,lcore]]"
-               "  [--enable-jumbo [--max-pkt-len PKTLEN]]"
+       printf("%s [EAL options] -- -p PORTMASK [-q NQ]"
+               "  [--max-pkt-len PKTLEN]"
                "  [--maxflows=<flows>]  [--flowttl=<ttl>[(s|ms)]]\n"
                "  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
-               "  -P : enable promiscuous mode\n"
-               "  --config (port,queue,lcore): rx queues configuration\n"
-               "  --no-numa: optional, disable numa awareness\n"
-               "  --enable-jumbo: enable jumbo frame"
-               " which max packet len is PKTLEN in decimal (64-9600)\n"
+               "  -q NQ: number of RX queues per lcore\n"
                "  --maxflows=<flows>: optional, maximum number of flows "
                "supported\n"
                "  --flowttl=<ttl>[(s|ms)]: optional, maximum TTL for each "
@@ -976,23 +642,6 @@ parse_flow_ttl(const char *str, uint32_t min, uint32_t max, uint32_t *val)
        return (0);
 }
 
-
-static int parse_max_pkt_len(const char *pktlen)
-{
-       char *end = NULL;
-       unsigned long len;
-
-       /* parse decimal string */
-       len = strtoul(pktlen, &end, 10);
-       if ((pktlen[0] == '\0') || (end == NULL) || (*end != '\0'))
-               return -1;
-
-       if (len == 0)
-               return -1;
-
-       return len;
-}
-
 static int
 parse_portmask(const char *portmask)
 {
@@ -1011,54 +660,23 @@ parse_portmask(const char *portmask)
 }
 
 static int
-parse_config(const char *q_arg)
+parse_nqueue(const char *q_arg)
 {
-       char s[256];
-       const char *p, *p0 = q_arg;
-       char *end;
-       enum fieldnames {
-               FLD_PORT = 0,
-               FLD_QUEUE,
-               FLD_LCORE,
-               _NUM_FLD
-       };
-       unsigned long int_fld[_NUM_FLD];
-       char *str_fld[_NUM_FLD];
-       int i;
-       unsigned size;
-
-       nb_lcore_params = 0;
+       char *end = NULL;
+       unsigned long n;
 
-       while ((p = strchr(p0,'(')) != NULL) {
-               ++p;
-               if((p0 = strchr(p,')')) == NULL)
-                       return -1;
+       printf("%p\n", q_arg);
 
-               size = p0 - p;
-               if(size >= sizeof(s))
-                       return -1;
+       /* parse hexadecimal string */
+       n = strtoul(q_arg, &end, 10);
+       if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+               return -1;
+       if (n == 0)
+               return -1;
+       if (n >= MAX_RX_QUEUE_PER_LCORE)
+               return -1;
 
-               rte_snprintf(s, sizeof(s), "%.*s", size, p);
-               if (rte_strsplit(s, sizeof(s), str_fld, _NUM_FLD, ',') != _NUM_FLD)
-                       return -1;
-               for (i = 0; i < _NUM_FLD; i++){
-                       errno = 0;
-                       int_fld[i] = strtoul(str_fld[i], &end, 0);
-                       if (errno != 0 || end == str_fld[i] || int_fld[i] > 255)
-                               return -1;
-               }
-               if (nb_lcore_params >= MAX_LCORE_PARAMS) {
-                       printf("exceeded max number of lcore params: %hu\n",
-                               nb_lcore_params);
-                       return -1;
-               }
-               lcore_params_array[nb_lcore_params].port_id = (uint8_t)int_fld[FLD_PORT];
-               lcore_params_array[nb_lcore_params].queue_id = (uint8_t)int_fld[FLD_QUEUE];
-               lcore_params_array[nb_lcore_params].lcore_id = (uint8_t)int_fld[FLD_LCORE];
-               ++nb_lcore_params;
-       }
-       lcore_params = lcore_params_array;
-       return 0;
+       return n;
 }
 
 /* Parse the argument given in the command line of the application */
@@ -1070,9 +688,7 @@ parse_args(int argc, char **argv)
        int option_index;
        char *prgname = argv[0];
        static struct option lgopts[] = {
-               {"config", 1, 0, 0},
-               {"no-numa", 0, 0, 0},
-               {"enable-jumbo", 0, 0, 0},
+               {"max-pkt-len", 1, 0, 0},
                {"maxflows", 1, 0, 0},
                {"flowttl", 1, 0, 0},
                {NULL, 0, 0, 0}
@@ -1080,7 +696,7 @@ parse_args(int argc, char **argv)
 
        argvopt = argv;
 
-       while ((opt = getopt_long(argc, argvopt, "p:P",
+       while ((opt = getopt_long(argc, argvopt, "p:q:",
                                lgopts, &option_index)) != EOF) {
 
                switch (opt) {
@@ -1093,27 +709,19 @@ parse_args(int argc, char **argv)
                                return -1;
                        }
                        break;
-               case 'P':
-                       printf("Promiscuous mode selected\n");
-                       promiscuous_on = 1;
+
+               /* nqueue */
+               case 'q':
+                       rx_queue_per_lcore = parse_nqueue(optarg);
+                       if (rx_queue_per_lcore < 0) {
+                               printf("invalid queue number\n");
+                               print_usage(prgname);
+                               return -1;
+                       }
                        break;
 
                /* long options */
                case 0:
-                       if (!strncmp(lgopts[option_index].name, "config", 6)) {
-                               ret = parse_config(optarg);
-                               if (ret) {
-                                       printf("invalid config\n");
-                                       print_usage(prgname);
-                                       return -1;
-                               }
-                       }
-
-                       if (!strncmp(lgopts[option_index].name, "no-numa", 7)) {
-                               printf("numa is disabled \n");
-                               numa_on = 0;
-                       }
-
                        if (!strncmp(lgopts[option_index].name,
                                        "maxflows", 8)) {
                                if ((ret = parse_flow_num(optarg, MIN_FLOW_NUM,
@@ -1141,26 +749,6 @@ parse_args(int argc, char **argv)
                                }
                        }
 
-                       if (!strncmp(lgopts[option_index].name, "enable-jumbo", 12)) {
-                               struct option lenopts = {"max-pkt-len", required_argument, 0, 0};
-
-                               printf("jumbo frame is enabled \n");
-                               port_conf.rxmode.jumbo_frame = 1;
-
-                               /* if no max-pkt-len set, use the default value ETHER_MAX_LEN */
-                               if (0 == getopt_long(argc, argvopt, "", &lenopts, &option_index)) {
-                                       ret = parse_max_pkt_len(optarg);
-                                       if ((ret < 64) || (ret > MAX_JUMBO_PKT_LEN)){
-                                               printf("invalid packet length\n");
-                                               print_usage(prgname);
-                                               return -1;
-                                       }
-                                       port_conf.rxmode.max_rx_pkt_len = ret;
-                               }
-                               printf("set jumbo frame max packet length to %u\n",
-                                               (unsigned int)port_conf.rxmode.max_rx_pkt_len);
-                       }
-
                        break;
 
                default:
@@ -1189,182 +777,6 @@ print_ethaddr(const char *name, const struct ether_addr *eth_addr)
                eth_addr->addr_bytes[5]);
 }
 
-#if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
-static void
-setup_hash(int socketid)
-{
-       struct rte_hash_parameters ipv4_l3fwd_hash_params = {
-               .name = NULL,
-               .entries = L3FWD_HASH_ENTRIES,
-               .bucket_entries = 4,
-               .key_len = sizeof(struct ipv4_5tuple),
-               .hash_func = DEFAULT_HASH_FUNC,
-               .hash_func_init_val = 0,
-       };
-
-       struct rte_hash_parameters ipv6_l3fwd_hash_params = {
-               .name = NULL,
-               .entries = L3FWD_HASH_ENTRIES,
-               .bucket_entries = 4,
-               .key_len = sizeof(struct ipv6_5tuple),
-               .hash_func = DEFAULT_HASH_FUNC,
-               .hash_func_init_val = 0,
-       };
-
-       unsigned i;
-       int ret;
-       char s[64];
-
-       /* create ipv4 hash */
-       rte_snprintf(s, sizeof(s), "ipv4_l3fwd_hash_%d", socketid);
-       ipv4_l3fwd_hash_params.name = s;
-       ipv4_l3fwd_hash_params.socket_id = socketid;
-       ipv4_l3fwd_lookup_struct[socketid] = rte_hash_create(&ipv4_l3fwd_hash_params);
-       if (ipv4_l3fwd_lookup_struct[socketid] == NULL)
-               rte_exit(EXIT_FAILURE, "Unable to create the l3fwd hash on "
-                               "socket %d\n", socketid);
-
-       /* create ipv6 hash */
-       rte_snprintf(s, sizeof(s), "ipv6_l3fwd_hash_%d", socketid);
-       ipv6_l3fwd_hash_params.name = s;
-       ipv6_l3fwd_hash_params.socket_id = socketid;
-       ipv6_l3fwd_lookup_struct[socketid] = rte_hash_create(&ipv6_l3fwd_hash_params);
-       if (ipv6_l3fwd_lookup_struct[socketid] == NULL)
-               rte_exit(EXIT_FAILURE, "Unable to create the l3fwd hash on "
-                               "socket %d\n", socketid);
-
-
-       /* populate the ipv4 hash */
-       for (i = 0; i < IPV4_L3FWD_NUM_ROUTES; i++) {
-               ret = rte_hash_add_key (ipv4_l3fwd_lookup_struct[socketid],
-                               (void *) &ipv4_l3fwd_route_array[i].key);
-               if (ret < 0) {
-                       rte_exit(EXIT_FAILURE, "Unable to add entry %u to the"
-                               "l3fwd hash on socket %d\n", i, socketid);
-               }
-               ipv4_l3fwd_out_if[ret] = ipv4_l3fwd_route_array[i].if_out;
-               printf("Hash: Adding key\n");
-               print_ipv4_key(ipv4_l3fwd_route_array[i].key);
-       }
-
-       /* populate the ipv6 hash */
-       for (i = 0; i < IPV6_L3FWD_NUM_ROUTES; i++) {
-               ret = rte_hash_add_key (ipv6_l3fwd_lookup_struct[socketid],
-                               (void *) &ipv6_l3fwd_route_array[i].key);
-               if (ret < 0) {
-                       rte_exit(EXIT_FAILURE, "Unable to add entry %u to the"
-                               "l3fwd hash on socket %d\n", i, socketid);
-               }
-               ipv6_l3fwd_out_if[ret] = ipv6_l3fwd_route_array[i].if_out;
-               printf("Hash: Adding key\n");
-               print_ipv6_key(ipv6_l3fwd_route_array[i].key);
-       }
-}
-#endif
-
-#if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
-static void
-setup_lpm(int socketid)
-{
-       struct rte_lpm6_config config;
-       unsigned i;
-       int ret;
-       char s[64];
-
-       /* create the LPM table */
-       rte_snprintf(s, sizeof(s), "IPV4_L3FWD_LPM_%d", socketid);
-       ipv4_l3fwd_lookup_struct[socketid] = rte_lpm_create(s, socketid,
-                               IPV4_L3FWD_LPM_MAX_RULES, 0);
-       if (ipv4_l3fwd_lookup_struct[socketid] == NULL)
-               rte_exit(EXIT_FAILURE, "Unable to create the l3fwd LPM table"
-                               " on socket %d\n", socketid);
-
-       /* populate the LPM table */
-       for (i = 0; i < IPV4_L3FWD_NUM_ROUTES; i++) {
-               ret = rte_lpm_add(ipv4_l3fwd_lookup_struct[socketid],
-                       ipv4_l3fwd_route_array[i].ip,
-                       ipv4_l3fwd_route_array[i].depth,
-                       ipv4_l3fwd_route_array[i].if_out);
-
-               if (ret < 0) {
-                       rte_exit(EXIT_FAILURE, "Unable to add entry %u to the "
-                               "l3fwd LPM table on socket %d\n",
-                               i, socketid);
-               }
-
-               printf("LPM: Adding route 0x%08x / %d (%d)\n",
-                       (unsigned)ipv4_l3fwd_route_array[i].ip,
-                       ipv4_l3fwd_route_array[i].depth,
-                       ipv4_l3fwd_route_array[i].if_out);
-       }
-
-       /* create the LPM6 table */
-       rte_snprintf(s, sizeof(s), "IPV6_L3FWD_LPM_%d", socketid);
-
-       config.max_rules = IPV6_L3FWD_LPM_MAX_RULES;
-       config.number_tbl8s = IPV6_L3FWD_LPM_NUMBER_TBL8S;
-       config.flags = 0;
-       ipv6_l3fwd_lookup_struct[socketid] = rte_lpm6_create(s, socketid,
-                               &config);
-       if (ipv6_l3fwd_lookup_struct[socketid] == NULL)
-               rte_exit(EXIT_FAILURE, "Unable to create the l3fwd LPM table"
-                               " on socket %d\n", socketid);
-
-       /* populate the LPM table */
-       for (i = 0; i < IPV6_L3FWD_NUM_ROUTES; i++) {
-               ret = rte_lpm6_add(ipv6_l3fwd_lookup_struct[socketid],
-                       ipv6_l3fwd_route_array[i].ip,
-                       ipv6_l3fwd_route_array[i].depth,
-                       ipv6_l3fwd_route_array[i].if_out);
-
-               if (ret < 0) {
-                       rte_exit(EXIT_FAILURE, "Unable to add entry %u to the "
-                               "l3fwd LPM table on socket %d\n",
-                               i, socketid);
-               }
-
-               printf("LPM: Adding route %s / %d (%d)\n",
-                       "IPV6",
-                       ipv6_l3fwd_route_array[i].depth,
-                       ipv6_l3fwd_route_array[i].if_out);
-       }
-}
-#endif
-
-static int
-init_mem(void)
-{
-       struct lcore_conf *qconf;
-       int socketid;
-       unsigned lcore_id;
-
-       for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
-               if (rte_lcore_is_enabled(lcore_id) == 0)
-                       continue;
-
-               if (numa_on)
-                       socketid = rte_lcore_to_socket_id(lcore_id);
-               else
-                       socketid = 0;
-
-               if (socketid >= NB_SOCKETS) {
-                       rte_exit(EXIT_FAILURE,
-                               "Socket %d of lcore %u is out of range %d\n",
-                               socketid, lcore_id, NB_SOCKETS);
-               }
-
-#if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
-                       setup_lpm(socketid);
-#else
-                       setup_hash(socketid);
-#endif
-               qconf = &lcore_conf[lcore_id];
-               qconf->ipv4_lookup_struct = ipv4_l3fwd_lookup_struct[socketid];
-               qconf->ipv6_lookup_struct = ipv6_l3fwd_lookup_struct[socketid];
-       }
-       return 0;
-}
-
 /* Check the link status of all ports in up to 9s, and print them finally */
 static void
 check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
@@ -1415,12 +827,73 @@ check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
                /* set the print_flag if all ports up or timeout */
                if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
                        print_flag = 1;
-                       printf("done\n");
+                       printf("\ndone\n");
                }
        }
 }
-static void
-setup_port_tbl(struct lcore_conf *qconf, uint32_t lcore, int socket,
+
+static int
+init_routing_table(void)
+{
+       struct rte_lpm *lpm;
+       struct rte_lpm6 *lpm6;
+       int socket, ret;
+       unsigned i;
+
+       for (socket = 0; socket < RTE_MAX_NUMA_NODES; socket++) {
+               if (socket_lpm[socket]) {
+                       lpm = socket_lpm[socket];
+                       /* populate the LPM table */
+                       for (i = 0; i < RTE_DIM(l3fwd_ipv4_route_array); i++) {
+                               ret = rte_lpm_add(lpm,
+                                       l3fwd_ipv4_route_array[i].ip,
+                                       l3fwd_ipv4_route_array[i].depth,
+                                       l3fwd_ipv4_route_array[i].if_out);
+
+                               if (ret < 0) {
+                                       RTE_LOG(ERR, IP_RSMBL, "Unable to add entry %i to the l3fwd "
+                                               "LPM table\n", i);
+                                       return -1;
+                               }
+
+                               RTE_LOG(INFO, IP_RSMBL, "Socket %i: adding route " IPv4_BYTES_FMT
+                                               "/%d (port %d)\n",
+                                       socket,
+                                       IPv4_BYTES(l3fwd_ipv4_route_array[i].ip),
+                                       l3fwd_ipv4_route_array[i].depth,
+                                       l3fwd_ipv4_route_array[i].if_out);
+                       }
+               }
+
+               if (socket_lpm6[socket]) {
+                       lpm6 = socket_lpm6[socket];
+                       /* populate the LPM6 table */
+                       for (i = 0; i < RTE_DIM(l3fwd_ipv6_route_array); i++) {
+                               ret = rte_lpm6_add(lpm6,
+                                       l3fwd_ipv6_route_array[i].ip,
+                                       l3fwd_ipv6_route_array[i].depth,
+                                       l3fwd_ipv6_route_array[i].if_out);
+
+                               if (ret < 0) {
+                                       RTE_LOG(ERR, IP_RSMBL, "Unable to add entry %i to the l3fwd "
+                                               "LPM6 table\n", i);
+                                       return -1;
+                               }
+
+                               RTE_LOG(INFO, IP_RSMBL, "Socket %i: adding route " IPv6_BYTES_FMT
+                                               "/%d (port %d)\n",
+                                       socket,
+                                       IPv6_BYTES(l3fwd_ipv6_route_array[i].ip),
+                                       l3fwd_ipv6_route_array[i].depth,
+                                       l3fwd_ipv6_route_array[i].if_out);
+                       }
+               }
+       }
+       return 0;
+}
+
+static int
+setup_port_tbl(struct lcore_queue_conf *qconf, uint32_t lcore, int socket,
        uint32_t port)
 {
        struct mbuf_table *mtb;
@@ -1431,32 +904,42 @@ setup_port_tbl(struct lcore_conf *qconf, uint32_t lcore, int socket,
        sz = sizeof (*mtb) + sizeof (mtb->m_table[0]) *  n;
 
        if ((mtb = rte_zmalloc_socket(__func__, sz, CACHE_LINE_SIZE,
-                       socket)) == NULL)
-               rte_exit(EXIT_FAILURE, "%s() for lcore: %u, port: %u "
+                       socket)) == NULL) {
+               RTE_LOG(ERR, IP_RSMBL, "%s() for lcore: %u, port: %u "
                        "failed to allocate %zu bytes\n",
                        __func__, lcore, port, sz);
+               return -1;
+       }
 
        mtb->len = n;
        qconf->tx_mbufs[port] = mtb;
+
+       return 0;
 }
 
-static void
-setup_queue_tbl(struct lcore_conf *qconf, uint32_t lcore, int socket,
-       uint32_t queue)
+static int
+setup_queue_tbl(struct rx_queue *rxq, uint32_t lcore, uint32_t queue)
 {
+       int socket;
        uint32_t nb_mbuf;
        uint64_t frag_cycles;
        char buf[RTE_MEMPOOL_NAMESIZE];
 
+       socket = rte_lcore_to_socket_id(lcore);
+       if (socket == SOCKET_ID_ANY)
+               socket = 0;
+
        frag_cycles = (rte_get_tsc_hz() + MS_PER_S - 1) / MS_PER_S *
                max_flow_ttl;
 
-       if ((qconf->frag_tbl[queue] = rte_ip_frag_table_create(max_flow_num,
-                       IPV4_FRAG_TBL_BUCKET_ENTRIES, max_flow_num, frag_cycles,
-                       socket)) == NULL)
-               rte_exit(EXIT_FAILURE, "ipv4_frag_tbl_create(%u) on "
+       if ((rxq->frag_tbl = rte_ip_frag_table_create(max_flow_num,
+                       IP_FRAG_TBL_BUCKET_ENTRIES, max_flow_num, frag_cycles,
+                       socket)) == NULL) {
+               RTE_LOG(ERR, IP_RSMBL, "ip_frag_tbl_create(%u) on "
                        "lcore: %u for queue: %u failed\n",
                        max_flow_num, lcore, queue);
+               return -1;
+       }
 
        /*
         * At any given moment up to <max_flow_num * (MAX_FRAG_NUM - 1)>
@@ -1464,40 +947,93 @@ setup_queue_tbl(struct lcore_conf *qconf, uint32_t lcore, int socket,
         * Plus, each TX queue can hold up to <max_flow_num> packets.
         */
 
-       nb_mbuf = 2 * RTE_MAX(max_flow_num, 2UL * MAX_PKT_BURST) *
-                       RTE_LIBRTE_IP_FRAG_MAX_FRAG;
+       nb_mbuf = 2 * RTE_MAX(max_flow_num, 2UL * MAX_PKT_BURST) * MAX_FRAG_NUM;
        nb_mbuf *= (port_conf.rxmode.max_rx_pkt_len + BUF_SIZE - 1) / BUF_SIZE;
        nb_mbuf += RTE_TEST_RX_DESC_DEFAULT + RTE_TEST_TX_DESC_DEFAULT;
+       nb_mbuf *= 2; /* ipv4 and ipv6 */
 
-       nb_mbuf = RTE_MAX(nb_mbuf, (uint32_t)DEF_MBUF_NUM);
+       nb_mbuf = RTE_MAX(nb_mbuf, (uint32_t)NB_MBUF);
 
        rte_snprintf(buf, sizeof(buf), "mbuf_pool_%u_%u", lcore, queue);
 
-       if ((qconf->pool[queue] = rte_mempool_create(buf, nb_mbuf, MBUF_SIZE, 0,
+       if ((rxq->pool = rte_mempool_create(buf, nb_mbuf, MBUF_SIZE, 0,
                        sizeof(struct rte_pktmbuf_pool_private),
                        rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, NULL,
-                       socket, MEMPOOL_F_SP_PUT | MEMPOOL_F_SC_GET)) == NULL)
-               rte_exit(EXIT_FAILURE, "mempool_create(%s) failed", buf);
+                       socket, MEMPOOL_F_SP_PUT | MEMPOOL_F_SC_GET)) == NULL) {
+               RTE_LOG(ERR, IP_RSMBL, "mempool_create(%s) failed", buf);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int
+init_mem(void)
+{
+       char buf[PATH_MAX];
+       struct rte_lpm *lpm;
+       struct rte_lpm6 *lpm6;
+       int socket;
+       unsigned lcore_id;
+
+       /* traverse through lcores and initialize structures on each socket */
+
+       for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+
+               if (rte_lcore_is_enabled(lcore_id) == 0)
+                       continue;
+
+               socket = rte_lcore_to_socket_id(lcore_id);
+
+               if (socket == SOCKET_ID_ANY)
+                       socket = 0;
+
+               if (socket_lpm[socket] == NULL) {
+                       RTE_LOG(INFO, IP_RSMBL, "Creating LPM table on socket %i\n", socket);
+                       rte_snprintf(buf, sizeof(buf), "IP_RSMBL_LPM_%i", socket);
+
+                       lpm = rte_lpm_create(buf, socket, LPM_MAX_RULES, 0);
+                       if (lpm == NULL) {
+                               RTE_LOG(ERR, IP_RSMBL, "Cannot create LPM table\n");
+                               return -1;
+                       }
+                       socket_lpm[socket] = lpm;
+               }
+
+               if (socket_lpm6[socket] == NULL) {
+                       RTE_LOG(INFO, IP_RSMBL, "Creating LPM6 table on socket %i\n", socket);
+                       rte_snprintf(buf, sizeof(buf), "IP_RSMBL_LPM_%i", socket);
+
+                       lpm6 = rte_lpm6_create("IP_RSMBL_LPM6", socket, &lpm6_config);
+                       if (lpm6 == NULL) {
+                               RTE_LOG(ERR, IP_RSMBL, "Cannot create LPM table\n");
+                               return -1;
+                       }
+                       socket_lpm6[socket] = lpm6;
+               }
+       }
+
+       return 0;
 }
 
 static void
 queue_dump_stat(void)
 {
        uint32_t i, lcore;
-       const struct lcore_conf *qconf;
+       const struct lcore_queue_conf *qconf;
 
        for (lcore = 0; lcore < RTE_MAX_LCORE; lcore++) {
                if (rte_lcore_is_enabled(lcore) == 0)
                        continue;
 
-               qconf = lcore_conf + lcore;
+               qconf = &lcore_queue_conf[lcore];
                for (i = 0; i < qconf->n_rx_queue; i++) {
 
                        fprintf(stdout, " -- lcoreid=%u portid=%hhu "
-                               "rxqueueid=%hhu frag tbl stat:\n",
-                               lcore,  qconf->rx_queue_list[i].port_id,
-                               qconf->rx_queue_list[i].queue_id);
-                       rte_ip_frag_table_statistics_dump(stdout, qconf->frag_tbl[i]);
+                               "frag tbl stat:\n",
+                               lcore,  qconf->rx_queue_list[i].portid);
+                       rte_ip_frag_table_statistics_dump(stdout,
+                                       qconf->rx_queue_list[i].frag_tbl);
                        fprintf(stdout, "TX bursts:\t%" PRIu64 "\n"
                                "TX packets _queued:\t%" PRIu64 "\n"
                                "TX packets dropped:\t%" PRIu64 "\n"
@@ -1521,13 +1057,14 @@ signal_handler(int signum)
 int
 MAIN(int argc, char **argv)
 {
-       struct lcore_conf *qconf;
-       int ret;
+       struct lcore_queue_conf *qconf;
+       struct rx_queue *rxq;
+       int ret, socket;
        unsigned nb_ports;
        uint16_t queueid;
-       unsigned lcore_id;
+       unsigned lcore_id = 0, rx_lcore_id = 0;
        uint32_t n_tx_queue, nb_lcores;
-       uint8_t portid, nb_rx_queue, queue, socketid;
+       uint8_t portid;
 
        /* init EAL */
        ret = rte_eal_init(argc, argv);
@@ -1539,28 +1076,23 @@ MAIN(int argc, char **argv)
        /* parse application arguments (after the EAL ones) */
        ret = parse_args(argc, argv);
        if (ret < 0)
-               rte_exit(EXIT_FAILURE, "Invalid L3FWD parameters\n");
-
-       if (check_lcore_params() < 0)
-               rte_exit(EXIT_FAILURE, "check_lcore_params failed\n");
-
-       ret = init_lcore_rx_queues();
-       if (ret < 0)
-               rte_exit(EXIT_FAILURE, "init_lcore_rx_queues failed\n");
-
+               rte_exit(EXIT_FAILURE, "Invalid IP reassembly parameters\n");
 
        if (rte_eal_pci_probe() < 0)
                rte_exit(EXIT_FAILURE, "Cannot probe PCI\n");
 
        nb_ports = rte_eth_dev_count();
-       if (nb_ports > MAX_PORTS)
-               nb_ports = MAX_PORTS;
-
-       if (check_port_config(nb_ports) < 0)
-               rte_exit(EXIT_FAILURE, "check_port_config failed\n");
+       if (nb_ports > RTE_MAX_ETHPORTS)
+               nb_ports = RTE_MAX_ETHPORTS;
+       else if (nb_ports == 0)
+               rte_exit(EXIT_FAILURE, "No ports found!\n");
 
        nb_lcores = rte_lcore_count();
 
+       /* initialize structures (mempools, lpm etc.) */
+       if (init_mem() < 0)
+               rte_panic("Cannot initialize memory structures!\n");
+
        /* initialize all ports */
        for (portid = 0; portid < nb_ports; portid++) {
                /* skip ports that are not enabled */
@@ -1569,30 +1101,62 @@ MAIN(int argc, char **argv)
                        continue;
                }
 
+               qconf = &lcore_queue_conf[rx_lcore_id];
+
+               /* get the lcore_id for this port */
+               while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+                          qconf->n_rx_queue == (unsigned)rx_queue_per_lcore) {
+
+                       rx_lcore_id++;
+                       if (rx_lcore_id >= RTE_MAX_LCORE)
+                               rte_exit(EXIT_FAILURE, "Not enough cores\n");
+
+                       qconf = &lcore_queue_conf[rx_lcore_id];
+               }
+
+               socket = rte_eth_dev_socket_id(portid);
+               if (socket == SOCKET_ID_ANY)
+                       socket = 0;
+
+               queueid = qconf->n_rx_queue;
+               rxq = &qconf->rx_queue_list[queueid];
+               rxq->portid = portid;
+               rxq->lpm = socket_lpm[socket];
+               rxq->lpm6 = socket_lpm6[socket];
+               if (setup_queue_tbl(rxq, rx_lcore_id, queueid) < 0)
+                       rte_exit(EXIT_FAILURE, "Failed to set up queue table\n");
+               qconf->n_rx_queue++;
+
                /* init port */
                printf("Initializing port %d ... ", portid );
                fflush(stdout);
 
-               nb_rx_queue = get_port_n_rx_queues(portid);
                n_tx_queue = nb_lcores;
                if (n_tx_queue > MAX_TX_QUEUE_PER_PORT)
                        n_tx_queue = MAX_TX_QUEUE_PER_PORT;
-               printf("Creating queues: nb_rxq=%d nb_txq=%u... ",
-                       nb_rx_queue, (unsigned)n_tx_queue );
-               ret = rte_eth_dev_configure(portid, nb_rx_queue,
-                                       (uint16_t)n_tx_queue, &port_conf);
-               if (ret < 0)
-                       rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%d\n",
+               ret = rte_eth_dev_configure(portid, 1, (uint16_t)n_tx_queue,
+                                           &port_conf);
+               if (ret < 0) {
+                       printf("\n");
+                       rte_exit(EXIT_FAILURE, "Cannot configure device: "
+                               "err=%d, port=%d\n",
                                ret, portid);
+               }
+
+               /* init one RX queue */
+               ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+                                            socket, &rx_conf,
+                                            rxq->pool);
+               if (ret < 0) {
+                       printf("\n");
+                       rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup: "
+                               "err=%d, port=%d\n",
+                               ret, portid);
+               }
 
                rte_eth_macaddr_get(portid, &ports_eth_addr[portid]);
                print_ethaddr(" Address:", &ports_eth_addr[portid]);
-               printf(", ");
-
-               /* init memory */
-               ret = init_mem();
-               if (ret < 0)
-                       rte_exit(EXIT_FAILURE, "init_mem failed\n");
+               printf("\n");
 
                /* init one TX queue per couple (lcore,port) */
                queueid = 0;
@@ -1600,57 +1164,24 @@ MAIN(int argc, char **argv)
                        if (rte_lcore_is_enabled(lcore_id) == 0)
                                continue;
 
-                       if (numa_on)
-                               socketid = (uint8_t)rte_lcore_to_socket_id(lcore_id);
-                       else
-                               socketid = 0;
+                       socket = (int) rte_lcore_to_socket_id(lcore_id);
 
-                       printf("txq=%u,%d,%d ", lcore_id, queueid, socketid);
+                       printf("txq=%u,%d,%d ", lcore_id, queueid, socket);
                        fflush(stdout);
                        ret = rte_eth_tx_queue_setup(portid, queueid, nb_txd,
-                                                    socketid, &tx_conf);
+                                       socket, &tx_conf);
                        if (ret < 0)
                                rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup: err=%d, "
                                        "port=%d\n", ret, portid);
 
-                       qconf = &lcore_conf[lcore_id];
+                       qconf = &lcore_queue_conf[lcore_id];
                        qconf->tx_queue_id[portid] = queueid;
-                       setup_port_tbl(qconf, lcore_id, socketid, portid);
+                       setup_port_tbl(qconf, lcore_id, socket, portid);
                        queueid++;
                }
                printf("\n");
        }
 
-       for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
-               if (rte_lcore_is_enabled(lcore_id) == 0)
-                       continue;
-               qconf = &lcore_conf[lcore_id];
-               printf("\nInitializing rx queues on lcore %u ... ", lcore_id );
-               fflush(stdout);
-               /* init RX queues */
-               for(queue = 0; queue < qconf->n_rx_queue; ++queue) {
-                       portid = qconf->rx_queue_list[queue].port_id;
-                       queueid = qconf->rx_queue_list[queue].queue_id;
-
-                       if (numa_on)
-                               socketid = (uint8_t)rte_lcore_to_socket_id(lcore_id);
-                       else
-                               socketid = 0;
-
-                       printf("rxq=%d,%d,%d ", portid, queueid, socketid);
-                       fflush(stdout);
-
-                       setup_queue_tbl(qconf, lcore_id, socketid, queue);
-
-                       ret = rte_eth_rx_queue_setup(portid, queueid, nb_rxd,
-                                       socketid, &rx_conf, qconf->pool[queue]);
-                       if (ret < 0)
-                               rte_exit(EXIT_FAILURE,
-                                       "rte_eth_rx_queue_setup: err=%d,"
-                                       "port=%d\n", ret, portid);
-               }
-       }
-
        printf("\n");
 
        /* start ports */
@@ -1664,16 +1195,12 @@ MAIN(int argc, char **argv)
                        rte_exit(EXIT_FAILURE, "rte_eth_dev_start: err=%d, port=%d\n",
                                ret, portid);
 
-               /*
-                * If enabled, put device in promiscuous mode.
-                * This allows IO forwarding mode to forward packets
-                * to itself through 2 cross-connected  ports of the
-                * target machine.
-                */
-               if (promiscuous_on)
-                       rte_eth_promiscuous_enable(portid);
+               rte_eth_promiscuous_enable(portid);
        }
 
+       if (init_routing_table() < 0)
+               rte_exit(EXIT_FAILURE, "Cannot init routing table\n");
+
        check_all_ports_link_status((uint8_t)nb_ports, enabled_port_mask);
 
        signal(SIGUSR1, signal_handler);