From 480ef35615b5b0cb21818b117d4bedec42de93e4 Mon Sep 17 00:00:00 2001
From: zhengjiebing <zhengjiebing_yewu@cmss.chinamobile.com>
Date: Tue, 31 Oct 2023 04:24:34 +0800
Subject: [PATCH] enable ipv6

---
 src/common/gazelle_opt.h                |   3 +-
 src/lstack/api/lstack_wrap.c            |  93 ++++++----------
 src/lstack/core/lstack_cfg.c            |  29 ++++-
 src/lstack/core/lstack_control_plane.c  |   4 +-
 src/lstack/core/lstack_dpdk.c           |  29 +++--
 src/lstack/core/lstack_lwip.c           |  38 +++++--
 src/lstack/core/lstack_protocol_stack.c |   5 +-
 src/lstack/include/lstack_cfg.h         |   2 +
 src/lstack/include/lstack_dpdk.h        |   3 +-
 src/lstack/netif/lstack_ethdev.c        | 141 ++++++++++++++++--------
 src/lstack/netif/lstack_vdev.c          |  36 +++---
 src/ltran/ltran_timer.c                 |   8 ++
 12 files changed, 241 insertions(+), 150 deletions(-)

diff --git a/src/common/gazelle_opt.h b/src/common/gazelle_opt.h
index 0479051..7316fc6 100644
--- a/src/common/gazelle_opt.h
+++ b/src/common/gazelle_opt.h
@@ -54,7 +54,8 @@
 
 #define MTU_DEFAULT_DATA_LEN        1460
 #define VLAN_HEAD_LEN               4
-#define MBUF_MAX_DATA_LEN           (MTU_DEFAULT_DATA_LEN - VLAN_HEAD_LEN)
+#define IPV6_EXTRA_HEAD_LEN         20
+#define MBUF_MAX_DATA_LEN           (MTU_DEFAULT_DATA_LEN - VLAN_HEAD_LEN - IPV6_EXTRA_HEAD_LEN)
 
 #define DPDK_PKT_BURST_SIZE         512
 
diff --git a/src/lstack/api/lstack_wrap.c b/src/lstack/api/lstack_wrap.c
index 5bad513..9468003 100644
--- a/src/lstack/api/lstack_wrap.c
+++ b/src/lstack/api/lstack_wrap.c
@@ -12,6 +12,8 @@
 
 #define _GNU_SOURCE
 #include <dlfcn.h>
+#include <netdb.h>
+#include <ifaddrs.h>
 
 #include <signal.h>
 #include <fcntl.h>
@@ -184,28 +186,6 @@ static int32_t do_accept4(int32_t s, struct sockaddr *addr, socklen_t *addrlen,
     return posix_api->accept4_fn(s, addr, addrlen, flags);
 }
 
-#define SIOCGIFADDR        0x8915
-static int get_addr(struct sockaddr_in *sin, char *interface)
-{
-    int sockfd = 0;
-    struct ifreq ifr;
-
-    if ((sockfd = posix_api->socket_fn(AF_INET, SOCK_STREAM, 0)) < 0) return -1;
-
-    memset_s(&ifr, sizeof(ifr), 0, sizeof(ifr));
-    snprintf_s(ifr.ifr_name, sizeof(ifr.ifr_name), (sizeof(ifr.ifr_name) - 1), "%s", interface);
-
-    if (posix_api->ioctl_fn(sockfd, SIOCGIFADDR, &ifr) < 0) {
-        posix_api->close_fn(sockfd);
-        return -1;
-    }
-    posix_api->close_fn(sockfd);
-
-    memcpy_s(sin, sizeof(struct sockaddr_in), &ifr.ifr_addr, sizeof(struct sockaddr_in));
-
-    return 0;
-}
-
 static int32_t do_bind(int32_t s, const struct sockaddr *name, socklen_t namelen)
 {
     if (name == NULL) {
@@ -229,55 +209,39 @@ static int32_t do_bind(int32_t s, const struct sockaddr *name, socklen_t namelen
 
 bool is_dst_ip_localhost(const struct sockaddr *addr)
 {
-    struct sockaddr_in *servaddr = (struct sockaddr_in *) addr;
-    char *line = NULL;
-    char *p;
-    size_t linel = 0;
-    int linenum = 0;
-    if (get_global_cfg_params()->host_addr.addr == servaddr->sin_addr.s_addr) {
-        return true;
-    }
+    struct ifaddrs *ifap;
+    struct ifaddrs *ifa;
 
-    FILE *ifh = fopen("/proc/net/dev", "r");
-    if (ifh == NULL) {
-        LSTACK_LOG(ERR, LSTACK, "failed to open /proc/net/dev, errno is %d\n", errno);
-        return false;
+    if (addr->sa_family == AF_INET) {
+        if (get_global_cfg_params()->host_addr.addr == ((struct sockaddr_in *)addr)->sin_addr.s_addr) {
+            return true;
+        }
     }
-    struct sockaddr_in* sin = malloc(sizeof(struct sockaddr_in));
-    if (sin == NULL) {
-        LSTACK_LOG(ERR, LSTACK, "sockaddr_in malloc failed\n");
-        fclose(ifh);
+
+    if (getifaddrs(&ifap) == -1) {
+        LSTACK_LOG(ERR, LSTACK, "get interface IP address failed\n");
         return false;
     }
 
-    while (getdelim(&line, &linel, '\n', ifh) > 0) {
-        /* 2: skip the first two lines, which are not nic name */
-        if (linenum++ < 2) {
+    for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+        if (ifa->ifa_addr == NULL) {
             continue;
         }
-
-        p = line;
-        while (isspace(*p)) {
-            ++p;
-        }
-        int n = strcspn(p, ": \t");
-
-        char interface[20] = {0}; /* 20: nic name len */
-        strncpy_s(interface, sizeof(interface), p, n);
-
-        memset_s(sin, sizeof(struct sockaddr_in), 0, sizeof(struct sockaddr_in));
-        int ret = get_addr(sin, interface);
-        if (ret == 0) {
-            if (sin->sin_addr.s_addr == servaddr->sin_addr.s_addr) {
-                free(sin);
-                fclose(ifh);
+        if (ifa->ifa_addr->sa_family == AF_INET && addr->sa_family == AF_INET) {
+            struct sockaddr_in *if_addr = (struct sockaddr_in *)ifa->ifa_addr;
+            if (memcmp(&if_addr->sin_addr, &((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr)) == 0) {
+                freeifaddrs(ifap);
+                return true;
+            }
+        } else if (ifa->ifa_addr->sa_family == AF_INET6 && addr->sa_family == AF_INET6) {
+            struct sockaddr_in6 *if_addr = (struct sockaddr_in6 *)ifa->ifa_addr;
+            if (memcmp(&if_addr->sin6_addr, &((struct sockaddr_in6 *)addr)->sin6_addr, sizeof(struct in6_addr)) == 0) {
+                freeifaddrs(ifap);
                 return true;
             }
         }
     }
-    free(sin);
-    fclose(ifh);
-
+    freeifaddrs(ifap);
     return false;
 }
 
@@ -303,11 +267,15 @@ static int32_t do_connect(int32_t s, const struct sockaddr *name, socklen_t name
     }
 
     int32_t ret = 0;
+    int32_t remote_port;
+    bool is_local = is_dst_ip_localhost(name);
+    
+    remote_port = htons(((struct sockaddr_in *)name)->sin_port);
+
     char listen_ring_name[RING_NAME_LEN];
-    int remote_port = htons(((struct sockaddr_in *)name)->sin_port);
     snprintf_s(listen_ring_name, sizeof(listen_ring_name), sizeof(listen_ring_name) - 1,
         "listen_rx_ring_%d", remote_port);
-    if (is_dst_ip_localhost(name) && rte_ring_lookup(listen_ring_name) == NULL) {
+    if (is_local && rte_ring_lookup(listen_ring_name) == NULL) {
         ret = posix_api->connect_fn(s, name, namelen);
         SET_CONN_TYPE_HOST(sock->conn);
     } else {
@@ -403,6 +371,7 @@ static inline int32_t do_socket(int32_t domain, int32_t type, int32_t protocol)
     }
 
     if ((domain != AF_INET && domain != AF_UNSPEC) ||
+        ((domain == AF_INET6) && !get_global_cfg_params()->ipv6_enable) ||
         ((type & SOCK_DGRAM) && !get_global_cfg_params()->udp_enable)) {
         return posix_api->socket_fn(domain, type, protocol);
     }
diff --git a/src/lstack/core/lstack_cfg.c b/src/lstack/core/lstack_cfg.c
index 729dccb..9f3143f 100644
--- a/src/lstack/core/lstack_cfg.c
+++ b/src/lstack/core/lstack_cfg.c
@@ -46,6 +46,7 @@ static struct cfg_params g_config_params;
 static config_t g_config;
 
 static int32_t parse_host_addr(void);
+static int32_t parse_host_addr6(void);
 static int32_t parse_low_power_mode(void);
 static int32_t parse_stack_cpu_number(void);
 static int32_t parse_app_bind_numa(void);
@@ -75,6 +76,7 @@ static int32_t parse_bond_mode(void);
 static int32_t parse_bond_slave_mac(void);
 static int32_t parse_use_sockmap(void);
 static int32_t parse_udp_enable(void);
+static int32_t parse_ipv6_enable(void);
 static int32_t parse_nic_rxqueue_size(void);
 static int32_t parse_nic_txqueue_size(void);
 static int32_t parse_stack_thread_mode(void);
@@ -107,6 +109,7 @@ struct config_vector_t {
 
 static struct config_vector_t g_config_tbl[] = {
     { "host_addr",    parse_host_addr },
+    { "host_addr6",    parse_host_addr6 },
     { "gateway_addr", parse_gateway_addr },
     { "mask_addr",    parse_mask_addr },
     { "use_ltran",    parse_use_ltran },
@@ -136,6 +139,7 @@ static struct config_vector_t g_config_tbl[] = {
     { "bond_slave_mac", parse_bond_slave_mac },
     { "use_sockmap", parse_use_sockmap },
     { "udp_enable", parse_udp_enable },
+    { "ipv6_enable", parse_ipv6_enable },
     { "nic_rxqueue_size", parse_nic_rxqueue_size},
     { "nic_txqueue_size", parse_nic_txqueue_size},
     { "stack_thread_mode", parse_stack_thread_mode },
@@ -221,15 +225,29 @@ static int32_t parse_host_addr(void)
     if (g_config_params.host_addr.addr == INADDR_NONE) {
         return -EINVAL;
     }
+    return 0;
+}
 
+static int32_t parse_host_addr6(void)
+{
+    char *value = NULL;
+    bool ok;
+
+    ok = config_lookup_string(&g_config, "host_addr6", (const char **)&value);
+    if (!ok) {
+        return 0;
+    }
+
+    if (ip6addr_aton(value, &g_config_params.host_addr6) == 0) {
+        return -EINVAL;
+    }
     return 0;
 }
 
 int32_t match_host_addr(uint32_t addr)
 {
     /* network byte order */
-    if (addr == g_config_params.host_addr.addr ||
-        addr == INADDR_ANY) {
+    if (addr == g_config_params.host_addr.addr || addr == INADDR_ANY) {
         return 1;
     }
     return 0;
@@ -1251,3 +1269,10 @@ static int32_t parse_nic_vlan_mode(void)
     }
     return ret;
 }
+
+static int32_t parse_ipv6_enable(void)
+{
+    int32_t ret;
+    PARSE_ARG(g_config_params.ipv6_enable, "ipv6_enable", 0, 0, 1, ret);
+    return ret;
+}
diff --git a/src/lstack/core/lstack_control_plane.c b/src/lstack/core/lstack_control_plane.c
index be156dc..f5049e9 100644
--- a/src/lstack/core/lstack_control_plane.c
+++ b/src/lstack/core/lstack_control_plane.c
@@ -355,15 +355,13 @@ static int32_t reg_conn(enum tcp_list_state table_state, enum reg_ring_type reg_
         if (conn->conn_list[i].state != table_state) {
             continue;
         }
-
         qtuple.protocol = 0;
         qtuple.src_ip = conn->conn_list[i].lip;
         qtuple.src_port = lwip_htons(conn->conn_list[i].l_port);
         qtuple.dst_ip = conn->conn_list[i].rip;
         qtuple.dst_port = lwip_htons(conn->conn_list[i].r_port);
 
-        if ((table_state == LISTEN_LIST) &&
-            (!match_host_addr(qtuple.src_ip))) {
+        if ((table_state == LISTEN_LIST) && (!match_host_addr(qtuple.src_ip))) {
             continue;
         }
 
diff --git a/src/lstack/core/lstack_dpdk.c b/src/lstack/core/lstack_dpdk.c
index 0776e50..6700357 100644
--- a/src/lstack/core/lstack_dpdk.c
+++ b/src/lstack/core/lstack_dpdk.c
@@ -763,20 +763,33 @@ int32_t init_dpdk_ethdev(void)
     return 0;
 }
 
-bool port_in_stack_queue(uint32_t src_ip, uint32_t dst_ip, uint16_t src_port, uint16_t dst_port)
+bool port_in_stack_queue(ip_addr_t src_ip, ip_addr_t dst_ip, uint16_t src_port, uint16_t dst_port)
 {
     struct protocol_stack_group *stack_group = get_protocol_stack_group();
     if (stack_group->reta_mask == 0 || stack_group->nb_queues <= 1) {
         return true;
     }
 
-    struct rte_ipv4_tuple tuple = {0};
-    tuple.src_addr = rte_be_to_cpu_32(src_ip);
-    tuple.dst_addr = rte_be_to_cpu_32(dst_ip);
-    tuple.sport = src_port;
-    tuple.dport = dst_port;
-
-    uint32_t hash = rte_softrss((uint32_t *)&tuple, RTE_THASH_V4_L4_LEN, g_default_rss_key);
+    union rte_thash_tuple tuple;
+    uint32_t hash = 0;
+    if (IP_IS_V4_VAL(src_ip)) {
+        tuple.v4.src_addr = rte_be_to_cpu_32(ip_2_ip4(&src_ip)->addr);
+        tuple.v4.dst_addr = rte_be_to_cpu_32(ip_2_ip4(&dst_ip)->addr);
+        tuple.v4.sport = src_port;
+        tuple.v4.dport = dst_port;
+        hash = rte_softrss((uint32_t *)&tuple, RTE_THASH_V4_L4_LEN, g_default_rss_key);
+    } else {
+        int i;
+        for (i = 0; i < 4; i++) {
+            *((uint32_t *)tuple.v6.src_addr + i) =
+                rte_be_to_cpu_32(*((const uint32_t *)src_ip.u_addr.ip6.addr + i));
+            *((uint32_t *)tuple.v6.dst_addr + i) =
+                rte_be_to_cpu_32(*((const uint32_t *)dst_ip.u_addr.ip6.addr + i));
+        }
+        tuple.v6.sport = src_port;
+        tuple.v6.dport = dst_port;
+        hash = rte_softrss((uint32_t *)&tuple, RTE_THASH_V6_L4_LEN, g_default_rss_key);
+    }
 
     uint32_t reta_index = hash & stack_group->reta_mask;
 
diff --git a/src/lstack/core/lstack_lwip.c b/src/lstack/core/lstack_lwip.c
index 3baddec..c8b4e8f 100644
--- a/src/lstack/core/lstack_lwip.c
+++ b/src/lstack/core/lstack_lwip.c
@@ -123,7 +123,7 @@ static struct pbuf *init_mbuf_to_pbuf(struct rte_mbuf *mbuf, pbuf_layer layer, u
         pbuf->allow_in = 1;
         pbuf->head = 0;
         pbuf->last = pbuf;
-        pbuf->addr.addr = 0;
+        pbuf->addr = *IP_ANY_TYPE;
         pbuf->port = 0;
         pthread_spin_init(&pbuf->pbuf_lock, PTHREAD_PROCESS_SHARED);
     }
@@ -441,10 +441,21 @@ static inline ssize_t app_buff_write(struct lwip_sock *sock, void *buf, size_t l
     ssize_t send_len = do_app_write(pbufs, buf, len, write_num);
 
     if (addr) {
-        struct sockaddr_in *saddr = (struct sockaddr_in *)addr;
-        for (int i = 0; i < write_num; i++) {
-            pbufs[i]->addr.addr = saddr->sin_addr.s_addr;
-            pbufs[i]->port = lwip_ntohs((saddr)->sin_port);
+        if (addr->sa_family == AF_INET) {
+            struct sockaddr_in *saddr = (struct sockaddr_in *)addr;
+            for (int i = 0; i < write_num; i++) {
+                pbufs[i]->addr.u_addr.ip4.addr = saddr->sin_addr.s_addr;
+                pbufs[i]->port = lwip_ntohs((saddr)->sin_port);
+            }
+        } else if (addr->sa_family == AF_INET6) {
+            struct sockaddr_in6 *saddr = (struct sockaddr_in6 *)addr;
+            for (int i = 0; i < write_num; i++) {
+                memcpy_s(pbufs[i]->addr.u_addr.ip6.addr, sizeof(pbufs[i]->addr.u_addr.ip6.addr),
+                    saddr->sin6_addr.s6_addr, sizeof(saddr->sin6_addr.s6_addr));
+                pbufs[i]->port = lwip_ntohs((saddr)->sin6_port);
+            }
+        } else {
+            return 0;
         }
     }
 
@@ -573,10 +584,15 @@ static ssize_t do_lwip_fill_sendring(struct lwip_sock *sock, const void *buf, si
             if (wakeup) {
                 wakeup->stat.app_write_cnt += write_num;
             }
-            if (addr) {
+            if (addr->sa_family == AF_INET) {
                 struct sockaddr_in *saddr = (struct sockaddr_in *)addr;
-                last_pbuf->addr.addr = saddr->sin_addr.s_addr;
+                last_pbuf->addr.u_addr.ip4.addr = saddr->sin_addr.s_addr;
                 last_pbuf->port = lwip_ntohs((saddr)->sin_port);
+            } else if (addr->sa_family == AF_INET6) {
+                struct sockaddr_in6 *saddr = (struct sockaddr_in6 *)addr;
+                memcpy_s(last_pbuf->addr.u_addr.ip6.addr, sizeof(last_pbuf->addr.u_addr.ip6.addr),
+                    saddr->sin6_addr.s6_addr, sizeof(saddr->sin6_addr.s6_addr));
+                last_pbuf->port = lwip_ntohs((saddr)->sin6_port);
             }
         } else {
             (void)rpc_call_replenish(stack, sock);
@@ -1122,8 +1138,8 @@ static void copy_pcb_to_conn(struct gazelle_stat_lstack_conn_info *conn, const s
 {
     struct netconn *netconn = (struct netconn *)pcb->callback_arg;
 
-    conn->lip = pcb->local_ip.addr;
-    conn->rip = pcb->remote_ip.addr;
+    conn->lip = ip_2_ip4(&pcb->local_ip)->addr;
+    conn->rip = ip_2_ip4(&pcb->remote_ip)->addr;
     conn->l_port = pcb->local_port;
     conn->r_port = pcb->remote_port;
     conn->in_send = pcb->snd_queuelen;
@@ -1173,7 +1189,7 @@ void do_lwip_clone_sockopt(struct lwip_sock *dst_sock, struct lwip_sock *src_soc
 
 int32_t do_lwip_socket(int domain, int type, int protocol)
 {
-    int32_t fd = lwip_socket(AF_INET, type, 0);
+    int32_t fd = lwip_socket(domain, type, 0);
     if (fd < 0) {
         return fd;
     }
@@ -1216,7 +1232,7 @@ uint32_t do_lwip_get_conntable(struct gazelle_stat_lstack_conn_info *conn,
     for (struct tcp_pcb_listen *pcbl = tcp_listen_pcbs.listen_pcbs; pcbl != NULL && conn_num < max_num;
         pcbl = pcbl->next) {
         conn[conn_num].state = LISTEN_LIST;
-        conn[conn_num].lip = pcbl->local_ip.addr;
+        conn[conn_num].lip = ip_2_ip4(&pcbl->local_ip)->addr;
         conn[conn_num].l_port = pcbl->local_port;
         conn[conn_num].tcp_sub_state = pcbl->state;
         struct netconn *netconn = (struct netconn *)pcbl->callback_arg;
diff --git a/src/lstack/core/lstack_protocol_stack.c b/src/lstack/core/lstack_protocol_stack.c
index 74a17d4..54cf9e8 100644
--- a/src/lstack/core/lstack_protocol_stack.c
+++ b/src/lstack/core/lstack_protocol_stack.c
@@ -936,10 +936,11 @@ void stack_create_shadow_fd(struct rpc_msg *msg)
         return;
     }
 
+    int domain = addr->sa_family;
     if (NETCONN_IS_UDP(sock)) {
-        clone_fd = do_lwip_socket(AF_INET, SOCK_DGRAM, 0);
+        clone_fd = do_lwip_socket(domain, SOCK_DGRAM, 0);
     } else {
-        clone_fd = do_lwip_socket(AF_INET, SOCK_STREAM, 0);
+        clone_fd = do_lwip_socket(domain, SOCK_STREAM, 0);
     }
 
     if (clone_fd < 0) {
diff --git a/src/lstack/include/lstack_cfg.h b/src/lstack/include/lstack_cfg.h
index a7b99af..e3edc57 100644
--- a/src/lstack/include/lstack_cfg.h
+++ b/src/lstack/include/lstack_cfg.h
@@ -68,6 +68,7 @@ struct cfg_nic_params {
 
 struct cfg_params {
     ip4_addr_t host_addr;
+    ip6_addr_t host_addr6;
     ip4_addr_t netmask;
     ip4_addr_t gateway_addr;
     uint8_t mac_addr[ETHER_ADDR_LEN];
@@ -116,6 +117,7 @@ struct cfg_params {
     struct rte_ether_addr bond_slave_mac_addr[GAZELLE_MAX_BOND_NUM];
     bool use_sockmap;
     bool udp_enable;
+    bool ipv6_enable;
     struct cfg_nic_params nic;
     bool stack_mode_rtc;
 };
diff --git a/src/lstack/include/lstack_dpdk.h b/src/lstack/include/lstack_dpdk.h
index 1a054d6..3a621d0 100644
--- a/src/lstack/include/lstack_dpdk.h
+++ b/src/lstack/include/lstack_dpdk.h
@@ -13,6 +13,7 @@
 #ifndef _GAZELLE_DPDK_H_
 #define _GAZELLE_DPDK_H_
 
+#include <lwip/ip_addr.h>
 #include "gazelle_opt.h"
 #include "gazelle_dfx_msg.h"
 
@@ -53,7 +54,7 @@ int dpdk_ethdev_start(void);
 void dpdk_skip_nic_init(void);
 int32_t dpdk_init_lstack_kni(void);
 void dpdk_restore_pci(void);
-bool port_in_stack_queue(uint32_t src_ip, uint32_t dst_ip, uint16_t src_port, uint16_t dst_port);
+bool port_in_stack_queue(ip_addr_t src_ip, ip_addr_t dst_ip, uint16_t src_port, uint16_t dst_port);
 uint16_t get_port_id(void);
 struct rte_mempool *create_pktmbuf_mempool(const char *name, uint32_t nb_mbuf,
                                            uint32_t mbuf_cache_size, uint16_t queue_id, unsigned numa_id);
diff --git a/src/lstack/netif/lstack_ethdev.c b/src/lstack/netif/lstack_ethdev.c
index 6914cff..02aa611 100644
--- a/src/lstack/netif/lstack_ethdev.c
+++ b/src/lstack/netif/lstack_ethdev.c
@@ -16,9 +16,11 @@
 #include <rte_kni.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
+#include <rte_ether.h>
 
 #include <lwip/debug.h>
 #include <lwip/etharp.h>
+#include <lwip/ethip6.h>
 #include <lwip/posix_api.h>
 #include <netif/ethernet.h>
 #include <lwip/tcp.h>
@@ -664,57 +666,92 @@ void concat_mbuf_and_queue_id(struct rte_mbuf *mbuf, uint16_t queue_id,
     sprintf_s(mbuf_and_queue_id, write_len, "%lu%s%u", mbuf, SPLIT_DELIM, queue_id);
 }
 
-int distribute_pakages(struct rte_mbuf *mbuf)
-{
-    struct rte_ipv4_hdr *iph = rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr));
-    uint8_t ip_version = (iph->version_ihl & 0xf0) >> IPV4_VERSION_OFFSET;
-    if (likely(ip_version == IPV4_VERSION)) {
-        if (likely(iph->next_proto_id == IPPROTO_TCP)) {
-            int each_process_queue_num = get_global_cfg_params()->num_queue;
-
-            struct rte_tcp_hdr *tcp_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_tcp_hdr *,
-                sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr));
-            uint16_t dst_port = tcp_hdr->dst_port;
-            uint32_t user_process_idx;
-
-            if (g_listen_ports[dst_port] != INVAILD_PROCESS_IDX) {
-                user_process_idx = g_listen_ports[dst_port];
-            } else {
-                user_process_idx = g_user_ports[dst_port];
+static int mbuf_to_idx(struct rte_mbuf *mbuf, uint16_t *dst_port)
+{
+    struct rte_ether_hdr *ethh = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr *);
+    u16_t type  = rte_be_to_cpu_16(ethh->ether_type);
+    uint32_t index = 0;
+    if (type == RTE_ETHER_TYPE_IPV4) {
+        struct rte_ipv4_hdr *iph = rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr));
+        uint8_t ip_version = (iph->version_ihl & 0xf0) >> IPV4_VERSION_OFFSET;
+        if (likely(ip_version == IPV4_VERSION)) {
+            if (likely(iph->next_proto_id == IPPROTO_TCP)) {
+                struct rte_tcp_hdr *tcp_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_tcp_hdr *,
+                    sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr));
+                *dst_port = tcp_hdr->dst_port;
+
+                if (unlikely(tcp_hdr->tcp_flags == TCP_SYN)) {
+                    uint32_t src_ip = iph->src_addr;
+                    uint16_t src_port = tcp_hdr->src_port;
+                    index = rte_jhash_3words(src_ip, src_port | ((*dst_port) << 16), 0, 0);
+                } else {
+                    return -1;
+                }
             }
+        }
+    } else if (type == RTE_ETHER_TYPE_IPV6) {
+        struct rte_ipv6_hdr *iph = rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv6_hdr *, sizeof(struct rte_ether_hdr));
+        if (likely(iph->proto == IPPROTO_TCP)) {
+            struct rte_tcp_hdr *tcp_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_tcp_hdr *,
+                sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv6_hdr));
+            *dst_port = tcp_hdr->dst_port;
 
-            if (user_process_idx == INVAILD_PROCESS_IDX) {
-                return TRANSFER_KERNEL;
-            }
             if (unlikely(tcp_hdr->tcp_flags == TCP_SYN)) {
-                uint32_t src_ip = iph->src_addr;
+                uint32_t *src_ip = (uint32_t *) &iph->src_addr;
                 uint16_t src_port = tcp_hdr->src_port;
-                uint32_t index = rte_jhash_3words(src_ip, src_port | ((dst_port) << 16), 0, 0);
-                index = index % each_process_queue_num;
-                uint16_t queue_id = 0;
-                if (get_global_cfg_params()->seperate_send_recv) {
-                    queue_id = user_process_idx * each_process_queue_num + (index / 2) * 2;
-                } else {
-                    queue_id = user_process_idx * each_process_queue_num + index;
-                }
-                if (queue_id != 0) {
-                    if (user_process_idx == 0) {
-                        transfer_tcp_to_thread(mbuf, queue_id);
-                    } else {
-                        char mbuf_and_queue_id[TRANSFER_TCP_MUBF_LEN];
-                        concat_mbuf_and_queue_id(mbuf, queue_id, mbuf_and_queue_id, TRANSFER_TCP_MUBF_LEN);
-                        transfer_pkt_to_other_process(mbuf_and_queue_id, user_process_idx,
-                            TRANSFER_TCP_MUBF_LEN, false);
-                    }
-                    return TRANSFER_OTHER_THREAD;
-                } else {
-                    return TRANSFER_CURRENT_THREAD;
-                }
+                uint32_t v = rte_jhash_3words(src_ip[0], src_ip[1], src_ip[2], 0);
+                index = rte_jhash_3words(src_ip[3], src_port | ((*dst_port) << 16), v, 0);
             } else {
-                return TRANSFER_CURRENT_THREAD;
+                return -1;
             }
         }
+    } else {
+        return -1;
+    }
+    return index;
+}
+
+int distribute_pakages(struct rte_mbuf *mbuf)
+{
+    uint16_t dst_port = 0;
+    uint32_t index = mbuf_to_idx(mbuf, &dst_port);
+    if (index == -1) {
+        return TRANSFER_CURRENT_THREAD;
+    }
+
+    uint16_t queue_id = 0;
+    uint32_t user_process_idx = 0;
+    int each_process_queue_num = get_global_cfg_params()->num_queue;
+    index = index % each_process_queue_num;
+    if (g_listen_ports[dst_port] != INVAILD_PROCESS_IDX) {
+        user_process_idx = g_listen_ports[dst_port];
+    } else {
+        user_process_idx = g_user_ports[dst_port];
+    }
+
+    if (user_process_idx == INVAILD_PROCESS_IDX) {
+        return TRANSFER_KERNEL;
+    }
+
+    if (get_global_cfg_params()->seperate_send_recv) {
+        queue_id = user_process_idx * each_process_queue_num + (index / 2) * 2;
+    } else {
+        queue_id = user_process_idx * each_process_queue_num + index;
+    }
+    if (queue_id != 0) {
+        if (user_process_idx == 0) {
+            transfer_tcp_to_thread(mbuf, queue_id);
+        } else {
+            char mbuf_and_queue_id[TRANSFER_TCP_MUBF_LEN];
+            concat_mbuf_and_queue_id(mbuf, queue_id, mbuf_and_queue_id, TRANSFER_TCP_MUBF_LEN);
+            transfer_pkt_to_other_process(mbuf_and_queue_id, user_process_idx,
+                TRANSFER_TCP_MUBF_LEN, false);
+        }
+        return TRANSFER_OTHER_THREAD;
+    } else {
+        return TRANSFER_CURRENT_THREAD;
     }
+    
     return TRANSFER_KERNEL;
 }
 
@@ -874,10 +911,11 @@ static err_t eth_dev_init(struct netif *netif)
 
     netif->name[0] = 'e';
     netif->name[1] = 't';
-    netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP;
+    netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP | NETIF_FLAG_MLD6;
     netif->mtu = FRAME_MTU;
     netif->output = etharp_output;
     netif->linkoutput = eth_dev_output;
+    netif->output_ip6 = ethip6_output;
 
     int32_t ret;
     ret = memcpy_s(netif->hwaddr, sizeof(netif->hwaddr), cfg->mac_addr, ETHER_ADDR_LEN);
@@ -914,11 +952,20 @@ int32_t ethdev_init(struct protocol_stack *stack)
 
     netif_set_default(&stack->netif);
 
-    struct netif *netif = netif_add(&stack->netif, &cfg->host_addr, &cfg->netmask, &cfg->gateway_addr, NULL,
-        eth_dev_init, ethernet_input);
+    struct netif *netif;
+    if (!ip4_addr_isany(&cfg->host_addr)) {
+        netif = netif_add(&stack->netif, &cfg->host_addr, &cfg->netmask,
+            &cfg->gateway_addr, NULL, eth_dev_init, ethernet_input);
+    } else {
+        netif = netif_add(&stack->netif, NULL, NULL, NULL, NULL, eth_dev_init, ethernet_input);
+    }
     if (netif == NULL) {
         LSTACK_LOG(ERR, LSTACK, "netif_add failed\n");
-        return ERR_IF;
+	return ERR_IF;
+    }
+    if (!ip6_addr_isany(&cfg->host_addr6)) {
+        netif_ip6_addr_set(&stack->netif, 0, &cfg->host_addr6);
+	netif_ip6_addr_set_state(&stack->netif, 0, IP6_ADDR_VALID);
     }
 
     netif_set_link_up(&stack->netif);
diff --git a/src/lstack/netif/lstack_vdev.c b/src/lstack/netif/lstack_vdev.c
index 4a93f87..d57ce59 100644
--- a/src/lstack/netif/lstack_vdev.c
+++ b/src/lstack/netif/lstack_vdev.c
@@ -90,24 +90,34 @@ static uint32_t vdev_rx_poll(struct protocol_stack *stack, struct rte_mbuf **pkt
 
     for (uint32_t i = 0; i < pkt_num; i++) {
         struct rte_ether_hdr *ethh = rte_pktmbuf_mtod(pkts[i], struct rte_ether_hdr *);
+        u16_t type  = ethh->ether_type;
 
-        if (unlikely(RTE_BE16(RTE_ETHER_TYPE_IPV4) != ethh->ether_type)) {
-            continue;
-        }
         pkts[i]->l2_len = sizeof(struct rte_ether_hdr);
 
-        struct rte_ipv4_hdr *iph = rte_pktmbuf_mtod_offset(pkts[i], struct rte_ipv4_hdr *,
-            sizeof(struct rte_ether_hdr));
-        if (unlikely((iph->version_ihl & IPV4_MASK) != IPV4_VERION)) {
-            continue;
-        }
-        pkts[i]->l3_len = sizeof(struct rte_ipv4_hdr);
+        if (type == RTE_BE16(RTE_ETHER_TYPE_IPV4)) {
+            struct rte_ipv4_hdr *iph = rte_pktmbuf_mtod_offset(pkts[i], struct rte_ipv4_hdr *,
+                sizeof(struct rte_ether_hdr));
+            if (unlikely((iph->version_ihl & IPV4_MASK) != IPV4_VERION)) {
+                continue;
+            }
+            pkts[i]->l3_len = sizeof(struct rte_ipv4_hdr);
 
-        struct rte_tcp_hdr *tcp_hdr = rte_pktmbuf_mtod_offset(pkts[i], struct rte_tcp_hdr *,
-            sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr));
-        pkts[i]->l4_len = TCP_HDR_LEN(tcp_hdr);
+            struct rte_tcp_hdr *tcp_hdr = rte_pktmbuf_mtod_offset(pkts[i], struct rte_tcp_hdr *,
+                sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr));
+            pkts[i]->l4_len = TCP_HDR_LEN(tcp_hdr);
 
-        pkts[i]->packet_type = RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_TCP;
+            pkts[i]->packet_type = RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_TCP;
+        } else if (type == RTE_BE16(RTE_ETHER_TYPE_IPV6)) {
+            pkts[i]->l3_len = sizeof(struct rte_ipv6_hdr);
+
+            struct rte_tcp_hdr *tcp_hdr = rte_pktmbuf_mtod_offset(pkts[i], struct rte_tcp_hdr *,
+                sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv6_hdr));
+            pkts[i]->l4_len = TCP_HDR_LEN(tcp_hdr);
+
+            pkts[i]->packet_type = RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L4_TCP;
+        } else {
+            continue;
+        }
     }
     pkt_num =  rte_gro_reassemble_burst(pkts, pkt_num, &gro_param);
 
diff --git a/src/ltran/ltran_timer.c b/src/ltran/ltran_timer.c
index 85ea324..749b8e0 100644
--- a/src/ltran/ltran_timer.c
+++ b/src/ltran/ltran_timer.c
@@ -24,6 +24,14 @@
 #include "ltran_tcp_conn.h"
 #include "ltran_instance.h"
 #include "ltran_timer.h"
+/* undefine lwip_ntohs in lwip/def.h */
+#ifdef ntohs
+#undef ntohs
+#endif
+#ifdef htons
+#undef htons
+#endif
+
 
 static uint64_t g_cycles_per_us = 0;
 
-- 
2.27.0

